pax_global_header00006660000000000000000000000064125721146210014513gustar00rootroot0000000000000052 comment=cf1ba60b676b3300e9c9554a20c696bec49d7f80 rtorrent-0.9.6/000077500000000000000000000000001257211462100134065ustar00rootroot00000000000000rtorrent-0.9.6/.gitignore000066400000000000000000000014451257211462100154020ustar00rootroot00000000000000# Compiled source # ################### *.o *.lo *.a *.la *.so *.in *.sub *.pc *.orig *.rej # Autoconf files # ################## .deps .libs Makefile aclocal.m4 autom4te.cache compile config.h config.guess config.status confdefs.h conftest.dir configure depcomp install-sh libtool ltmain.sh missing stamp-h1 scripts/libtool.m4 scripts/lt*.m4 # Editor poo # ############## .#* \#*# *~ # Packages # ############ # it's better to unpack these files and commit the raw source # git has its own built in compression methods *.gz *.tar *.zip # Logs and databases # ###################### *.log # OS generated files # ###################### .DS_Store? ehthumbs.db Icon? Thumbs.db TAGS # rTorrent specific files ########################### src/rtorrent test/rtorrentTest test-driver test/rtorrentTest.trs rtorrent-0.9.6/AUTHORS000066400000000000000000000000401257211462100144500ustar00rootroot00000000000000Jari Sundell rtorrent-0.9.6/COPYING000066400000000000000000000431101257211462100144400ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. rtorrent-0.9.6/ChangeLog000066400000000000000000000000001257211462100151460ustar00rootroot00000000000000rtorrent-0.9.6/INSTALL000066400000000000000000000220241257211462100144370ustar00rootroot00000000000000Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. 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 only 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. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. 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. 4. Type `make install' to install the programs and any data files and documentation. 5. 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. 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=c89 CFLAGS=-O2 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 must use a version of `make' that supports the `VPATH' variable, such as 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 `..'. If you have to use a `make' that does not support the `VPATH' variable, you have 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. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' 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. 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'. Optional Features ================= 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. 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 `--target=TYPE' option 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 will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--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. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. rtorrent-0.9.6/Makefile.am000066400000000000000000000010021257211462100154330ustar00rootroot00000000000000SUBDIRS = \ doc \ src \ test EXTRA_DIST= \ autogen.sh \ rak/address_info.h \ rak/algorithm.h \ rak/allocators.h \ rak/error_number.h \ rak/file_stat.h \ rak/fs_stat.h \ rak/functional.h \ rak/functional_fun.h \ rak/path.h \ rak/partial_queue.h \ rak/priority_queue.h \ rak/priority_queue_default.h \ rak/regex.h \ rak/socket_address.h \ rak/string_manip.h \ rak/timer.h \ rak/unordered_vector.h \ scripts/checks.m4 \ scripts/common.m4 \ scripts/attributes.m4 ACLOCAL_AMFLAGS = -I scripts rtorrent-0.9.6/NEWS000066400000000000000000000000001257211462100140730ustar00rootroot00000000000000rtorrent-0.9.6/README000066400000000000000000000021401257211462100142630ustar00rootroot00000000000000BUILDING Run "./autogen.sh" to generate the configure scripts if nessesary. The man page "doc/rtorrent.1" must be generated with "docbook2man rtorrent.1.xml" if it is missing. Note that rtorrent follows the development of libtorrent closely, and thus the versions must be in sync. This should not be nessesary in the future, when the library API stabilizes. USAGE See the man page or website for instructions. LICENSE GNU GPL, see COPYING. "libtorrent/src/utils/sha_fast.{cc,h}" is originally from the Mozilla NSS and is under a triple license; MPL, LGPL and GPL. An exception to non-NSS code has been added for linking to OpenSSL as requested by Debian, though the author considers that library to be part of the Operative System and thus linking is allowed according to the GPL. Use whatever fits your purpose, the code required to compile with Mozilla's NSS implementation of SHA1 has been retained and can be compiled if the user wishes to avoid using OpenSSL. DEPENDENCIES libcurl >= 7.12.0 ncurses CONTACT Send bug reports, suggestions and patches to or to the mailinglist. rtorrent-0.9.6/autogen.sh000077500000000000000000000020131257211462100154030ustar00rootroot00000000000000#! /bin/sh echo aclocal... (aclocal --version) < /dev/null > /dev/null 2>&1 || { echo aclocal not found exit 1 } aclocal -I ./scripts -I . ${ACLOCAL_FLAGS} || exit 1 echo autoheader... (autoheader --version) < /dev/null > /dev/null 2>&1 || { echo autoheader not found exit 1 } autoheader || exit 1 echo -n "libtoolize... " if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then echo "using glibtoolize" glibtoolize --automake --copy --force || exit 1 elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then echo "using libtoolize" libtoolize --automake --copy --force || exit 1 else echo "libtoolize nor glibtoolize not found" exit 1 fi echo automake... (automake --version) < /dev/null > /dev/null 2>&1 || { echo automake not found exit 1 } automake --add-missing --copy --gnu || exit 1 echo autoconf... (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo autoconf not found exit 1 } autoconf || exit 1 echo ready to configure exit 0 rtorrent-0.9.6/configure.ac000066400000000000000000000034671257211462100157060ustar00rootroot00000000000000AC_INIT(rtorrent, 0.9.6, sundell.software@gmail.com) AC_DEFINE(API_VERSION, 9, api version) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS(config.h) AM_PATH_CPPUNIT(1.9.6) AC_PROG_CXX AC_PROG_LIBTOOL TORRENT_CHECK_CXXFLAGS() TORRENT_ENABLE_DEBUG() TORRENT_ENABLE_EXTRA_DEBUG() TORRENT_ENABLE_WERROR() TORRENT_ENABLE_TR1() TORRENT_ENABLE_CXX11() TORRENT_DISABLE_IPV6 AC_SYS_LARGEFILE TORRENT_CHECK_EXECINFO() TORRENT_OTFD() TORRENT_ENABLE_ARCH TORRENT_WITH_SYSROOT TORRENT_WITHOUT_VARIABLE_FDSET() TORRENT_WITHOUT_STATVFS() TORRENT_WITHOUT_STATFS() AX_PTHREAD([], AC_MSG_ERROR([requires pthread])) AX_WITH_CURSES() if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then AC_MSG_ERROR([requires either NcursesW or Ncurses library]) fi CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS" CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS" LIBS="$PTHREAD_LIBS $CURSES_LIB $LIBS" PKG_CHECK_MODULES([libcurl], libcurl >= 7.15.4, CXXFLAGS="$CXXFLAGS $libcurl_CFLAGS"; LIBS="$LIBS $libcurl_LIBS") PKG_CHECK_MODULES([libtorrent], libtorrent >= 0.13.6, CXXFLAGS="$CXXFLAGS $libtorrent_CFLAGS"; LIBS="$LIBS $libtorrent_LIBS") AC_LANG_PUSH(C++) TORRENT_WITH_XMLRPC_C AC_LANG_POP(C++) AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included) AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent) AC_CHECK_FUNCS(posix_memalign) TORRENT_CHECK_CACHELINE() TORRENT_CHECK_POPCOUNT() CC_ATTRIBUTE_UNUSED( AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]), AC_DEFINE([__UNUSED], [], [Null-wrapper if unused attribute is unsupported]) ) AC_OUTPUT([ Makefile doc/Makefile src/Makefile src/core/Makefile src/display/Makefile src/input/Makefile src/rpc/Makefile src/ui/Makefile src/utils/Makefile test/Makefile ]) rtorrent-0.9.6/doc/000077500000000000000000000000001257211462100141535ustar00rootroot00000000000000rtorrent-0.9.6/doc/Makefile.am000066400000000000000000000000331257211462100162030ustar00rootroot00000000000000EXTRA_DIST= \ rtorrent.rc rtorrent-0.9.6/doc/debugging000066400000000000000000000007521257211462100160350ustar00rootroot00000000000000=== Dumping core files on mac == ulimit -c unlimited sysctl kern.corefile schedule = log_vmmap,5,600,"execute_nothrow=/Users/rakshasa/trunk/rtorrent/doc/log_vmmap.sh,\"$cat=/Users/rakshasa/Downloads/session/vmmap.system.,$system.pid="; log.vmmap.dump=\"$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid=\"" log.vmmap.dump="$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid=" print="$cat=/Users/rakshasa/Downloads/session/vmmap.rtorrent.,$system.pid=" rtorrent-0.9.6/doc/faq.xml000066400000000000000000000075511257211462100154540ustar00rootroot00000000000000
rTorrent Frequently Asked Questions This is the user FAQ for Rakshasa's BitTorrent client. RTorrent is an ncurses based client that uses libTorrent and is written in C++. Efficiency and good code is the main goal of both projects. How do I add new torrents while the client is running? Use the backspace key to enter file input mode. The bottom line will change into a prompt which allows you to enter URL's or file paths to torrents. File name completion and directory listing is supported with the tab key. I got the message "Could not create download, failed to parse the bencoded data" when adding a torrent, what does it mean? The torrent data the library received was not a valid torrent file. If this was a direct http download, try downloading the torrent file and add it manually. This usually happens when the torrent link uses some form of redirection that libcurl does not automatically redirect. If the failure still happens, make sure the file is infact an uncorrupted torrent. How does the session feature work? When you start the client you can use the "-s" switch to specify a session directory. The client will save all currently running torrents in the session directory and fast resume data will be written when the client exits. Upon restarting the client it will resume all the torrents in the session directory. How do i query the tracker for more peers? Go into the download view screen and press 't' to initiate a new tracker request. If the tracker requires a minimum timeout between requests you can override this by using the capital 'T'. Don't abuse this feature. Why do I sometimes need to press ctrl-Q twice to exit the client? The first time you press ctrl-q you initiate the shutdown. This causes rTorrent to send a stop message to the trackers of each torrent, and if the tracker is slow it might take more than a few seconds or until the requests time out. The second time ctrl-q is pressed forces the client to shutdown. It doesn't help how much i press ctrl-q, it still won't quit. Perhaps your terminal sends a different key-code to the application. There's no configuration files for keys yet, so modify rtorrent/src/ui/root.cc:56 to use whatever key you want for quitting. When I try downloading a torrent the client aborts (SIGABRT), what should I do? Make sure you arn't using "-fomit-frame-pointer" when compiling libtorrent and rtorrent, this is known to produce bad code for C++ exception handling. If this doesn't help, run the client in gdb and use "bt -20" to get a backtrace. Send this with a bug report.
rtorrent-0.9.6/doc/log_proc_vmmap.sh000077500000000000000000000000461257211462100175160ustar00rootroot00000000000000#!/bin/bash cat /proc/$PPID/maps > $1 rtorrent-0.9.6/doc/log_rtorrent.sh000077500000000000000000000000601257211462100172260ustar00rootroot00000000000000#!/bin/bash args=($@) echo "${args[@]:1}" >> $1 rtorrent-0.9.6/doc/log_stats.plot000077500000000000000000000175371257211462100170720ustar00rootroot00000000000000#/bin/bash gnuplot << EOF # 1) system.time_seconds= # # 2) throttle.global_up.rate # 3) throttle.global_up.total # 4) throttle.global_down.rate # 5) throttle.global_down.total # # 6) pieces.memory.current # 7) pieces.memory.sync_queue # 8) pieces.memory.block_count # 9) pieces.stats.total_size # 10) pieces.hash.queue_size # # file.append = (cat,/foo/bandwidth_stats.,(system.pid)),"timestamp","\"upload rate\"","\"upload total\"","\"download rate\"","\"download total\"","\"memory usage\"","\"sync queue\"","\"block count\"","\"total size\"","\"hash queue size\"" # schedule = log_bandwidth_stats,5,10,((file.append,((cat,/foo/bandwidth_stats.,((system.pid)))),((system.time_seconds)),((throttle.global_up.rate)),((throttle.global_up.total)),((throttle.global_down.rate)),((throttle.global_down.total)),((pieces.memory.current)),((pieces.memory.sync_queue)),((pieces.memory.block_count)),((pieces.stats.total_size)),((pieces.hash.queue_size)))) # # 1) system.time_seconds # # 2) throttle.unchoked_uploads # 3) throttle.unchoked_downloads # 4) network.open_sockets # # 5) view.size,leeching # 6) view.size,seeding # 7) view.size,active # # file.append = (cat,/foo/peer_stats.,(system.pid)),"timestamp","\"upload unchoked\"","\"download unchoked\"","\"open sockets\"","leeching","seeding","active" # schedule = log_peer_stats,5,10,((file.append,((cat,/foo/peer_stats.,((system.pid)))),((system.time_seconds)),((throttle.unchoked_uploads)),((throttle.unchoked_downloads)),((network.open_sockets)),((view.size,leeching)),((view.size,seeding)),((view.size,active)))) # # Choke groups: # # file.append = (cat,/foo/choke_group_stats.,(system.pid)),"timestamp",\ # "\"default up unchoked\"","\"default up queued\"","\"default up rate\"",\ # "\"default down unchoked\"","\"default down queued\"","\"default down rate\"","\"default torrents\"",\ # "\"leech up unchoked\"","\"leech up queued\"","\"leech up rate\"",\ # "\"leech down unchoked\"","\"leech down queued\"","\"leech down rate\"","\"leech torrents\"",\ # "\"seed boost up unchoked\"","\"seed boost up queued\"","\"seed boost up rate\"",\ # "\"seed boost down unchoked\"","\"seed boost down queued\"","\"seed boost down rate\"","\"seed boost torrents\"",\ # "\"seed up unchoked\"","\"seed up queued\"","\"seed up rate\"",\ # "\"seed down unchoked\"","\"seed down queued\"","\"seed down rate\"","\"seed torrents\"" # # schedule = log_choke_group_stats,5,10,((file.append,((cat,/foo/choke_group_stats.,((system.pid)))),((system.time_seconds)),\ # ((choke_group.up.unchoked,0)),((choke_group.up.queued,0)),((choke_group.up.rate,0)),((choke_group.down.unchoked,0)),((choke_group.down.queued,0)),((choke_group.down.rate,0)),((choke_group.size,0)),\ # ((choke_group.up.unchoked,1)),((choke_group.up.queued,1)),((choke_group.up.rate,1)),((choke_group.down.unchoked,1)),((choke_group.down.queued,1)),((choke_group.down.rate,1)),((choke_group.size,1)),\ # ((choke_group.up.unchoked,2)),((choke_group.up.queued,2)),((choke_group.up.rate,2)),((choke_group.down.unchoked,2)),((choke_group.down.queued,2)),((choke_group.down.rate,2)),((choke_group.size,2)),\ # ((choke_group.up.unchoked,3)),((choke_group.up.queued,3)),((choke_group.up.rate,3)),((choke_group.down.unchoked,3)),((choke_group.down.queued,3)),((choke_group.down.rate,3)),((choke_group.size,3)) )) # # Mincore stats: # # file.append = (cat,/foo/mincore_stats.,(system.pid)),"timestamp","\"incore cont. /10s\"","\"not incore cont. /10s\"","\"incore new /10s\"","\"not incore new /10s\"","\"incore break /10s\"","\"sync success /10s\"","\"sync failed /10s\"","\"sync not synced /10s\"","\"sync not deallocated /10s\"","\"alloc failed /10s\"","\"allocate velocity /10s\"","\"deallocate velocity /10s\"" # log.libtorrent = mincore_stats,(cat,"/foo/mincore_stats.",(system.pid)) set terminal png size 1024,768 enhanced #set terminal png size 2*1024,768 enhanced set xdata time set timefmt "%s" set format x "%H:%M" set format y2 "%.0f" set y2tics set autoscale xfix set key autotitle columnhead set output "output_$1_sockets.png" plot "peer_stats.$1" using 1:7 smooth sbezier with lines lw 4,\ "peer_stats.$1" using 1:5 smooth sbezier with lines lw 4,\ "peer_stats.$1" using 1:6 smooth sbezier with lines lw 4,\ " $1 rtorrent-0.9.6/doc/manual/000077500000000000000000000000001257211462100154305ustar00rootroot00000000000000rtorrent-0.9.6/doc/manual/choke_groups.md000066400000000000000000000016551257211462100204510ustar00rootroot00000000000000# Choke Groups ## Settings choke_group.insert = "leech_fast" Create a new group named "leech_fast", accessible by the string or index / reverse index according to order of insertion. E.g. '-1' refers to the last inserted choke group, while 0 refers to the first. All commands that applies to a group requires the first argument to be the index, reverse index or the group name. choke_group.tracker.mode.set = -1,"aggressive" Set the tracker mode for torrents in this group. choke_group.up.heuristics.set = -1,"upload_leech_experimental" choke_group.down.heuristics.set = -1,"download_leech" Set the heuristics used when deciding on which peers to choke and unchoke. Use "strings.choke_heuristics{,.upload,.download}" to get a list of the available heuristics. choke_group.up.max.set = -1,250 choke_group.down.max.set = -1,500 Set the max total number of unchoked peers for all torrents in this choke group. rtorrent-0.9.6/doc/manual/ip_filtering.md000066400000000000000000000032511257211462100204260ustar00rootroot00000000000000# IP filtering ## Introduction ## Make a new ip table ip_tables.insert_table = Create a new empty table with the name ’table\_name’, with the default value returned being $0$. There is currently no use of the generic ip tables commands. ## Add a new address block ip_tables.add_address = , 10.0.0.0/8, Set for all addresses in the address block, overwriting prior values. ## Add a new address block ip_tables.load = , ~/foo.txt, Set for all addresses in the file ’foo.txt’ separated by newline, similar to ’add\_address’. ## Get value for address ip_tables.get = , 10.10.10.10 Returns the value set for an address, or the address block it belongs to. The default is $0$. ## Size of data structures ip_tables.size_data = Returns the size in bytes of all data structures for this table, excluding the root class object itself. Note that the in-memory table is dynamically consolidated, as such memory use will always be based on actual fragmentation. The table is a b-tree with 1024 nodes per branch. ## IPv4 filtering table ipv4_filter.add_address = 10.0.0.0/8, unwanted ipv4_filter.add_address = 11.0.0.0/8, preferred ipv4_filter.load = ~/filters.txt, unwanted ipv4_filter.get = 10.10.10.10 ipv4_filter.size_data = The main ip filter, currently supporting ’unwanted’ (do not allow connections) and ’preferred’ (currently used only in private code). ## Constants strings.ip_filter = => { "unwanted", PeerInfo::flag_unwanted }, { "preferred", PeerInfo::flag_preferred }, Constants used by ipv4\_filter values. rtorrent-0.9.6/doc/manual/ip_filtering.tex000066400000000000000000000036311257211462100206300ustar00rootroot00000000000000\section{IP filtering} \subsection{Introduction} \subsection{Make a new ip table} \begin{verbatim} ip_tables.insert_table = \end{verbatim} Create a new empty table with the name 'table\_name', with the default value returned being $0$. There is currently no use of the generic ip tables commands. \subsection{Add a new address block} \begin{verbatim} ip_tables.add_address = , 10.0.0.0/8, \end{verbatim} Set for all addresses in the address block, overwriting prior values. \subsection{Add a new address block} \begin{verbatim} ip_tables.load = , ~/foo.txt, \end{verbatim} Set for all addresses in the file 'foo.txt' separated by newline, similar to 'add\_address'. \subsection{Get value for address} \begin{verbatim} ip_tables.get = , 10.10.10.10 \end{verbatim} Returns the value set for an address, or the address block it belongs to. The default is $0$. \subsection{Size of data structures} \begin{verbatim} ip_tables.size_data = \end{verbatim} Returns the size in bytes of all data structures for this table, excluding the root class object itself. Note that the in-memory table is dynamically consolidated, as such memory use will always be based on actual fragmentation. The table is a b-tree with 1024 nodes per branch. \subsection{IPv4 filtering table} \begin{verbatim} ipv4_filter.add_address = 10.0.0.0/8, unwanted ipv4_filter.add_address = 11.0.0.0/8, preferred ipv4_filter.load = ~/filters.txt, unwanted ipv4_filter.get = 10.10.10.10 ipv4_filter.size_data = \end{verbatim} The main ip filter, currently supporting 'unwanted' (do not allow connections) and 'preferred' (currently used only in private code). \subsection{Constants} \begin{verbatim} strings.ip_filter = => { "unwanted", PeerInfo::flag_unwanted }, { "preferred", PeerInfo::flag_preferred }, \end{verbatim} Constants used by ipv4_filter values. rtorrent-0.9.6/doc/manual/logging.md000066400000000000000000000022561257211462100174050ustar00rootroot00000000000000# Logging ## Opening log files # log.open_file = "log name", "file path" log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid)) A newly opened log file is not connected to any logging events. Some control over formatting will be provided at a later date. ## Adding outputs to events # log.add_output = "logging event", "log name" log.add_output = "info", "rtorrent.log" log.add_output = "dht_debug", "tracker.log" log.add_output = "tracker_debug", "tracker.log" Each log handle can be added to multiple different logging events. ## Logging events "critical" "error" "warn" "notice" "info" "debug" The above events receive logging events from all the sub-groups displayed below, and each event also reciving events from the event above in importance. Thus some high-volume sub-group events such as “tracker\_debug” are not part of “debug” and every “warn” event will receive events from “error”, “critical”. "connection_*" "dht_*" "peer_*" "rpc_*" "storage_*" "thread_*" "tracker_*" "torrent_*" All sub-groups have events from “critical” to “debug” defined. rtorrent-0.9.6/doc/manual/logging.tex000066400000000000000000000023711257211462100176030ustar00rootroot00000000000000\section{Logging} \subsection{Opening log files} \begin{verbatim} # log.open_file = "log name", "file path" log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid)) \end{verbatim} A newly opened log file is not connected to any logging events. Some control over formatting will be provided at a later date. \subsection{Adding outputs to events} \begin{verbatim} # log.add_output = "logging event", "log name" log.add_output = "info", "rtorrent.log" log.add_output = "dht_debug", "tracker.log" log.add_output = "tracker_debug", "tracker.log" \end{verbatim} Each log handle can be added to multiple different logging events. \subsection{Logging events} \begin{verbatim} "critical" "error" "warn" "notice" "info" "debug" \end{verbatim} The above events receive logging events from all the sub-groups displayed below, and each event also reciving events from the event above in importance. Thus some high-volume sub-group events such as ``tracker\_debug'' are not part of ``debug'' and every ``warn'' event will receive events from ``error'', ``critical''. \begin{verbatim} "connection_*" "dht_*" "peer_*" "rpc_*" "storage_*" "thread_*" "tracker_*" "torrent_*" \end{verbatim} All sub-groups have events from ``critical'' to ``debug'' defined. rtorrent-0.9.6/doc/old/000077500000000000000000000000001257211462100147315ustar00rootroot00000000000000rtorrent-0.9.6/doc/old/rtorrent.1000066400000000000000000000434351257211462100167030ustar00rootroot00000000000000.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "RTORRENT" "1" "14 May 2009" "BitTorrent client for ncurses" "" .SH NAME rtorrent \- a BitTorrent client for ncurses .SH SYNOPSIS \fBrtorrent\fR [ \fB-h\fR ] [ \fB-n\fR ] [ \fB-o key1=opt1,...\fR ] [ \fB-O key=opt\fR ] [ \fBURL | FILE\fR\fI ...\fR ] .SH "DESCRIPTION" .PP \fBrtorrent\fR is a BitTorrent client for ncurses, using the \fBlibtorrent\fR library. The client and library is written in C++ with emphasis on speed and efficiency, while delivering equivalent features to those found in GUI based clients in an ncurses client. .PP Most of the options below have their own default unit in addition to supporting B, K, M and G suffixes. .SH "KEYBOARD CONTROL" .PP .SS "GLOBAL KEYS" .TP \fB^q\fR Initiate shutdown, press again to force the shutdown and skip sending the stop signal to trackers. .TP \fBup | down | left | right arrow keys\fR .TP \fB^P | ^N | ^B | ^F\fR Select entries or change windows. The right arrow key or ^F is often used for viewing details about the selected entry, while the left arrow key or ^B often returns to the previous screen. .TP \fBa | s | d\fR Increase the upload throttle by 1/5/50 KB. .TP \fBA | S | D\fR Increase the download throttle by 1/5/50 KB. .TP \fBz | x | c\fR Decrease the upload throttle by 1/5/50 KB. .TP \fBZ | X | C\fR Decrease the download throttle by 1/5/50 KB. .SS "MAIN VIEW KEYS" .TP \fB->\fR View download. .TP \fB1 - 7\fR Change view. .TP \fB^S\fR Start download. .TP \fB^D\fR Stop an active download, or remove a stopped download. .TP \fB^K\fR Close a torrent and its files. .TP \fB^E\fR Set the 'create/resize queued' flags on all files in a torrent. This is necessary if the underlying files in a torrent have been deleted or truncated, and thus rtorrent must recreate them. .TP \fB^R\fR Initiate hash check of torrent. .TP \fB^O\fR Change the destination directory of the download. The torrent must be closed. .TP \fB^X\fR Call commands or change settings. .TP \fB^B\fR Set download to perform initial seeding. Only use when you are the first and only seeder so far for the download. .TP \fB+ | -\fR Change the priority of the download. .TP \fBbackspace\fR Add torrent using an URL or file path. Use \fBtab\fR to view directory content and do auto-complete. .TP \fBl\fR View log. Exit by pressing the space-bar. .TP \fBU\fR Delete the file the torrent is tied to, and clear the association. .TP \fBI\fR Toggle whether torrent ignores ratio settings. .SS "DOWNLOAD VIEW KEYS" .TP \fB->\fR View torrent file list. Use the space-bar to change the file priority and \fB*\fR to change the priority of all files. Use \fB/\fR to collapse the directories. OUTDATED .TP \fB1 | 2\fR Adjust max uploads. .TP \fB3 | 4\fR Adjust min peers. .TP \fB5 | 6\fR Adjust max peers. .TP \fBu\fR Display transfering blocks. .TP \fBi\fR Display chunk rarity. .TP \fBo\fR Display the tracker list. Cycle the trackers in a group with the space-bar. .TP \fBp\fR View peer and torrent information. .TP \fBt | T\fR Initiate tracker request. Use capital T to force the request, ignoring the "min interval" set by the tracker. .TP \fBk\fR Disconnect peer. .TP \fB*\fR Choke/Snub peer. .SH "OPTIONS" .TP \fB-b \fIa.b.c.d\fB\fR Bind listening socket and outgoing connections to this network interface address. .TP \fB-d \fIdirectory\fB\fR Set the default download directory. Defaults to "./". .TP \fB-h\fR Display help and exit. .TP \fB-i \fIa.b.c.d\fB\fR Set the address reported to the tracker. .TP \fB-n\fR Don't load ~/.rtorrent.rc on startup. .TP \fB-o key1=opt1,...\fR .TP \fB-O key=opt\fR Set any number of options, see the SETTINGS section. The options given here override the resource files. Use capital \fB-O\fR to allow comma in the option. .TP \fB-p \fIa-b\fB\fR Try to open a listening port in the range \fBa\fR up to and including \fBb\fR\&. .TP \fB-s \fIdirectory\fB\fR Session management will be enabled and the torrent files for all open downloads will be stored in this directory. Only one instance of rtorrent should be used with each session directory, though at the moment no locking is done. An empty string will disable the session directory. .SH "GENERAL SETTINGS" .PP .TP \fBbind = \fIa.b.c.d\fB\fR Bind listening socket and outgoing connections to this network interface address. .TP \fBip = \fIa.b.c.d\fB\fR .TP \fBip = \fIhostname\fB\fR Set the address reported to the tracker. .TP \fBport_range = \fIa-b\fB\fR Try to open a listening port in the range \fBa\fR up to and including \fBb\fR\&. .TP \fBport_random = \fIyes | no\fB\fR Open the listening port at a random position in the port range. .TP \fBcheck_hash = \fIyes | no\fB\fR Perform hash check on torrents that have finished downloading. .TP \fBdirectory = \fIdirectory\fB\fR Set the default download directory. Defaults to "./". .TP \fBsession = \fIdirectory\fB\fR Session management will be enabled and the torrent files for all open downloads will be stored in this directory. Only one instance of rtorrent can be used per session directory. An empty string will disable the session directory. .TP \fBhttp_proxy = \fIurl\fB\fR Use a http proxy. Use an empty string to disable. .TP \fBencoding_list = \fIencoding\fB\fR Add a preferred filename encoding to the list. The encodings are attempted in the order they are inserted, if none match the torrent default is used. .TP \fBencryption = \fIoption\fB,\fI\&...\fB\fR Set how rtorrent should deal with encrypted Bittorrent connections. By default, encryption is disabled, equivalent to specifying the option \fBnone\fR\&. Alternatively, any number of the following options may be specified: \fBallow_incoming\fR (allow incoming encrypted connections), \fBtry_outgoing\fR (use encryption for outgoing connections), \fBrequire\fR (disable unencrypted handshakes), \fBrequire_RC4\fR (also disable plaintext transmission after the initial encrypted handshake), \fBenable_retry\fR (if the initial outgoing connection fails, retry with encryption turned on if it was off or off if it was on), \fBprefer_plaintext\fR (choose plaintext when peer offers a choice between plaintext transmission and RC4 encryption, otherwise RC4 will be used). .TP \fBpeer_exchange = \fIyes | no\fB\fR Enable/disable peer exchange for torrents that aren't marked private. Disabled by default. .TP \fBschedule = \fIid\fB,\fIstart\fB,\fIinterval\fB,\fIcommand\fB\fR Call \fBcommand\fR every \fBinterval\fR seconds, starting from \fBstart\fR\&. An \fBinterval\fR of zero calls the task once, while a \fBstart\fR of zero calls it immediately. Currently \fBcommand\fR is forwarded to the option handler. \fBstart\fR and \fBinterval\fR may optionally use a time format, \fBdd:hh:mm:ss\fR\&. F.ex to start a task every day at \fB18:00\fR, use \fB18:00:00,24:00:00\fR\&. .TP \fBschedule_remove = \fIid\fB\fR Delete \fBid\fR from the scheduler. .TP \fBstart_tied =\fR Start torrents that are tied to filenames that have been re-added. .TP \fBstop_untied =\fR .TP \fBclose_untied =\fR .TP \fBremove_untied =\fR Stop, close or remove the torrents that are tied to filenames that have been deleted. Clear the association with the 'U' key. .TP \fBclose_low_diskspace = \fIspace\fB\fR Close any active torrents on filesystems with less than \fBspace\fR diskspace left. Use with the \fBschedule\fR option. A default scheduled event with id \fBlow_diskspace\fR is set to 500Mb. .TP \fBload = \fIfile\fB\fR .TP \fBload_verbose = \fIfile\fB\fR .TP \fBload_start = \fIfile\fB\fR .TP \fBload_start_verbose = \fIfile\fB\fR Load and possibly start a file, or possibly multiple files by using the wild-card "*". This is meant for use with \fBschedule\fR, though ensure that the \fBstart\fR is non-zero. The loaded file will be tied to the filename provided. .TP \fBimport = \fIfile\fB\fR .TP \fBtry_import = \fIfile\fB\fR Load a resource file. \fBtry_import\fR does not throw torrent::input_error exception on bad input. .TP \fBstop_on_ratio = \fImin_ratio\fB\fR .TP \fBstop_on_ratio = \fImin_ratio\fB,\fImin_upload\fB\fR .TP \fBstop_on_ratio = \fImin_ratio\fB,\fImin_upload\fB,\fImax_ratio\fB\fR Stop torrents when they reach the given upload ratio \fBmin_ratio\fR in percent. If the optional \fBmin_upload\fR is given, require a total upload amount of this many bytes as well. If the optional \fBmax_ratio\fR is given, stop the torrent when reaching this ratio regardless of the total upload amount. Exclude certain torrent by pressing \fBShift+I\fR in the downlist list. Use with the \fBschedule\fR option. .TP \fBon_insert = \fIid\fB,\fIcommand\fB\fR .TP \fBon_erase = \fIid\fB,\fIcommand\fB\fR .TP \fBon_open = \fIid\fB,\fIcommand\fB\fR .TP \fBon_close = \fIid\fB,\fIcommand\fB\fR .TP \fBon_start = \fIid\fB,\fIcommand\fB\fR .TP \fBon_stop = \fIid\fB,\fIcommand\fB\fR .TP \fBon_hash_queued = \fIid\fB,\fIcommand\fB\fR .TP \fBon_hash_removed = \fIid\fB,\fIcommand\fB\fR .TP \fBon_hash_done = \fIid\fB,\fIcommand\fB\fR .TP \fBon_finished = \fIid\fB,\fIcommand\fB\fR Call a command on a download when its state changes. Only a subset of commands are available. .SH "THROTTLE SETTINGS" .TP \fBupload_rate = \fIKB\fB\fR .TP \fBdownload_rate = \fIKB\fB\fR Set the maximum global uploand and download rates. .TP \fBmin_peers = \fIvalue\fB\fR .TP \fBmax_peers = \fIvalue\fB\fR Set the minimum and maximum number of peers to allow in each download. .TP \fBmin_peers_seed = \fIvalue\fB\fR .TP \fBmax_peers_seed = \fIvalue\fB\fR Set the minimum nad maximum number of peers to allow while seeding, or -1 (default) to use max_peers. .TP \fBmax_uploads = \fIvalue\fB\fR Set the maximum number of simultaneous uploads per download. .TP \fBmax_uploads_div = \fIvalue\fB\fR .TP \fBmax_downloads_div = \fIvalue\fB\fR Change the divider used to calculate the max upload and download slots to use when the throttle is changed. Disable by setting \fB0\fR\&. .TP \fBmax_uploads_global = \fIvalue\fB\fR .TP \fBmax_downloads_global = \fIvalue\fB\fR Max upload and download slots allowed. Disable by setting \fB0\fR\&. .TP \fBthrottle_up = \fIname\fB, \fIupload_rate\fB\fR .TP \fBthrottle_down = \fIname\fB, \fIdownload_rate\fB\fR Define secondary throttle and/or set the given upload or download rate. Attach to a download with the d.set_throttle_name=name command or switch throttles with Ctrl-T. Download must be stopped when changing throttles. Note that secondary throttles only work if the global upload/download is throttled. Setting a download to use the \fBNULL\fR throttle makes the download unthrottled even when there is a global throttle. Note that this special case bypasses the global throttle entirely, and as such its rate and transfer amounts are not included in the global statistics. .TP \fBthrottle_ip = \fIname\fB, \fIhost\fB\fR .TP \fBthrottle_ip = \fIname\fB, \fInetwork/prefix\fB\fR .TP \fBthrottle_ip = \fIname\fB, \fIstart\fB, \fIend\fB\fR Use the given secondary throttle for a host, CIDR network or IP range. All peers with a matching IP will use this throttle instead of the global throttle or a custom download throttle. The name may be \fBNULL\fR to make these peers unthrottled, with the same caveats as explained above. .SH "TRACKER RELATED SETTINGS" .PP Tracker related settings. .TP \fBenable_trackers = \fIyes\fB\fR Set to \fBno\fR to disable all tracker requests. Useful for disabling rtorrent with the \fBschedule\fR command. .TP \fBtracker_dump = \fIfilename\fB\fR Dump tracker requests to \fBfilename\fR, disable by supplying an empty string. Only torrents loaded while \fBtracker_dump\fR contains a non-empty string will be logged at the moment, although disabling it will work as expected. .TP \fBtracker_numwant = \fInumber\fB\fR Set the numwant field sent to the tracker, which indicates how many peers we want. A negative value disables this feature. .TP \fBuse_udp_trackers = \fIyes\fB\fR Use UDP trackers. Disable if you are behind a firewall, etc, that does not allow connections to UDP trackers. .TP \fBdht = \fIdisabled|off|auto|on\fB\fR Support for querying the distributed hash table (DHT) to find peers for trackerless torrents or when all trackers are down. Set to \fBdisable\fR to completely disable DHT, \fBoff\fR (default) to enable DHT but to not start the DHT server, \fBauto\fR to automatically start and stop the DHT server as needed or \fBon\fR for permanently keeping the DHT server running. When set to automatic, the DHT server will start up when the first non-private torrent is started, and will stop 15-30 minutes after the last non-private torrent is stopped (or when rTorrent quits). For DHT to work, a session directory must be set (for saving the DHT cache). .TP \fBdht_port = \fInumber\fB\fR Set the UDP listen port for DHT. Defaults to 6881. .TP \fBdht_add_node = \fIhost[:port]\fB\fR Not intended for use in the configuration file but as one-time option in the client or on the command line to bootstrap an empty DHT node table. Contacts the given node and attempts to bootstrap from it if it replies. The port is optional, with port 6881 being used by default. .TP \fBhttp_capath = \fIpath\fB\fR .TP \fBhttp_cacert = \fIfilename\fB\fR Set the certificates to use in http requests. See Curl's CURLOPT_CAPATH and CURLOPT_CAINFO options for further information. .SH "USER-INTERFACE SETTINGS" .PP Display related settings. .TP \fBview_add = \fIname\fB\fR Create a new view. .TP \fBview_sort = \fIname\fB\fR .TP \fBview_sort = \fIname\fB,\fIseconds\fB\fR Sort a view according the the criteria set by \fBview_sort_current\fR\&. If the optional argument is supplied, the view is not sorted if a change happened during the last \fBseconds\fR\&. This command is meant to be used with \fBschedule\fR\&. .TP \fBview_sort_new = \fIname\fB,\fI\&...\fB\fR .TP \fBview_sort_current = \fIname\fB,\fI\&...\fB\fR Set the sorting criteria for when new elements inserted or \fBview_sort\fR is called. The list can contain any number of criteria, including zero, from the following: \fBname\fR, \fBname_reverse\fR, \fBstopped\fR, \fBstarted\fR, \fBcomplete\fR, \fBincomplete\fR, \fBstate_changed\fR, \fBstate_changed_reverse\fR .TP \fBkey_layout = \fIqwerty|azerty|qwertz|dvorak\fB\fR Change the key-bindings. .SH "FILE-SYSTEM SETTINGS" .PP File-system related settings. .TP \fBmax_file_size = \fIsize\fB\fR Set the maximum size a file can have. Disable by passing \fB-1\fR\&. .TP \fBsplit_file_size = \fIsize\fB\fR Split files in a torrent larger than \fBsize\fR into seperate files. Disable by passing \fB-1\fR\&. .TP \fBsplit_suffix = \fIstring\fB\fR Set the suffix used on split files. Defaults to \fB\&.part\fR\&. .SH "DOWNLOAD SETTINGS" .PP Settings that require a download as a target, the options need to be called through f.ex \fBon_finished\fR\&. .TP \fBcreate_link = \fItype\fB,\fIpath\fB,\fIsuffix\fB\fR .TP \fBdelete_link = \fItype\fB,\fIpath\fB,\fIsuffix\fB\fR Create or delete a symbolic link. The link path is the concatenation of \fBpath\fR, the result of the \fBtype\fR on the download, and \fBsuffix\fR\&. Available types are; \fBbase_path\fR uses the base path of the download, \fBbase_filename\fR uses the base filename of the download, \fBtied\fR uses the path of the file the download is tied to, see \fBstart_tied\fR\&. .SH "ADVANCED SETTINGS" .PP This list contains settings users shouldn't need to touch, some may even cause crashes or similar if incorrectly set. .TP \fBhash_read_ahead = \fIMB\fB\fR Configure how far ahead we ask the kernel to read when doing hash checking. The hash checker uses madvise(..., MADV_WILLNEED) for the requests. .TP \fBhash_interval = \fIms\fB\fR Interval between attempts to check the hash when the chunk is not in memory, in milliseconds. .TP \fBhash_max_tries = \fItries\fB\fR Number of attempts to check the hash while using the mincore status, before forcing. Overworked systems might need lower values to get a decent hash checking rate. .TP \fBsafe_sync = \fIyes|no\fB\fR Always use MS_SYNC rather than MS_ASYNC when syncing chunks. This may be nessesary in case of filesystem bugs like NFS in linux ~2.6.13. .TP \fBmax_open_files = \fIvalue\fB\fR Number of files to simultaneously keep open. LibTorrent dynamically opens and closes files as necessary when mapping files to memory. Default is based on sysconf(_SC_OPEN_MAX). You probably only think you know what this option does, so don't touch it. .TP \fBmax_open_sockets = \fIvalue\fB\fR Number of network sockets to simultaneously keep open. This value is set to a reasonable value based on \fBsysconf(_SC_OPEN_MAX)\fR\&. .TP \fBmax_open_http = \fIvalue\fB\fR Number of sockets to simultaneously keep open. This value is set to \fB32\fR by default. .TP \fBmax_memory_usage = \fIbytes\fB\fR Set the max amount of memory space used to mapping file chunks. This may also be set using \fBulimit -m\fR where 3/4 will be allocated to file chunks. .TP \fBsend_buffer_size = \fIvalue\fB\fR .TP \fBreceive_buffer_size = \fIvalue\fB\fR Adjust the send and receive buffer size for socket. .TP \fBumask = \fI0022\fB\fR Set the umask for this process, which is applied to all files created by the program. .TP \fBcwd = \fIdirectory\fB\fR Changes the working directory of the process using \fBchdir\fR\&. .TP \fBsession_on_completion = \fIyes\fB\fR Controls if the session torrent is saved when a torrent finishes. By default on. .TP \fBsession_lock = \fIyes\fB\fR Controls if a lock file is created in the session directory on startup. .TP \fBsession_save = \fR Save the session files for all downloads. .TP \fBtos = \fIdefault|lowdelay|throughput|reliability|mincost\fB\fR .TP \fBtos = \fIhex\fB\fR Change the TOS of peer connections, by default set to \fBthroughput\fR\&. If the option is set to \fBdefault\fR then the system default TOS is used. A hex value may be used for non-standard settings. .TP \fBhandshake_log = \fIyes\fB\fR Enable logging of the peer handshake. This generates a large number of log messages, but may be useful to debug connection problems. .SH "AUTHORS" .PP Jari "Rakshasa" Sundell rtorrent-0.9.6/doc/old/rtorrent.1.xml000066400000000000000000001006771257211462100175040ustar00rootroot00000000000000 rtorrent 1 June 25th, 2005 BitTorrent client for ncurses rtorrent a BitTorrent client for ncurses rtorrent -h -n -o key1=opt1,... -O key=opt URL | FILE DESCRIPTION rtorrent is a BitTorrent client for ncurses, using the libtorrent library. The client and library is written in C++ with emphasis on speed and efficiency, while delivering equivalent features to those found in GUI based clients in an ncurses client. Most of the options below have their own default unit in addition to supporting B, K, M and G suffixes. KEYBOARD CONTROL Global Keys ^q Initiate shutdown, press again to force the shutdown and skip sending the stop signal to trackers. up | down | left | right arrow keys ^P | ^N | ^B | ^F Select entries or change windows. The right arrow key or ^F is often used for viewing details about the selected entry, while the left arrow key or ^B often returns to the previous screen. a | s | d Increase the upload throttle by 1/5/50 KB. A | S | D Increase the download throttle by 1/5/50 KB. z | x | c Decrease the upload throttle by 1/5/50 KB. Z | X | C Decrease the download throttle by 1/5/50 KB. Main View Keys -> View download. 1 - 7 Change view. ^S Start download. ^D Stop an active download, or remove a stopped download. ^K Close a torrent and its files. ^E Set the 'create/resize queued' flags on all files in a torrent. This is necessary if the underlying files in a torrent have been deleted or truncated, and thus rtorrent must recreate them. ^R Initiate hash check of torrent. ^O Change the destination directory of the download. The torrent must be closed. ^X Call commands or change settings. ^B Set download to perform initial seeding. Only use when you are the first and only seeder so far for the download. + | - Change the priority of the download. backspace Add torrent using an URL or file path. Use tab to view directory content and do auto-complete. l View log. Exit by pressing the space-bar. U Delete the file the torrent is tied to, and clear the association. I Toggle whether torrent ignores ratio settings. Download View Keys -> View torrent file list. Use the space-bar to change the file priority and * to change the priority of all files. Use / to collapse the directories. OUTDATED 1 | 2 Adjust max uploads. 3 | 4 Adjust min peers. 5 | 6 Adjust max peers. u Display transfering blocks. i Display chunk rarity. o Display the tracker list. Cycle the trackers in a group with the space-bar. p View peer and torrent information. t | T Initiate tracker request. Use capital T to force the request, ignoring the "min interval" set by the tracker. k Disconnect peer. * Choke/Snub peer. OPTIONS -b a.b.c.d Bind listening socket and outgoing connections to this network interface address. -d directory Set the default download directory. Defaults to "./". -h Display help and exit. -i a.b.c.d Set the address reported to the tracker. -n Don't load ~/.rtorrent.rc on startup. -o key1=opt1,... -O key=opt Set any number of options, see the SETTINGS section. The options given here override the resource files. Use capital -O to allow comma in the option. -p a-b Try to open a listening port in the range a up to and including b. -s directory Session management will be enabled and the torrent files for all open downloads will be stored in this directory. Only one instance of rtorrent should be used with each session directory, though at the moment no locking is done. An empty string will disable the session directory. GENERAL SETTINGS bind = a.b.c.d Bind listening socket and outgoing connections to this network interface address. ip = a.b.c.d ip = hostname Set the address reported to the tracker. port_range = a-b Try to open a listening port in the range a up to and including b. port_random = yes | no Open the listening port at a random position in the port range. check_hash = yes | no Perform hash check on torrents that have finished downloading. directory = directory Set the default download directory. Defaults to "./". session = directory Session management will be enabled and the torrent files for all open downloads will be stored in this directory. Only one instance of rtorrent can be used per session directory. An empty string will disable the session directory. http_proxy = url Use a http proxy. Use an empty string to disable. encoding_list = encoding Add a preferred filename encoding to the list. The encodings are attempted in the order they are inserted, if none match the torrent default is used. encryption = option,... Set how rtorrent should deal with encrypted Bittorrent connections. By default, encryption is disabled, equivalent to specifying the option none. Alternatively, any number of the following options may be specified: allow_incoming (allow incoming encrypted connections), try_outgoing (use encryption for outgoing connections), require (disable unencrypted handshakes), require_RC4 (also disable plaintext transmission after the initial encrypted handshake), enable_retry (if the initial outgoing connection fails, retry with encryption turned on if it was off or off if it was on), prefer_plaintext (choose plaintext when peer offers a choice between plaintext transmission and RC4 encryption, otherwise RC4 will be used). peer_exchange = yes | no Enable/disable peer exchange for torrents that aren't marked private. Disabled by default. start_tied = Start torrents that are tied to filenames that have been re-added. stop_untied = close_untied = remove_untied = Stop, close or remove the torrents that are tied to filenames that have been deleted. Clear the association with the 'U' key. close_low_diskspace = space Close any active torrents on filesystems with less than space diskspace left. Use with the schedule option. A default scheduled event with id low_diskspace is set to 500Mb. load = file load_verbose = file load_start = file load_start_verbose = file Load and possibly start a file, or possibly multiple files by using the wild-card "*". This is meant for use with schedule, though ensure that the start is non-zero. The loaded file will be tied to the filename provided. import = file try_import = file Load a resource file. try_import does not throw torrent::input_error exception on bad input. THROTTLE SETTINGS upload_rate = KB download_rate = KB set_upload_rate = TODO set_download_rate = TODO Set the maximum global uploand and download rates. min_peers = value max_peers = value Set the minimum and maximum number of peers to allow in each download. min_peers_seed = value max_peers_seed = value Set the minimum nad maximum number of peers to allow while seeding, or -1 (default) to use max_peers. max_uploads = value max_downloads = value min_uploads = value min_downloads = value Set the maximum/minimum number of simultaneous uploads/downloads per download/upload. max_uploads_div = value max_downloads_div = value set_max_uploads_div = value set_max_downloads_div = value Change the divider used to calculate the max upload and download slots to use when the throttle is changed. Disable by setting 0. max_uploads_global = value max_downloads_global = value set_max_uploads_global = value set_max_downloads_global = value Max upload and download slots allowed. Disable by setting 0. throttle_up = name, upload_rate throttle_down = name, download_rate Define secondary throttle and/or set the given upload or download rate. Attach to a download with the d.set_throttle_name=name command or switch throttles with Ctrl-T. Download must be stopped when changing throttles. Note that secondary throttles only work if the global upload/download is throttled. Setting a download to use the NULL throttle makes the download unthrottled even when there is a global throttle. Note that this special case bypasses the global throttle entirely, and as such its rate and transfer amounts are not included in the global statistics. throttle_ip = name, host throttle_ip = name, network/prefix throttle_ip = name, start, end Use the given secondary throttle for a host, CIDR network or IP range. All peers with a matching IP will use this throttle instead of the global throttle or a custom download throttle. The name may be NULL to make these peers unthrottled, with the same caveats as explained above. TRACKER RELATED SETTINGS Tracker related settings. enable_trackers = yes Set to no to disable all tracker requests. Useful for disabling rtorrent with the schedule command. tracker_dump = filename Dump tracker requests to filename, disable by supplying an empty string. Only torrents loaded while tracker_dump contains a non-empty string will be logged at the moment, although disabling it will work as expected. tracker_numwant = number Set the numwant field sent to the tracker, which indicates how many peers we want. A negative value disables this feature. use_udp_trackers = yes Use UDP trackers. Disable if you are behind a firewall, etc, that does not allow connections to UDP trackers. http_capath = path http_cacert = filename Set the certificates to use in http requests. See Curl's CURLOPT_CAPATH and CURLOPT_CAINFO options for further information. DHT-RELATED SETTINGS Settings related to DHT dht = disabled|off|auto|on Support for querying the distributed hash table (DHT) to find peers for trackerless torrents or when all trackers are down. Set to disable to completely disable DHT, off (default) to enable DHT but to not start the DHT server, auto to automatically start and stop the DHT server as needed or on for permanently keeping the DHT server running. When set to automatic, the DHT server will start up when the first non-private torrent is started, and will stop 15-30 minutes after the last non-private torrent is stopped (or when rTorrent quits). For DHT to work, a session directory must be set (for saving the DHT cache). dht_port = number Set the UDP listen port for DHT. Defaults to 6881. dht_add_node = host[:port] Not intended for use in the configuration file but as one-time option in the client or on the command line to bootstrap an empty DHT node table. Contacts the given node and attempts to bootstrap from it if it replies. The port is optional, with port 6881 being used by default. dht_statistics = TODO TODO set_dht_port = TODO TODO set_dht_throttle = TODO TODO USER-INTERFACE SETTINGS Display related settings. view_add = name Create a new view. view_sort = name view_sort = name,seconds Sort a view according the the criteria set by view_sort_current. If the optional argument is supplied, the view is not sorted if a change happened during the last seconds. This command is meant to be used with schedule. view_sort_new = name,... view_sort_current = name,... Set the sorting criteria for when new elements inserted or view_sort is called. The list can contain any number of criteria, including zero, from the following: name, name_reverse, stopped, started, complete, incomplete, state_changed, state_changed_reverse key_layout = qwerty|azerty|qwertz|dvorak Change the key-bindings. FILE-SYSTEM SETTINGS File-system related settings. max_file_size = size Set the maximum size a file can have. Disable by passing -1. split_file_size = size Split files in a torrent larger than size into seperate files. Disable by passing -1. split_suffix = string Set the suffix used on split files. Defaults to .part. DOWNLOAD SETTINGS Settings that require a download as a target, the options need to be called through f.ex on_finished. create_link = type,path,suffix delete_link = type,path,suffix Create or delete a symbolic link. The link path is the concatenation of path, the result of the type on the download, and suffix. Available types are; base_path uses the base path of the download, base_filename uses the base filename of the download, tied uses the path of the file the download is tied to, see start_tied. ADVANCED SETTINGS This list contains settings users shouldn't need to touch, some may even cause crashes or similar if incorrectly set. hash_read_ahead = MB Configure how far ahead we ask the kernel to read when doing hash checking. The hash checker uses madvise(..., MADV_WILLNEED) for the requests. hash_interval = ms Interval between attempts to check the hash when the chunk is not in memory, in milliseconds. hash_max_tries = tries Number of attempts to check the hash while using the mincore status, before forcing. Overworked systems might need lower values to get a decent hash checking rate. safe_sync = yes|no Always use MS_SYNC rather than MS_ASYNC when syncing chunks. This may be nessesary in case of filesystem bugs like NFS in linux ~2.6.13. max_open_files = value Number of files to simultaneously keep open. LibTorrent dynamically opens and closes files as necessary when mapping files to memory. Default is based on sysconf(_SC_OPEN_MAX). You probably only think you know what this option does, so don't touch it. max_open_sockets = value Number of network sockets to simultaneously keep open. This value is set to a reasonable value based on sysconf(_SC_OPEN_MAX). max_open_http = value Number of sockets to simultaneously keep open. This value is set to 32 by default. max_memory_usage = bytes Set the max amount of memory space used to mapping file chunks. This may also be set using ulimit -m where 3/4 will be allocated to file chunks. send_buffer_size = value receive_buffer_size = value Adjust the send and receive buffer size for socket. umask = 0022 Set the umask for this process, which is applied to all files created by the program. cwd = directory Changes the working directory of the process using chdir. session_on_completion = yes Controls if the session torrent is saved when a torrent finishes. By default on. session_lock = yes Controls if a lock file is created in the session directory on startup. session_save = Save the session files for all downloads. tos = default|lowdelay|throughput|reliability|mincost tos = hex Change the TOS of peer connections, by default set to throughput. If the option is set to default then the system default TOS is used. A hex value may be used for non-standard settings. handshake_log = yes Enable logging of the peer handshake. This generates a large number of log messages, but may be useful to debug connection problems. AUTHORS Jari "Rakshasa" Sundell jaris@ifi.uio.no rtorrent-0.9.6/doc/plot/000077500000000000000000000000001257211462100151315ustar00rootroot00000000000000rtorrent-0.9.6/doc/plot/instrumentation_transfers.sh000077500000000000000000000053451257211462100230310ustar00rootroot00000000000000#/bin/bash gnuplot << EOF set terminal png size 1024,768 enhanced set xdata time set timefmt "%s" set format x "%H:%M" set y2tics set autoscale xfix set key autotitle columnhead # set datafile missing '0' set format y "%.0f" set format y2 "%.0f" set yrange [0:] set y2range [0:] set output "output_$1_transfer_requests.png" plot \ "instrumentation_transfers.log.$1" using 1:2 title 'delegated' with lines lw 4 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:3 title 'downloading' with lines lw 4 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:4 title 'finished' with lines lw 4 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:5 title 'skipped' with lines lw 2 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:6 title 'unknown' with lines lw 2 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:7 title 'unordered' with lines lw 2 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:19 title 'unaccounted' with lines lw 2 axis x1y2 set output "output_$1_transfer_queues.png" plot \ "instrumentation_transfers.log.$1" using 1:8 title 'queue added' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:9 title 'queue moved' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:10 title 'queue removed' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:11 title 'queue total' with lines lw 4 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:12 title 'unordered added' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:13 title 'unordered moved' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:14 title 'unordered removed' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:15 title 'unordered total' with lines lw 4 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:16 title 'stalled added' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:17 title 'stalled moved' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:18 title 'stalled removed' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:19 title 'stalled total' with lines lw 4 axis x1y2,\ "instrumentation_transfers.log.$1" using 1:20 title 'choked added' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:21 title 'choked moved' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:22 title 'choked removed' with lines lw 2 axis x1y1,\ "instrumentation_transfers.log.$1" using 1:23 title 'choked total' with lines lw 4 axis x1y2 EOF rtorrent-0.9.6/doc/plot/mincore.sh000077500000000000000000000021761257211462100171320ustar00rootroot00000000000000#/bin/bash gnuplot << EOF set terminal png size 1024,768 enhanced set xdata time set timefmt "%s" set format x "%H:%M" set y2tics set autoscale xfix set key autotitle columnhead set format y "%.0f" set format y2 "%.0f" set output "output_$1_incore_sync.png" plot \ "instrumentation_mincore.log.$1" using 1:6 title 'success' smooth sbezier with lines lw 4 axis x1y1,\ "instrumentation_mincore.log.$1" using 1:7 title 'failed' smooth sbezier with lines lw 4 axis x1y1,\ "instrumentation_mincore.log.$1" using 1:8 title 'not synced' smooth sbezier with lines lw 4 axis x1y2,\ "instrumentation_mincore.log.$1" using 1:9 title 'not deallocated' smooth sbezier with lines lw 4 axis x1y2 set format y "%.0g" set output "output_$1_incore_alloc.png" plot \ "instrumentation_mincore.log.$1" using 1:12 title 'allocations' smooth sbezier with lines lw 2 axis x1y1,\ "instrumentation_mincore.log.$1" using 1:13 title 'deallocations' smooth sbezier with lines lw 4 axis x1y1,\ "instrumentation_mincore.log.$1" using 1:10 title 'alloc failed' smooth sbezier with lines lw 2 axis x1y2 EOF rtorrent-0.9.6/doc/rtorrent.rc000066400000000000000000000052451257211462100163660ustar00rootroot00000000000000# This is an example resource file for rTorrent. Copy to # ~/.rtorrent.rc and enable/modify the options as needed. Remember to # uncomment the options you wish to enable. # Maximum and minimum number of peers to connect to per torrent. #min_peers = 40 #max_peers = 100 # Same as above but for seeding completed torrents (-1 = same as downloading) #min_peers_seed = 10 #max_peers_seed = 50 # Maximum number of simultanious uploads per torrent. #max_uploads = 15 # Global upload and download rate in KiB. "0" for unlimited. #download_rate = 0 #upload_rate = 0 # Default directory to save the downloaded torrents. #directory = ./ # Default session directory. Make sure you don't run multiple instance # of rtorrent using the same session directory. Perhaps using a # relative path? #session = ./session # Watch a directory for new torrents, and stop those that have been # deleted. #schedule = watch_directory,5,5,load_start=./watch/*.torrent #schedule = untied_directory,5,5,stop_untied= # Close torrents when diskspace is low. #schedule = low_diskspace,5,60,close_low_diskspace=100M # The ip address reported to the tracker. #ip = 127.0.0.1 #ip = rakshasa.no # The ip address the listening socket and outgoing connections is # bound to. #bind = 127.0.0.1 #bind = rakshasa.no # Port range to use for listening. #port_range = 6890-6999 # Start opening ports at a random position within the port range. #port_random = no # Check hash for finished torrents. Might be usefull until the bug is # fixed that causes lack of diskspace not to be properly reported. #check_hash = no # Set whether the client should try to connect to UDP trackers. #use_udp_trackers = yes # Alternative calls to bind and ip that should handle dynamic ip's. #schedule = ip_tick,0,1800,ip=rakshasa #schedule = bind_tick,0,1800,bind=rakshasa # Encryption options, set to none (default) or any combination of the following: # allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext # # The example value allows incoming encrypted connections, starts unencrypted # outgoing connections but retries with encryption if they fail, preferring # plaintext to RC4 encryption after the encrypted handshake # # encryption = allow_incoming,enable_retry,prefer_plaintext # Enable DHT support for trackerless torrents or when all trackers are down. # May be set to "disable" (completely disable DHT), "off" (do not start DHT), # "auto" (start and stop DHT as needed), or "on" (start DHT immediately). # The default is "off". For DHT to work, a session directory must be defined. # # dht = auto # UDP port to use for DHT. # # dht_port = 6881 # Enable peer exchange (for torrents not marked private) # # peer_exchange = yes rtorrent-0.9.6/doc/rtorrent_fast_resume.pl000077500000000000000000000075531257211462100210010ustar00rootroot00000000000000#!/usr/bin/perl # Perl script to add rTorrent fast resume data to torrent files. # # Usage: # rtorrent_fast_resume.pl [base-directory] < plain.torrent > with_fast_resume.torrent # -OR- # rtorrent_fast_resume.pl [base-directory] plain.torrent [with_fast_resume.torrent] use strict; use warnings; use Convert::Bencode_XS qw(bencode bdecode); use File::Spec; # core module use POSIX; # core module $/ = undef; $| = 1; # Process ARGV my $d = $ARGV[0]; if ($d and not -d $d) { if (-f $d and -s $d and not $ARGV[2]) { # missing directory, but has file $ARGV[2] = $ARGV[1]; $ARGV[1] = $ARGV[0]; $d = ''; } else { die "$d is not a directory\n"; } } $d ||= "."; $d .= "/" unless $d =~ m#/$#; my ($in, $out, $msg); my ($in_file, $out_file) = ('', ''); if ($ARGV[1]) { $in_file = $ARGV[1]; open($in, ($ARGV[2] ? '<' : '+<'), $in_file) || die "Cannot open $in_file for input!\n"; unless ($ARGV[2]) { $out = $in; $out_file = $in_file; } } else { $in = *STDIN; } if ($ARGV[2]) { $out_file = $ARGV[2]; open($out, '>', $out_file) || die "Cannot open $out_file for output!\n"; $msg = *STDOUT; } elsif (!$ARGV[1]) { $out = *STDOUT; } $msg //= *STDERR; print {$msg} "Total input torrent size: ".sprintf('%.2f', (-s $in_file) / 1024)." KB\n" if $in_file; print {$msg} "Decoding ".($in_file || 'torrent from standard input')."..."; my $t = bdecode(scalar <$in>); die "No info key.\n" unless ref $t eq "HASH" and exists $t->{info}; my $psize = $t->{info}{"piece length"} or die "No piece length key.\n"; print {$msg} "done\n\n"; my @files; my $tsize = 0; if (exists $t->{info}{files}) { print {$msg} "Multi file torrent: $t->{info}{name}\n"; for (@{$t->{info}{files}}) { push @files, join "/", $t->{info}{name},@{$_->{path}}; $tsize += $_->{length}; } } else { print {$msg} "Single file torrent: $t->{info}{name}\n"; @files = ($t->{info}{name}); $tsize = $t->{info}{length}; } my $chunks = int(($tsize + $psize - 1) / $psize); print {$msg} "Total size: ".sprintf('%.2f', $tsize / 1024**2)." MB; $chunks chunks; ", scalar @files, " files.\n\n"; die "Inconsistent piece information!\n" if $chunks*20 != length $t->{info}{pieces}; print {$msg} "Adding fast resume information..."; # flags => 1+16+ my $pmod = 0; $t->{libtorrent_resume}{bitfield} = $chunks; foreach my $f (0..$#files) { die "$d$files[$f] not found.\n" unless -e "$d$files[$f]"; my $mtime = (stat "$d$files[$f]")[9]; # Compute number of chunks per file my $fsize = $t->{info}{files}[$f]{length}; my $fchunks = ($pmod ? 1 : 0); if ($pmod >= $fsize) { ($fsize, $pmod ) = (0, $pmod-$fsize); } else { ($pmod, $fsize) = (0, $fsize-$pmod); } $fchunks += ceil($fsize / $psize); $pmod ||= $psize - ($fsize % $psize); $t->{libtorrent_resume}{files}[$f] = { priority => 0, # Don't download; we already have the file, so don't clobber it! mtime => $mtime, completed => $fchunks, }; }; $t->{libtorrent_resume}{'uncertain_pieces.timestamp'} = time; # Some extra information to re-enforce the fact that this is a finished torrent $d .= $t->{info}{name}; $t->{rtorrent} = { state => 1, # started state_changed => time, state_counter => 1, chunks_wanted => 0, chunks_done => $chunks, complete => 1, hashing => 0, # Not hashing directory => File::Spec->file_name_is_absolute($d) ? $d : File::Spec->rel2abs($d), ((tied_to_file => File::Spec->file_name_is_absolute($out_file) ? $out_file : File::Spec->rel2abs($out_file)) x!! $out_file), 'timestamp.finished' => 0, 'timestamp.started' => time, }; print {$msg} "done\n"; print {$msg} "Encoding ".($out_file || 'torrent from standard output')."..."; seek($out, 0, 0); # just in case files are the same print {$out} bencode($t); close($in); close($out); print {$msg} "done\n"; exit; rtorrent-0.9.6/doc/torrent_data000077500000000000000000000011541257211462100165700ustar00rootroot00000000000000#!/usr/bin/perl # Perl script to read torrent data use strict; use warnings; use Convert::Bencode_XS qw(bdecode); use Data::Dumper; $/ = undef; $| = 1; my $in; my $in_file = $ARGV[0]; if ($in_file) { open($in, '<', $in_file) || die "Cannot open $in_file for input!\n"; } else { $in = *STDIN; } print "Total input torrent size: ".sprintf('%.2f', (-s $in_file) / 1024)." KB\n" if $in_file; print "Decoding ".($in_file || 'torrent from standard input')."..."; my $t = bdecode(scalar <$in>); print "done\n\n"; print Data::Dumper->new([$t], ['*Torrent'])->Indent(1)->Useqq(1)->Quotekeys(0)->Sortkeys(1)->Dump; rtorrent-0.9.6/rak/000077500000000000000000000000001257211462100141635ustar00rootroot00000000000000rtorrent-0.9.6/rak/address_info.h000066400000000000000000000075041257211462100170020ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // Wrapper for addrinfo with focus on zero-copy conversion to and from // the c-type and wrapper. // // Do use the wrapper on a pre-existing struct addrinfo, cast the // pointer rather than the base type. #ifndef RAK_ADDRESS_INFO_H #define RAK_ADDRESS_INFO_H #include #include namespace rak { class address_info { public: void clear() { std::memset(this, 0, sizeof(address_info)); } int flags() const { return m_addrinfo.ai_flags; } void set_flags(int f) { m_addrinfo.ai_flags = f; } int family() const { return m_addrinfo.ai_family; } void set_family(int f) { m_addrinfo.ai_family = f; } int socket_type() const { return m_addrinfo.ai_socktype; } void set_socket_type(int t) { m_addrinfo.ai_socktype = t; } int protocol() const { return m_addrinfo.ai_protocol; } void set_protocol(int p) { m_addrinfo.ai_protocol = p; } size_t length() const { return m_addrinfo.ai_addrlen; } socket_address* address() { return reinterpret_cast(m_addrinfo.ai_addr); } addrinfo* c_addrinfo() { return &m_addrinfo; } const addrinfo* c_addrinfo() const { return &m_addrinfo; } address_info* next() { return reinterpret_cast(m_addrinfo.ai_next); } static int get_address_info(const char* node, int domain, int type, address_info** ai); static void free_address_info(address_info* ai) { ::freeaddrinfo(ai->c_addrinfo()); } static const char* strerror(int err) { return gai_strerror(err); } private: addrinfo m_addrinfo; }; inline int address_info::get_address_info(const char* node, int pfamily, int stype, address_info** ai) { address_info hints; hints.clear(); hints.set_family(pfamily); hints.set_socket_type(stype); return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast(ai)); } } #endif rtorrent-0.9.6/rak/algorithm.h000066400000000000000000000116461257211462100163320ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_ALGORITHM_H #define RAK_ALGORITHM_H #include #include #include namespace rak { template _Function for_each_pre(_InputIter __first, _InputIter __last, _Function __f) { _InputIter __tmp; while (__first != __last) { __tmp = __first++; __f(*__tmp); } return __f; } // Return a range with a distance of no more than __distance and // between __first and __last, centered on __middle1. template std::pair<_InputIter, _InputIter> advance_bidirectional(_InputIter __first, _InputIter __middle1, _InputIter __last, _Distance __distance) { _InputIter __middle2 = __middle1; do { if (!__distance) break; if (__middle2 != __last) { ++__middle2; --__distance; } else if (__middle1 == __first) { break; } if (!__distance) break; if (__middle1 != __first) { --__middle1; --__distance; } else if (__middle2 == __last) { break; } } while (true); return std::make_pair(__middle1, __middle2); } template _InputIter advance_forward(_InputIter __first, _InputIter __last, _Distance __distance) { while (__first != __last && __distance != 0) { __first++; __distance--; } return __first; } template _InputIter advance_backward(_InputIter __first, _InputIter __last, _Distance __distance) { while (__first != __last && __distance != 0) { __first--; __distance--; } return __first; } template struct compare_base : public std::binary_function<_Value, _Value, bool> { bool operator () (const _Value& complete, const _Value& base) const { return !complete.compare(0, base.size(), base); } }; // Count the number of elements from the start of the containers to // the first inequal element. template typename std::iterator_traits<_InputIter1>::difference_type count_base(_InputIter1 __first1, _InputIter1 __last1, _InputIter2 __first2, _InputIter2 __last2) { typename std::iterator_traits<_InputIter1>::difference_type __n = 0; for ( ;__first1 != __last1 && __first2 != __last2; ++__first1, ++__first2, ++__n) if (*__first1 != *__first2) return __n; return __n; } template _Return make_base(_InputIter __first, _InputIter __last, _Ftor __ftor) { if (__first == __last) return ""; _Return __base = __ftor(*__first++); for ( ;__first != __last; ++__first) { typename std::iterator_traits<_InputIter>::difference_type __pos = count_base(__base.begin(), __base.end(), __ftor(*__first).begin(), __ftor(*__first).end()); if (__pos < (typename std::iterator_traits<_InputIter>::difference_type)__base.size()) __base.resize(__pos); } return __base; } template inline int popcount_wrapper(T t) { #if USE_BUILTIN_POPCOUNT if (std::numeric_limits::digits <= std::numeric_limits::digits) return __builtin_popcount(t); else return __builtin_popcountll(t); #else #error __builtin_popcount not found. unsigned int count = 0; while (t) { count += t & 0x1; t >> 1; } return count; #endif } } #endif rtorrent-0.9.6/rak/allocators.h000066400000000000000000000071131257211462100165010ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // Some allocators for cacheline aligned chunks of memory, etc. #ifndef RAK_ALLOCATORS_H #define RAK_ALLOCATORS_H #include #include #include #include namespace rak { template class cacheline_allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef const void* const_void_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; cacheline_allocator() throw() { } cacheline_allocator(const cacheline_allocator&) throw() { } template cacheline_allocator(const cacheline_allocator&) throw() { } ~cacheline_allocator() throw() { } template struct rebind { typedef cacheline_allocator other; }; // return address of values pointer address (reference value) const { return &value; } const_pointer address (const_reference value) const { return &value; } size_type max_size () const throw() { return std::numeric_limits::max() / sizeof(T); } pointer allocate(size_type num, const_void_pointer hint = 0) { return alloc_size(num*sizeof(T)); } static pointer alloc_size(size_type size) { pointer ptr = NULL; int __UNUSED result = posix_memalign((void**)&ptr, LT_SMP_CACHE_BYTES, size); return ptr; } void construct (pointer p, const T& value) { new((void*)p)T(value); } void destroy (pointer p) { p->~T(); } void deallocate (pointer p, size_type num) { free((void*)p); } }; template bool operator== (const cacheline_allocator&, const cacheline_allocator&) throw() { return true; } template bool operator!= (const cacheline_allocator&, const cacheline_allocator&) throw() { return false; } } // // Operator new with custom allocators: // template void* operator new(size_t s, rak::cacheline_allocator a) { return a.alloc_size(s); } #endif // namespace rak rtorrent-0.9.6/rak/error_number.h000066400000000000000000000064431257211462100170440ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_ERROR_NUMBER_H #define RAK_ERROR_NUMBER_H #include #include namespace rak { class error_number { public: static const int e_access = EACCES; static const int e_again = EAGAIN; static const int e_connreset = ECONNRESET; static const int e_connaborted = ECONNABORTED; static const int e_deadlk = EDEADLK; static const int e_noent = ENOENT; static const int e_nodev = ENODEV; static const int e_nomem = ENOMEM; static const int e_notdir = ENOTDIR; static const int e_isdir = EISDIR; static const int e_intr = EINTR; error_number() : m_errno(0) {} error_number(int e) : m_errno(e) {} bool is_valid() const { return m_errno != 0; } int value() const { return m_errno; } const char* c_str() const { return std::strerror(m_errno); } bool is_blocked_momentary() const { return m_errno == e_again || m_errno == e_intr; } bool is_blocked_prolonged() const { return m_errno == e_deadlk; } bool is_closed() const { return m_errno == e_connreset || m_errno == e_connaborted; } bool is_bad_path() const { return m_errno == e_noent || m_errno == e_notdir || m_errno == e_access; } static error_number current() { return errno; } static void clear_global() { errno = 0; } static void set_global(error_number err) { errno = err.m_errno; } bool operator == (const error_number& e) const { return m_errno == e.m_errno; } private: int m_errno; }; } #endif rtorrent-0.9.6/rak/file_stat.h000066400000000000000000000065461257211462100163210ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_FILE_STAT_H #define RAK_FILE_STAT_H #include #include #include namespace rak { class file_stat { public: // Consider storing rak::error_number. bool update(int fd) { return fstat(fd, &m_stat) == 0; } bool update(const char* filename) { return stat(filename, &m_stat) == 0; } bool update(const std::string& filename) { return update(filename.c_str()); } bool update_link(const char* filename) { return lstat(filename, &m_stat) == 0; } bool update_link(const std::string& filename) { return update_link(filename.c_str()); } bool is_regular() const { return S_ISREG(m_stat.st_mode); } bool is_directory() const { return S_ISDIR(m_stat.st_mode); } bool is_character() const { return S_ISCHR(m_stat.st_mode); } bool is_block() const { return S_ISBLK(m_stat.st_mode); } bool is_fifo() const { return S_ISFIFO(m_stat.st_mode); } bool is_link() const { return S_ISLNK(m_stat.st_mode); } bool is_socket() const { return S_ISSOCK(m_stat.st_mode); } off_t size() const { return m_stat.st_size; } time_t access_time() const { return m_stat.st_atime; } time_t change_time() const { return m_stat.st_ctime; } time_t modified_time() const { return m_stat.st_mtime; } private: struct stat m_stat; }; } #endif rtorrent-0.9.6/rak/fs_stat.h000066400000000000000000000054421257211462100160040ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_FS_STAT_H #define RAK_FS_STAT_H #include #include #include #if HAVE_SYS_VFS_H #include #endif #if HAVE_SYS_STATVFS_H #include #endif #if HAVE_SYS_STATFS_H #include #endif #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_MOUNT_H #include #endif namespace rak { class fs_stat { public: typedef FS_STAT_SIZE_TYPE blocksize_type; typedef FS_STAT_COUNT_TYPE blockcount_type; typedef FS_STAT_STRUCT fs_stat_type; bool update(int fd) { return FS_STAT_FD; } bool update(const char* fn) { return FS_STAT_FN; } bool update(const std::string& filename) { return update(filename.c_str()); } blocksize_type blocksize() { return FS_STAT_BLOCK_SIZE; } blockcount_type blocks_avail() { return m_stat.f_bavail; } int64_t bytes_avail() { return (int64_t) blocksize() * m_stat.f_bavail; } private: fs_stat_type m_stat; }; } #endif rtorrent-0.9.6/rak/functional.h000066400000000000000000000412141257211462100165000ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_FUNCTIONAL_H #define RAK_FUNCTIONAL_H #include #include namespace rak { template struct reference_fix { typedef Type type; }; template struct reference_fix { typedef Type type; }; template struct value_t { value_t(Type v) : m_v(v) {} Type operator () () const { return m_v; } Type m_v; }; template inline value_t value(Type v) { return value_t(v); } template struct accumulate_t { accumulate_t(Type t, Ftor f) : result(t), m_f(f) {} template void operator () (const Arg& a) { result += m_f(a); } Type result; Ftor m_f; }; template inline accumulate_t accumulate(Type t, Ftor f) { return accumulate_t(t, f); } // Operators: template struct equal_t { typedef bool result_type; equal_t(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t == m_f(a); } Type m_t; Ftor m_f; }; template inline equal_t equal(Type t, Ftor f) { return equal_t(t, f); } template struct equal_ptr_t { typedef bool result_type; equal_ptr_t(Type* t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (const Arg& a) { return *m_t == *m_f(a); } Type* m_t; Ftor m_f; }; template inline equal_ptr_t equal_ptr(Type* t, Ftor f) { return equal_ptr_t(t, f); } template struct not_equal_t { typedef bool result_type; not_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t != m_f(a); } Type m_t; Ftor m_f; }; template inline not_equal_t not_equal(Type t, Ftor f) { return not_equal_t(t, f); } template struct less_t { typedef bool result_type; less_t(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t < m_f(a); } Type m_t; Ftor m_f; }; template inline less_t less(Type t, Ftor f) { return less_t(t, f); } template struct less2_t : public std::binary_function { less2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {} bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) { return m_f_a(a) < m_f_b(b); } FtorA m_f_a; FtorB m_f_b; }; template inline less2_t less2(FtorA f_a, FtorB f_b) { return less2_t(f_a,f_b); } template struct _greater { typedef bool result_type; _greater(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t > m_f(a); } Type m_t; Ftor m_f; }; template inline _greater greater(Type t, Ftor f) { return _greater(t, f); } template struct greater2_t : public std::binary_function { greater2_t(FtorA f_a, FtorB f_b) : m_f_a(f_a), m_f_b(f_b) {} bool operator () (typename FtorA::argument_type a, typename FtorB::argument_type b) { return m_f_a(a) > m_f_b(b); } FtorA m_f_a; FtorB m_f_b; }; template inline greater2_t greater2(FtorA f_a, FtorB f_b) { return greater2_t(f_a,f_b); } template struct less_equal_t { typedef bool result_type; less_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t <= m_f(a); } Type m_t; Ftor m_f; }; template inline less_equal_t less_equal(Type t, Ftor f) { return less_equal_t(t, f); } template struct greater_equal_t { typedef bool result_type; greater_equal_t(Type t, Ftor f) : m_t(t), m_f(f) {} template bool operator () (Arg& a) { return m_t >= m_f(a); } Type m_t; Ftor m_f; }; template inline greater_equal_t greater_equal(Type t, Ftor f) { return greater_equal_t(t, f); } template struct invert : public std::unary_function { Tp operator () (const Tp& x) const { return ~x; } }; template struct on_t : public std::unary_function { typedef typename Dest::result_type result_type; on_t(Src s, Dest d) : m_dest(d), m_src(s) {} result_type operator () (typename reference_fix::type arg) { return m_dest(m_src(arg)); } Dest m_dest; Src m_src; }; template inline on_t on(Src s, Dest d) { return on_t(s, d); } template struct on2_t : public std::binary_function { typedef typename Dest::result_type result_type; on2_t(Src s, Dest d) : m_dest(d), m_src(s) {} result_type operator () (typename reference_fix::type first, typename reference_fix::type second) { return m_dest(m_src(first), second); } Dest m_dest; Src m_src; }; template inline on2_t on2(Src s, Dest d) { return on2_t(s, d); } // Creates a functor for accessing a member. template struct mem_ptr_t : public std::unary_function { mem_ptr_t(Member Class::*m) : m_member(m) {} Member& operator () (Class* c) { return c->*m_member; } const Member& operator () (const Class* c) { return c->*m_member; } Member Class::*m_member; }; template inline mem_ptr_t mem_ptr(Member Class::*m) { return mem_ptr_t(m); } template struct mem_ref_t : public std::unary_function { mem_ref_t(Member Class::*m) : m_member(m) {} Member& operator () (Class& c) { return c.*m_member; } Member Class::*m_member; }; template struct const_mem_ref_t : public std::unary_function { const_mem_ref_t(const Member Class::*m) : m_member(m) {} const Member& operator () (const Class& c) { return c.*m_member; } const Member Class::*m_member; }; template inline mem_ref_t mem_ref(Member Class::*m) { return mem_ref_t(m); } template inline const_mem_ref_t const_mem_ref(const Member Class::*m) { return const_mem_ref_t(m); } template struct if_then_t { if_then_t(Cond c, Then t) : m_cond(c), m_then(t) {} template void operator () (Arg& a) { if (m_cond(a)) m_then(a); } Cond m_cond; Then m_then; }; template inline if_then_t if_then(Cond c, Then t) { return if_then_t(c, t); } template struct call_delete : public std::unary_function { void operator () (T* t) { delete t; } }; template inline void call_delete_func(T* t) { delete t; } template class bind1st_t : public std::unary_function { public: typedef typename reference_fix::type value_type; typedef typename reference_fix::type argument_type; bind1st_t(const Operation& op, const value_type v) : m_op(op), m_value(v) {} typename Operation::result_type operator () (const argument_type arg) { return m_op(m_value, arg); } protected: Operation m_op; value_type m_value; }; template inline bind1st_t bind1st(const Operation& op, const Type& val) { return bind1st_t(op, val); } template class bind2nd_t : public std::unary_function { public: typedef typename reference_fix::type argument_type; typedef typename reference_fix::type value_type; bind2nd_t(const Operation& op, const value_type v) : m_op(op), m_value(v) {} typename Operation::result_type operator () (argument_type arg) { return m_op(arg, m_value); } protected: Operation m_op; value_type m_value; }; template inline bind2nd_t bind2nd(const Operation& op, const Type& val) { return bind2nd_t(op, val); } // Lightweight callback function including pointer to object. Should // be replaced by TR1 stuff later. Requires an object to bind, instead // of using a seperate functor for that. template class ptr_fun0 { public: typedef Ret result_type; typedef Ret (*Function)(); ptr_fun0() {} ptr_fun0(Function f) : m_function(f) {} bool is_valid() const { return m_function; } Ret operator () () { return m_function(); } private: Function m_function; }; template class mem_fun0 { public: typedef Ret result_type; typedef Ret (Object::*Function)(); mem_fun0() : m_object(NULL) {} mem_fun0(Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } Ret operator () () { return (m_object->*m_function)(); } private: Object* m_object; Function m_function; }; template class const_mem_fun0 { public: typedef Ret result_type; typedef Ret (Object::*Function)() const; const_mem_fun0() : m_object(NULL) {} const_mem_fun0(const Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } Ret operator () () const { return (m_object->*m_function)(); } private: const Object* m_object; Function m_function; }; template class mem_fun1 { public: typedef Ret result_type; typedef Ret (Object::*Function)(Arg1); mem_fun1() : m_object(NULL) {} mem_fun1(Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } Ret operator () (Arg1 a1) { return (m_object->*m_function)(a1); } private: Object* m_object; Function m_function; }; template class const_mem_fun1 { public: typedef Ret result_type; typedef Ret (Object::*Function)(Arg1) const; const_mem_fun1() : m_object(NULL) {} const_mem_fun1(const Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } Ret operator () (Arg1 a1) const { return (m_object->*m_function)(a1); } private: const Object* m_object; Function m_function; }; template class mem_fun2 : public std::binary_function { public: typedef Ret result_type; typedef Ret (Object::*Function)(Arg1, Arg2); typedef Object object_type; mem_fun2() : m_object(NULL) {} mem_fun2(Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } object_type* object() { return m_object; } const object_type* object() const { return m_object; } Ret operator () (Arg1 a1, Arg2 a2) { return (m_object->*m_function)(a1, a2); } private: Object* m_object; Function m_function; }; template class mem_fun3 { public: typedef Ret result_type; typedef Ret (Object::*Function)(Arg1, Arg2, Arg3); mem_fun3() : m_object(NULL) {} mem_fun3(Object* o, Function f) : m_object(o), m_function(f) {} bool is_valid() const { return m_object; } Ret operator () (Arg1 a1, Arg2 a2, Arg3 a3) { return (m_object->*m_function)(a1, a2, a3); } private: Object* m_object; Function m_function; }; template inline ptr_fun0 ptr_fun(Ret (*f)()) { return ptr_fun0(f); } template inline mem_fun0 make_mem_fun(Object* o, Ret (Object::*f)()) { return mem_fun0(o, f); } template inline const_mem_fun0 make_mem_fun(const Object* o, Ret (Object::*f)() const) { return const_mem_fun0(o, f); } template inline mem_fun1 make_mem_fun(Object* o, Ret (Object::*f)(Arg1)) { return mem_fun1(o, f); } template inline const_mem_fun1 make_mem_fun(const Object* o, Ret (Object::*f)(Arg1) const) { return const_mem_fun1(o, f); } template inline mem_fun2 make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2)) { return mem_fun2(o, f); } template inline mem_fun3 make_mem_fun(Object* o, Ret (Object::*f)(Arg1, Arg2, Arg3)) { return mem_fun3(o, f); } template inline void slot_list_call(const Container& slot_list) { if (slot_list.empty()) return; typename Container::const_iterator first = slot_list.begin(); typename Container::const_iterator next = slot_list.begin(); while (++next != slot_list.end()) { (*first)(); first = next; } (*first)(); } template inline void slot_list_call(const Container& slot_list, Arg1 arg1) { if (slot_list.empty()) return; typename Container::const_iterator first = slot_list.begin(); typename Container::const_iterator next = slot_list.begin(); while (++next != slot_list.end()) { (*first)(arg1); first = next; } (*first)(arg1); } template inline void slot_list_call(const Container& slot_list, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { if (slot_list.empty()) return; typename Container::const_iterator first = slot_list.begin(); typename Container::const_iterator next = slot_list.begin(); while (++next != slot_list.end()) { (*first)(arg1, arg2, arg3, arg4); first = next; } (*first)(arg1, arg2, arg3, arg4); } } #endif rtorrent-0.9.6/rak/functional_fun.h000066400000000000000000000501441257211462100173520ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // This file contains functors that wrap function pointers and member // function pointers. // // 'fn' functors are polymorphic and derives from 'rak::function' and // thus is less strict about types, this adds the cost of calling a // virtual function. // // 'fun' functors are non-polymorphic and thus cheaper, but requires // the target object's type in the functor's template arguments. // // This should be replaced with TR1 stuff when it becomes widely // available. At the moment it behaves like std::auto_ptr, so be // careful when copying. #ifndef RAK_FUNCTIONAL_FUN_H #define RAK_FUNCTIONAL_FUN_H #include #include #include #include namespace rak { template class function_base0 { public: virtual ~function_base0() {} virtual Result operator () () = 0; }; template class function_base1 : public std::unary_function { public: virtual ~function_base1() {} virtual Result operator () (Arg1 arg1) = 0; }; template class function_base2 : public std::binary_function { public: virtual ~function_base2() {} virtual Result operator () (Arg1 arg1, Arg2 arg2) = 0; }; template class function_base3 { public: virtual ~function_base3() {} virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) = 0; }; template class function0 { public: typedef Result result_type; typedef function_base0 base_type; bool is_valid() const { return m_base.get() != NULL; } void set(base_type* base) { m_base = std::tr1::shared_ptr(base); } base_type* release() { return m_base.release(); } Result operator () () { return (*m_base)(); } private: std::tr1::shared_ptr m_base; }; template class function1 { public: typedef Result result_type; typedef function_base1 base_type; bool is_valid() const { return m_base.get() != NULL; } void set(base_type* base) { m_base = std::tr1::shared_ptr(base); } base_type* release() { return m_base.release(); } Result operator () (Arg1 arg1) { return (*m_base)(arg1); } private: std::tr1::shared_ptr m_base; }; template class function2 { public: typedef Result result_type; typedef function_base2 base_type; bool is_valid() const { return m_base.get() != NULL; } void set(base_type* base) { m_base = std::tr1::shared_ptr(base); } base_type* release() { return m_base.release(); } Result operator () (Arg1 arg1, Arg2 arg2) { return (*m_base)(arg1, arg2); } private: std::tr1::shared_ptr m_base; }; template class function2 { public: typedef Result result_type; typedef function_base1 base_type; bool is_valid() const { return m_base.get() != NULL; } void set(base_type* base) { m_base = std::tr1::shared_ptr(base); } base_type* release() { return m_base.release(); } Result operator () (Arg2 arg2) { return (*m_base)(arg2); } template Result operator () (Discard discard, Arg2 arg2) { return (*m_base)(arg2); } private: std::tr1::shared_ptr m_base; }; template class function3 { public: typedef Result result_type; typedef function_base3 base_type; bool is_valid() const { return m_base.get() != NULL; } void set(base_type* base) { m_base = std::tr1::shared_ptr(base); } base_type* release() { return m_base.release(); } Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (*m_base)(arg1, arg2, arg3); } private: std::tr1::shared_ptr m_base; }; template class ptr_fn0_t : public function_base0 { public: typedef Result (*Func)(); ptr_fn0_t(Func func) : m_func(func) {} virtual ~ptr_fn0_t() {} virtual Result operator () () { return m_func(); } private: Func m_func; }; template class ptr_fn1_t : public function_base1 { public: typedef Result (*Func)(Arg1); ptr_fn1_t(Func func) : m_func(func) {} virtual ~ptr_fn1_t() {} virtual Result operator () (Arg1 arg1) { return m_func(arg1); } private: Func m_func; }; template class ptr_fn2_t : public function_base2 { public: typedef Result (*Func)(Arg1, Arg2); ptr_fn2_t(Func func) : m_func(func) {} virtual ~ptr_fn2_t() {} virtual Result operator () (Arg1 arg1, Arg2 arg2) { return m_func(arg1, arg2); } private: Func m_func; }; template class mem_fn0_t : public function_base0 { public: typedef Result (Object::*Func)(); mem_fn0_t(Object* object, Func func) : m_object(object), m_func(func) {} virtual ~mem_fn0_t() {} virtual Result operator () () { return (m_object->*m_func)(); } private: Object* m_object; Func m_func; }; template class mem_fn1_t : public function_base1 { public: typedef Result (Object::*Func)(Arg1); mem_fn1_t(Object* object, Func func) : m_object(object), m_func(func) {} virtual ~mem_fn1_t() {} virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); } private: Object* m_object; Func m_func; }; template class mem_fn3_t : public function_base3 { public: typedef Result (Object::*Func)(Arg1, Arg2, Arg3); mem_fn3_t(Object* object, Func func) : m_object(object), m_func(func) {} virtual ~mem_fn3_t() {} virtual Result operator () (Arg1 arg1, Arg2 arg2, Arg3 arg3) { return (m_object->*m_func)(arg1, arg2, arg3); } private: Object* m_object; Func m_func; }; template class mem_fn2_t : public function_base2 { public: typedef Result (Object::*Func)(Arg1, Arg2); mem_fn2_t(Object* object, Func func) : m_object(object), m_func(func) {} virtual ~mem_fn2_t() {} virtual Result operator () (Arg1 arg1, Arg2 arg2) { return (m_object->*m_func)(arg1, arg2); } private: Object* m_object; Func m_func; }; template class const_mem_fn0_t : public function_base0 { public: typedef Result (Object::*Func)() const; const_mem_fn0_t(const Object* object, Func func) : m_object(object), m_func(func) {} virtual ~const_mem_fn0_t() {} virtual Result operator () () { return (m_object->*m_func)(); } private: const Object* m_object; Func m_func; }; template class const_mem_fn1_t : public function_base1 { public: typedef Result (Object::*Func)(Arg1) const; const_mem_fn1_t(const Object* object, Func func) : m_object(object), m_func(func) {} virtual ~const_mem_fn1_t() {} virtual Result operator () (Arg1 arg1) { return (m_object->*m_func)(arg1); } private: const Object* m_object; Func m_func; }; // Unary functor with a bound argument. template class mem_fn0_b1_t : public function_base0 { public: typedef Result (Object::*Func)(Arg1); mem_fn0_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {} virtual ~mem_fn0_b1_t() {} virtual Result operator () () { return (m_object->*m_func)(m_arg1); } private: Object* m_object; Func m_func; const Arg1 m_arg1; }; template class mem_fn1_b1_t : public function_base1 { public: typedef Result (Object::*Func)(Arg1, Arg2); mem_fn1_b1_t(Object* object, Func func, const Arg1 arg1) : m_object(object), m_func(func), m_arg1(arg1) {} virtual ~mem_fn1_b1_t() {} virtual Result operator () (const Arg2 arg2) { return (m_object->*m_func)(m_arg1, arg2); } private: Object* m_object; Func m_func; const Arg1 m_arg1; }; template class mem_fn1_b2_t : public function_base1 { public: typedef Result (Object::*Func)(Arg1, Arg2); mem_fn1_b2_t(Object* object, Func func, const Arg2 arg2) : m_object(object), m_func(func), m_arg2(arg2) {} virtual ~mem_fn1_b2_t() {} virtual Result operator () (const Arg1 arg1) { return (m_object->*m_func)(arg1, m_arg2); } private: Object* m_object; Func m_func; const Arg2 m_arg2; }; template class ptr_fn0_b1_t : public function_base0 { public: typedef Result (*Func)(Arg1); ptr_fn0_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {} virtual ~ptr_fn0_b1_t() {} virtual Result operator () () { return m_func(m_arg1); } private: Func m_func; Arg1 m_arg1; }; template class ptr_fn1_b1_t : public function_base1 { public: typedef Result (*Func)(Arg1, Arg2); ptr_fn1_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {} virtual ~ptr_fn1_b1_t() {} virtual Result operator () (Arg2 arg2) { return m_func(m_arg1, arg2); } private: Func m_func; Arg1 m_arg1; }; template class ptr_fn2_b1_t : public function_base2 { public: typedef Result (*Func)(Arg1, Arg2, Arg3); ptr_fn2_b1_t(Func func, const Arg1 arg1) : m_func(func), m_arg1(arg1) {} virtual ~ptr_fn2_b1_t() {} virtual Result operator () (Arg2 arg2, Arg3 arg3) { return m_func(m_arg1, arg2, arg3); } private: Func m_func; Arg1 m_arg1; }; template class ftor_fn1_t : public function_base1 { public: typedef typename Ftor::result_type result_type; typedef typename Ftor::argument_type argument_type; ftor_fn1_t(Ftor ftor) : m_ftor(ftor) {} virtual ~ftor_fn1_t() {} virtual result_type operator () (argument_type arg1) { return m_ftor(arg1); } private: Ftor m_ftor; }; template class ftor_fn2_t : public function_base2 { public: typedef typename Ftor::result_type result_type; typedef typename Ftor::first_argument_type first_argument_type; typedef typename Ftor::second_argument_type second_argument_type; ftor_fn2_t(Ftor ftor) : m_ftor(ftor) {} virtual ~ftor_fn2_t() {} virtual result_type operator () (first_argument_type arg1, second_argument_type arg2) { return m_ftor(arg1, arg2); } private: Ftor m_ftor; }; template class value_fn0_t : public function_base0 { public: value_fn0_t(const Result& val) : m_value(val) {} virtual Result operator () () { return m_value; } private: Result m_value; }; template class convert_fn0_t : public function_base0 { public: typedef function0 src_type; convert_fn0_t(typename src_type::base_type* object) { m_object.set(object); } virtual ~convert_fn0_t() {} virtual Result operator () () { return m_object(); } private: src_type m_object; }; template class convert_fn1_t : public function_base1 { public: typedef function1 src_type; convert_fn1_t(typename src_type::base_type* object) { m_object.set(object); } virtual ~convert_fn1_t() {} virtual Result operator () (Arg1 arg1) { return m_object(arg1); } private: src_type m_object; }; template class convert_fn2_t : public function_base2 { public: typedef function2 src_type; convert_fn2_t(typename src_type::base_type* object) { m_object.set(object); } virtual ~convert_fn2_t() {} virtual Result operator () (Arg1 arg1, Arg2 arg2) { return m_object(arg1, arg2); } private: src_type m_object; }; template inline function_base0* ptr_fn(Result (*func)()) { return new ptr_fn0_t(func); } template inline function_base1* ptr_fn(Result (*func)(Arg1)) { return new ptr_fn1_t(func); } template inline function_base2* ptr_fn(Result (*func)(Arg1, Arg2)) { return new ptr_fn2_t(func); } template inline function_base0* mem_fn(Object* object, Result (Object::*func)()) { return new mem_fn0_t(object, func); } template inline function_base1* mem_fn(Object* object, Result (Object::*func)(Arg1)) { return new mem_fn1_t(object, func); } template inline function_base2* mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2)) { return new mem_fn2_t(object, func); } template inline function_base3* mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2, Arg3)) { return new mem_fn3_t(object, func); } template inline function_base0* mem_fn(const Object* object, Result (Object::*func)() const) { return new const_mem_fn0_t(object, func); } template inline function_base1* mem_fn(const Object* object, Result (Object::*func)(Arg1) const) { return new const_mem_fn1_t(object, func); } template inline function_base0* bind_mem_fn(Object* object, Result (Object::*func)(Arg1), const Arg1 arg1) { return new mem_fn0_b1_t(object, func, arg1); } template inline function_base1* bind_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg1 arg1) { return new mem_fn1_b1_t(object, func, arg1); } template inline function_base1* bind2_mem_fn(Object* object, Result (Object::*func)(Arg1, Arg2), const Arg2 arg2) { return new mem_fn1_b2_t(object, func, arg2); } template inline function_base0* bind_ptr_fn(Result (*func)(Arg1), const Arg1 arg1) { return new ptr_fn0_b1_t(func, arg1); } template inline function_base1* bind_ptr_fn(Result (*func)(Arg1, Arg2), const Arg1 arg1) { return new ptr_fn1_b1_t(func, arg1); } template inline function_base2* bind_ptr_fn(Result (*func)(Arg1, Arg2, Arg3), const Arg1 arg1) { return new ptr_fn2_b1_t(func, arg1); } template inline function_base1* ftor_fn1(Ftor ftor) { return new ftor_fn1_t(ftor); } template inline function_base2* ftor_fn2(Ftor ftor) { return new ftor_fn2_t(ftor); } template inline function_base0* value_fn(const Result& val) { return new value_fn0_t(val); } template struct equal_types_t { typedef A first_type; typedef B second_type; const static int result = 0; }; template struct equal_types_t { typedef A first_type; typedef A second_type; const static int result = 1; }; template inline function_base0* convert_fn(function_base0* src) { if (equal_types_t, function_base0 >::result) // The pointer cast never gets done if the types are different, // but needs to be here to pleasant the compiler. return reinterpret_cast, function_base0 >::first_type*>(src); else return new convert_fn0_t(src); } template inline function_base1* convert_fn(function_base1* src) { if (equal_types_t, function_base1 >::result) // The pointer cast never gets done if the types are different, // but needs to be here to pleasant the compiler. return reinterpret_cast, function_base1 >::first_type*>(src); else return new convert_fn1_t(src); } template inline function_base2* convert_fn(function_base2* src) { if (equal_types_t, function_base2 >::result) // The pointer cast never gets done if the types are different, // but needs to be here to pleasant the compiler. return reinterpret_cast, function_base2 >::first_type*>(src); else return new convert_fn2_t(src); } } #endif rtorrent-0.9.6/rak/partial_queue.h000066400000000000000000000136731257211462100172060ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_PARTIAL_QUEUE_H #define RAK_PARTIAL_QUEUE_H #include #include #include namespace rak { // First step, don't allow overflowing to the next layer. Only disable // the above layers for now. // We also include 0 in a single layer as some chunk may be available // only through seeders. class partial_queue { public: typedef uint8_t key_type; typedef uint32_t mapped_type; typedef uint16_t size_type; typedef std::pair size_pair_type; static const size_type num_layers = 8; partial_queue() : m_data(NULL), m_maxLayerSize(0) {} ~partial_queue() { disable(); } bool is_full() const { return m_ceiling == 0; } bool is_layer_full(size_type l) const { return m_layers[l].second >= m_maxLayerSize; } bool is_enabled() const { return m_data != NULL; } // Add check to see if we can add more. Also make it possible to // check how full we are in the lower parts so the caller knows when // he can stop searching. // // Though propably not needed, as we must continue til the first // layer is full. size_type max_size() const { return m_maxLayerSize * num_layers; } size_type max_layer_size() const { return m_maxLayerSize; } // Must be less that or equal to (max size_type) / num_layers. void enable(size_type ls); void disable(); void clear(); // Safe to call while pop'ing and it will not reuse pop'ed indices // so it is guaranteed to reach max_size at some point. This will // ensure that the user needs to refill with new data at regular // intervals. bool insert(key_type key, mapped_type value); // Only call this when pop'ing as it moves the index. bool prepare_pop(); mapped_type pop(); private: partial_queue(const partial_queue&); void operator = (const partial_queue&); static size_type ceiling(size_type layer) { return (2 << layer) - 1; } void find_non_empty(); mapped_type* m_data; size_type m_maxLayerSize; size_type m_index; size_type m_ceiling; size_pair_type m_layers[num_layers]; }; inline void partial_queue::enable(size_type ls) { if (ls == 0) throw std::logic_error("partial_queue::enable(...) ls == 0."); delete [] m_data; m_data = new mapped_type[ls * num_layers]; m_maxLayerSize = ls; } inline void partial_queue::disable() { delete [] m_data; m_data = NULL; m_maxLayerSize = 0; } inline void partial_queue::clear() { if (m_data == NULL) return; m_index = 0; m_ceiling = ceiling(num_layers - 1); std::memset(m_layers, 0, num_layers * sizeof(size_pair_type)); } inline bool partial_queue::insert(key_type key, mapped_type value) { if (key >= m_ceiling) return false; size_type idx = 0; // Hmm... since we already check the 'm_ceiling' above, we only need // to find the target layer. Could this be calculated directly? while (key >= ceiling(idx)) ++idx; m_index = std::min(m_index, idx); // Currently don't allow overflow. if (is_layer_full(idx)) throw std::logic_error("partial_queue::insert(...) layer already full."); //return false; m_data[m_maxLayerSize * idx + m_layers[idx].second] = value; m_layers[idx].second++; if (is_layer_full(idx)) // Set the ceiling to 0 when layer 0 is full so no more values can // be inserted. m_ceiling = idx > 0 ? ceiling(idx - 1) : 0; return true; } // is_empty() will iterate to the first layer with un-popped elements // and return true, else return false when it reaches a overflowed or // the last layer. inline bool partial_queue::prepare_pop() { while (m_layers[m_index].first == m_layers[m_index].second) { if (is_layer_full(m_index) || m_index + 1 == num_layers) return false; m_index++; } return true; } inline partial_queue::mapped_type partial_queue::pop() { if (m_index >= num_layers || m_layers[m_index].first >= m_layers[m_index].second) throw std::logic_error("partial_queue::pop() bad state."); return m_data[m_index * m_maxLayerSize + m_layers[m_index].first++]; } } #endif rtorrent-0.9.6/rak/path.h000066400000000000000000000054321257211462100152740ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // Various functions for manipulating file paths. Also consider making // a directory iterator. #ifndef RAK_PATH_H #define RAK_PATH_H #include #include namespace rak { inline std::string path_expand(const std::string& path) { if (path.empty() || path[0] != '~') return path; char* home = std::getenv("HOME"); if (home == NULL) return path; return home + path.substr(1); } // Don't inline this... // // Same strlcpy as found in *bsd. inline size_t strlcpy(char *dest, const char *src, size_t size) { size_t n = size; const char* first = src; if (n != 0) { while (--n != 0) if ((*dest++ = *src++) == '\0') break; } if (n == 0) { if (size != 0) *dest = '\0'; while (*src++) ; } return src - first - 1; } inline char* path_expand(const char* src, char* first, char* last) { if (*src == '~') { char* home = std::getenv("HOME"); if (home == NULL) return first; first += strlcpy(first, home, std::distance(first, last)); if (first > last) return last; src++; } return std::min(first + strlcpy(first, src, std::distance(first, last)), last); } } #endif rtorrent-0.9.6/rak/priority_queue.h000066400000000000000000000112211257211462100174160ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // priority_queue is a priority queue implemented using a binary // heap. It can contain multiple instances of a value. #ifndef RAK_PRIORITY_QUEUE_H #define RAK_PRIORITY_QUEUE_H #include #include #include namespace rak { template > class priority_queue : public std::vector { public: typedef std::vector base_type; typedef typename base_type::reference reference; typedef typename base_type::const_reference const_reference; typedef typename base_type::iterator iterator; typedef typename base_type::const_iterator const_iterator; typedef typename base_type::value_type value_type; using base_type::begin; using base_type::end; using base_type::size; using base_type::empty; priority_queue(Compare l = Compare(), Equal e = Equal()) : m_compare(l), m_equal(e) {} const_reference top() const { return base_type::front(); } void pop() { std::pop_heap(begin(), end(), m_compare); base_type::pop_back(); } void push(const value_type& value) { base_type::push_back(value); std::push_heap(begin(), end(), m_compare); } template iterator find(const Key& key) { return std::find_if(begin(), end(), std::bind2nd(m_equal, key)); } template bool erase(const Key& key) { iterator itr = find(key); if (itr == end()) return false; erase(itr); return true; } // Removes 'itr' from the queue. This assumes 'itr' has been // modified such that it has a higher priority than any other // element in the queue. void erase(iterator itr) { // std::push_heap(begin(), ++itr, m_compare); // pop(); base_type::erase(itr); std::make_heap(begin(), end(), m_compare); } private: Compare m_compare; Equal m_equal; }; // Iterate while the top node has higher priority, as 'Compare' // returns false. template class queue_pop_iterator : public std::iterator { public: typedef Queue container_type; queue_pop_iterator() : m_queue(NULL) {} queue_pop_iterator(Queue* q, Compare c) : m_queue(q), m_compare(c) {} queue_pop_iterator& operator ++ () { m_queue->pop(); return *this; } queue_pop_iterator& operator ++ (int) { m_queue->pop(); return *this; } typename container_type::const_reference operator * () { return m_queue->top(); } bool operator != (const queue_pop_iterator& itr) { return !m_queue->empty() && !m_compare(m_queue->top()); } bool operator == (const queue_pop_iterator& itr) { return m_queue->empty() || m_compare(m_queue->top()); } private: Queue* m_queue; Compare m_compare; }; template inline queue_pop_iterator queue_popper(Queue& queue, Compare comp) { return queue_pop_iterator(&queue, comp); } } #endif rtorrent-0.9.6/rak/priority_queue_default.h000066400000000000000000000112431257211462100211260ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_PRIORITY_QUEUE_DEFAULT_H #define RAK_PRIORITY_QUEUE_DEFAULT_H #include #include #include #include #include "torrent/exceptions.h" namespace rak { class priority_item { public: typedef std::tr1::function slot_void; priority_item() {} ~priority_item() { if (is_queued()) throw torrent::internal_error("priority_item::~priority_item() called on a queued item."); m_time = timer(); m_slot = slot_void(); } bool is_valid() const { return (bool)m_slot; } bool is_queued() const { return m_time != timer(); } slot_void& slot() { return m_slot; } const timer& time() const { return m_time; } void clear_time() { m_time = timer(); } void set_time(const timer& t) { m_time = t; } bool compare(const timer& t) const { return m_time > t; } private: priority_item(const priority_item&); void operator = (const priority_item&); timer m_time; slot_void m_slot; }; struct priority_compare { bool operator () (const priority_item* const p1, const priority_item* const p2) const { return p1->time() > p2->time(); } }; typedef std::equal_to priority_equal; typedef priority_queue > priority_queue_default; inline void priority_queue_perform(priority_queue_default* queue, timer t) { while (!queue->empty() && queue->top()->time() <= t) { priority_item* v = queue->top(); queue->pop(); v->clear_time(); v->slot()(); } } inline void priority_queue_insert(priority_queue_default* queue, priority_item* item, timer t) { if (t == timer()) throw torrent::internal_error("priority_queue_insert(...) received a bad timer."); if (!item->is_valid()) throw torrent::internal_error("priority_queue_insert(...) called on an invalid item."); if (item->is_queued()) throw torrent::internal_error("priority_queue_insert(...) called on an already queued item."); if (queue->find(item) != queue->end()) throw torrent::internal_error("priority_queue_insert(...) item found in queue."); item->set_time(t); queue->push(item); } inline void priority_queue_erase(priority_queue_default* queue, priority_item* item) { if (!item->is_queued()) return; // Check is_valid() after is_queued() so that it is safe to call // erase on untouched instances. if (!item->is_valid()) throw torrent::internal_error("priority_queue_erase(...) called on an invalid item."); // Clear time before erasing to force it to the top. item->clear_time(); if (!queue->erase(item)) throw torrent::internal_error("priority_queue_erase(...) could not find item in queue."); if (queue->find(item) != queue->end()) throw torrent::internal_error("priority_queue_erase(...) item still in queue."); } } #endif rtorrent-0.9.6/rak/regex.h000066400000000000000000000066171257211462100154600ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // This is a hacked up whole string pattern matching. Replace with // TR1's regex when that becomes widely available. It is intended for // small strings. #ifndef RAK_REGEX_H #define RAK_REGEX_H #include #include #include #include #include namespace rak { class regex : public std::unary_function { public: regex() {} regex(const std::string& p) : m_pattern(p) {} const std::string& pattern() const { return m_pattern; } bool operator () (const std::string& p) const; private: std::string m_pattern; }; // This isn't optimized, or very clean. A simple hack that should work. inline bool regex::operator () (const std::string& text) const { if (m_pattern.empty() || text.empty() || (m_pattern[0] != '*' && m_pattern[0] != text[0])) return false; // Replace with unordered_vector? std::list paths; paths.push_front(0); for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) { for (std::list::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) { unsigned int next = *itrPaths + 1; if (m_pattern[*itrPaths] != '*') itrPaths = paths.erase(itrPaths); else itrPaths++; // When we reach the end of 'm_pattern', we don't have a whole // match of 'text'. if (next == m_pattern.size()) continue; // Push to the back so that '*' will match zero length strings. if (m_pattern[next] == '*') paths.push_back(next); if (m_pattern[next] == *itrText) paths.push_front(next); } if (paths.empty()) return false; } return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end(); } } #endif rtorrent-0.9.6/rak/socket_address.h000066400000000000000000000327401257211462100173370ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // Wrappers for the various sockaddr types with focus on zero-copy // casting between the original type and the wrapper class. // // The default ctor does not initialize any data. // // _n suffixes indicate that the argument or return value is in // network byte order, _h that they are in hardware byte order. // Add define for inet6 scope id? #ifndef RAK_SOCKET_ADDRESS_H #define RAK_SOCKET_ADDRESS_H #include #include #include #include #include #include #include namespace rak { class socket_address_inet; class socket_address_inet6; class socket_address { public: static const sa_family_t af_inet = AF_INET; static const int pf_inet = PF_INET; static const sa_family_t af_inet6 = AF_INET6; static const int pf_inet6 = PF_INET6; static const sa_family_t af_unspec = AF_UNSPEC; static const int pf_unspec = PF_UNSPEC; #ifdef AF_LOCAL static const sa_family_t af_local = AF_LOCAL; static const int pf_local = PF_LOCAL; #else static const sa_family_t af_local = AF_UNIX; static const int pf_local = PF_UNIX; #endif bool is_valid() const; bool is_bindable() const; bool is_address_any() const; // Should we need to set AF_UNSPEC? void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); } sa_family_t family() const { return m_sockaddr.sa_family; } void set_family() { m_sockaddr.sa_family = af_unspec; } uint16_t port() const; void set_port(uint16_t p); std::string address_str() const; bool address_c_str(char* buf, socklen_t size) const; // Attemts to set it as an inet, then an inet6 address. It will // never set anything but net addresses, no local/unix. bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); } bool set_address_c_str(const char* a); uint32_t length() const; socket_address_inet* sa_inet() { return reinterpret_cast(this); } const socket_address_inet* sa_inet() const { return reinterpret_cast(this); } sockaddr* c_sockaddr() { return &m_sockaddr; } sockaddr_in* c_sockaddr_inet() { return &m_sockaddrInet; } const sockaddr* c_sockaddr() const { return &m_sockaddr; } const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; } #ifdef RAK_USE_INET6 socket_address_inet6* sa_inet6() { return reinterpret_cast(this); } const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); } sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; } const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; } #endif // Copy a socket address which has the length 'length. Zero out any // extranous bytes and ensure it does not go beyond the size of this // struct. void copy(const socket_address& src, size_t length); static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast(sa); } static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast(sa); } // The different families will be sorted according to the // sa_family_t's numeric value. bool operator == (const socket_address& rhs) const; bool operator < (const socket_address& rhs) const; bool operator == (const sockaddr& rhs) const { return *this == *cast_from(&rhs); } bool operator == (const sockaddr* rhs) const { return *this == *cast_from(rhs); } bool operator < (const sockaddr& rhs) const { return *this == *cast_from(&rhs); } bool operator < (const sockaddr* rhs) const { return *this == *cast_from(rhs); } private: union { sockaddr m_sockaddr; sockaddr_in m_sockaddrInet; #ifdef RAK_USE_INET6 sockaddr_in6 m_sockaddrInet6; #endif }; }; // Remeber to set the AF_INET. class socket_address_inet { public: bool is_any() const { return is_port_any() && is_address_any(); } bool is_valid() const { return !is_port_any() && !is_address_any(); } bool is_port_any() const { return port() == 0; } bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); } void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); } uint16_t port() const { return ntohs(m_sockaddr.sin_port); } uint16_t port_n() const { return m_sockaddr.sin_port; } void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); } void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; } // Should address() return the uint32_t? in_addr address() const { return m_sockaddr.sin_addr; } uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); } uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; } std::string address_str() const; bool address_c_str(char* buf, socklen_t size) const; void set_address(in_addr a) { m_sockaddr.sin_addr = a; } void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); } void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; } bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); } bool set_address_c_str(const char* a); void set_address_any() { set_port(0); set_address_h(INADDR_ANY); } sa_family_t family() const { return m_sockaddr.sin_family; } void set_family() { m_sockaddr.sin_family = AF_INET; } sockaddr* c_sockaddr() { return reinterpret_cast(&m_sockaddr); } sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; } const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); } const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; } bool operator == (const socket_address_inet& rhs) const; bool operator < (const socket_address_inet& rhs) const; private: struct sockaddr_in m_sockaddr; }; // Unique key for the address, excluding port numbers etc. class socket_address_key { public: // socket_address_host_key() {} socket_address_key(const socket_address& sa) { *this = sa; } socket_address_key& operator = (const socket_address& sa) { if (sa.family() == 0) { std::memset(this, 0, sizeof(socket_address_key)); } else if (sa.family() == socket_address::af_inet) { // Using hardware order as we use operator < to compare when // using inet only. m_addr.s_addr = sa.sa_inet()->address_h(); } else { // When we implement INET6 handling, embed the ipv4 address in // the ipv6 address. throw std::logic_error("socket_address_key(...) received an unsupported protocol family."); } return *this; } // socket_address_key& operator = (const socket_address_key& sa) { // } bool operator < (const socket_address_key& sa) const { // Compare the memory area instead. return m_addr.s_addr < sa.m_addr.s_addr; } private: union { in_addr m_addr; // #ifdef RAK_USE_INET6 // in_addr6 m_addr6; // #endif }; }; inline bool socket_address::is_valid() const { switch (family()) { case af_inet: return sa_inet()->is_valid(); // case af_inet6: // return sa_inet6().is_valid(); default: return false; } } inline bool socket_address::is_bindable() const { switch (family()) { case af_inet: return !sa_inet()->is_address_any(); default: return false; } } inline bool socket_address::is_address_any() const { switch (family()) { case af_inet: return sa_inet()->is_address_any(); default: return true; } } inline uint16_t socket_address::port() const { switch (family()) { case af_inet: return sa_inet()->port(); default: return 0; } } inline void socket_address::set_port(uint16_t p) { switch (family()) { case af_inet: return sa_inet()->set_port(p); default: break; } } inline std::string socket_address::address_str() const { switch (family()) { case af_inet: return sa_inet()->address_str(); default: return std::string(); } } inline bool socket_address::address_c_str(char* buf, socklen_t size) const { switch (family()) { case af_inet: return sa_inet()->address_c_str(buf, size); default: return false; } } inline bool socket_address::set_address_c_str(const char* a) { if (sa_inet()->set_address_c_str(a)) { sa_inet()->set_family(); return true; } else { return false; } } // Is the zero length really needed, should we require some length? inline uint32_t socket_address::length() const { switch(family()) { case af_inet: return sizeof(sockaddr_in); default: return 0; } } inline void socket_address::copy(const socket_address& src, size_t length) { length = std::min(length, sizeof(socket_address)); // Does this get properly optimized? std::memset(this, 0, sizeof(socket_address)); std::memcpy(this, &src, length); } // Should we be able to compare af_unspec? inline bool socket_address::operator == (const socket_address& rhs) const { if (family() != rhs.family()) return false; switch (family()) { case af_inet: return *sa_inet() == *rhs.sa_inet(); // case af_inet6: // return *sa_inet6() == *rhs.sa_inet6(); default: throw std::logic_error("socket_address::operator == (rhs) invalid type comparison."); } } inline bool socket_address::operator < (const socket_address& rhs) const { if (family() != rhs.family()) return family() < rhs.family(); switch (family()) { case af_inet: return *sa_inet() < *rhs.sa_inet(); // case af_inet6: // return *sa_inet6() < *rhs.sa_inet6(); default: throw std::logic_error("socket_address::operator < (rhs) invalid type comparison."); } } inline std::string socket_address_inet::address_str() const { char buf[INET_ADDRSTRLEN]; if (!address_c_str(buf, INET_ADDRSTRLEN)) return std::string(); return std::string(buf); } inline bool socket_address_inet::address_c_str(char* buf, socklen_t size) const { return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size); } inline bool socket_address_inet::set_address_c_str(const char* a) { return inet_pton(AF_INET, a, &m_sockaddr.sin_addr); } inline bool socket_address_inet::operator == (const socket_address_inet& rhs) const { return m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr && m_sockaddr.sin_port == rhs.m_sockaddr.sin_port; } inline bool socket_address_inet::operator < (const socket_address_inet& rhs) const { return m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr || (m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr && m_sockaddr.sin_port < rhs.m_sockaddr.sin_port); } } #endif rtorrent-0.9.6/rak/string_manip.h000066400000000000000000000224401257211462100170300ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_STRING_MANIP_H #define RAK_STRING_MANIP_H #include #include #include #include #include namespace rak { // Use these trim functions until n1872 is widely supported. template Sequence trim_begin(const Sequence& seq) { if (seq.empty() || !std::isspace(*seq.begin())) return seq; typename Sequence::size_type pos = 0; while (pos != seq.length() && std::isspace(seq[pos])) pos++; return seq.substr(pos, seq.length() - pos); } template Sequence trim_end(const Sequence& seq) { if (seq.empty() || !std::isspace(*(--seq.end()))) return seq; typename Sequence::size_type pos = seq.size(); while (pos != 0 && std::isspace(seq[pos - 1])) pos--; return seq.substr(0, pos); } template Sequence trim(const Sequence& seq) { return trim_begin(trim_end(seq)); } template Sequence trim_begin_classic(const Sequence& seq) { if (seq.empty() || !std::isspace(*seq.begin(), std::locale::classic())) return seq; typename Sequence::size_type pos = 0; while (pos != seq.length() && std::isspace(seq[pos], std::locale::classic())) pos++; return seq.substr(pos, seq.length() - pos); } template Sequence trim_end_classic(const Sequence& seq) { if (seq.empty() || !std::isspace(*(--seq.end()), std::locale::classic())) return seq; typename Sequence::size_type pos = seq.size(); while (pos != 0 && std::isspace(seq[pos - 1], std::locale::classic())) pos--; return seq.substr(0, pos); } template Sequence trim_classic(const Sequence& seq) { return trim_begin_classic(trim_end_classic(seq)); } // Consider rewritting such that m_seq is replaced by first/last. template class split_iterator_t { public: typedef typename Sequence::const_iterator const_iterator; typedef typename Sequence::value_type value_type; split_iterator_t() {} split_iterator_t(const Sequence& seq, value_type delim) : m_seq(&seq), m_delim(delim), m_pos(seq.begin()), m_next(std::find(seq.begin(), seq.end(), delim)) { } Sequence operator * () { return Sequence(m_pos, m_next); } split_iterator_t& operator ++ () { m_pos = m_next; if (m_pos == m_seq->end()) return *this; m_pos++; m_next = std::find(m_pos, m_seq->end(), m_delim); return *this; } bool operator == (__UNUSED const split_iterator_t& itr) const { return m_pos == m_seq->end(); } bool operator != (__UNUSED const split_iterator_t& itr) const { return m_pos != m_seq->end(); } private: const Sequence* m_seq; value_type m_delim; const_iterator m_pos; const_iterator m_next; }; template inline split_iterator_t split_iterator(const Sequence& seq, typename Sequence::value_type delim) { return split_iterator_t(seq, delim); } template inline split_iterator_t split_iterator(__UNUSED const Sequence& seq) { return split_iterator_t(); } // Could optimize this abit. inline char hexchar_to_value(char c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'A' && c <= 'F') return 10 + c - 'A'; else return 10 + c - 'a'; } template inline char value_to_hexchar(Value v) { v >>= pos * 4; v &= 0xf; if (v < 0xA) return '0' + v; else return 'A' + v - 0xA; } template OutputIterator copy_escape_html(InputIterator first, InputIterator last, OutputIterator dest) { while (first != last) { if (std::isalpha(*first, std::locale::classic()) || std::isdigit(*first, std::locale::classic()) || *first == '-') { *(dest++) = *first; } else { *(dest++) = '%'; *(dest++) = value_to_hexchar<1>(*first); *(dest++) = value_to_hexchar<0>(*first); } ++first; } return dest; } template OutputIterator copy_escape_html(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) { while (first1 != last1) { if (std::isalpha(*first1, std::locale::classic()) || std::isdigit(*first1, std::locale::classic()) || *first1 == '-') { if (first2 == last2) break; else *(first2++) = *first1; } else { if (first2 == last2) break; else *(first2++) = '%'; if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1); if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1); } ++first1; } return first2; } template inline std::string copy_escape_html(Iterator first, Iterator last) { std::string dest; copy_escape_html(first, last, std::back_inserter(dest)); return dest; } template inline Sequence copy_escape_html(const Sequence& src) { Sequence dest; copy_escape_html(src.begin(), src.end(), std::back_inserter(dest)); return dest; } template inline std::string copy_escape_html_str(const Sequence& src) { std::string dest; copy_escape_html(src.begin(), src.end(), std::back_inserter(dest)); return dest; } // Consider support for larger than char type. template OutputIterator transform_hex(InputIterator first, InputIterator last, OutputIterator dest) { while (first != last) { *(dest++) = value_to_hexchar<1>(*first); *(dest++) = value_to_hexchar<0>(*first); ++first; } return dest; } template OutputIterator transform_hex(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) { while (first1 != last1) { if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1); if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1); ++first1; } return first2; } template inline Sequence transform_hex(const Sequence& src) { Sequence dest; transform_hex(src.begin(), src.end(), std::back_inserter(dest)); return dest; } template inline std::string transform_hex(Iterator first, Iterator last) { std::string dest; transform_hex(first, last, std::back_inserter(dest)); return dest; } template inline std::string transform_hex_str(const Sequence& seq) { std::string dest; transform_hex(seq.begin(), seq.end(), std::back_inserter(dest)); return dest; } template Sequence generate_random(size_t length) { Sequence s; s.reserve(length); std::generate_n(std::back_inserter(s), length, &::random); return s; } template inline bool is_all_alpha(Iterator first, Iterator last) { while (first != last) if (!std::isalpha(*first++, std::locale::classic())) return false; return true; } template inline bool is_all_alpha(const Sequence& src) { return is_all_alpha(src.begin(), src.end()); } template inline bool is_all_alnum(Iterator first, Iterator last) { while (first != last) if (!std::isalnum(*first++, std::locale::classic())) return false; return true; } template inline bool is_all_alnum(const Sequence& src) { return is_all_alnum(src.begin(), src.end()); } template inline bool is_all_name(Iterator first, Iterator last) { while (first != last) { if (!std::isalnum(*first, std::locale::classic()) && *first != '_') return false; first++; } return true; } template inline bool is_all_name(const Sequence& src) { return is_all_name(src.begin(), src.end()); } } #endif rtorrent-0.9.6/rak/timer.h000066400000000000000000000114161257211462100154570ustar00rootroot00000000000000// libTorrent - BitTorrent library // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_TIMER_H #define RAK_TIMER_H #include #include #include namespace rak { // Don't convert negative Timer to timeval and then back to Timer, that will bork. class timer { public: timer(int64_t usec = 0) : m_time(usec) {} timer(timeval tv) : m_time((int64_t)(uint32_t)tv.tv_sec * 1000000 + (int64_t)(uint32_t)tv.tv_usec % 1000000) {} bool is_zero() const { return m_time == 0; } bool is_not_zero() const { return m_time != 0; } int32_t seconds() const { return m_time / 1000000; } int32_t seconds_ceiling() const { return (m_time + 1000000 - 1) / 1000000; } int64_t usec() const { return m_time; } timer round_seconds() const { return (m_time / 1000000) * 1000000; } timer round_seconds_ceiling() const { return ((m_time + 1000000 - 1) / 1000000) * 1000000; } timeval tval() const { timeval val; val.tv_sec = m_time / 1000000; val.tv_usec = m_time % 1000000; return val; } static timer current(); static int64_t current_seconds() { return current().seconds(); } static int64_t current_usec() { return current().usec(); } static timer from_minutes(uint32_t minutes) { return rak::timer((uint64_t)minutes * 60 * 1000000); } static timer from_seconds(uint32_t seconds) { return rak::timer((uint64_t)seconds * 1000000); } static timer from_milliseconds(uint32_t msec) { return rak::timer((uint64_t)msec * 1000); } static timer max() { return std::numeric_limits::max(); } bool operator < (const timer& t) const { return m_time < t.m_time; } bool operator > (const timer& t) const { return m_time > t.m_time; } bool operator <= (const timer& t) const { return m_time <= t.m_time; } bool operator >= (const timer& t) const { return m_time >= t.m_time; } bool operator == (const timer& t) const { return m_time == t.m_time; } bool operator != (const timer& t) const { return m_time != t.m_time; } timer operator - (const timer& t) const { return timer(m_time - t.m_time); } timer operator + (const timer& t) const { return timer(m_time + t.m_time); } timer operator * (int64_t t) const { return timer(m_time * t); } timer operator / (int64_t t) const { return timer(m_time / t); } timer operator -= (int64_t t) { m_time -= t; return *this; } timer operator -= (const timer& t) { m_time -= t.m_time; return *this; } timer operator += (int64_t t) { m_time += t; return *this; } timer operator += (const timer& t) { m_time += t.m_time; return *this; } private: int64_t m_time; }; inline timer timer::current() { timeval t; gettimeofday(&t, 0); return timer(t); } } #endif rtorrent-0.9.6/rak/unordered_vector.h000066400000000000000000000066411257211462100177140ustar00rootroot00000000000000// rak - Rakshasa's toolbox // Copyright (C) 2005-2007, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RAK_UNORDERED_VECTOR_H #define RAK_UNORDERED_VECTOR_H #include namespace rak { template class unordered_vector : private std::vector<_Tp> { public: typedef std::vector<_Tp> Base; typedef typename Base::value_type value_type; typedef typename Base::pointer pointer; typedef typename Base::const_pointer const_pointer; typedef typename Base::reference reference; typedef typename Base::const_reference const_reference; typedef typename Base::size_type size_type; typedef typename Base::difference_type difference_type; typedef typename Base::allocator_type allocator_type; typedef typename Base::iterator iterator; typedef typename Base::reverse_iterator reverse_iterator; typedef typename Base::const_iterator const_iterator; typedef typename Base::const_reverse_iterator const_reverse_iterator; using Base::clear; using Base::empty; using Base::size; using Base::reserve; using Base::front; using Base::back; using Base::begin; using Base::end; using Base::rbegin; using Base::rend; using Base::push_back; using Base::pop_back; // Use the range erase function, the single element erase gets // overloaded. using Base::erase; iterator insert(iterator position, const value_type& x); iterator erase(iterator position); private: }; template typename unordered_vector<_Tp>::iterator unordered_vector<_Tp>::insert(iterator position, const value_type& x) { Base::push_back(x); return --end(); } template typename unordered_vector<_Tp>::iterator unordered_vector<_Tp>::erase(iterator position) { // We don't need to check if position == end - 1 since we then copy // to the position we pop later. *position = Base::back(); Base::pop_back(); return position; } } #endif rtorrent-0.9.6/scripts/000077500000000000000000000000001257211462100150755ustar00rootroot00000000000000rtorrent-0.9.6/scripts/attributes.m4000066400000000000000000000076501257211462100175350ustar00rootroot00000000000000# Functions to check for attributes support in compiler AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ AC_CACHE_CHECK([if compiler supports __attribute__((constructor))], [cc_cv_attribute_constructor], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void ctor() __attribute__((constructor)); void ctor() { }; ])], [cc_cv_attribute_constructor=yes], [cc_cv_attribute_constructor=no]) ]) if test "x$cc_cv_attribute_constructor" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_CONSTRUCTOR], 1, [Define this if the compiler supports the constructor attribute]) $1 else true $2 fi ]) AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ AC_CACHE_CHECK([if compiler supports __attribute__((format(printf, n, n)))], [cc_cv_attribute_format], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { } ])], [cc_cv_attribute_format=yes], [cc_cv_attribute_format=no]) ]) if test "x$cc_cv_attribute_format" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_FORMAT], 1, [Define this if the compiler supports the format attribute]) $1 else true $2 fi ]) AC_DEFUN([CC_ATTRIBUTE_INTERNAL], [ AC_CACHE_CHECK([if compiler supports __attribute__((visibility("internal")))], [cc_cv_attribute_internal], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void __attribute__((visibility("internal"))) internal_function() { } ])], [cc_cv_attribute_internal=yes], [cc_cv_attribute_internal=no]) ]) if test "x$cc_cv_attribute_internal" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_INTERNAL], 1, [Define this if the compiler supports the internal visibility attribute]) $1 else true $2 fi ]) AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ AC_LANG_PUSH(C++) tmp_CXXFLAGS=$CXXFLAGS CXXFLAGS="$CXXFLAGS -fvisibility=hidden" AC_CACHE_CHECK([if compiler supports __attribute__((visibility("default")))], [cc_cv_attribute_visibility], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void __attribute__((visibility("default"))) visibility_function() { } ])], [cc_cv_attribute_visibility=yes], [cc_cv_attribute_visibility=no]) ]) CXXFLAGS=$tmp_CXXFLAGS AC_LANG_POP(C++) if test "x$cc_cv_attribute_visibility" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_VISIBILITY], 1, [Define this if the compiler supports the visibility attributes.]) CXXFLAGS="$CXXFLAGS -fvisibility=hidden" $1 else true $2 fi ]) AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ AC_CACHE_CHECK([if compiler supports __attribute__((nonnull()))], [cc_cv_attribute_nonnull], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void some_function(void *foo, void *bar) __attribute__((nonnull())); void some_function(void *foo, void *bar) { } ])], [cc_cv_attribute_nonnull=yes], [cc_cv_attribute_nonnull=no]) ]) if test "x$cc_cv_attribute_nonnull" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_NONNULL], 1, [Define this if the compiler supports the nonnull attribute]) $1 else true $2 fi ]) AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ AC_CACHE_CHECK([if compiler supports __attribute__((unused))], [cc_cv_attribute_unused], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void some_function(void *foo, __attribute__((unused)) void *bar); ])], [cc_cv_attribute_unused=yes], [cc_cv_attribute_unused=no]) ]) if test "x$cc_cv_attribute_unused" = "xyes"; then AC_DEFINE([SUPPORT_ATTRIBUTE_UNUSED], 1, [Define this if the compiler supports the unused attribute]) $1 else true $2 fi ]) AC_DEFUN([CC_FUNC_EXPECT], [ AC_CACHE_CHECK([if compiler has __builtin_expect function], [cc_cv_func_expect], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([ int some_function() { int a = 3; return (int)__builtin_expect(a, 3); } ])], [cc_cv_func_expect=yes], [cc_cv_func_expect=no]) ]) if test "x$cc_cv_func_expect" = "xyes"; then AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, [Define this if the compiler supports __builtin_expect() function]) $1 else true $2 fi ]) rtorrent-0.9.6/scripts/ax_pthread.m4000066400000000000000000000304451257211462100174640ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 17 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) AC_MSG_RESULT($ax_pthread_ok) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="none pthreads -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; *-darwin*) ax_pthread_flags="none -pthread $ax_pthread_flags" ;; esac if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($ax_pthread_ok) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *-osf* | *-hpux*) flag="-D_REENTRANT";; *solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], ax_cv_PTHREAD_PRIO_INHERIT, [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD rtorrent-0.9.6/scripts/ax_with_curses.m4000066400000000000000000000634021257211462100203730ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_with_curses.html # =========================================================================== # # SYNOPSIS # # AX_WITH_CURSES # # DESCRIPTION # # This macro checks whether a SysV or X/Open-compatible Curses library is # present, along with the associated header file. The NcursesW # (wide-character) library is searched for first, followed by Ncurses, # then the system-default plain Curses. The first library found is the # one returned. # # The following options are understood: --with-ncursesw, --with-ncurses, # --without-ncursesw, --without-ncurses. The "--with" options force the # macro to use that particular library, terminating with an error if not # found. The "--without" options simply skip the check for that library. # The effect on the search pattern is: # # (no options) - NcursesW, Ncurses, Curses # --with-ncurses --with-ncursesw - NcursesW only [*] # --without-ncurses --with-ncursesw - NcursesW only [*] # --with-ncursesw - NcursesW only [*] # --with-ncurses --without-ncursesw - Ncurses only [*] # --with-ncurses - NcursesW, Ncurses [**] # --without-ncurses --without-ncursesw - Curses only # --without-ncursesw - Ncurses, Curses # --without-ncurses - NcursesW, Curses # # [*] If the library is not found, abort the configure script. # # [**] If the second library (Ncurses) is not found, abort configure. # # The following preprocessor symbols may be defined by this macro if the # appropriate conditions are met: # # HAVE_CURSES - if any SysV or X/Open Curses library found # HAVE_CURSES_ENHANCED - if library supports X/Open Enhanced functions # HAVE_CURSES_COLOR - if library supports color (enhanced functions) # HAVE_CURSES_OBSOLETE - if library supports certain obsolete features # HAVE_NCURSESW - if NcursesW (wide char) library is to be used # HAVE_NCURSES - if the Ncurses library is to be used # # HAVE_CURSES_H - if is present and should be used # HAVE_NCURSESW_H - if should be used # HAVE_NCURSES_H - if should be used # HAVE_NCURSESW_CURSES_H - if should be used # HAVE_NCURSES_CURSES_H - if should be used # # (These preprocessor symbols are discussed later in this document.) # # The following output variable is defined by this macro; it is precious # and may be overridden on the ./configure command line: # # CURSES_LIB - library to add to xxx_LDADD # # The library listed in CURSES_LIB is NOT added to LIBS by default. You # need to add CURSES_LIB to the appropriate xxx_LDADD line in your # Makefile.am. For example: # # prog_LDADD = @CURSES_LIB@ # # If CURSES_LIB is set on the configure command line (such as by running # "./configure CURSES_LIB=-lmycurses"), then the only header searched for # is . The user may use the CPPFLAGS precious variable to # override the standard #include search path. If the user needs to # specify an alternative path for a library (such as for a non-standard # NcurseW), the user should use the LDFLAGS variable. # # The following shell variables may be defined by this macro: # # ax_cv_curses - set to "yes" if any Curses library found # ax_cv_curses_enhanced - set to "yes" if Enhanced functions present # ax_cv_curses_color - set to "yes" if color functions present # ax_cv_curses_obsolete - set to "yes" if obsolete features present # # ax_cv_ncursesw - set to "yes" if NcursesW library found # ax_cv_ncurses - set to "yes" if Ncurses library found # ax_cv_plaincurses - set to "yes" if plain Curses library found # ax_cv_curses_which - set to "ncursesw", "ncurses", "plaincurses" or "no" # # These variables can be used in your configure.ac to determine the level # of support you need from the Curses library. For example, if you must # have either Ncurses or NcursesW, you could include: # # AX_WITH_CURSES # if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then # AX_MSG_ERROR([requires either NcursesW or Ncurses library]) # fi # # If any Curses library will do (but one must be present and must support # color), you could use: # # AX_WITH_CURSES # if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then # AC_MSG_ERROR([requires an X/Open-compatible Curses library with color]) # fi # # Certain preprocessor symbols and shell variables defined by this macro # can be used to determine various features of the Curses library. In # particular, HAVE_CURSES and ax_cv_curses are defined if the Curses # library found conforms to the traditional SysV and/or X/Open Base Curses # definition. Any working Curses library conforms to this level. # # HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the # library supports the X/Open Enhanced Curses definition. In particular, # the wide-character types attr_t, cchar_t and wint_t, the functions # wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES # are checked. The Ncurses library does NOT conform to this definition, # although NcursesW does. # # HAVE_CURSES_COLOR and ax_cv_curses_color are defined if the library # supports color functions and macros such as COLOR_PAIR, A_COLOR, # COLOR_WHITE, COLOR_RED and init_pair(). These are NOT part of the # X/Open Base Curses definition, but are part of the Enhanced set of # functions. The Ncurses library DOES support these functions, as does # NcursesW. # # HAVE_CURSES_OBSOLETE and ax_cv_curses_obsolete are defined if the # library supports certain features present in SysV and BSD Curses but not # defined in the X/Open definition. In particular, the functions # getattrs(), getcurx() and getmaxx() are checked. # # To use the HAVE_xxx_H preprocessor symbols, insert the following into # your system.h (or equivalent) header file: # # #if defined HAVE_NCURSESW_CURSES_H # # include # #elif defined HAVE_NCURSESW_H # # include # #elif defined HAVE_NCURSES_CURSES_H # # include # #elif defined HAVE_NCURSES_H # # include # #elif defined HAVE_CURSES_H # # include # #else # # error "SysV or X/Open-compatible Curses header file required" # #endif # # For previous users of this macro: you should not need to change anything # in your configure.ac or Makefile.am, as the previous (serial 10) # semantics are still valid. However, you should update your system.h (or # equivalent) header file to the fragment shown above. You are encouraged # also to make use of the extended functionality provided by this version # of AX_WITH_CURSES, as well as in the additional macros # AX_WITH_CURSES_PANEL, AX_WITH_CURSES_MENU and AX_WITH_CURSES_FORM. # # LICENSE # # Copyright (c) 2009 Mark Pulford # Copyright (c) 2009 Damian Pietras # Copyright (c) 2012 Reuben Thomas # Copyright (c) 2011 John Zaitseff # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 13 AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES]) AC_DEFUN([AX_WITH_CURSES], [ AC_ARG_VAR([CURSES_LIB], [linker library for Curses, e.g. -lcurses]) AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses], [force the use of Ncurses or NcursesW])], [], [with_ncurses=check]) AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw], [do not use NcursesW (wide character support)])], [], [with_ncursesw=check]) ax_saved_LIBS=$LIBS AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes], [ax_with_plaincurses=no], [ax_with_plaincurses=check]) ax_cv_curses_which=no # Test for NcursesW AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncursesw" != xno], [ LIBS="$ax_saved_LIBS -lncursesw" AC_CACHE_CHECK([for NcursesW wide-character library], [ax_cv_ncursesw], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_ncursesw=yes], [ax_cv_ncursesw=no]) ]) AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [ AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library]) ]) AS_IF([test "x$ax_cv_ncursesw" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=ncursesw CURSES_LIB="-lncursesw" AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) AC_CACHE_CHECK([for working ncursesw/curses.h], [ax_cv_header_ncursesw_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncursesw_curses_h=yes], [ax_cv_header_ncursesw_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSESW_CURSES_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncursesw.h], [ax_cv_header_ncursesw_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncursesw_h=yes], [ax_cv_header_ncursesw_h=no]) ]) AS_IF([test "x$ax_cv_header_ncursesw_h" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSESW_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h_with_ncursesw], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncurses_h_with_ncursesw=yes], [ax_cv_header_ncurses_h_with_ncursesw=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_h_with_ncursesw" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) ]) AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [ AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h]) ]) dnl Test if we need to explicitly link against -ltinfow. AC_CACHE_CHECK([if curses tinfo library is linked properly], [ax_cv_ncurses_compiled], [ LIBS="$ax_saved_LIBS $CURSES_LIB" AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_ncurses_compiled=yes], [ax_cv_ncurses_compiled=no]) LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfo" AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfo_compiled=yes], [ax_cv_tinfo_compiled=no]) LIBS="$ax_saved_LIBS $CURSES_LIB -ltinfow" AC_LINK_IFELSE([AC_LANG_CALL([], [keypad])], [ax_cv_tinfow_compiled=yes], [ax_cv_tinfow_compiled=no]) LIBS=$ax_saved_LIBS ]) AS_IF([test "x$ax_cv_ncurses_compiled" = xno], [ AS_IF( [test "x$ax_cv_tinfo_compiled" = xyes], [ AC_MSG_RESULT([adding libtinfo]) CURSES_LIB="$CURSES_LIB -ltinfo" ], [test "x$ax_cv_tinfow_compiled" = xyes], [ AC_MSG_RESULT([adding libtinfow]) CURSES_LIB="$CURSES_LIB -ltinfow" ], [ AC_MSG_ERROR([no]) ]) ]) ]) ]) # Test for Ncurses AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [ LIBS="$ax_saved_LIBS -lncurses" AC_CACHE_CHECK([for Ncurses library], [ax_cv_ncurses], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_ncurses=yes], [ax_cv_ncurses=no]) ]) AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [ AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library]) ]) AS_IF([test "x$ax_cv_ncurses" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=ncurses CURSES_LIB="-lncurses" AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) AC_CACHE_CHECK([for working ncurses/curses.h], [ax_cv_header_ncurses_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_header_ncurses_curses_h=yes], [ax_cv_header_ncurses_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xyes], [ ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_CURSES_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_header_ncurses_h=yes], [ax_cv_header_ncurses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_h" = xyes], [ ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) ]) AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xno && test "x$ax_cv_header_ncurses_h" = xno], [ AC_MSG_WARN([could not find a working ncurses/curses.h or ncurses.h]) ]) ]) ]) # Test for plain Curses (or if CURSES_LIB was set by user) AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [ AS_IF([test "x$CURSES_LIB" != x], [ LIBS="$ax_saved_LIBS $CURSES_LIB" ], [ LIBS="$ax_saved_LIBS -lcurses" ]) AC_CACHE_CHECK([for Curses library], [ax_cv_plaincurses], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_plaincurses=yes], [ax_cv_plaincurses=no]) ]) AS_IF([test "x$ax_cv_plaincurses" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=plaincurses AS_IF([test "x$CURSES_LIB" = x], [ CURSES_LIB="-lcurses" ]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) # Check for base conformance (and header file) AC_CACHE_CHECK([for working curses.h], [ax_cv_header_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; initscr(); ]])], [ax_cv_header_curses_h=yes], [ax_cv_header_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_curses_h" = xyes], [ AC_DEFINE([HAVE_CURSES_H], [1], [Define to 1 if is present]) # Check for X/Open Enhanced conformance AC_CACHE_CHECK([for X/Open Enhanced Curses conformance], [ax_cv_plaincurses_enhanced], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include @%:@ifndef _XOPEN_CURSES @%:@error "this Curses library is not enhanced" "this Curses library is not enhanced" @%:@endif ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_plaincurses_enhanced=yes], [ax_cv_plaincurses_enhanced=no]) ]) AS_IF([test "x$ax_cv_plaincurses_enhanced" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) ]) # Check for color functions AC_CACHE_CHECK([for Curses color functions], [ax_cv_plaincurses_color], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_plaincurses_color=yes], [ax_cv_plaincurses_color=no]) ]) AS_IF([test "x$ax_cv_plaincurses_color" = xyes], [ ax_cv_curses_color=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) ]) # Check for obsolete functions AC_CACHE_CHECK([for obsolete Curses functions], [ax_cv_plaincurses_obsolete], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); ]])], [ax_cv_plaincurses_obsolete=yes], [ax_cv_plaincurses_obsolete=no]) ]) AS_IF([test "x$ax_cv_plaincurses_obsolete" = xyes], [ ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) ]) ]) AS_IF([test "x$ax_cv_header_curses_h" = xno], [ AC_MSG_WARN([could not find a working curses.h]) ]) ]) ]) AS_IF([test "x$ax_cv_curses" != xyes], [ax_cv_curses=no]) AS_IF([test "x$ax_cv_curses_enhanced" != xyes], [ax_cv_curses_enhanced=no]) AS_IF([test "x$ax_cv_curses_color" != xyes], [ax_cv_curses_color=no]) AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no]) LIBS=$ax_saved_LIBS ])dnl rtorrent-0.9.6/scripts/checks.m4000066400000000000000000000336431257211462100166100ustar00rootroot00000000000000AC_DEFUN([TORRENT_CHECK_XFS], [ AC_MSG_CHECKING(for XFS support) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include int main() { struct xfs_flock64 l; ioctl(0, XFS_IOC_RESVSP64, &l); return 0; } ])], [ AC_DEFINE(USE_XFS, 1, Use XFS filesystem stuff.) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_WITHOUT_XFS], [ AC_ARG_WITH(xfs, AC_HELP_STRING([--without-xfs], [do not check for XFS filesystem support]), [ if test "$withval" = "yes"; then TORRENT_CHECK_XFS fi ], [ TORRENT_CHECK_XFS ]) ]) AC_DEFUN([TORRENT_WITH_XFS], [ AC_ARG_WITH(xfs, AC_HELP_STRING([--with-xfs], [check for XFS filesystem support]), [ if test "$withval" = "yes"; then TORRENT_CHECK_XFS fi ]) ]) AC_DEFUN([TORRENT_CHECK_EPOLL], [ AC_MSG_CHECKING(for epoll support) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main() { int fd = epoll_create(100); return 0; } ])], [ AC_DEFINE(USE_EPOLL, 1, Use epoll.) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_WITHOUT_EPOLL], [ AC_ARG_WITH(epoll, AC_HELP_STRING([--without-epoll], [do not check for epoll support]), [ if test "$withval" = "yes"; then TORRENT_CHECK_EPOLL fi ], [ TORRENT_CHECK_EPOLL ]) ]) AC_DEFUN([TORRENT_CHECK_KQUEUE], [ AC_MSG_CHECKING(for kqueue support) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include /* Because OpenBSD's sys/event.h fails to compile otherwise. Yeah... */ #include int main() { int fd = kqueue(); return 0; } ])], [ AC_DEFINE(USE_KQUEUE, 1, Use kqueue.) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_CHECK_KQUEUE_SOCKET_ONLY], [ AC_MSG_CHECKING(whether kqueue supports pipes and ptys) AC_RUN_IFELSE([AC_LANG_SOURCE([ #include #include #include #include #include int main() { struct kevent ev@<:@2@:>@, ev_out@<:@2@:>@; struct timespec ts = { 0, 0 }; int pfd@<:@2@:>@, pty@<:@2@:>@, kfd, n; char buffer@<:@9001@:>@; if (pipe(pfd) == -1) return 1; if (fcntl(pfd@<:@1@:>@, F_SETFL, O_NONBLOCK) == -1) return 2; while ((n = write(pfd@<:@1@:>@, buffer, sizeof(buffer))) == sizeof(buffer)); if ((pty@<:@0@:>@=posix_openpt(O_RDWR | O_NOCTTY)) == -1) return 3; if ((pty@<:@1@:>@=grantpt(pty@<:@0@:>@)) == -1) return 4; EV_SET(ev+0, pfd@<:@1@:>@, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL); EV_SET(ev+1, pty@<:@1@:>@, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); if ((kfd = kqueue()) == -1) return 5; if ((n = kevent(kfd, ev, 2, NULL, 0, NULL)) == -1) return 6; if (ev_out@<:@0@:>@.flags & EV_ERROR) return 7; if (ev_out@<:@1@:>@.flags & EV_ERROR) return 8; read(pfd@<:@0@:>@, buffer, sizeof(buffer)); if ((n = kevent(kfd, NULL, 0, ev_out, 2, &ts)) < 1) return 9; return 0; } ])], [ AC_MSG_RESULT(yes) ], [ AC_DEFINE(KQUEUE_SOCKET_ONLY, 1, kqueue only supports sockets.) AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_WITH_KQUEUE], [ AC_ARG_WITH(kqueue, AC_HELP_STRING([--with-kqueue], [enable kqueue [[default=no]]]), [ if test "$withval" = "yes"; then TORRENT_CHECK_KQUEUE TORRENT_CHECK_KQUEUE_SOCKET_ONLY fi ]) ]) AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [ AC_ARG_WITH(kqueue, AC_HELP_STRING([--without-kqueue], [do not check for kqueue support]), [ if test "$withval" = "yes"; then TORRENT_CHECK_KQUEUE TORRENT_CHECK_KQUEUE_SOCKET_ONLY fi ], [ TORRENT_CHECK_KQUEUE TORRENT_CHECK_KQUEUE_SOCKET_ONLY ]) ]) AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [ AC_ARG_WITH(variable-fdset, AC_HELP_STRING([--without-variable-fdset], [do not use non-portable variable sized fd_set's]), [ if test "$withval" = "yes"; then AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size) fi ], [ AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size) ]) ]) AC_DEFUN([TORRENT_CHECK_FALLOCATE], [ AC_MSG_CHECKING(for fallocate) AC_TRY_LINK([#include #include ],[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0; ], [ AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [ AC_MSG_CHECKING(for posix_fallocate) AC_TRY_LINK([#include ],[ posix_fallocate(0, 0, 0); ], [ AC_DEFINE(USE_POSIX_FALLOCATE, 1, posix_fallocate supported.) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [ AC_ARG_WITH(posix-fallocate, AC_HELP_STRING([--with-posix-fallocate], [check for and use posix_fallocate to allocate files]), [ if test "$withval" = "yes"; then TORRENT_CHECK_POSIX_FALLOCATE fi ]) ]) AC_DEFUN([TORRENT_CHECK_STATVFS], [ AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h) AC_MSG_CHECKING(for statvfs) AC_TRY_LINK( [ #if HAVE_SYS_VFS_H #include #endif #if HAVE_SYS_STATVFS_H #include #endif #if HAVE_SYS_STATFS_H #include #endif ],[ struct statvfs s; fsblkcnt_t c; statvfs("", &s); fstatvfs(0, &s); ], [ AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd) AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename) AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function) AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct) AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct) AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size) AC_MSG_RESULT(ok) have_stat_vfs=yes ], [ AC_MSG_RESULT(no) have_stat_vfs=no ]) ]) AC_DEFUN([TORRENT_CHECK_STATFS], [ AC_CHECK_HEADERS(sys/statfs.h sys/param.h sys/mount.h) AC_MSG_CHECKING(for statfs) AC_TRY_LINK( [ #if HAVE_SYS_STATFS_H #include #endif #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_MOUNT_H #include #endif ],[ struct statfs s; statfs("", &s); fstatfs(0, &s); ], [ AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd) AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename) AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function) AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct) AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct) AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size) AC_MSG_RESULT(ok) have_stat_vfs=yes ], [ AC_MSG_RESULT(no) have_stat_vfs=no ]) ]) AC_DEFUN([TORRENT_DISABLED_STATFS], [ AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd) AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename) AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function) AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct) AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct) AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size) AC_MSG_RESULT(No filesystem stats available) ]) AC_DEFUN([TORRENT_WITHOUT_STATVFS], [ AC_ARG_WITH(statvfs, AC_HELP_STRING([--without-statvfs], [don't try to use statvfs to find free diskspace]), [ if test "$withval" = "yes"; then TORRENT_CHECK_STATVFS else have_stat_vfs=no fi ], [ TORRENT_CHECK_STATVFS ]) ]) AC_DEFUN([TORRENT_WITHOUT_STATFS], [ AC_ARG_WITH(statfs, AC_HELP_STRING([--without-statfs], [don't try to use statfs to find free diskspace]), [ if test "$have_stat_vfs" = "no"; then if test "$withval" = "yes"; then TORRENT_CHECK_STATFS else TORRENT_DISABLED_STATFS fi fi ], [ if test "$have_stat_vfs" = "no"; then TORRENT_CHECK_STATFS if test "$have_stat_vfs" = "no"; then TORRENT_DISABLED_STATFS fi fi ]) ]) AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [ AC_ARG_WITH(address-space, AC_HELP_STRING([--with-address-space=MB], [change the default address space size [[default=1024mb]]]), [ if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval]) else AC_MSG_ERROR(--with-address-space requires a parameter.) fi ], [ AC_CHECK_SIZEOF(long) if test $ac_cv_sizeof_long = 8; then AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 4096, Default address space size.) else AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 1024, Default address space size.) fi ]) ]) AC_DEFUN([TORRENT_CHECK_TR1], [ AC_LANG_PUSH(C++) AC_MSG_CHECKING(for TR1 support) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include class Foo; typedef std::tr1::unordered_map Bar; ])], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_TR1, 1, Define to 1 if your C++ library supports the extensions from Technical Report 1) ], [ AC_MSG_RESULT(no) ] ) AC_LANG_POP(C++) ]) AC_DEFUN([TORRENT_CHECK_CXX11], [ AC_LANG_PUSH(C++) AC_MSG_CHECKING(for C++11 support) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include class Foo; typedef std::unordered_map Bar; union test { Bar b1; }; ])], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_CXX11, 1, Define to 1 if your C++ compiler has support for C++11.) ], [ AC_MSG_RESULT(no) ] ) AC_LANG_POP(C++) ]) AC_DEFUN([TORRENT_WITH_FASTCGI], [ AC_ARG_WITH(fastcgi, AC_HELP_STRING([--with-fastcgi=PATH], [enable FastCGI RPC support (DO NOT USE)]), [ AC_MSG_CHECKING([for FastCGI (DO NOT USE)]) if test "$withval" = "no"; then AC_MSG_RESULT(no) elif test "$withval" = "yes"; then CXXFLAGS="$CXXFLAGS" LIBS="$LIBS -lfcgi" AC_TRY_LINK( [ #include ],[ FCGX_Init(); ], [ AC_MSG_RESULT(ok) ], [ AC_MSG_RESULT(not found) AC_MSG_ERROR(Could not compile FastCGI test.) ]) AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.) else CXXFLAGS="$CXXFLAGS -I$withval/include" LIBS="$LIBS -lfcgi -L$withval/lib" AC_TRY_LINK( [ #include ],[ FCGX_Init(); ], [ AC_MSG_RESULT(ok) ], [ AC_MSG_RESULT(not found) AC_MSG_ERROR(Could not compile FastCGI test.) ]) AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.) fi ]) ]) AC_DEFUN([TORRENT_WITH_XMLRPC_C], [ AC_MSG_CHECKING(for XMLRPC-C) AC_ARG_WITH(xmlrpc-c, AC_HELP_STRING([--with-xmlrpc-c=PATH], [enable XMLRPC-C support]), [ if test "$withval" = "no"; then AC_MSG_RESULT(no) else if test "$withval" = "yes"; then xmlrpc_cc_prg="xmlrpc-c-config" else xmlrpc_cc_prg="$withval" fi if eval $xmlrpc_cc_prg --version 2>/dev/null >/dev/null; then CXXFLAGS="$CXXFLAGS `$xmlrpc_cc_prg --cflags server-util`" LIBS="$LIBS `$xmlrpc_cc_prg server-util --libs`" AC_TRY_LINK( [ #include ],[ xmlrpc_registry_new(NULL); ], [ AC_MSG_RESULT(ok) ], [ AC_MSG_RESULT(failed) AC_MSG_ERROR(Could not compile XMLRPC-C test.) ]) AC_DEFINE(HAVE_XMLRPC_C, 1, Support for XMLRPC-C.) else AC_MSG_RESULT(failed) AC_MSG_ERROR(Could not compile XMLRPC-C test.) fi fi ],[ AC_MSG_RESULT(ignored) ]) ]) AC_DEFUN([TORRENT_WITH_INOTIFY], [ AC_LANG_PUSH(C++) AC_CHECK_HEADERS([sys/inotify.h mcheck.h]) AC_MSG_CHECKING([whether sys/inotify.h actually works]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main(int,const char**) { return (-1 == inotify_init()); }]) ],[ AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly]) AC_MSG_RESULT(yes)], [AC_MSG_RESULT(failed)] ) AC_LANG_POP(C++) ]) AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [ AC_CHECK_HEADERS(pthread.h) AC_MSG_CHECKING(for pthread_setname_np type) AC_TRY_LINK([ #include #include ],[ pthread_t t; pthread_setname_np(t, "foo"); ],[ AC_DEFINE(HAS_PTHREAD_SETNAME_NP_GENERIC, 1, The function to set pthread name has a pthread_t argumet.) AC_MSG_RESULT(generic) ],[ AC_TRY_LINK([ #include #include ],[ pthread_t t; pthread_setname_np("foo"); ],[ AC_DEFINE(HAS_PTHREAD_SETNAME_NP_DARWIN, 1, The function to set pthread name has no pthread argument.) AC_MSG_RESULT(darwin) ],[ AC_MSG_RESULT(no) ]) ]) ]) rtorrent-0.9.6/scripts/common.m4000066400000000000000000000216301257211462100166310ustar00rootroot00000000000000AC_DEFUN([TORRENT_CHECK_CXXFLAGS], [ AC_MSG_CHECKING([for user-defined CXXFLAGS]) if test -n "$CXXFLAGS"; then AC_MSG_RESULT([user-defined "$CXXFLAGS"]) else CXXFLAGS="-O2 -Wall" AC_MSG_RESULT([default "$CXXFLAGS"]) fi ]) AC_DEFUN([TORRENT_ENABLE_DEBUG], [ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]), [ if test "$enableval" = "yes"; then CXXFLAGS="$CXXFLAGS -g -DDEBUG" else CXXFLAGS="$CXXFLAGS -DNDEBUG" fi ],[ CXXFLAGS="$CXXFLAGS -g -DDEBUG" ]) ]) AC_DEFUN([TORRENT_ENABLE_WERROR], [ AC_ARG_ENABLE(werror, AC_HELP_STRING([--enable-werror], [enable the -Werror and -Wall flag [[default=no]]]), [ if test "$enableval" = "yes"; then CXXFLAGS="$CXXFLAGS -Werror -Wall" fi ]) ]) AC_DEFUN([TORRENT_ENABLE_EXTRA_DEBUG], [ AC_ARG_ENABLE(extra-debug, AC_HELP_STRING([--enable-extra-debug], [enable extra debugging checks [[default=no]]]), [ if test "$enableval" = "yes"; then AC_DEFINE(USE_EXTRA_DEBUG, 1, Enable extra debugging checks.) fi ]) ]) AC_DEFUN([TORRENT_WITH_SYSROOT], [ AC_ARG_WITH(sysroot, AC_HELP_STRING([--with-sysroot=PATH], [compile and link with a specific sysroot]), [ AC_MSG_CHECKING(for sysroot) if test "$withval" = "no"; then AC_MSG_RESULT(no) elif test "$withval" = "yes"; then AC_MSG_RESULT(not a path) AC_MSG_ERROR(The sysroot option must point to a directory, like f.ex "/Developer/SDKs/MacOSX10.4u.sdk".) else AC_MSG_RESULT($withval) CXXFLAGS="$CXXFLAGS -isysroot $withval" LDFLAGS="$LDFLAGS -Wl,-syslibroot,$withval" fi ]) ]) AC_DEFUN([TORRENT_ENABLE_ARCH], [ AC_ARG_ENABLE(arch, AC_HELP_STRING([--enable-arch=ARCH], [comma seprated list of architectures to compile for]), [ AC_MSG_CHECKING(for target architectures) if test "$enableval" = "yes"; then AC_MSG_ERROR(no arch supplied) elif test "$enableval" = "no"; then AC_MSG_RESULT(using default) else AC_MSG_RESULT($enableval) for i in `IFS=,; echo $enableval`; do CFLAGS="$CFLAGS -march=$i" CXXFLAGS="$CXXFLAGS -march=$i" LDFLAGS="$LDFLAGS -march=$i" done fi ]) ]) AC_DEFUN([TORRENT_OTFD], [ AC_LANG_PUSH(C++) AC_MSG_CHECKING(for proper overloaded template function disambiguation) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ template void f(T&) {} template void f(T*) {} int main() { int *i = 0; f(*i); f(i); } ])], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) AC_MSG_ERROR([your compiler does not properly handle overloaded template function disambiguation]) ]) AC_LANG_POP(C++) ]) AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [ AC_LANG_PUSH(C++) AC_MSG_CHECKING(signedness of mincore parameter) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include #include void f() { mincore((char*)0, 0, (unsigned char*)0); } ])], [ AC_DEFINE(USE_MINCORE, 1, Use mincore) AC_DEFINE(USE_MINCORE_UNSIGNED, 1, use unsigned char* in mincore) AC_MSG_RESULT(unsigned) ], [ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include #include void f() { mincore((char*)0, 0, (char*)0); } ])], [ AC_DEFINE(USE_MINCORE, 1, Use mincore) AC_DEFINE(USE_MINCORE_UNSIGNED, 0, use char* in mincore) AC_MSG_RESULT(signed) ], [ AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32.]) ]) ]) AC_LANG_POP(C++) ]) AC_DEFUN([TORRENT_MINCORE], [ AC_ARG_ENABLE(mincore, AC_HELP_STRING([--disable-mincore], [disable mincore check [[default=enable]]]), [ if test "$enableval" = "yes"; then TORRENT_MINCORE_SIGNEDNESS() else AC_MSG_CHECKING(for mincore) AC_MSG_RESULT(disabled) fi ],[ TORRENT_MINCORE_SIGNEDNESS() ]) ]) AC_DEFUN([TORRENT_CHECK_MADVISE], [ AC_MSG_CHECKING(for madvise) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include void f() { static char test@<:@1024@:>@; madvise((void *)test, sizeof(test), MADV_NORMAL); } ])], [ AC_MSG_RESULT(yes) AC_DEFINE(USE_MADVISE, 1, Use madvise) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_CHECK_POPCOUNT], [ AC_MSG_CHECKING(for __builtin_popcount) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ int f() { return __builtin_popcount(0); } ])], [ AC_MSG_RESULT(yes) AC_DEFINE(USE_BUILTIN_POPCOUNT, 1, Use __builtin_popcount.) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_CHECK_CACHELINE], [ AC_MSG_CHECKING(for cacheline) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include void* vptr __cacheline_aligned; void f() { posix_memalign(&vptr, SMP_CACHE_BYTES, 42); } ])], [ AC_MSG_RESULT(found builtin) dnl AC_DEFINE(LT_SMP_CACHE_BYTES, SMP_CACHE_BYTES, Largest L1 cache size we know of, should work on all archs.) dnl AC_DEFINE(lt_cacheline_aligned, __cacheline_aligned, LibTorrent defined cacheline aligned.) dnl Need to fix this so that it uses the stuff defined by the system. AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.) AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.) ], [ AC_MSG_RESULT(using default 128 bytes) AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.) AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.) ]) ]) AC_DEFUN([TORRENT_CHECK_EXECINFO], [ AC_MSG_CHECKING(for execinfo.h) AC_RUN_IFELSE([AC_LANG_SOURCE([ #include int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;} ])], [ AC_MSG_RESULT(yes) AC_DEFINE(USE_EXECINFO, 1, Use execinfo.h) ], [ AC_MSG_RESULT(no) ]) ]) AC_DEFUN([TORRENT_CHECK_ALIGNED], [ AC_MSG_CHECKING(the byte alignment) AC_RUN_IFELSE([AC_LANG_SOURCE([ #include int main() { char buf@<:@8@:>@ = { 0, 0, 0, 0, 1, 0, 0, 0 }; int i; for (i = 1; i < 4; ++i) if (*(uint32_t*)(buf + i) == 0) return -1; return 0; } ])], [ AC_MSG_RESULT(none needed) ], [ AC_DEFINE(USE_ALIGNED, 1, Require byte alignment) AC_MSG_RESULT(required) ]) ]) AC_DEFUN([TORRENT_ENABLE_ALIGNED], [ AC_ARG_ENABLE(aligned, AC_HELP_STRING([--enable-aligned], [enable alignment safe code [[default=check]]]), [ if test "$enableval" = "yes"; then AC_DEFINE(USE_ALIGNED, 1, Require byte alignment) fi ],[ TORRENT_CHECK_ALIGNED ]) ]) AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [ AC_MSG_CHECKING([if instrumentation should be included]) AC_ARG_ENABLE(instrumentation, AC_HELP_STRING([--disable-instrumentation], [disable instrumentation [[default=enabled]]]), [ if test "$enableval" = "yes"; then AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi ],[ AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation) AC_MSG_RESULT(yes) ]) ]) AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [ AC_ARG_ENABLE(interrupt-socket, AC_HELP_STRING([--enable-interrupt-socket], [enable interrupt socket [[default=no]]]), [ if test "$enableval" = "yes"; then AC_DEFINE(USE_INTERRUPT_SOCKET, 1, Use interrupt socket instead of pthread_kill) fi ] ) ]) AC_DEFUN([TORRENT_DISABLE_IPV6], [ AC_ARG_ENABLE(ipv6, AC_HELP_STRING([--enable-ipv6], [enable ipv6 [[default=no]]]), [ if test "$enableval" = "yes"; then AC_DEFINE(RAK_USE_INET6, 1, enable ipv6 stuff) fi ]) ]) AC_DEFUN([TORRENT_ENABLE_TR1], [ AC_ARG_ENABLE(std_tr1, AC_HELP_STRING([--disable-std_tr1], [disable check for support for TR1 [[default=enable]]]), [ if test "$enableval" = "yes"; then TORRENT_CHECK_TR1() else AC_MSG_CHECKING(for TR1 support) AC_MSG_RESULT(disabled) fi ],[ TORRENT_CHECK_TR1() ]) ]) AC_DEFUN([TORRENT_ENABLE_CXX11], [ AC_ARG_ENABLE(std_c++11, AC_HELP_STRING([--disable-std_c++11], [disable check for support for C++11 [[default=enable]]]), [ if test "$enableval" = "yes"; then TORRENT_CHECK_CXX11() else AC_MSG_CHECKING(for C++11 support) AC_MSG_RESULT(disabled) fi ],[ TORRENT_CHECK_CXX11() ] ) ]) rtorrent-0.9.6/src/000077500000000000000000000000001257211462100141755ustar00rootroot00000000000000rtorrent-0.9.6/src/Makefile.am000066400000000000000000000016661257211462100162420ustar00rootroot00000000000000SUBDIRS = \ core \ display \ input \ rpc \ ui \ utils noinst_LIBRARIES = libsub_root.a libsub_root_a_SOURCES = \ command_download.cc \ command_dynamic.cc \ command_events.cc \ command_file.cc \ command_ip.cc \ command_helpers.cc \ command_helpers.h \ command_groups.cc \ command_local.cc \ command_logging.cc \ command_network.cc \ command_peer.cc \ command_throttle.cc \ command_tracker.cc \ command_scheduler.cc \ command_ui.cc \ control.cc \ control.h \ globals.cc \ globals.h \ option_parser.cc \ option_parser.h \ signal_handler.cc \ signal_handler.h \ thread_base.cc \ thread_base.h \ thread_worker.cc \ thread_worker.h bin_PROGRAMS = rtorrent rtorrent_LDADD = \ libsub_root.a \ ui/libsub_ui.a \ core/libsub_core.a \ display/libsub_display.a \ input/libsub_input.a \ rpc/libsub_rpc.a \ utils/libsub_utils.a \ @PTHREAD_LIBS@ rtorrent_SOURCES = \ main.cc AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) rtorrent-0.9.6/src/command_download.cc000066400000000000000000001170741257211462100200230ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/download_store.h" #include "core/manager.h" #include "rpc/parse.h" #include "globals.h" #include "control.h" #include "command_helpers.h" std::string retrieve_d_base_path(core::Download* download) { if (download->file_list()->is_multi_file()) return download->file_list()->frozen_root_dir(); else return download->file_list()->empty() ? std::string() : download->file_list()->at(0)->frozen_path(); } std::string retrieve_d_base_filename(core::Download* download) { const std::string* base; if (download->file_list()->is_multi_file()) base = &download->file_list()->frozen_root_dir(); else base = &download->file_list()->at(0)->frozen_path(); std::string::size_type split = base->rfind('/'); if (split == std::string::npos) return *base; else return base->substr(split + 1); } torrent::Object apply_d_change_link(core::Download* download, const torrent::Object::list_type& args, int changeType) { if (args.size() != 3) throw torrent::input_error("Wrong argument count."); torrent::Object::list_const_iterator itr = args.begin(); const std::string& type = (itr++)->as_string(); const std::string& prefix = (itr++)->as_string(); const std::string& postfix = (itr++)->as_string(); if (type.empty()) throw torrent::input_error("Invalid arguments."); std::string target; std::string link; if (type == "base_path") { target = rpc::call_command_string("d.base_path", rpc::make_target(download)); link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix); } else if (type == "base_filename") { target = rpc::call_command_string("d.base_path", rpc::make_target(download)); link = rak::path_expand(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix); // } else if (type == "directory_path") { // target = rpc::call_command_string("d.directory", rpc::make_target(download)); // link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix); } else if (type == "tied") { link = rak::path_expand(rpc::call_command_string("d.tied_to_file", rpc::make_target(download))); if (link.empty()) return torrent::Object(); link = rak::path_expand(prefix + link + postfix); target = rpc::call_command_string("d.base_path", rpc::make_target(download)); } else { throw torrent::input_error("Unknown type argument."); } switch (changeType) { case 0: if (symlink(target.c_str(), link.c_str()) == -1){ lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s", rak::error_number::current().c_str()); } break; case 1: { rak::file_stat fileStat; rak::error_number::clear_global(); if (!fileStat.update_link(link) || !fileStat.is_link() || unlink(link.c_str()) == -1){ lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s", rak::error_number::current().c_str()); } break; } default: break; } return torrent::Object(); } torrent::Object apply_d_delete_tied(core::Download* download) { const std::string& tie = rpc::call_command_string("d.tied_to_file", rpc::make_target(download)); if (tie.empty()) return torrent::Object(); if (::unlink(rak::path_expand(tie).c_str()) == -1) control->core()->push_log_std("Could not unlink tied file: " + std::string(rak::error_number::current().c_str())); rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(download)); return torrent::Object(); } void apply_d_directory(core::Download* download, const std::string& name) { if (!download->file_list()->is_multi_file()) download->set_root_directory(name); else if (name.empty() || *name.rbegin() == '/') download->set_root_directory(name + download->info()->name()); else download->set_root_directory(name + "/" + download->info()->name()); } torrent::Object apply_d_connection_type(core::Download* download, const std::string& name) { torrent::Download::ConnectionType t = (torrent::Download::ConnectionType)torrent::option_find_string(torrent::OPTION_CONNECTION_TYPE, name.c_str()); download->download()->set_connection_type(t); return torrent::Object(); } torrent::Object apply_d_choke_heuristics(core::Download* download, const std::string& name, bool is_down) { torrent::Download::HeuristicType t = (torrent::Download::HeuristicType)torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str()); if (is_down) download->download()->set_download_choke_heuristic(t); else download->download()->set_upload_choke_heuristic(t); return torrent::Object(); } const char* retrieve_d_priority_str(core::Download* download) { switch (download->priority()) { case 0: return "off"; case 1: return "low"; case 2: return "normal"; case 3: return "high"; default: throw torrent::input_error("Priority out of range."); } } torrent::Object retrieve_d_ratio(core::Download* download) { if (download->is_hash_checking()) return int64_t(); int64_t bytesDone = download->download()->bytes_done(); int64_t upTotal = download->info()->up_rate()->total(); return bytesDone > 0 ? (1000 * upTotal) / bytesDone : 0; } torrent::Object apply_d_custom(core::Download* download, const torrent::Object::list_type& args) { torrent::Object::list_const_iterator itr = args.begin(); if (itr == args.end()) throw torrent::bencode_error("Missing key argument."); const std::string& key = itr->as_string(); if (++itr == args.end()) throw torrent::bencode_error("Missing value argument."); download->bencode()->get_key("rtorrent"). insert_preserve_copy("custom", torrent::Object::create_map()).first->second. insert_key(key, itr->as_string()); return torrent::Object(); } torrent::Object retrieve_d_custom(core::Download* download, const std::string& key) { try { return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key); } catch (torrent::bencode_error& e) { return std::string(); } } torrent::Object retrieve_d_custom_throw(core::Download* download, const std::string& key) { try { return download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key); } catch (torrent::bencode_error& e) { throw torrent::input_error("No such custom value."); } } torrent::Object retrieve_d_bitfield(core::Download* download) { const torrent::Bitfield* bitField = download->download()->file_list()->bitfield(); if (bitField->empty()) return torrent::Object(""); return torrent::Object(rak::transform_hex(bitField->begin(), bitField->end())); } struct call_add_d_peer_t { call_add_d_peer_t(core::Download* d, int port) : m_download(d), m_port(port) { } void operator() (const sockaddr* sa, int err) { if (sa == NULL) { lt_log_print(torrent::LOG_CONNECTION_WARN, "Could not resolve hostname for added peer."); } else { m_download->download()->add_peer(sa, m_port); } } core::Download* m_download; int m_port; }; void apply_d_add_peer(core::Download* download, const std::string& arg) { int port, ret; char dummy; char host[1024]; if (download->download()->info()->is_private()) throw torrent::input_error("Download is private."); ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); if (ret == 1) port = 6881; else if (ret != 2) throw torrent::input_error("Could not parse host."); if (port < 1 || port > 65535) throw torrent::input_error("Invalid port number."); torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_STREAM, call_add_d_peer_t(download, port)); } torrent::Object d_chunks_seen(core::Download* download) { const uint8_t* seen = download->download()->chunks_seen(); if (seen == NULL) return std::string(); uint32_t size = download->download()->file_list()->size_chunks(); std::string result; result.resize(size * 2); rak::transform_hex((const char*)seen, (const char*)seen + size, result.begin()); return result; } torrent::Object f_multicall(core::Download* download, const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Too few arguments."); // We ignore the first arg for now, but it will be used for // selecting what files to include. // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); std::vector regex_list; bool use_regex = true; if (args.front().is_list()) std::transform(args.front().as_list().begin(), args.front().as_list().end(), std::back_inserter(regex_list), tr1::bind(&torrent::Object::as_string_c, tr1::placeholders::_1)); else if (args.front().is_string() && !args.front().as_string().empty()) regex_list.push_back(args.front().as_string()); else use_regex = false; for (torrent::FileList::const_iterator itr = download->file_list()->begin(), last = download->file_list()->end(); itr != last; itr++) { if (use_regex && std::find_if(regex_list.begin(), regex_list.end(), tr1::bind(&rak::regex::operator(), tr1::placeholders::_1, (*itr)->path()->as_string())) == regex_list.end()) continue; torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { const std::string& cmd = cItr->as_string(); row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first); } } return resultRaw; } torrent::Object t_multicall(core::Download* download, const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Too few arguments."); // We ignore the first arg for now, but it will be used for // selecting what files to include. // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); for (int itr = 0, last = download->tracker_list()->size(); itr != last; itr++) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { const std::string& cmd = cItr->as_string(); torrent::Tracker* t = download->tracker_list()->at(itr); row.push_back(rpc::parse_command(rpc::make_target(t), cmd.c_str(), cmd.c_str() + cmd.size()).first); } } return resultRaw; } torrent::Object p_multicall(core::Download* download, const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Too few arguments."); // We ignore the first arg for now, but it will be used for // selecting what files to include. // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end(); itr != last; itr++) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { const std::string& cmd = cItr->as_string(); row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first); } } return resultRaw; } torrent::Object p_call_target(const torrent::Object::list_type& args) { if (args.empty() || args.begin() + 1 == args.end() || args.begin() + 2 == args.end()) throw torrent::input_error("Too few arguments."); // We ignore the first arg for now, but it will be used for // selecting what files to include. // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. torrent::Object::list_const_iterator itr = args.begin(); core::Download* download = control->core()->download_list()->find_hex_ptr(itr++->as_string().c_str()); const std::string& peer_id = itr++->as_string(); const std::string& command_key = itr++->as_string(); torrent::HashString hash; if (peer_id.size() != 40 || torrent::hash_string_from_hex_c_str(peer_id.c_str(), hash) == peer_id.c_str()) throw torrent::input_error("Not a hash string."); torrent::ConnectionList::iterator peerItr = download->connection_list()->find(hash.c_str()); if (peerItr == download->connection_list()->end()) throw torrent::input_error("Could not find peer."); if (itr == args.end()) return rpc::commands.call(command_key.c_str()); if (itr + 1 == args.end()) return rpc::commands.call(command_key.c_str(), *itr); return rpc::commands.call(command_key.c_str(), torrent::Object::create_list_range(itr, args.end())); } torrent::Object download_tracker_insert(core::Download* download, const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); int64_t group; if (args.front().is_string()) rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group); else group = args.front().as_value(); if (group < 0 || group > 32) throw torrent::input_error("Tracker group number invalid."); download->download()->tracker_list()->insert_url(group, args.back().as_string(), true); return torrent::Object(); } // // New download commands and macros: // torrent::Object& download_get_variable(core::Download* download, const char* first_key, const char* second_key = NULL) { if (second_key == NULL) return download->bencode()->get_key(first_key); return download->bencode()->get_key(first_key).get_key(second_key); } torrent::Object download_set_variable(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key = NULL) { if (second_key == NULL) return download->bencode()->get_key(first_key) = torrent::object_create_normal(rawArgs); return download->bencode()->get_key(first_key).get_key(second_key) = torrent::object_create_normal(rawArgs); } torrent::Object download_set_variable_value(core::Download* download, const torrent::Object::value_type& args, const char* first_key, const char* second_key = NULL) { if (second_key == NULL) return download->bencode()->get_key(first_key) = args; return download->bencode()->get_key(first_key).get_key(second_key) = args; } torrent::Object download_set_variable_value_ifz(core::Download* download, const torrent::Object::value_type& args, const char* first_key, const char* second_key = NULL) { torrent::Object& object = second_key == NULL ? download->bencode()->get_key(first_key) : download->bencode()->get_key(first_key).get_key(second_key); if (object.as_value() == 0) object = args; return object; } torrent::Object download_set_variable_string(core::Download* download, const torrent::Object::string_type& args, const char* first_key, const char* second_key = NULL) { if (second_key == NULL) return download->bencode()->get_key(first_key) = args; return download->bencode()->get_key(first_key).get_key(second_key) = args; } // // // torrent::Object d_list_push_back(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) { download_get_variable(download, first_key, second_key).as_list().push_back(rawArgs); return torrent::Object(); } torrent::Object d_list_push_back_unique(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) { const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs; torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list(); if (std::find_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) == list.end()) list.push_back(rawArgs); return torrent::Object(); } torrent::Object d_list_has(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) { const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs; torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list(); return (int64_t)(std::find_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) != list.end()); } torrent::Object d_list_remove(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) { const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs; torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list(); list.erase(std::remove_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)), list.end()); return torrent::Object(); } #define CMD2_ON_INFO(func) tr1::bind(&torrent::DownloadInfo::func, tr1::bind(&core::Download::info, tr1::placeholders::_1)) #define CMD2_ON_DATA(func) tr1::bind(&torrent::download_data::func, tr1::bind(&core::Download::data, tr1::placeholders::_1)) #define CMD2_ON_DL(func) tr1::bind(&torrent::Download::func, tr1::bind(&core::Download::download, tr1::placeholders::_1)) #define CMD2_ON_FL(func) tr1::bind(&torrent::FileList::func, tr1::bind(&core::Download::file_list, tr1::placeholders::_1)) #define CMD2_BIND_DL tr1::bind(&core::Download::download, tr1::placeholders::_1) #define CMD2_BIND_CL tr1::bind(&core::Download::connection_list, tr1::placeholders::_1) #define CMD2_BIND_FL tr1::bind(&core::Download::file_list, tr1::placeholders::_1) #define CMD2_BIND_PL tr1::bind(&core::Download::c_peer_list, tr1::placeholders::_1) #define CMD2_BIND_TL tr1::bind(&core::Download::tracker_list, tr1::placeholders::_1) #define CMD2_BIND_TC tr1::bind(&core::Download::tracker_controller, tr1::placeholders::_1) #define CMD2_BIND_INFO tr1::bind(&core::Download::info, tr1::placeholders::_1) #define CMD2_BIND_DATA tr1::bind(&core::Download::data, tr1::placeholders::_1) #define CMD2_DL_VAR_VALUE(key, first_key, second_key) \ CMD2_DL(key, tr1::bind(&download_get_variable, tr1::placeholders::_1, first_key, second_key)); \ CMD2_DL_VALUE_P(key ".set", tr1::bind(&download_set_variable_value, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); #define CMD2_DL_VAR_VALUE_PUBLIC(key, first_key, second_key) \ CMD2_DL(key, tr1::bind(&download_get_variable, tr1::placeholders::_1, first_key, second_key)); \ CMD2_DL_VALUE(key ".set", tr1::bind(&download_set_variable_value, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); #define CMD2_DL_TIMESTAMP(key, first_key, second_key) \ CMD2_DL(key, tr1::bind(&download_get_variable, tr1::placeholders::_1, first_key, second_key)); \ CMD2_DL_VALUE_P(key ".set", tr1::bind(&download_set_variable_value, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); \ CMD2_DL_VALUE_P(key ".set_if_z", tr1::bind(&download_set_variable_value_ifz, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); \ #define CMD2_DL_VAR_STRING(key, first_key, second_key) \ CMD2_DL(key, tr1::bind(&download_get_variable, tr1::placeholders::_1, first_key, second_key)); \ CMD2_DL_STRING_P(key ".set", tr1::bind(&download_set_variable_string, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); #define CMD2_DL_VAR_STRING_PUBLIC(key, first_key, second_key) \ CMD2_DL(key, tr1::bind(&download_get_variable, tr1::placeholders::_1, first_key, second_key)); \ CMD2_DL_STRING(key ".set", tr1::bind(&download_set_variable_string, \ tr1::placeholders::_1, tr1::placeholders::_2, \ first_key, second_key)); int64_t cg_d_group(core::Download* download); const std::string& cg_d_group_name(core::Download* download); void cg_d_group_set(core::Download* download, const torrent::Object& arg); void initialize_command_download() { CMD2_DL("d.hash", tr1::bind(&rak::transform_hex_str, CMD2_ON_INFO(hash))); CMD2_DL("d.local_id", tr1::bind(&rak::transform_hex_str, CMD2_ON_INFO(local_id))); CMD2_DL("d.local_id_html", tr1::bind(&rak::copy_escape_html_str, CMD2_ON_INFO(local_id))); CMD2_DL("d.bitfield", tr1::bind(&retrieve_d_bitfield, tr1::placeholders::_1)); CMD2_DL("d.base_path", tr1::bind(&retrieve_d_base_path, tr1::placeholders::_1)); CMD2_DL("d.base_filename", tr1::bind(&retrieve_d_base_filename, tr1::placeholders::_1)); CMD2_DL("d.name", CMD2_ON_INFO(name)); CMD2_DL("d.creation_date", CMD2_ON_INFO(creation_date)); CMD2_DL("d.load_date", CMD2_ON_INFO(load_date)); // // Network related: // CMD2_DL ("d.up.rate", tr1::bind(&torrent::Rate::rate, CMD2_ON_INFO(up_rate))); CMD2_DL ("d.up.total", tr1::bind(&torrent::Rate::total, CMD2_ON_INFO(up_rate))); CMD2_DL ("d.down.rate", tr1::bind(&torrent::Rate::rate, CMD2_ON_INFO(down_rate))); CMD2_DL ("d.down.total", tr1::bind(&torrent::Rate::total, CMD2_ON_INFO(down_rate))); CMD2_DL ("d.skip.rate", tr1::bind(&torrent::Rate::rate, CMD2_ON_INFO(skip_rate))); CMD2_DL ("d.skip.total", tr1::bind(&torrent::Rate::total, CMD2_ON_INFO(skip_rate))); CMD2_DL ("d.peer_exchange", CMD2_ON_INFO(is_pex_enabled)); CMD2_DL_VALUE_V ("d.peer_exchange.set", tr1::bind(&torrent::Download::set_pex_enabled, CMD2_BIND_DL, tr1::placeholders::_2)); CMD2_DL_LIST ("d.create_link", tr1::bind(&apply_d_change_link, tr1::placeholders::_1, tr1::placeholders::_2, 0)); CMD2_DL_LIST ("d.delete_link", tr1::bind(&apply_d_change_link, tr1::placeholders::_1, tr1::placeholders::_2, 1)); CMD2_DL ("d.delete_tied", tr1::bind(&apply_d_delete_tied, tr1::placeholders::_1)); CMD2_FUNC_SINGLE("d.start", "d.hashing_failed.set=0 ;view.set_visible=started"); CMD2_FUNC_SINGLE("d.stop", "view.set_visible=stopped"); CMD2_FUNC_SINGLE("d.try_start", "branch=\"or={d.hashing_failed=,d.ignore_commands=}\",{},{view.set_visible=started}"); CMD2_FUNC_SINGLE("d.try_stop", "branch=d.ignore_commands=, {}, {view.set_visible=stopped}"); CMD2_FUNC_SINGLE("d.try_close", "branch=d.ignore_commands=, {}, {view.set_visible=stopped, d.close=}"); // // Control functinos: // CMD2_DL ("d.is_open", CMD2_ON_INFO(is_open)); CMD2_DL ("d.is_active", CMD2_ON_INFO(is_active)); CMD2_DL ("d.is_hash_checked", tr1::bind(&torrent::Download::is_hash_checked, CMD2_BIND_DL)); CMD2_DL ("d.is_hash_checking", tr1::bind(&torrent::Download::is_hash_checking, CMD2_BIND_DL)); CMD2_DL ("d.is_multi_file", tr1::bind(&torrent::FileList::is_multi_file, CMD2_BIND_FL)); CMD2_DL ("d.is_private", CMD2_ON_INFO(is_private)); CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active)); CMD2_DL ("d.is_partially_done", CMD2_ON_DATA(is_partially_done)); CMD2_DL ("d.is_not_partially_done", CMD2_ON_DATA(is_not_partially_done)); CMD2_DL_V ("d.resume", tr1::bind(&core::DownloadList::resume_default, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.pause", tr1::bind(&core::DownloadList::pause_default, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.open", tr1::bind(&core::DownloadList::open_throw, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.close", tr1::bind(&core::DownloadList::close_throw, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.close.directly", tr1::bind(&core::DownloadList::close_directly, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.erase", tr1::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL_V ("d.check_hash", tr1::bind(&core::DownloadList::check_hash, control->core()->download_list(), tr1::placeholders::_1)); CMD2_DL ("d.save_resume", tr1::bind(&core::DownloadStore::save_resume, control->core()->download_store(), tr1::placeholders::_1)); CMD2_DL ("d.save_full_session", tr1::bind(&core::DownloadStore::save_full, control->core()->download_store(), tr1::placeholders::_1)); CMD2_DL_V ("d.update_priorities", CMD2_ON_DL(update_priorities)); CMD2_DL_STRING_V("add_peer", tr1::bind(&apply_d_add_peer, tr1::placeholders::_1, tr1::placeholders::_2)); // // Custom settings: // CMD2_DL_STRING("d.custom", tr1::bind(&retrieve_d_custom, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_STRING("d.custom_throw", tr1::bind(&retrieve_d_custom_throw, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_LIST ("d.custom.set", tr1::bind(&apply_d_custom, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_VAR_STRING_PUBLIC("d.custom1", "rtorrent", "custom1"); CMD2_DL_VAR_STRING_PUBLIC("d.custom2", "rtorrent", "custom2"); CMD2_DL_VAR_STRING_PUBLIC("d.custom3", "rtorrent", "custom3"); CMD2_DL_VAR_STRING_PUBLIC("d.custom4", "rtorrent", "custom4"); CMD2_DL_VAR_STRING_PUBLIC("d.custom5", "rtorrent", "custom5"); // 0 - stopped // 1 - started CMD2_DL_VAR_VALUE("d.state", "rtorrent", "state"); CMD2_DL_VAR_VALUE("d.complete", "rtorrent", "complete"); CMD2_FUNC_SINGLE ("d.incomplete", "not=(d.complete)"); // 0 off // 1 scheduled, being controlled by a download scheduler. Includes a priority. // 3 forced off // 2 forced on CMD2_DL_VAR_VALUE("d.mode", "rtorrent", "mode"); // 0 - Not hashing // 1 - Normal hashing // 2 - Download finished, hashing // 3 - Rehashing CMD2_DL_VAR_VALUE("d.hashing", "rtorrent", "hashing"); // 'tied_to_file' is the file the download is associated with, and // can be changed by the user. // // 'loaded_file' is the file this instance of the torrent was loaded // from, and should not be changed. CMD2_DL_VAR_STRING_PUBLIC("d.tied_to_file", "rtorrent", "tied_to_file"); CMD2_DL_VAR_STRING("d.loaded_file", "rtorrent", "loaded_file"); // The "state_changed" variable is required to be a valid unix time // value, it indicates the last time the torrent changed its state, // resume/pause. CMD2_DL_VAR_VALUE("d.state_changed", "rtorrent", "state_changed"); CMD2_DL_VAR_VALUE("d.state_counter", "rtorrent", "state_counter"); CMD2_DL_VAR_VALUE_PUBLIC("d.ignore_commands", "rtorrent", "ignore_commands"); CMD2_DL_TIMESTAMP("d.timestamp.started", "rtorrent", "timestamp.started"); CMD2_DL_TIMESTAMP("d.timestamp.finished", "rtorrent", "timestamp.finished"); CMD2_DL ("d.connection_current", tr1::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type))); CMD2_DL_STRING("d.connection_current.set", tr1::bind(&apply_d_connection_type, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_VAR_STRING("d.connection_leech", "rtorrent", "connection_leech"); CMD2_DL_VAR_STRING("d.connection_seed", "rtorrent", "connection_seed"); CMD2_DL ("d.up.choke_heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(upload_choke_heuristic))); CMD2_DL_STRING("d.up.choke_heuristics.set", tr1::bind(&apply_d_choke_heuristics, tr1::placeholders::_1, tr1::placeholders::_2, false)); CMD2_DL ("d.down.choke_heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(download_choke_heuristic))); CMD2_DL_STRING("d.down.choke_heuristics.set", tr1::bind(&apply_d_choke_heuristics, tr1::placeholders::_1, tr1::placeholders::_2, true)); CMD2_DL_VAR_STRING("d.up.choke_heuristics.leech", "rtorrent", "choke_heuristics.up.leech"); CMD2_DL_VAR_STRING("d.up.choke_heuristics.seed", "rtorrent", "choke_heuristics.up.seed"); CMD2_DL_VAR_STRING("d.down.choke_heuristics.leech", "rtorrent", "choke_heuristics.down.leech"); CMD2_DL_VAR_STRING("d.down.choke_heuristics.seed", "rtorrent", "choke_heuristics.down.seed"); CMD2_DL ("d.hashing_failed", tr1::bind(&core::Download::is_hash_failed, tr1::placeholders::_1)); CMD2_DL_VALUE_V ("d.hashing_failed.set", tr1::bind(&core::Download::set_hash_failed, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL ("d.views", tr1::bind(&download_get_variable, tr1::placeholders::_1, "rtorrent", "views")); CMD2_DL ("d.views.has", tr1::bind(&d_list_has, tr1::placeholders::_1, tr1::placeholders::_2, "rtorrent", "views")); CMD2_DL ("d.views.remove", tr1::bind(&d_list_remove, tr1::placeholders::_1, tr1::placeholders::_2, "rtorrent", "views")); CMD2_DL ("d.views.push_back", tr1::bind(&d_list_push_back, tr1::placeholders::_1, tr1::placeholders::_2, "rtorrent", "views")); CMD2_DL ("d.views.push_back_unique", tr1::bind(&d_list_push_back_unique, tr1::placeholders::_1, tr1::placeholders::_2, "rtorrent", "views")); // This command really needs to be improved, so we have proper // logging support. CMD2_DL ("d.message", tr1::bind(&core::Download::message, tr1::placeholders::_1)); CMD2_DL_STRING_V("d.message.set", tr1::bind(&core::Download::set_message, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL ("d.max_file_size", CMD2_ON_FL(max_file_size)); CMD2_DL_VALUE_V ("d.max_file_size.set", tr1::bind(&torrent::FileList::set_max_file_size, CMD2_BIND_FL, tr1::placeholders::_2)); CMD2_DL ("d.peers_min", tr1::bind(&torrent::ConnectionList::min_size, CMD2_BIND_CL)); CMD2_DL_VALUE_V ("d.peers_min.set", tr1::bind(&torrent::ConnectionList::set_min_size, CMD2_BIND_CL, tr1::placeholders::_2)); CMD2_DL ("d.peers_max", tr1::bind(&torrent::ConnectionList::max_size, CMD2_BIND_CL)); CMD2_DL_VALUE_V ("d.peers_max.set", tr1::bind(&torrent::ConnectionList::set_max_size, CMD2_BIND_CL, tr1::placeholders::_2)); CMD2_DL ("d.uploads_max", tr1::bind(&torrent::Download::uploads_max, CMD2_BIND_DL)); CMD2_DL_VALUE_V ("d.uploads_max.set", tr1::bind(&torrent::Download::set_uploads_max, CMD2_BIND_DL, tr1::placeholders::_2)); CMD2_DL ("d.uploads_min", tr1::bind(&torrent::Download::uploads_min, CMD2_BIND_DL)); CMD2_DL_VALUE_V ("d.uploads_min.set", tr1::bind(&torrent::Download::set_uploads_min, CMD2_BIND_DL, tr1::placeholders::_2)); CMD2_DL ("d.downloads_max", tr1::bind(&torrent::Download::downloads_max, CMD2_BIND_DL)); CMD2_DL_VALUE_V ("d.downloads_max.set", tr1::bind(&torrent::Download::set_downloads_max, CMD2_BIND_DL, tr1::placeholders::_2)); CMD2_DL ("d.downloads_min", tr1::bind(&torrent::Download::downloads_min, CMD2_BIND_DL)); CMD2_DL_VALUE_V ("d.downloads_min.set", tr1::bind(&torrent::Download::set_downloads_min, CMD2_BIND_DL, tr1::placeholders::_2)); CMD2_DL ("d.peers_connected", tr1::bind(&torrent::ConnectionList::size, CMD2_BIND_CL)); CMD2_DL ("d.peers_not_connected", tr1::bind(&torrent::PeerList::available_list_size, CMD2_BIND_PL)); CMD2_DL ("d.peers_complete", CMD2_ON_DL(peers_complete)); CMD2_DL ("d.peers_accounted", CMD2_ON_DL(peers_accounted)); CMD2_DL_V ("d.disconnect.seeders", tr1::bind(&torrent::ConnectionList::erase_seeders, CMD2_BIND_CL)); CMD2_DL ("d.accepting_seeders", CMD2_ON_INFO(is_accepting_seeders)); CMD2_DL_V ("d.accepting_seeders.enable", tr1::bind(&torrent::DownloadInfo::public_set_flags, CMD2_BIND_INFO, torrent::DownloadInfo::flag_accepting_seeders)); CMD2_DL_V ("d.accepting_seeders.disable", tr1::bind(&torrent::DownloadInfo::public_unset_flags, CMD2_BIND_INFO, torrent::DownloadInfo::flag_accepting_seeders)); CMD2_DL ("d.throttle_name", tr1::bind(&download_get_variable, tr1::placeholders::_1, "rtorrent", "throttle_name")); CMD2_DL_STRING_V("d.throttle_name.set", tr1::bind(&core::Download::set_throttle_name, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL ("d.bytes_done", CMD2_ON_DL(bytes_done)); CMD2_DL ("d.ratio", tr1::bind(&retrieve_d_ratio, tr1::placeholders::_1)); CMD2_DL ("d.chunks_hashed", CMD2_ON_DL(chunks_hashed)); CMD2_DL ("d.free_diskspace", CMD2_ON_FL(free_diskspace)); CMD2_DL ("d.size_files", CMD2_ON_FL(size_files)); CMD2_DL ("d.size_bytes", CMD2_ON_FL(size_bytes)); CMD2_DL ("d.size_chunks", CMD2_ON_FL(size_chunks)); CMD2_DL ("d.chunk_size", CMD2_ON_FL(chunk_size)); CMD2_DL ("d.size_pex", CMD2_ON_DL(size_pex)); CMD2_DL ("d.max_size_pex", CMD2_ON_DL(max_size_pex)); CMD2_DL ("d.chunks_seen", tr1::bind(&d_chunks_seen, tr1::placeholders::_1)); CMD2_DL ("d.completed_bytes", CMD2_ON_FL(completed_bytes)); CMD2_DL ("d.completed_chunks", CMD2_ON_FL(completed_chunks)); CMD2_DL ("d.left_bytes", CMD2_ON_FL(left_bytes)); CMD2_DL ("d.wanted_chunks", CMD2_ON_DATA(wanted_chunks)); CMD2_DL_V ("d.tracker_announce", tr1::bind(&torrent::Download::manual_request, CMD2_BIND_DL, false)); CMD2_DL ("d.tracker_numwant", tr1::bind(&torrent::TrackerList::numwant, CMD2_BIND_TL)); CMD2_DL_VALUE_V ("d.tracker_numwant.set", tr1::bind(&torrent::TrackerList::set_numwant, CMD2_BIND_TL, tr1::placeholders::_2)); // TODO: Deprecate 'd.tracker_focus'. CMD2_DL ("d.tracker_focus", tr1::bind(&core::Download::tracker_list_size, tr1::placeholders::_1)); CMD2_DL ("d.tracker_size", tr1::bind(&core::Download::tracker_list_size, tr1::placeholders::_1)); CMD2_DL_LIST ("d.tracker.insert", tr1::bind(&download_tracker_insert, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_VALUE_V ("d.tracker.send_scrape", tr1::bind(&torrent::TrackerController::scrape_request, CMD2_BIND_TC, tr1::placeholders::_2)); CMD2_DL ("d.directory", CMD2_ON_FL(root_dir)); CMD2_DL_STRING_V("d.directory.set", tr1::bind(&apply_d_directory, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL ("d.directory_base", CMD2_ON_FL(root_dir)); CMD2_DL_STRING_V("d.directory_base.set", tr1::bind(&core::Download::set_root_directory, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL ("d.priority", tr1::bind(&core::Download::priority, tr1::placeholders::_1)); CMD2_DL ("d.priority_str", tr1::bind(&retrieve_d_priority_str, tr1::placeholders::_1)); CMD2_DL_VALUE_V ("d.priority.set", tr1::bind(&core::Download::set_priority, tr1::placeholders::_1, tr1::placeholders::_2)); // CMD2_DL ("d.group", tr1::bind(&torrent::resource_manager_entry::group, // tr1::bind(&torrent::ResourceManager::entry_at, torrent::resource_manager(), // tr1::bind(&core::Download::main, tr1::placeholders::_1)))); // CMD2_DL_V ("d.group.set", tr1::bind(&torrent::ResourceManager::set_group, // torrent::resource_manager(), // tr1::bind(&torrent::ResourceManager::find_throw, torrent::resource_manager(), // tr1::bind(&core::Download::main, tr1::placeholders::_1)), // CG_GROUP_INDEX())); CMD2_DL ("d.group", tr1::bind(&cg_d_group, tr1::placeholders::_1)); CMD2_DL ("d.group.name", tr1::bind(&cg_d_group, tr1::placeholders::_1)); CMD2_DL_V ("d.group.set", tr1::bind(&cg_d_group_set, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_LIST ("f.multicall", tr1::bind(&f_multicall, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_LIST ("p.multicall", tr1::bind(&p_multicall, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_LIST ("t.multicall", tr1::bind(&t_multicall, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_ANY_LIST ("p.call_target", tr1::bind(&p_call_target, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_dynamic.cc000066400000000000000000000447451257211462100176440ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include "globals.h" #include "control.h" #include "command_helpers.h" #include "rpc/parse.h" std::string system_method_generate_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) { std::string command; while (first != last) { if (!command.empty()) command += " ;"; command += (first++)->as_string(); } return command; } void system_method_generate_command2(torrent::Object* object, torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) { if (first == last) { // TODO: Use empty object. *object = ""; return; } if (first->is_string()) { std::string command; while (first != last) { if (!command.empty()) command += " ;"; command += (first++)->as_string(); } *object = command; return; } if (first + 1 == last) { if (!first->is_dict_key()) throw torrent::input_error("New command of wrong type."); *object = *first; uint32_t flags = object->flags() & torrent::Object::mask_function; object->unset_flags(torrent::Object::mask_function); object->set_flags((flags >> 1) & torrent::Object::mask_function); } else { *object = torrent::Object::create_list(); while (first != last) { if (!first->is_dict_key()) throw torrent::input_error("New command of wrong type."); object->as_list().push_back(*first++); uint32_t flags = object->as_list().back().flags() & torrent::Object::mask_function; object->as_list().back().unset_flags(torrent::Object::mask_function); object->as_list().back().set_flags((flags >> 1) & torrent::Object::mask_function); } } } // torrent::Object // system_method_insert_function(const torrent::Object::list_type& args, int flags) { // } torrent::Object system_method_insert_object(const torrent::Object::list_type& args, int flags) { if (args.empty()) throw torrent::input_error("Invalid argument count."); torrent::Object::list_const_iterator itrArgs = args.begin(); const std::string& rawKey = (itrArgs++)->as_string(); if (rawKey.empty() || control->object_storage()->find_local(torrent::raw_string::from_string(rawKey)) != control->object_storage()->end(0) || rpc::commands.has(rawKey) || rpc::commands.has(rawKey + ".set")) throw torrent::input_error("Invalid key."); torrent::Object value; switch (flags & rpc::object_storage::mask_type) { case rpc::object_storage::flag_bool_type: case rpc::object_storage::flag_value_type: value = itrArgs != args.end() ? rpc::convert_to_value(*itrArgs) : int64_t(); break; case rpc::object_storage::flag_string_type: value = itrArgs != args.end() ? rpc::convert_to_string(*itrArgs) : ""; break; case rpc::object_storage::flag_function_type: system_method_generate_command2(&value, itrArgs, args.end()); break; case rpc::object_storage::flag_multi_type: break; default: throw torrent::input_error("Invalid type."); } int cmd_flags = 0; if (!(flags & rpc::object_storage::flag_static)) cmd_flags |= rpc::CommandMap::flag_modifiable; if (!(flags & rpc::object_storage::flag_private)) cmd_flags |= rpc::CommandMap::flag_public_xmlrpc; control->object_storage()->insert_str(rawKey, value, flags); if ((flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_function_type || (flags & rpc::object_storage::mask_type) == rpc::object_storage::flag_multi_type) { rpc::commands.insert_slot >::type> (create_new_key(rawKey), tr1::bind(&rpc::object_storage::call_function_str, control->object_storage(), rawKey, tr1::placeholders::_1, tr1::placeholders::_2), &rpc::command_base_call, cmd_flags, NULL, NULL); } else { rpc::commands.insert_slot >::type> (create_new_key(rawKey), tr1::bind(&rpc::object_storage::get_str, control->object_storage(), rawKey), &rpc::command_base_call, cmd_flags, NULL, NULL); } // Not the right argument. // if (flags & rpc::object_storage::flag_rlookup) { // rpc::commands.insert_slot >::type> // (create_new_key<9>(rawKey, ".rlookup"), // tr1::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), rawKey), // &rpc::command_base_call_string, // cmd_flags, NULL, NULL); // } // TODO: Next... Make test class for this. // // Ehm... no proper handling if these throw. if (!(flags & rpc::object_storage::flag_constant)) { switch (flags & rpc::object_storage::mask_type) { case rpc::object_storage::flag_bool_type: rpc::commands.insert_slot >::type> (create_new_key<5>(rawKey, ".set"), tr1::bind(&rpc::object_storage::set_str_bool, control->object_storage(), rawKey, tr1::placeholders::_2), &rpc::command_base_call_value, cmd_flags, NULL, NULL); break; case rpc::object_storage::flag_value_type: rpc::commands.insert_slot >::type> (create_new_key<5>(rawKey, ".set"), tr1::bind(&rpc::object_storage::set_str_value, control->object_storage(), rawKey, tr1::placeholders::_2), &rpc::command_base_call_value, cmd_flags, NULL, NULL); break; case rpc::object_storage::flag_string_type: rpc::commands.insert_slot >::type> (create_new_key<5>(rawKey, ".set"), tr1::bind(&rpc::object_storage::set_str_string, control->object_storage(), rawKey, tr1::placeholders::_2), &rpc::command_base_call_string, cmd_flags, NULL, NULL); break; case rpc::object_storage::flag_function_type: case rpc::object_storage::flag_multi_type: default: break; } } return torrent::Object(); } // method.insert {name, "simple|private|const", ...} // method.insert {name, "multi|private|const"} // method.insert {name, "value|private|const"} // method.insert {name, "value|private|const", value} // method.insert {name, "bool|private|const"} // method.insert {name, "bool|private|const", bool} // method.insert {name, "string|private|const"} // method.insert {name, "string|private|const", string} // // Add a new user-defined method called 'name' and any number of // lines. // // TODO: Make a static version of this that doesn't need to be called // as a command, and which takes advantage of static const char // strings, etc. torrent::Object system_method_insert(const torrent::Object::list_type& args) { if (args.empty() || ++args.begin() == args.end()) throw torrent::input_error("Invalid argument count."); torrent::Object::list_const_iterator itrArgs = args.begin(); const std::string& rawKey = (itrArgs++)->as_string(); if (rawKey.empty() || rpc::commands.has(rawKey)) throw torrent::input_error("Invalid key."); int flags = rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc; const std::string& options = itrArgs->as_string(); if (options.find("private") != std::string::npos) flags &= ~rpc::CommandMap::flag_public_xmlrpc; if (options.find("const") != std::string::npos) flags &= ~rpc::CommandMap::flag_modifiable; if (options.find("multi") != std::string::npos) { torrent::Object::list_type new_args; new_args.push_back(rawKey); new_args.push_back(system_method_generate_command(++itrArgs, args.end())); int new_flags = rpc::object_storage::flag_multi_type; if (options.find("static") != std::string::npos) new_flags |= rpc::object_storage::flag_static; if (options.find("private") != std::string::npos) new_flags |= rpc::object_storage::flag_private; if (options.find("const") != std::string::npos) new_flags |= rpc::object_storage::flag_constant; if (options.find("rlookup") != std::string::npos) new_flags |= rpc::object_storage::flag_rlookup; return system_method_insert_object(new_args, new_flags); } else if (options.find("simple") != std::string::npos) { torrent::Object::list_type new_args; new_args.push_back(rawKey); new_args.push_back(system_method_generate_command(++itrArgs, args.end())); int new_flags = rpc::object_storage::flag_function_type; if (options.find("static") != std::string::npos) new_flags |= rpc::object_storage::flag_static; if (options.find("private") != std::string::npos) new_flags |= rpc::object_storage::flag_private; if (options.find("const") != std::string::npos) new_flags |= rpc::object_storage::flag_constant; return system_method_insert_object(new_args, new_flags); } else if (options.find("value") != std::string::npos || options.find("bool") != std::string::npos || options.find("string") != std::string::npos || options.find("list") != std::string::npos || options.find("simple") != std::string::npos) { torrent::Object::list_type new_args; new_args.push_back(rawKey); if (++itrArgs != args.end()) new_args.insert(new_args.end(), itrArgs, args.end()); int new_flags; if (options.find("value") != std::string::npos) new_flags = rpc::object_storage::flag_value_type; else if (options.find("bool") != std::string::npos) new_flags = rpc::object_storage::flag_bool_type; else if (options.find("string") != std::string::npos) new_flags = rpc::object_storage::flag_string_type; else if (options.find("list") != std::string::npos) new_flags = rpc::object_storage::flag_list_type; else if (options.find("simple") != std::string::npos) new_flags = rpc::object_storage::flag_function_type; else throw torrent::input_error("No support for 'list' variable type."); if (options.find("static") != std::string::npos) new_flags |= rpc::object_storage::flag_static; if (options.find("private") != std::string::npos) new_flags |= rpc::object_storage::flag_private; if (options.find("const") != std::string::npos) new_flags |= rpc::object_storage::flag_constant; return system_method_insert_object(new_args, new_flags); } else { // THROW. } return torrent::Object(); } // method.erase <> {name} // // Erase a modifiable method called 'name. Trying to remove methods // that aren't modifiable, e.g. defined by rtorrent or set to // read-only by the user, will result in an error. torrent::Object system_method_erase(const torrent::Object::string_type& args) { rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str()); if (itr == rpc::commands.end()) return torrent::Object(); if (!rpc::commands.is_modifiable(itr)) throw torrent::input_error("Command not modifiable."); rpc::commands.erase(itr); return torrent::Object(); } torrent::Object system_method_redirect(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Invalid argument count."); std::string new_key = torrent::object_create_string(args.front()); std::string dest_key = torrent::object_create_string(args.back()); rpc::commands.create_redirect(create_new_key(new_key), create_new_key(dest_key), rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable); return torrent::Object(); } torrent::Object system_method_set_function(const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Invalid argument count."); rpc::object_storage::local_iterator itr = control->object_storage()->find_local(torrent::raw_string::from_string(args.front().as_string())); if (itr == control->object_storage()->end(0) || itr->second.flags & rpc::object_storage::flag_constant) throw torrent::input_error("Command is not modifiable."); return control->object_storage()->set_str_function(args.front().as_string(), system_method_generate_command(++args.begin(), args.end())); } torrent::Object system_method_has_key(const torrent::Object::list_type& args) { if (args.empty() || ++args.begin() == args.end()) throw torrent::input_error("Invalid argument count."); torrent::Object::list_const_iterator itrArgs = args.begin(); const std::string& key = (itrArgs++)->as_string(); const std::string& cmd_key = (itrArgs++)->as_string(); return control->object_storage()->has_str_multi_key(key, cmd_key); } torrent::Object system_method_set_key(const torrent::Object::list_type& args) { if (args.empty() || ++args.begin() == args.end()) throw torrent::input_error("Invalid argument count."); torrent::Object::list_const_iterator itrArgs = args.begin(); const std::string& key = (itrArgs++)->as_string(); const std::string& cmd_key = (itrArgs++)->as_string(); if (itrArgs == args.end()) { control->object_storage()->erase_str_multi_key(key, cmd_key); return torrent::Object(); } if (itrArgs->is_dict_key() || itrArgs->is_list()) control->object_storage()->set_str_multi_key_obj(key.c_str(), cmd_key, *itrArgs); else control->object_storage()->set_str_multi_key(key, cmd_key, system_method_generate_command(itrArgs, args.end())); return torrent::Object(); } torrent::Object system_method_list_keys(const torrent::Object::string_type& args) { const torrent::Object::map_type& multi_cmd = control->object_storage()->get_str(args).as_map(); torrent::Object rawResult = torrent::Object::create_list(); torrent::Object::list_type& result = rawResult.as_list(); for (torrent::Object::map_const_iterator itr = multi_cmd.begin(), last = multi_cmd.end(); itr != last; itr++) result.push_back(itr->first); return rawResult; } torrent::Object cmd_catch(rpc::target_type target, const torrent::Object& args) { try { return rpc::call_object(args, target); } catch (torrent::input_error& e) { lt_log_print(torrent::LOG_WARN, "Caught exception: '%s'.", e.what()); return torrent::Object(); } } #define CMD2_METHOD_INSERT(key, flags) \ CMD2_ANY_LIST(key, tr1::bind(&system_method_insert_object, tr1::placeholders::_2, flags)); void initialize_command_dynamic() { CMD2_VAR_BOOL ("method.use_deprecated", true); CMD2_VAR_VALUE ("method.use_intermediate", 1); CMD2_ANY_LIST ("method.insert", tr1::bind(&system_method_insert, tr1::placeholders::_2)); CMD2_ANY_LIST ("method.insert.value", tr1::bind(&system_method_insert_object, tr1::placeholders::_2, rpc::object_storage::flag_value_type)); CMD2_METHOD_INSERT("method.insert.simple", rpc::object_storage::flag_function_type); CMD2_METHOD_INSERT("method.insert.c_simple", rpc::object_storage::flag_constant | rpc::object_storage::flag_function_type); CMD2_METHOD_INSERT("method.insert.s_c_simple", rpc::object_storage::flag_static | rpc::object_storage::flag_constant |rpc::object_storage::flag_function_type); CMD2_ANY_STRING ("method.erase", tr1::bind(&system_method_erase, tr1::placeholders::_2)); CMD2_ANY_LIST ("method.redirect", tr1::bind(&system_method_redirect, tr1::placeholders::_2)); CMD2_ANY_STRING ("method.get", tr1::bind(&rpc::object_storage::get_str, control->object_storage(), tr1::placeholders::_2)); CMD2_ANY_LIST ("method.set", tr1::bind(&system_method_set_function, tr1::placeholders::_2)); CMD2_ANY_STRING ("method.const", tr1::bind(&rpc::object_storage::has_flag_str, control->object_storage(), tr1::placeholders::_2, rpc::object_storage::flag_constant)); CMD2_ANY_STRING_V("method.const.enable", tr1::bind(&rpc::object_storage::enable_flag_str, control->object_storage(), tr1::placeholders::_2, rpc::object_storage::flag_constant)); CMD2_ANY_LIST ("method.has_key", tr1::bind(&system_method_has_key, tr1::placeholders::_2)); CMD2_ANY_LIST ("method.set_key", tr1::bind(&system_method_set_key, tr1::placeholders::_2)); CMD2_ANY_STRING ("method.list_keys", tr1::bind(&system_method_list_keys, tr1::placeholders::_2)); CMD2_ANY_STRING ("method.rlookup", tr1::bind(&rpc::object_storage::rlookup_obj_list, control->object_storage(), tr1::placeholders::_2)); CMD2_ANY_STRING_V("method.rlookup.clear", tr1::bind(&rpc::object_storage::rlookup_clear, control->object_storage(), tr1::placeholders::_2)); CMD2_ANY ("catch", tr1::bind(&cmd_catch, tr1::placeholders::_1, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_events.cc000066400000000000000000000321671257211462100175170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/download_list.h" #include "core/manager.h" #include "core/view_manager.h" #include "rpc/command_scheduler.h" #include "rpc/parse.h" #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "command_helpers.h" #include "thread_worker.h" torrent::Object apply_on_ratio(const torrent::Object& rawArgs) { const std::string& groupName = rawArgs.as_string(); char buffer[32 + groupName.size()]; sprintf(buffer, "group2.%s.view", groupName.c_str()); core::ViewManager::iterator viewItr = control->view_manager()->find(rpc::commands.call(buffer, rpc::make_target()).as_string()); if (viewItr == control->view_manager()->end()) throw torrent::input_error("Could not find view."); char* bufferStart = buffer + sprintf(buffer, "group2.%s.ratio.", groupName.c_str()); // first argument: minimum ratio to reach // second argument: minimum upload amount to reach [optional] // third argument: maximum ratio to reach [optional] std::strcpy(bufferStart, "min"); int64_t minRatio = rpc::commands.call(buffer, rpc::make_target()).as_value(); std::strcpy(bufferStart, "max"); int64_t maxRatio = rpc::commands.call(buffer, rpc::make_target()).as_value(); std::strcpy(bufferStart, "upload"); int64_t minUpload = rpc::commands.call(buffer, rpc::make_target()).as_value(); std::vector downloads; for (core::View::iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) { if (!(*itr)->is_seeding() || rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) != 0) continue; // rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}"); int64_t totalDone = (*itr)->download()->bytes_done(); int64_t totalUpload = (*itr)->info()->up_rate()->total(); if (!(totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) && !(maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) continue; downloads.push_back(*itr); } sprintf(buffer, "group.%s.ratio.command", groupName.c_str()); for (std::vector::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) { // rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command."); rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: "); } return torrent::Object(); } torrent::Object apply_start_tied() { for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 1) continue; rak::file_stat fs; const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_start="); } return torrent::Object(); } torrent::Object apply_stop_untied() { for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 0) continue; rak::file_stat fs; const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop="); } return torrent::Object(); } torrent::Object apply_close_untied() { for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { rak::file_stat fs; const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_close="); } return torrent::Object(); } torrent::Object apply_remove_untied() { for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) { rak::file_stat fs; const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) { // Need to clear tied_to_file so it doesn't try to delete it. rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(*itr)); itr = control->core()->download_list()->erase(itr); } else { ++itr; } } return torrent::Object(); } torrent::Object apply_schedule(const torrent::Object::list_type& args) { if (args.size() != 4) throw torrent::input_error("Wrong number of arguments."); torrent::Object::list_const_iterator itr = args.begin(); const std::string& arg1 = (itr++)->as_string(); const std::string& arg2 = (itr++)->as_string(); const std::string& arg3 = (itr++)->as_string(); control->command_scheduler()->parse(arg1, arg2, arg3, *itr); return torrent::Object(); } torrent::Object apply_load(const torrent::Object::list_type& args, int flags) { torrent::Object::list_const_iterator argsItr = args.begin(); if (argsItr == args.end()) throw torrent::input_error("Too few arguments."); const std::string& filename = argsItr->as_string(); core::Manager::command_list_type commands; while (++argsItr != args.end()) commands.push_back(argsItr->as_string()); control->core()->try_create_download_expand(filename, flags, commands); return torrent::Object(); } void apply_import(const std::string& path) { if (!rpc::parse_command_file(path)) throw torrent::input_error("Could not open option file: " + path); } void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); } torrent::Object apply_close_low_diskspace(int64_t arg) { core::DownloadList* downloadList = control->core()->download_list(); bool closed = false; core::Manager::DListItr itr = downloadList->begin(); while ((itr = std::find_if(itr, downloadList->end(), std::mem_fun(&core::Download::is_downloading))) != downloadList->end()) { if ((*itr)->file_list()->free_diskspace() < (uint64_t)arg) { downloadList->close(*itr); (*itr)->set_hash_failed(true); (*itr)->set_message(std::string("Low diskspace.")); closed = true; } ++itr; } if (closed) lt_log_print(torrent::LOG_TORRENT_ERROR, "Closed torrents due to low diskspace."); return torrent::Object(); } torrent::Object apply_download_list(const torrent::Object::list_type& args) { torrent::Object::list_const_iterator argsItr = args.begin(); core::ViewManager* viewManager = control->view_manager(); core::ViewManager::iterator viewItr; if (argsItr != args.end() && !argsItr->as_string().empty()) viewItr = viewManager->find((argsItr++)->as_string()); else viewItr = viewManager->find("default"); if (viewItr == viewManager->end()) throw torrent::input_error("Could not find view."); torrent::Object result = torrent::Object::create_list(); torrent::Object::list_type& resultList = result.as_list(); for (core::View::const_iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) { const torrent::HashString* hashString = &(*itr)->info()->hash(); resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end())); } return result; } torrent::Object d_multicall(const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Too few arguments."); core::ViewManager* viewManager = control->view_manager(); core::ViewManager::iterator viewItr; if (!args.front().as_string().empty()) viewItr = viewManager->find(args.front().as_string()); else viewItr = viewManager->find("default"); if (viewItr == viewManager->end()) throw torrent::input_error("Could not find view."); // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. unsigned int dlist_size = (*viewItr)->size_visible(); core::Download* dlist[dlist_size]; std::copy((*viewItr)->begin_visible(), (*viewItr)->end_visible(), dlist); torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { const std::string& cmd = cItr->as_string(); row.push_back(rpc::parse_command(rpc::make_target(*vItr), cmd.c_str(), cmd.c_str() + cmd.size()).first); } } return resultRaw; } void initialize_command_events() { CMD2_ANY_STRING ("on_ratio", tr1::bind(&apply_on_ratio, tr1::placeholders::_2)); CMD2_ANY ("start_tied", tr1::bind(&apply_start_tied)); CMD2_ANY ("stop_untied", tr1::bind(&apply_stop_untied)); CMD2_ANY ("close_untied", tr1::bind(&apply_close_untied)); CMD2_ANY ("remove_untied", tr1::bind(&apply_remove_untied)); CMD2_ANY_LIST ("schedule2", tr1::bind(&apply_schedule, tr1::placeholders::_2)); CMD2_ANY_STRING_V("schedule_remove2", tr1::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), tr1::placeholders::_2)); CMD2_ANY_STRING_V("import", tr1::bind(&apply_import, tr1::placeholders::_2)); CMD2_ANY_STRING_V("try_import", tr1::bind(&apply_try_import, tr1::placeholders::_2)); CMD2_ANY_LIST ("load.normal", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied)); CMD2_ANY_LIST ("load.verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_tied)); CMD2_ANY_LIST ("load.start", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start)); CMD2_ANY_LIST ("load.start_verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_tied | core::Manager::create_start)); CMD2_ANY_LIST ("load.raw", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data)); CMD2_ANY_LIST ("load.raw_verbose", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_raw_data)); CMD2_ANY_LIST ("load.raw_start", tr1::bind(&apply_load, tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data)); CMD2_ANY_VALUE ("close_low_diskspace", tr1::bind(&apply_close_low_diskspace, tr1::placeholders::_2)); CMD2_ANY_LIST ("download_list", tr1::bind(&apply_download_list, tr1::placeholders::_2)); CMD2_ANY_LIST ("d.multicall2", tr1::bind(&d_multicall, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_file.cc000066400000000000000000000154431257211462100171300ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/manager.h" #include "globals.h" #include "control.h" #include "command_helpers.h" void apply_f_set_priority(torrent::File* file, uint32_t value) { if (value > torrent::PRIORITY_HIGH) throw torrent::input_error("Invalid value."); file->set_priority((torrent::priority_t)value); } // TODO: Redundant. torrent::Object apply_f_path(torrent::File* file) { if (file->path()->empty()) return std::string(); torrent::Object resultRaw(*file->path()->begin()); torrent::Object::string_type& result = resultRaw.as_string(); for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++) result += '/' + *itr; return resultRaw; } torrent::Object apply_f_path_components(torrent::File* file) { torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++) result.push_back(*itr); return resultRaw; } torrent::Object apply_f_path_depth(torrent::File* file) { return (int64_t)file->path()->size(); } torrent::Object apply_fi_filename_last(torrent::FileListIterator* itr) { if (itr->file()->path()->empty()) return "EMPTY"; if (itr->depth() >= itr->file()->path()->size()) return "ERROR"; return itr->file()->path()->at(itr->depth()); } void initialize_command_file() { CMD2_FILE("f.is_created", tr1::bind(&torrent::File::is_created, tr1::placeholders::_1)); CMD2_FILE("f.is_open", tr1::bind(&torrent::File::is_open, tr1::placeholders::_1)); CMD2_FILE("f.is_create_queued", tr1::bind(&torrent::File::is_create_queued, tr1::placeholders::_1)); CMD2_FILE("f.is_resize_queued", tr1::bind(&torrent::File::is_resize_queued, tr1::placeholders::_1)); CMD2_FILE_VALUE_V("f.set_create_queued", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_create_queued)); CMD2_FILE_VALUE_V("f.set_resize_queued", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_resize_queued)); CMD2_FILE_VALUE_V("f.unset_create_queued", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_create_queued)); CMD2_FILE_VALUE_V("f.unset_resize_queued", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_resize_queued)); CMD2_FILE ("f.prioritize_first", tr1::bind(&torrent::File::has_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first)); CMD2_FILE_V("f.prioritize_first.enable", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first)); CMD2_FILE_V("f.prioritize_first.disable", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_first)); CMD2_FILE ("f.prioritize_last", tr1::bind(&torrent::File::has_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last)); CMD2_FILE_V("f.prioritize_last.enable", tr1::bind(&torrent::File::set_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last)); CMD2_FILE_V("f.prioritize_last.disable", tr1::bind(&torrent::File::unset_flags, tr1::placeholders::_1, torrent::File::flag_prioritize_last)); CMD2_FILE("f.size_bytes", tr1::bind(&torrent::File::size_bytes, tr1::placeholders::_1)); CMD2_FILE("f.size_chunks", tr1::bind(&torrent::File::size_chunks, tr1::placeholders::_1)); CMD2_FILE("f.completed_chunks", tr1::bind(&torrent::File::completed_chunks, tr1::placeholders::_1)); CMD2_FILE("f.offset", tr1::bind(&torrent::File::offset, tr1::placeholders::_1)); CMD2_FILE("f.range_first", tr1::bind(&torrent::File::range_first, tr1::placeholders::_1)); CMD2_FILE("f.range_second", tr1::bind(&torrent::File::range_second, tr1::placeholders::_1)); CMD2_FILE("f.priority", tr1::bind(&torrent::File::priority, tr1::placeholders::_1)); CMD2_FILE_VALUE_V("f.priority.set", tr1::bind(&apply_f_set_priority, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_FILE("f.path", tr1::bind(&apply_f_path, tr1::placeholders::_1)); CMD2_FILE("f.path_components", tr1::bind(&apply_f_path_components, tr1::placeholders::_1)); CMD2_FILE("f.path_depth", tr1::bind(&apply_f_path_depth, tr1::placeholders::_1)); CMD2_FILE("f.frozen_path", tr1::bind(&torrent::File::frozen_path, tr1::placeholders::_1)); CMD2_FILE("f.match_depth_prev", tr1::bind(&torrent::File::match_depth_prev, tr1::placeholders::_1)); CMD2_FILE("f.match_depth_next", tr1::bind(&torrent::File::match_depth_next, tr1::placeholders::_1)); CMD2_FILE("f.last_touched", tr1::bind(&torrent::File::last_touched, tr1::placeholders::_1)); CMD2_FILEITR("fi.filename_last", tr1::bind(&apply_fi_filename_last, tr1::placeholders::_1)); CMD2_FILEITR("fi.is_file", tr1::bind(&torrent::FileListIterator::is_file, tr1::placeholders::_1)); } rtorrent-0.9.6/src/command_groups.cc000066400000000000000000000367411257211462100175340ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "ui/root.h" #include "rpc/parse.h" #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "command_helpers.h" // For cg_d_group. #include "core/download.h" // A hack to allow testing of the new choke_group API without the // working parts present. #define USE_CHOKE_GROUP 0 #if USE_CHOKE_GROUP int64_t cg_get_index(const torrent::Object& raw_args) { const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args; int64_t index = 0; if (arg.is_string()) { if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) return torrent::resource_manager()->group_index_of(arg.as_string()); } else { index = arg.as_value(); } if (index < 0) index = (int64_t)torrent::resource_manager()->group_size() + index; return std::min(index, torrent::resource_manager()->group_size()); } torrent::choke_group* cg_get_group(const torrent::Object& raw_args) { return torrent::resource_manager()->group_at(cg_get_index(raw_args)); } int64_t cg_d_group(core::Download* download) { return torrent::resource_manager()->entry_at(download->main()).group(); } const std::string& cg_d_group_name(core::Download* download) { return torrent::resource_manager()->group_at(torrent::resource_manager()->entry_at(download->main()).group())->name(); } void cg_d_group_set(core::Download* download, const torrent::Object& arg) { torrent::resource_manager()->set_group(torrent::resource_manager()->find_throw(download->main()), cg_get_index(arg)); } torrent::Object apply_cg_list() { torrent::Object::list_type result; for (torrent::ResourceManager::group_iterator itr = torrent::resource_manager()->group_begin(), last = torrent::resource_manager()->group_end(); itr != last; itr++) result.push_back((*itr)->name()); return torrent::Object::from_list(result); } torrent::Object apply_cg_insert(const std::string& arg) { int64_t dummy; if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy)) throw torrent::input_error("Cannot use a value string as choke group name."); torrent::resource_manager()->push_group(arg); return torrent::Object(); } // // The hacked version: // #else std::vector cg_list_hack; int64_t cg_get_index(const torrent::Object& raw_args) { const torrent::Object& arg = (raw_args.is_list() && !raw_args.as_list().empty()) ? raw_args.as_list().front() : raw_args; int64_t index = 0; if (arg.is_string()) { if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) { std::vector::iterator itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), rak::equal(arg.as_string(), std::mem_fun(&torrent::choke_group::name))); if (itr == cg_list_hack.end()) throw torrent::input_error("Choke group not found."); return std::distance(cg_list_hack.begin(), itr); } } else { index = arg.as_value(); } if (index < 0) index = (int64_t)cg_list_hack.size() + index; if ((size_t)index >= cg_list_hack.size()) throw torrent::input_error("Choke group not found."); return index; } torrent::choke_group* cg_get_group(const torrent::Object& raw_args) { int64_t index = cg_get_index(raw_args); if ((size_t)index >= cg_list_hack.size()) throw torrent::input_error("Choke group not found."); return cg_list_hack.at(index); } int64_t cg_d_group(core::Download* download) { return download->group(); } void cg_d_group_set(core::Download* download, const torrent::Object& arg) { download->set_group(cg_get_index(arg)); } torrent::Object apply_cg_list() { torrent::Object::list_type result; for (std::vector::iterator itr = cg_list_hack.begin(), last = cg_list_hack.end(); itr != last; itr++) result.push_back((*itr)->name()); return torrent::Object::from_list(result); } torrent::Object apply_cg_insert(const std::string& arg) { int64_t dummy; if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy)) throw torrent::input_error("Cannot use a value string as choke group name."); if (arg.empty() || std::find_if(cg_list_hack.begin(), cg_list_hack.end(), rak::equal(arg, std::mem_fun(&torrent::choke_group::name))) != cg_list_hack.end()) throw torrent::input_error("Duplicate name for choke group."); cg_list_hack.push_back(new torrent::choke_group()); cg_list_hack.back()->set_name(arg); cg_list_hack.back()->up_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_UPLOAD_LEECH); cg_list_hack.back()->down_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_DOWNLOAD_LEECH); return torrent::Object(); } torrent::Object apply_cg_index_of(const std::string& arg) { std::vector::iterator itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), rak::equal(arg, std::mem_fun(&torrent::choke_group::name))); if (itr == cg_list_hack.end()) throw torrent::input_error("Choke group not found."); return std::distance(cg_list_hack.begin(), itr); } // // End of choke group hack. // #endif torrent::Object apply_cg_max_set(const torrent::Object::list_type& args, bool is_up) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); int64_t second_arg = 0; rpc::parse_whole_value(args.back().as_string().c_str(), &second_arg); if (is_up) cg_get_group(args.front())->up_queue()->set_max_unchoked(second_arg); else cg_get_group(args.front())->down_queue()->set_max_unchoked(second_arg); return torrent::Object(); } torrent::Object apply_cg_heuristics_set(const torrent::Object::list_type& args, bool is_up) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); int t = torrent::option_find_string(is_up ? torrent::OPTION_CHOKE_HEURISTICS_UPLOAD : torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD, args.back().as_string().c_str()); if (is_up) cg_get_group(args.front())->up_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t); else cg_get_group(args.front())->down_queue()->set_heuristics((torrent::choke_queue::heuristics_enum)t); return torrent::Object(); } torrent::Object apply_cg_tracker_mode_set(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); int t = torrent::option_find_string(torrent::OPTION_TRACKER_MODE, args.back().as_string().c_str()); cg_get_group(args.front())->set_tracker_mode((torrent::choke_group::tracker_mode_enum)t); return torrent::Object(); } #define CG_GROUP_AT() tr1::bind(&cg_get_group, tr1::placeholders::_2) #define CHOKE_GROUP(direction) tr1::bind(direction, CG_GROUP_AT()) /* -> '0'..'(choke_group.size)' -> '-1'..'-(choke_group.size)' -> '' (choke_group.list) -> List of group names. (choke_group.size) -> Number of groups. (choke_group.insert,"group_name") Adds a new group with default settings, use index '-1' to accessing it immediately afterwards. (choke_group.index_of,"group_name") -> Throws if the group name was not found. (choke_group.general.size,) -> Number of torrents in this group. (choke_group.tracker.mode,) -> "tracker_mode" (choke_group.tracker.mode.set,,"tracker_mode") Decide on how aggressive a tracker should be, see 'strings.tracker_mode' for list of available options (choke_group.up.rate,) -> (choke_group.down.rate,) -> Upload / download rate for the aggregate of all torrents in this particular group. (choke_group.up.max,) -> (choke_group.up.max.unlimited,) -> (choke_group.up.max.set,, ) (choke_group.down.max,) -> (choke_group.down.max.unlimited,) -> (choke_group.down.max.set,, ) -> (choke_group.up.queued,) -> (choke_group.up.unchoked,) -> (choke_group.down.total,) -> (choke_group.down.queued,) -> (choke_group.down.unchoked,) -> (choke_group.up.heuristics,) -> "heuristics" (choke_group.up.heuristics.set,,"heuristics") (choke_group.down.heuristics,) -> "heuristics" (choke_group.down.heuristics.set,,"heuristics") Heuristics are used for deciding what peers to choke and unchoke, see 'strings.choke_heuristics{,_download,_upload}' for a list of available options. (d.group) -> (d.group.name) -> "choke_group_name" (d.group.set,) */ void initialize_command_groups() { // Move somewhere else? CMD2_ANY ("strings.choke_heuristics", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS)); CMD2_ANY ("strings.choke_heuristics.upload", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_UPLOAD)); CMD2_ANY ("strings.choke_heuristics.download", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD)); CMD2_ANY ("strings.tracker_mode", tr1::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE)); CMD2_ANY ("choke_group.list", tr1::bind(&apply_cg_list)); CMD2_ANY_STRING ("choke_group.insert", tr1::bind(&apply_cg_insert, tr1::placeholders::_2)); #if USE_CHOKE_GROUP CMD2_ANY ("choke_group.size", tr1::bind(&torrent::ResourceManager::group_size, torrent::resource_manager())); CMD2_ANY_STRING ("choke_group.index_of", tr1::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), tr1::placeholders::_2)); #else apply_cg_insert("default"); CMD2_ANY ("choke_group.size", tr1::bind(&std::vector::size, cg_list_hack)); CMD2_ANY_STRING ("choke_group.index_of", tr1::bind(&apply_cg_index_of, tr1::placeholders::_2)); #endif // Commands specific for a group. Supports as the first argument the // name, the index or a negative index. CMD2_ANY ("choke_group.general.size", tr1::bind(&torrent::choke_group::size, CG_GROUP_AT())); CMD2_ANY ("choke_group.tracker.mode", tr1::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE, tr1::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT()))); CMD2_ANY_LIST ("choke_group.tracker.mode.set", tr1::bind(&apply_cg_tracker_mode_set, tr1::placeholders::_2)); CMD2_ANY ("choke_group.up.rate", tr1::bind(&torrent::choke_group::up_rate, CG_GROUP_AT())); CMD2_ANY ("choke_group.down.rate", tr1::bind(&torrent::choke_group::down_rate, CG_GROUP_AT())); CMD2_ANY ("choke_group.up.max.unlimited", tr1::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue))); CMD2_ANY ("choke_group.up.max", tr1::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue))); CMD2_ANY_LIST ("choke_group.up.max.set", tr1::bind(&apply_cg_max_set, tr1::placeholders::_2, true)); CMD2_ANY ("choke_group.up.total", tr1::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue))); CMD2_ANY ("choke_group.up.queued", tr1::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue))); CMD2_ANY ("choke_group.up.unchoked", tr1::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue))); CMD2_ANY ("choke_group.up.heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, tr1::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue)))); CMD2_ANY_LIST ("choke_group.up.heuristics.set", tr1::bind(&apply_cg_heuristics_set, tr1::placeholders::_2, true)); CMD2_ANY ("choke_group.down.max.unlimited", tr1::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue))); CMD2_ANY ("choke_group.down.max", tr1::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue))); CMD2_ANY_LIST ("choke_group.down.max.set", tr1::bind(&apply_cg_max_set, tr1::placeholders::_2, false)); CMD2_ANY ("choke_group.down.total", tr1::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue))); CMD2_ANY ("choke_group.down.queued", tr1::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue))); CMD2_ANY ("choke_group.down.unchoked", tr1::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue))); CMD2_ANY ("choke_group.down.heuristics", tr1::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, tr1::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue)))); CMD2_ANY_LIST ("choke_group.down.heuristics.set", tr1::bind(&apply_cg_heuristics_set, tr1::placeholders::_2, false)); } rtorrent-0.9.6/src/command_helpers.cc000066400000000000000000000052321257211462100176460ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "globals.h" #include "control.h" #include "command_helpers.h" void initialize_command_dynamic(); void initialize_command_download(); void initialize_command_events(); void initialize_command_file(); void initialize_command_ip(); void initialize_command_peer(); void initialize_command_local(); void initialize_command_logging(); void initialize_command_network(); void initialize_command_groups(); void initialize_command_throttle(); void initialize_command_tracker(); void initialize_command_scheduler(); void initialize_command_ui(); void initialize_commands() { initialize_command_dynamic(); initialize_command_events(); initialize_command_network(); initialize_command_groups(); initialize_command_local(); initialize_command_logging(); initialize_command_ui(); initialize_command_download(); initialize_command_file(); initialize_command_ip(); initialize_command_peer(); initialize_command_throttle(); initialize_command_tracker(); initialize_command_scheduler(); } rtorrent-0.9.6/src/command_helpers.h000066400000000000000000000302301257211462100175040ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_COMMAND_HELPERS_H #define RTORRENT_UTILS_COMMAND_HELPERS_H #include "rpc/command.h" #include "rpc/parse_commands.h" #include "rpc/object_storage.h" namespace tr1 { using namespace std::tr1; } void initialize_commands(); // // New std::function based command_base helper functions: // #define CMD2_A_FUNCTION(key, function, slot, parm, doc) \ rpc::commands.insert_slot::type>(key, slot, &rpc::function, \ rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); #define CMD2_A_FUNCTION_PRIVATE(key, function, slot, parm, doc) \ rpc::commands.insert_slot::type>(key, slot, &rpc::function, \ rpc::CommandMap::flag_dont_delete, NULL, NULL); #define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call, slot, "i:", "") #define CMD2_ANY_VOID(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(slot), "i:", "") #define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, object_convert_void(slot), "i:", "") #define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, slot, "A:", "") #define CMD2_ANY_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, slot, "i:i", "") #define CMD2_ANY_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:i", "") #define CMD2_ANY_VALUE_KB(key, slot) CMD2_A_FUNCTION(key, command_base_call_value_kb, object_convert_void(slot), "i:i", "") #define CMD2_ANY_STRING(key, slot) CMD2_A_FUNCTION(key, command_base_call_string, slot, "i:s", "") #define CMD2_ANY_STRING_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_string, object_convert_void(slot), "i:s", "") #define CMD2_ANY_LIST(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, slot, "i:", "") #define CMD2_DL(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_DL_V(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(slot), "i:", "") #define CMD2_DL_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, slot, "i:", "") #define CMD2_DL_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:", "") #define CMD2_DL_STRING(key, slot) CMD2_A_FUNCTION(key, command_base_call_string, slot, "i:", "") #define CMD2_DL_STRING_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_string, object_convert_void(slot), "i:", "") #define CMD2_DL_LIST(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, slot, "i:", "") #define CMD2_DL_VALUE_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call_value, slot, "i:", "") #define CMD2_DL_STRING_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call_string, slot, "i:", "") #define CMD2_FILE(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_FILE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(slot), "i:", "") #define CMD2_FILE_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:i", "") #define CMD2_FILEITR(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_PEER(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_PEER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(slot), "i:", "") #define CMD2_PEER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:i", "") #define CMD2_TRACKER(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") #define CMD2_TRACKER_V(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(slot), "i:", "") #define CMD2_TRACKER_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:i", "") #define CMD2_VAR_BOOL(key, value) \ control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_bool_type); \ CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); \ CMD2_ANY_VALUE(key ".set", tr1::bind(&rpc::object_storage::set_bool, control->object_storage(), \ torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); #define CMD2_VAR_VALUE(key, value) \ control->object_storage()->insert_c_str(key, int64_t(value), rpc::object_storage::flag_value_type); \ CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); \ CMD2_ANY_VALUE(key ".set", tr1::bind(&rpc::object_storage::set_value, control->object_storage(), \ torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); #define CMD2_VAR_STRING(key, value) \ control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \ CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); \ CMD2_ANY_STRING(key ".set", tr1::bind(&rpc::object_storage::set_string, control->object_storage(), \ torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); #define CMD2_VAR_C_STRING(key, value) \ control->object_storage()->insert_c_str(key, value, rpc::object_storage::flag_string_type); \ CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); #define CMD2_VAR_LIST(key) \ control->object_storage()->insert_c_str(key, torrent::Object::create_list(), rpc::object_storage::flag_list_type); \ CMD2_ANY(key, tr1::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); \ CMD2_ANY_LIST(key ".set", tr1::bind(&rpc::object_storage::set_list, control->object_storage(), \ torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); \ CMD2_ANY_VOID(key ".push_back", tr1::bind(&rpc::object_storage::list_push_back, control->object_storage(), \ torrent::raw_string::from_c_str(key), tr1::placeholders::_2)); #define CMD2_FUNC_SINGLE(key, cmds) \ CMD2_ANY(key, tr1::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \ tr1::placeholders::_1, tr1::placeholders::_2)); #define CMD2_REDIRECT(from_key, to_key) \ rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_dont_delete); #define CMD2_REDIRECT_GENERIC(from_key, to_key) \ rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete); #define CMD2_REDIRECT_GENERIC_NO_EXPORT(from_key, to_key) \ rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete); #define CMD2_REDIRECT_FILE(from_key, to_key) \ rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete); #define CMD2_REDIRECT_TRACKER(from_key, to_key) \ rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete); #define CMD2_REDIRECT_GENERIC_STR(from_key, to_key) \ rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \ rpc::CommandMap::flag_public_xmlrpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key); #define CMD2_REDIRECT_GENERIC_STR_NO_EXPORT(from_key, to_key) \ rpc::commands.create_redirect(create_new_key(from_key), create_new_key(to_key), \ rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_delete_key); // // Conversion of return types: // template struct object_convert_type; template struct object_convert_type { template struct result { typedef torrent::Object type; }; object_convert_type(Functor s) : m_slot(s) {} torrent::Object operator () () { m_slot(); return torrent::Object(); } template torrent::Object operator () (Arg1& arg1) { m_slot(arg1); return torrent::Object(); } template torrent::Object operator () (const Arg1& arg1) { m_slot(arg1); return torrent::Object(); } template torrent::Object operator () (Arg1& arg1, Arg2& arg2) { m_slot(arg1, arg2); return torrent::Object(); } template torrent::Object operator () (const Arg1& arg1, const Arg2& arg2) { m_slot(arg1, arg2); return torrent::Object(); } Functor m_slot; }; template object_convert_type object_convert_void(T f) { return f; } // // Key creation: // template inline const char* create_new_key(const std::string& key, const char postfix[postfix_size]) { char *buffer = new char[key.size() + std::max(postfix_size, 1)]; std::memcpy(buffer, key.c_str(), key.size() + 1); std::memcpy(buffer + key.size(), postfix, postfix_size); return buffer; } inline const char* create_new_key(const std::string& key) { char *buffer = new char[key.size() + 1]; std::memcpy(buffer, key.c_str(), key.size() + 1); return buffer; } #endif rtorrent-0.9.6/src/command_ip.cc000066400000000000000000000245701257211462100166220ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "globals.h" #include "command_helpers.h" void ipv4_filter_parse(const char* address, int value) { uint32_t ip_values[4] = { 0, 0, 0, 0 }; unsigned int block = rpc::ipv4_table::mask_bits; char ip_dot; int values_read; if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u", ip_values + 0, &ip_dot, ip_values + 1, &ip_dot, ip_values + 2, &ip_dot, ip_values + 3, &block)) < 2 || // Make sure the dot is included. (values_read < 7 && values_read % 2) || ip_values[0] >= 256 || ip_values[1] >= 256 || ip_values[2] >= 256 || ip_values[3] >= 256 || block > rpc::ipv4_table::mask_bits) throw torrent::input_error("Invalid address format."); // E.g. '10.10.' will be '10.10.0.0/16'. if (values_read < 7) block = 8 * (values_read / 2); lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %u.%u.%u.%u/%u.", ip_values[0], ip_values[1], ip_values[2], ip_values[3], block); torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], rpc::ipv4_table::mask_bits - block, value); } torrent::Object apply_ip_tables_insert_table(const std::string& args) { if (ip_tables.find(args) != ip_tables.end()) throw torrent::input_error("IP table already exists."); ip_tables.insert(args); return torrent::Object(); } torrent::Object apply_ip_tables_size_data(const std::string& args) { rpc::ip_table_list::const_iterator itr = ip_tables.find(args); if (itr != ip_tables.end()) throw torrent::input_error("IP table does not exist."); return itr->table.sizeof_data(); } torrent::Object apply_ip_tables_get(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); torrent::Object::list_const_iterator args_itr = args.begin(); const std::string& name = (args_itr++)->as_string(); const std::string& address = (args_itr++)->as_string(); // Move to a helper function, add support for addresses. uint32_t ip_values[4]; if (sscanf(address.c_str(), "%u.%u.%u.%u", ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) throw torrent::input_error("Invalid address format."); rpc::ip_table_list::iterator table_itr = ip_tables.find(name); if (table_itr == ip_tables.end()) throw torrent::input_error("Could not find ip table."); return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); } torrent::Object apply_ip_tables_add_address(const torrent::Object::list_type& args) { if (args.size() != 3) throw torrent::input_error("Incorrect number of arguments."); torrent::Object::list_const_iterator args_itr = args.begin(); const std::string& name = (args_itr++)->as_string(); const std::string& address = (args_itr++)->as_string(); const std::string& value_str = (args_itr++)->as_string(); // Move to a helper function, add support for addresses. uint32_t ip_values[4]; unsigned int block = rpc::ipv4_table::mask_bits; if (sscanf(address.c_str(), "%u.%u.%u.%u/%u", ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 || block > rpc::ipv4_table::mask_bits) throw torrent::input_error("Invalid address format."); int value; if (value_str == "block") value = 1; else throw torrent::input_error("Invalid value."); rpc::ip_table_list::iterator table_itr = ip_tables.find(name); if (table_itr == ip_tables.end()) throw torrent::input_error("Could not find ip table."); table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], rpc::ipv4_table::mask_bits - block, value); return torrent::Object(); } // // IPv4 filter functions: // torrent::Object apply_ipv4_filter_size_data() { return torrent::PeerList::ipv4_filter()->sizeof_data(); } torrent::Object apply_ipv4_filter_get(const std::string& args) { // Move to a helper function, add support for addresses. uint32_t ip_values[4]; if (sscanf(args.c_str(), "%u.%u.%u.%u", ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) throw torrent::input_error("Invalid address format."); return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); } torrent::Object apply_ipv4_filter_add_address(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); ipv4_filter_parse(args.front().as_string().c_str(), torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str())); return torrent::Object(); } torrent::Object apply_ipv4_filter_load(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Incorrect number of arguments."); std::string filename = args.front().as_string(); std::string value_name = args.back().as_string(); int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, value_name.c_str()); std::fstream file(rak::path_expand(filename).c_str(), std::ios::in); if (!file.is_open()) throw torrent::input_error("Could not open ip filter file: " + filename); unsigned int lineNumber = 0; char buffer[4096]; try { while (file.good() && !file.getline(buffer, 4096).fail()) { if (file.gcount() == 0) throw torrent::internal_error("parse_command_file(...) file.gcount() == 0."); lineNumber++; if (buffer[0] == '\0' || buffer[0] == '#') continue; ipv4_filter_parse(buffer, value); } } catch (torrent::input_error& e) { snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", filename.c_str(), lineNumber, e.what()); throw torrent::input_error(buffer); } lt_log_print(torrent::LOG_CONNECTION_INFO, "Loaded %u %s address blocks (%u kb in-memory) from '%s'.", lineNumber, value_name.c_str(), torrent::PeerList::ipv4_filter()->sizeof_data() / 1024, filename.c_str()); return torrent::Object(); } static void append_table(torrent::ipv4_table::base_type* extent, torrent::Object::list_type& result) { torrent::ipv4_table::table_type::iterator first = extent->table.begin(); torrent::ipv4_table::table_type::iterator last = extent->table.end(); while (first != last) { if (first->first != NULL) { // Do something more here?... append_table(first->first, result); } else if (first->second != 0) { uint32_t position = extent->partition_pos(first); char buffer[256]; snprintf(buffer, 256, "%u.%u.%u.%u/%u %s", (position >> 24) & 0xff, (position >> 16) & 0xff, (position >> 8) & 0xff, (position >> 0) & 0xff, extent->mask_bits, torrent::option_as_string(torrent::OPTION_IP_FILTER, first->second)); result.push_back((std::string)buffer); } first++; } } torrent::Object apply_ipv4_filter_dump() { torrent::Object raw_result = torrent::Object::create_list(); torrent::Object::list_type& result = raw_result.as_list(); append_table(torrent::PeerList::ipv4_filter()->data(), result); return raw_result; } void initialize_command_ip() { CMD2_ANY ("strings.ip_filter", tr1::bind(&torrent::option_list_strings, torrent::OPTION_IP_FILTER)); CMD2_ANY ("strings.ip_tos", tr1::bind(&torrent::option_list_strings, torrent::OPTION_IP_TOS)); CMD2_ANY_STRING ("ip_tables.insert_table", tr1::bind(&apply_ip_tables_insert_table, tr1::placeholders::_2)); CMD2_ANY_STRING ("ip_tables.size_data", tr1::bind(&apply_ip_tables_size_data, tr1::placeholders::_2)); CMD2_ANY_LIST ("ip_tables.get", tr1::bind(&apply_ip_tables_get, tr1::placeholders::_2)); CMD2_ANY_LIST ("ip_tables.add_address", tr1::bind(&apply_ip_tables_add_address, tr1::placeholders::_2)); CMD2_ANY ("ipv4_filter.size_data", tr1::bind(&apply_ipv4_filter_size_data)); CMD2_ANY_STRING ("ipv4_filter.get", tr1::bind(&apply_ipv4_filter_get, tr1::placeholders::_2)); CMD2_ANY_LIST ("ipv4_filter.add_address", tr1::bind(&apply_ipv4_filter_add_address, tr1::placeholders::_2)); CMD2_ANY_LIST ("ipv4_filter.load", tr1::bind(&apply_ipv4_filter_load, tr1::placeholders::_2)); CMD2_ANY_LIST ("ipv4_filter.dump", tr1::bind(&apply_ipv4_filter_dump)); } rtorrent-0.9.6/src/command_local.cc000066400000000000000000000400461257211462100173000ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/download_list.h" #include "core/download_store.h" #include "core/manager.h" #include "rak/string_manip.h" #include "rpc/parse_commands.h" #include "rpc/scgi.h" #include "utils/file_status_cache.h" #include "globals.h" #include "control.h" #include "command_helpers.h" typedef torrent::ChunkManager CM_t; typedef torrent::FileManager FM_t; torrent::Object apply_pieces_stats_total_size() { uint64_t size = 0; core::DownloadList* d_list = control->core()->download_list(); for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++) if ((*itr)->is_active()) size += (*itr)->file_list()->size_bytes(); return size; } torrent::Object system_hostname() { char buffer[1024]; if (gethostname(buffer, 1023) == -1) throw torrent::input_error("Unable to read hostname."); // if (shorten) // *std::find(buffer, buffer + 1023, '.') = '\0'; return std::string(buffer); } torrent::Object system_get_cwd() { char* buffer = getcwd(NULL, 0); if (buffer == NULL) throw torrent::input_error("Unable to read cwd."); torrent::Object result = torrent::Object(std::string(buffer)); free(buffer); return result; } torrent::Object system_set_cwd(const torrent::Object::string_type& rawArgs) { if (::chdir(rawArgs.c_str()) != 0) throw torrent::input_error("Could not change current working directory."); return torrent::Object(); } inline torrent::Object::list_const_iterator post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object::list_const_iterator& last) { if (itr == last) throw torrent::input_error("Invalid number of arguments."); return itr++; } inline const std::string& check_name(const std::string& str) { if (!rak::is_all_name(str)) throw torrent::input_error("Non-alphanumeric characters found."); return str; } torrent::Object group_insert(const torrent::Object::list_type& args) { torrent::Object::list_const_iterator itr = args.begin(); torrent::Object::list_const_iterator last = args.end(); const std::string& name = check_name(post_increment(itr, last)->as_string()); const std::string& view = check_name(post_increment(itr, last)->as_string()); rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.enable", "simple", "schedule2=group." + name + ".ratio,5,60,on_ratio=" + name)); rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple", "schedule_remove2=group." + name + ".ratio")); rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple", "d.try_close= ;d.ignore_commands.set=1")); rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".view", "string", view)); rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.min", "value", (int64_t)200)); rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.max", "value", (int64_t)300)); rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.upload", "value", (int64_t)20 << 20)); if (rpc::call_command_value("method.use_intermediate") == 1) { // Deprecated in 0.7.0: CMD2_REDIRECT_GENERIC_STR("group." + name + ".view", "group2." + name + ".view"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".view.set", "group2." + name + ".view.set"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min", "group2." + name + ".ratio.min"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max", "group2." + name + ".ratio.max"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload"); CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set"); } if (rpc::call_command_value("method.use_intermediate") == 2) { // Deprecated in 0.7.0: CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view", "group2." + name + ".view"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view.set", "group2." + name + ".view.set"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min", "group2." + name + ".ratio.min"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max", "group2." + name + ".ratio.max"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload"); CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set"); } return name; } static const int file_print_use_space = 0x1; static const int file_print_delim_space = 0x2; void file_print_list(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last, FILE* output, int flags) { while (first != last) { switch (first->type()) { case torrent::Object::TYPE_STRING: fprintf(output, (const char*)" %s" + !(flags & file_print_use_space), first->as_string().c_str()); break; case torrent::Object::TYPE_VALUE: fprintf(output, (const char*)" %lli" + !(flags & file_print_use_space), first->as_value()); break; case torrent::Object::TYPE_LIST: file_print_list(first->as_list().begin(), first->as_list().end(), output, 0); break; case torrent::Object::TYPE_NONE: break; default: throw torrent::input_error("Invalid type."); } flags |= (flags & file_print_delim_space) >> 1; first++; } } torrent::Object cmd_file_append(const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Invalid number of arguments."); FILE* output = fopen(args.front().as_string().c_str(), "a"); if (output == NULL) throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + rak::error_number::current().c_str()); file_print_list(++args.begin(), args.end(), output, file_print_delim_space); fprintf(output, "\n"); fclose(output); return torrent::Object(); } void initialize_command_local() { torrent::ChunkManager* chunkManager = torrent::chunk_manager(); torrent::FileManager* fileManager = torrent::file_manager(); core::DownloadList* dList = control->core()->download_list(); core::DownloadStore* dStore = control->core()->download_store(); CMD2_ANY ("system.hostname", tr1::bind(&system_hostname)); CMD2_ANY ("system.pid", tr1::bind(&getpid)); CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION); CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION); CMD2_VAR_C_STRING("system.library_version", torrent::version()); CMD2_VAR_VALUE ("system.file.allocate", 0); CMD2_VAR_VALUE ("system.file.max_size", (int64_t)128 << 30); CMD2_VAR_VALUE ("system.file.split_size", -1); CMD2_VAR_STRING ("system.file.split_suffix", ".part"); CMD2_ANY ("system.file_status_cache.size", tr1::bind(&utils::FileStatusCache::size, (utils::FileStatusCache::base_type*)control->core()->file_status_cache())); CMD2_ANY_V ("system.file_status_cache.prune", tr1::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache())); CMD2_VAR_BOOL ("file.prioritize_toc", 0); CMD2_VAR_LIST ("file.prioritize_toc.first"); CMD2_VAR_LIST ("file.prioritize_toc.last"); CMD2_ANY ("system.files.opened_counter", tr1::bind(&FM_t::files_opened_counter, fileManager)); CMD2_ANY ("system.files.closed_counter", tr1::bind(&FM_t::files_closed_counter, fileManager)); CMD2_ANY ("system.files.failed_counter", tr1::bind(&FM_t::files_failed_counter, fileManager)); CMD2_ANY ("system.time", tr1::bind(&rak::timer::seconds, &cachedTime)); CMD2_ANY ("system.time_seconds", tr1::bind(&rak::timer::current_seconds)); CMD2_ANY ("system.time_usec", tr1::bind(&rak::timer::current_usec)); CMD2_ANY_VALUE_V ("system.umask.set", tr1::bind(&umask, tr1::placeholders::_2)); CMD2_ANY ("system.cwd", tr1::bind(&system_get_cwd)); CMD2_ANY_STRING ("system.cwd.set", tr1::bind(&system_set_cwd, tr1::placeholders::_2)); CMD2_ANY ("pieces.sync.always_safe", tr1::bind(&CM_t::safe_sync, chunkManager)); CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", tr1::bind(&CM_t::set_safe_sync, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.sync.safe_free_diskspace", tr1::bind(&CM_t::safe_free_diskspace, chunkManager)); CMD2_ANY ("pieces.sync.timeout", tr1::bind(&CM_t::timeout_sync, chunkManager)); CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", tr1::bind(&CM_t::set_timeout_sync, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.sync.timeout_safe", tr1::bind(&CM_t::timeout_safe_sync, chunkManager)); CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", tr1::bind(&CM_t::set_timeout_safe_sync, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.sync.queue_size", tr1::bind(&CM_t::sync_queue_size, chunkManager)); CMD2_ANY ("pieces.preload.type", tr1::bind(&CM_t::preload_type, chunkManager)); CMD2_ANY_VALUE_V ("pieces.preload.type.set", tr1::bind(&CM_t::set_preload_type, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.preload.min_size", tr1::bind(&CM_t::preload_min_size, chunkManager)); CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", tr1::bind(&CM_t::set_preload_min_size, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.preload.min_rate", tr1::bind(&CM_t::preload_required_rate, chunkManager)); CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", tr1::bind(&CM_t::set_preload_required_rate, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.memory.current", tr1::bind(&CM_t::memory_usage, chunkManager)); CMD2_ANY ("pieces.memory.sync_queue", tr1::bind(&CM_t::sync_queue_memory_usage, chunkManager)); CMD2_ANY ("pieces.memory.block_count", tr1::bind(&CM_t::memory_block_count, chunkManager)); CMD2_ANY ("pieces.memory.max", tr1::bind(&CM_t::max_memory_usage, chunkManager)); CMD2_ANY_VALUE_V ("pieces.memory.max.set", tr1::bind(&CM_t::set_max_memory_usage, chunkManager, tr1::placeholders::_2)); CMD2_ANY ("pieces.stats_preloaded", tr1::bind(&CM_t::stats_preloaded, chunkManager)); CMD2_ANY ("pieces.stats_not_preloaded", tr1::bind(&CM_t::stats_not_preloaded, chunkManager)); CMD2_ANY ("pieces.stats.total_size", tr1::bind(&apply_pieces_stats_total_size)); CMD2_ANY ("pieces.hash.queue_size", tr1::bind(&torrent::hash_queue_size)); CMD2_VAR_BOOL ("pieces.hash.on_completion", true); CMD2_VAR_STRING ("directory.default", "./"); CMD2_VAR_STRING ("session.name", ""); CMD2_VAR_BOOL ("session.use_lock", true); CMD2_VAR_BOOL ("session.on_completion", true); CMD2_ANY ("session.path", tr1::bind(&core::DownloadStore::path, dStore)); CMD2_ANY_STRING_V("session.path.set", tr1::bind(&core::DownloadStore::set_path, dStore, tr1::placeholders::_2)); CMD2_ANY_V ("session.save", tr1::bind(&core::DownloadList::session_save, dList)); #define CMD2_EXECUTE(key, flags) \ CMD2_ANY(key, tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, tr1::placeholders::_2, flags)); CMD2_EXECUTE ("execute2", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background); CMD2_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde); CMD2_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background); CMD2_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background); CMD2_EXECUTE ("execute.raw_nothrow", 0); CMD2_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background); CMD2_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture); CMD2_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture); CMD2_ANY_LIST ("file.append", tr1::bind(&cmd_file_append, tr1::placeholders::_2)); // TODO: Convert to new command types: *rpc::command_base::argument(0) = "placeholder.0"; *rpc::command_base::argument(1) = "placeholder.1"; *rpc::command_base::argument(2) = "placeholder.2"; *rpc::command_base::argument(3) = "placeholder.3"; CMD2_ANY_P("argument.0", tr1::bind(&rpc::command_base::argument_ref, 0)); CMD2_ANY_P("argument.1", tr1::bind(&rpc::command_base::argument_ref, 1)); CMD2_ANY_P("argument.2", tr1::bind(&rpc::command_base::argument_ref, 2)); CMD2_ANY_P("argument.3", tr1::bind(&rpc::command_base::argument_ref, 3)); CMD2_ANY_LIST ("group.insert", tr1::bind(&group_insert, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_logging.cc000066400000000000000000000141571257211462100176400ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "core/download.h" #include "core/download_list.h" #include "core/manager.h" #include "rak/path.h" #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "command_helpers.h" static const int log_flag_use_gz = 0x1; static const int log_flag_append_pid = 0x2; void log_add_group_output_str(const char* group_name, const char* output_id) { int log_group = torrent::option_find_string(torrent::OPTION_LOG_GROUP, group_name); torrent::log_add_group_output(log_group, output_id); } torrent::Object apply_log_open(int output_flags, const torrent::Object::list_type& args) { if (args.size() < 2) throw torrent::input_error("Invalid number of arguments."); torrent::Object::list_const_iterator itr = args.begin(); std::string output_id = (itr++)->as_string(); std::string file_name = rak::path_expand((itr++)->as_string()); if ((output_flags & log_flag_append_pid)) { char buffer[32]; snprintf(buffer, 32, ".%li", (long)getpid()); file_name += buffer; } if ((output_flags & log_flag_use_gz)) torrent::log_open_gz_file_output(output_id.c_str(), file_name.c_str()); else torrent::log_open_file_output(output_id.c_str(), file_name.c_str()); while (itr != args.end()) log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str()); return torrent::Object(); } torrent::Object apply_log_add_output(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Invalid number of arguments."); log_add_group_output_str(args.front().as_string().c_str(), args.back().as_string().c_str()); return torrent::Object(); } // TODO: Deprecated. torrent::Object apply_log(const torrent::Object::string_type& arg, int logType) { if (rpc::execFile.log_fd() != -1) { switch (logType) { case 0: ::close(rpc::execFile.log_fd()); rpc::execFile.set_log_fd(-1); break; case 1: // if (control->scgi()) { // ::close(control->scgi()->log_fd()); // control->scgi()->set_log_fd(-1); // } break; default: break; } } if (!arg.empty()) { int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644); if (logFd < 0) throw torrent::input_error("Could not open execute log file."); switch (logType) { case 0: rpc::execFile.set_log_fd(logFd); break; // case 1: if (control->scgi()) control->scgi()->set_log_fd(logFd); break; default: break; } control->core()->push_log("Opened log file."); } else { control->core()->push_log("Closed log file."); } return torrent::Object(); } torrent::Object log_vmmap_dump(const std::string& str) { core::DownloadList* d_list = control->core()->download_list(); std::vector all_mappings; for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++) { std::vector tmp_mappings = torrent::chunk_list_mapping((*itr)->download()); all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end()); } FILE* log_file = fopen(str.c_str(), "w"); for (std::vector::iterator itr = all_mappings.begin(), last = all_mappings.end(); itr != last; itr++) { fprintf(log_file, "%8p-%8p [%5llxk]\n", itr->ptr, (char*)itr->ptr + itr->length, (long long unsigned int)(itr->length / 1024)); } fclose(log_file); return torrent::Object(); } void initialize_command_logging() { CMD2_ANY_LIST ("log.open_file", tr1::bind(&apply_log_open, 0, tr1::placeholders::_2)); CMD2_ANY_LIST ("log.open_gz_file", tr1::bind(&apply_log_open, log_flag_use_gz, tr1::placeholders::_2)); CMD2_ANY_LIST ("log.open_file_pid", tr1::bind(&apply_log_open, log_flag_append_pid, tr1::placeholders::_2)); CMD2_ANY_LIST ("log.open_gz_file_pid", tr1::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, tr1::placeholders::_2)); CMD2_ANY_LIST ("log.add_output", tr1::bind(&apply_log_add_output, tr1::placeholders::_2)); CMD2_ANY_STRING ("log.execute", tr1::bind(&apply_log, tr1::placeholders::_2, 0)); CMD2_ANY_STRING ("log.vmmap.dump", tr1::bind(&log_vmmap_dump, tr1::placeholders::_2)); CMD2_ANY_STRING_V("log.xmlrpc", tr1::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_network.cc000066400000000000000000000321351257211462100176770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/manager.h" #include "rpc/scgi.h" #include "ui/root.h" #include "rpc/parse.h" #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "command_helpers.h" namespace tr1 { using namespace std::tr1; } torrent::Object apply_encryption(const torrent::Object::list_type& args) { uint32_t options_mask = torrent::ConnectionManager::encryption_none; for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, itr->as_string().c_str()); if (opt == torrent::ConnectionManager::encryption_none) options_mask = torrent::ConnectionManager::encryption_none; else options_mask |= opt; } torrent::connection_manager()->set_encryption_options(options_mask); return torrent::Object(); } torrent::Object apply_tos(const torrent::Object::string_type& arg) { rpc::command_base::value_type value; if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1)) value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str()); torrent::connection_manager()->set_priority(value); return torrent::Object(); } torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); } torrent::File* xmlrpc_find_file(core::Download* download, uint32_t index) { if (index >= download->file_list()->size_files()) return NULL; return (*download->file_list())[index]; } // Ergh... time to update the Tracker API to allow proper ptrs. torrent::Tracker* xmlrpc_find_tracker(core::Download* download, uint32_t index) { if (index >= download->tracker_list()->size()) return NULL; return download->tracker_list()->at(index); } torrent::Peer* xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) { torrent::ConnectionList::iterator itr = download->connection_list()->find(hash.c_str()); if (itr == download->connection_list()->end()) return NULL; return *itr; } void initialize_xmlrpc() { rpc::xmlrpc.initialize(); rpc::xmlrpc.slot_find_download() = tr1::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), tr1::placeholders::_1); rpc::xmlrpc.slot_find_file() = tr1::bind(&xmlrpc_find_file, tr1::placeholders::_1, tr1::placeholders::_2); rpc::xmlrpc.slot_find_tracker() = tr1::bind(&xmlrpc_find_tracker, tr1::placeholders::_1, tr1::placeholders::_2); rpc::xmlrpc.slot_find_peer() = tr1::bind(&xmlrpc_find_peer, tr1::placeholders::_1, tr1::placeholders::_2); unsigned int count = 0; for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++, count++) { if (!(itr->second.m_flags & rpc::CommandMap::flag_public_xmlrpc)) continue; rpc::xmlrpc.insert_command(itr->first, itr->second.m_parm, itr->second.m_doc); } lt_log_print(torrent::LOG_RPC_EVENTS, "XMLRPC initialized with %u functions.", count); } torrent::Object apply_scgi(const std::string& arg, int type) { if (worker_thread->scgi() != NULL) throw torrent::input_error("SCGI already enabled."); if (!rpc::xmlrpc.is_valid()) initialize_xmlrpc(); rpc::SCgi* scgi = new rpc::SCgi; rak::address_info* ai = NULL; rak::socket_address sa; rak::socket_address* saPtr; try { int port, err; char dummy; char address[1024]; std::string path; switch (type) { case 1: if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) { sa.sa_inet()->clear(); saPtr = &sa; lt_log_print(torrent::LOG_RPC_EVENTS, "The SCGI socket has not been bound to any address and likely poses a security risk."); } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) { if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + "."); saPtr = ai->address(); lt_log_print(torrent::LOG_RPC_EVENTS, "The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'."); } else { throw torrent::input_error("Could not parse address."); } if (port <= 0 || port >= (1 << 16)) throw torrent::input_error("Invalid port number."); saPtr->set_port(port); scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route")); break; case 2: default: path = rak::path_expand(arg); unlink(path.c_str()); scgi->open_named(path); break; } if (ai != NULL) rak::address_info::free_address_info(ai); } catch (torrent::local_error& e) { if (ai != NULL) rak::address_info::free_address_info(ai); delete scgi; throw torrent::input_error(e.what()); } worker_thread->set_scgi(scgi); return torrent::Object(); } torrent::Object apply_xmlrpc_dialect(const std::string& arg) { int value; if (arg == "i8") value = rpc::XmlRpc::dialect_i8; else if (arg == "apache") value = rpc::XmlRpc::dialect_apache; else if (arg == "generic") value = rpc::XmlRpc::dialect_generic; else value = -1; rpc::xmlrpc.set_dialect(value); return torrent::Object(); } void initialize_command_network() { torrent::ConnectionManager* cm = torrent::connection_manager(); torrent::FileManager* fileManager = torrent::file_manager(); core::CurlStack* httpStack = control->core()->http_stack(); CMD2_ANY ("strings.connection_type", tr1::bind(&torrent::option_list_strings, torrent::OPTION_CONNECTION_TYPE)); CMD2_ANY ("strings.encryption", tr1::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION)); // CMD2_ANY_STRING ("encoding_list", tr1::bind(&apply_encoding_list, tr1::placeholders::_2)); CMD2_ANY_STRING ("encoding.add", tr1::bind(&apply_encoding_list, tr1::placeholders::_2)); // Isn't port_open used? CMD2_VAR_BOOL ("network.port_open", true); CMD2_VAR_BOOL ("network.port_random", true); CMD2_VAR_STRING ("network.port_range", "6881-6999"); CMD2_ANY ("network.listen.port", tr1::bind(&torrent::ConnectionManager::listen_port, cm)); CMD2_ANY ("network.listen.backlog", tr1::bind(&torrent::ConnectionManager::listen_backlog, cm)); CMD2_ANY_VALUE_V ("network.listen.backlog.set", tr1::bind(&torrent::ConnectionManager::set_listen_backlog, cm, tr1::placeholders::_2)); CMD2_VAR_BOOL ("protocol.pex", true); CMD2_ANY_LIST ("protocol.encryption.set", tr1::bind(&apply_encryption, tr1::placeholders::_2)); CMD2_VAR_STRING ("protocol.connection.leech", "leech"); CMD2_VAR_STRING ("protocol.connection.seed", "seed"); CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech"); CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech"); CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech"); CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech"); CMD2_ANY ("network.http.capath", tr1::bind(&core::CurlStack::http_capath, httpStack)); CMD2_ANY_STRING_V("network.http.capath.set", tr1::bind(&core::CurlStack::set_http_capath, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.http.cacert", tr1::bind(&core::CurlStack::http_cacert, httpStack)); CMD2_ANY_STRING_V("network.http.cacert.set", tr1::bind(&core::CurlStack::set_http_cacert, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.http.proxy_address", tr1::bind(&core::CurlStack::http_proxy, httpStack)); CMD2_ANY_STRING_V("network.http.proxy_address.set", tr1::bind(&core::CurlStack::set_http_proxy, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.http.max_open", tr1::bind(&core::CurlStack::max_active, httpStack)); CMD2_ANY_VALUE_V ("network.http.max_open.set", tr1::bind(&core::CurlStack::set_max_active, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.http.ssl_verify_peer", tr1::bind(&core::CurlStack::ssl_verify_peer, httpStack)); CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", tr1::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.http.dns_cache_timeout", tr1::bind(&core::CurlStack::dns_timeout, httpStack)); CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", tr1::bind(&core::CurlStack::set_dns_timeout, httpStack, tr1::placeholders::_2)); CMD2_ANY ("network.send_buffer.size", tr1::bind(&torrent::ConnectionManager::send_buffer_size, cm)); CMD2_ANY_VALUE_V ("network.send_buffer.size.set", tr1::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, tr1::placeholders::_2)); CMD2_ANY ("network.receive_buffer.size", tr1::bind(&torrent::ConnectionManager::receive_buffer_size, cm)); CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", tr1::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, tr1::placeholders::_2)); CMD2_ANY_STRING ("network.tos.set", tr1::bind(&apply_tos, tr1::placeholders::_2)); CMD2_ANY ("network.bind_address", tr1::bind(&core::Manager::bind_address, control->core())); CMD2_ANY_STRING_V("network.bind_address.set", tr1::bind(&core::Manager::set_bind_address, control->core(), tr1::placeholders::_2)); CMD2_ANY ("network.local_address", tr1::bind(&core::Manager::local_address, control->core())); CMD2_ANY_STRING_V("network.local_address.set", tr1::bind(&core::Manager::set_local_address, control->core(), tr1::placeholders::_2)); CMD2_ANY ("network.proxy_address", tr1::bind(&core::Manager::proxy_address, control->core())); CMD2_ANY_STRING_V("network.proxy_address.set", tr1::bind(&core::Manager::set_proxy_address, control->core(), tr1::placeholders::_2)); CMD2_ANY ("network.max_open_files", tr1::bind(&torrent::FileManager::max_open_files, fileManager)); CMD2_ANY_VALUE_V ("network.max_open_files.set", tr1::bind(&torrent::FileManager::set_max_open_files, fileManager, tr1::placeholders::_2)); CMD2_ANY ("network.open_sockets", tr1::bind(&torrent::ConnectionManager::size, cm)); CMD2_ANY ("network.max_open_sockets", tr1::bind(&torrent::ConnectionManager::max_size, cm)); CMD2_ANY_VALUE_V ("network.max_open_sockets.set", tr1::bind(&torrent::ConnectionManager::set_max_size, cm, tr1::placeholders::_2)); CMD2_ANY_STRING ("network.scgi.open_port", tr1::bind(&apply_scgi, tr1::placeholders::_2, 1)); CMD2_ANY_STRING ("network.scgi.open_local", tr1::bind(&apply_scgi, tr1::placeholders::_2, 2)); CMD2_VAR_BOOL ("network.scgi.dont_route", false); CMD2_ANY_STRING ("network.xmlrpc.dialect.set", tr1::bind(&apply_xmlrpc_dialect, tr1::placeholders::_2)); CMD2_ANY ("network.xmlrpc.size_limit", tr1::bind(&rpc::XmlRpc::size_limit)); CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", tr1::bind(&rpc::XmlRpc::set_size_limit, tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_peer.cc000066400000000000000000000137321257211462100171430ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include "core/manager.h" #include "display/utils.h" #include "globals.h" #include "control.h" #include "command_helpers.h" torrent::Object retrieve_p_id(torrent::Peer* peer) { const torrent::HashString* hashString = &peer->id(); return rak::transform_hex(hashString->begin(), hashString->end()); } torrent::Object retrieve_p_id_html(torrent::Peer* peer) { const torrent::HashString* hashString = &peer->id(); return rak::copy_escape_html(hashString->begin(), hashString->end()); } torrent::Object retrieve_p_address(torrent::Peer* peer) { return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str(); } torrent::Object retrieve_p_port(torrent::Peer* peer) { return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port(); } torrent::Object retrieve_p_client_version(torrent::Peer* peer) { char buf[128]; display::print_client_version(buf, buf + 128, peer->peer_info()->client_info()); return std::string(buf); } torrent::Object retrieve_p_options_str(torrent::Peer* peer) { return rak::transform_hex(peer->peer_info()->options(), peer->peer_info()->options() + 8); } torrent::Object retrieve_p_completed_percent(torrent::Peer* peer) { return (100 * peer->bitfield()->size_set()) / peer->bitfield()->size_bits(); } void initialize_command_peer() { CMD2_PEER("p.id", tr1::bind(&retrieve_p_id, tr1::placeholders::_1)); CMD2_PEER("p.id_html", tr1::bind(&retrieve_p_id_html, tr1::placeholders::_1)); CMD2_PEER("p.client_version", tr1::bind(&retrieve_p_client_version, tr1::placeholders::_1)); CMD2_PEER("p.options_str", tr1::bind(&retrieve_p_options_str, tr1::placeholders::_1)); CMD2_PEER("p.is_encrypted", tr1::bind(&torrent::Peer::is_encrypted, tr1::placeholders::_1)); CMD2_PEER("p.is_incoming", tr1::bind(&torrent::Peer::is_incoming, tr1::placeholders::_1)); CMD2_PEER("p.is_obfuscated", tr1::bind(&torrent::Peer::is_obfuscated, tr1::placeholders::_1)); CMD2_PEER("p.is_snubbed", tr1::bind(&torrent::Peer::is_snubbed, tr1::placeholders::_1)); CMD2_PEER("p.is_unwanted", tr1::bind(&torrent::PeerInfo::is_unwanted, tr1::bind(&torrent::Peer::peer_info, tr1::placeholders::_1))); CMD2_PEER("p.is_preferred", tr1::bind(&torrent::PeerInfo::is_preferred, tr1::bind(&torrent::Peer::peer_info, tr1::placeholders::_1))); CMD2_PEER("p.address", tr1::bind(&retrieve_p_address, tr1::placeholders::_1)); CMD2_PEER("p.port", tr1::bind(&retrieve_p_port, tr1::placeholders::_1)); CMD2_PEER("p.completed_percent", tr1::bind(&retrieve_p_completed_percent, tr1::placeholders::_1)); CMD2_PEER("p.up_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::up_rate, tr1::placeholders::_1))); CMD2_PEER("p.up_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::up_rate, tr1::placeholders::_1))); CMD2_PEER("p.down_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::down_rate, tr1::placeholders::_1))); CMD2_PEER("p.down_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::down_rate, tr1::placeholders::_1))); CMD2_PEER("p.peer_rate", tr1::bind(&torrent::Rate::rate, tr1::bind(&torrent::Peer::peer_rate, tr1::placeholders::_1))); CMD2_PEER("p.peer_total", tr1::bind(&torrent::Rate::total, tr1::bind(&torrent::Peer::peer_rate, tr1::placeholders::_1))); CMD2_PEER ("p.snubbed", tr1::bind(&torrent::Peer::is_snubbed, tr1::placeholders::_1)); CMD2_PEER_VALUE_V("p.snubbed.set", tr1::bind(&torrent::Peer::set_snubbed, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_PEER ("p.banned", tr1::bind(&torrent::Peer::is_banned, tr1::placeholders::_1)); CMD2_PEER_VALUE_V("p.banned.set", tr1::bind(&torrent::Peer::set_banned, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_PEER_V("p.disconnect", tr1::bind(&torrent::Peer::disconnect, tr1::placeholders::_1, 0)); CMD2_PEER_V("p.disconnect_delayed", tr1::bind(&torrent::Peer::disconnect, tr1::placeholders::_1, torrent::ConnectionList::disconnect_delayed)); } rtorrent-0.9.6/src/command_scheduler.cc000066400000000000000000000104531257211462100201630ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "core/manager.h" #include "core/download.h" #include "core/download_list.h" #include "core/view.h" #include "core/view_manager.h" #include "globals.h" #include "control.h" #include "command_helpers.h" torrent::Object cmd_scheduler_simple_added(core::Download* download) { unsigned int numActive = (*control->view_manager()->find("active"))->size_visible(); int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value(); if (numActive < (uint64_t)maxActive) control->core()->download_list()->resume(download); return torrent::Object(); } torrent::Object cmd_scheduler_simple_removed(core::Download* download) { control->core()->download_list()->pause(download); core::View* viewActive = *control->view_manager()->find("active"); int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value(); if ((int64_t)viewActive->size_visible() >= maxActive) return torrent::Object(); // The 'started' view contains all the views we may choose amongst. core::View* viewStarted = *control->view_manager()->find("started"); for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) { if ((*itr)->is_active()) continue; control->core()->download_list()->resume(*itr); } return torrent::Object(); } torrent::Object cmd_scheduler_simple_update(core::Download* download) { core::View* viewActive = *control->view_manager()->find("active"); core::View* viewStarted = *control->view_manager()->find("started"); unsigned int numActive = viewActive->size_visible(); uint64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value(); if (viewActive->size_visible() < maxActive) { for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) { if ((*itr)->is_active()) continue; control->core()->download_list()->resume(*itr); if (++numActive >= maxActive) break; } } else if (viewActive->size_visible() > maxActive) { while (viewActive->size_visible() > maxActive) control->core()->download_list()->pause(*viewActive->begin_visible()); } return torrent::Object(); } void initialize_command_scheduler() { CMD2_VAR_VALUE("scheduler.max_active", int64_t(-1)); CMD2_DL("scheduler.simple.added", tr1::bind(&cmd_scheduler_simple_added, tr1::placeholders::_1)); CMD2_DL("scheduler.simple.removed", tr1::bind(&cmd_scheduler_simple_removed, tr1::placeholders::_1)); CMD2_DL("scheduler.simple.update", tr1::bind(&cmd_scheduler_simple_update, tr1::placeholders::_1)); } rtorrent-0.9.6/src/command_throttle.cc000066400000000000000000000253731257211462100200610ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/manager.h" #include "ui/root.h" #include "rpc/parse.h" #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "command_helpers.h" std::pair parse_address_range(const torrent::Object::list_type& args, torrent::Object::list_type::const_iterator itr) { unsigned int prefixWidth, ret; char dummy; char host[1024]; rak::address_info* ai; ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy); if (ret < 1 || rak::address_info::get_address_info(host, PF_INET, SOCK_STREAM, &ai) != 0) throw torrent::input_error("Could not resolve host."); uint32_t begin, end; rak::socket_address sa; sa.copy(*ai->address(), ai->length()); begin = end = sa.sa_inet()->address_h(); rak::address_info::free_address_info(ai); if (ret == 2) { if (++itr != args.end()) throw torrent::input_error("Cannot specify both network and range end."); uint32_t netmask = std::numeric_limits::max() << (32 - prefixWidth); if (prefixWidth >= 32 || sa.sa_inet()->address_h() & ~netmask) throw torrent::input_error("Invalid address/prefix."); end = sa.sa_inet()->address_h() | ~netmask; } else if (++itr != args.end()) { if (rak::address_info::get_address_info(itr->as_string().c_str(), PF_INET, SOCK_STREAM, &ai) != 0) throw torrent::input_error("Could not resolve host."); sa.copy(*ai->address(), ai->length()); rak::address_info::free_address_info(ai); end = sa.sa_inet()->address_h(); } // convert to [begin, end) making sure the end doesn't overflow // (this precludes 255.255.255.255 from ever matching, but that's not a real IP anyway) return std::make_pair((uint32_t)begin, (uint32_t)std::max(end, end + 1)); } torrent::Object apply_throttle(const torrent::Object::list_type& args, bool up) { torrent::Object::list_const_iterator argItr = args.begin(); const std::string& name = argItr->as_string(); if (name.empty() || name == "NULL") throw torrent::input_error("Invalid throttle name."); if ((++argItr)->as_string().empty()) return torrent::Object(); int64_t rate; rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate); if (rate < 0) throw torrent::input_error("Throttle rate must be non-negative."); core::ThrottleMap::iterator itr = control->core()->throttles().find(name); if (itr == control->core()->throttles().end()) itr = control->core()->throttles().insert(std::make_pair(name, torrent::ThrottlePair(NULL, NULL))).first; torrent::Throttle*& throttle = up ? itr->second.first : itr->second.second; if (rate != 0 && throttle == NULL) throttle = (up ? torrent::up_throttle_global() : torrent::down_throttle_global())->create_slave(); if (throttle != NULL) throttle->set_max_rate(rate * 1024); return torrent::Object(); } static const int throttle_info_up = (1 << 0); static const int throttle_info_down = (1 << 1); static const int throttle_info_max = (1 << 2); static const int throttle_info_rate = (1 << 3); torrent::Object retrieve_throttle_info(const torrent::Object::string_type& name, int flags) { core::ThrottleMap::iterator itr = control->core()->throttles().find(name); torrent::ThrottlePair throttles = itr == control->core()->throttles().end() ? torrent::ThrottlePair(NULL, NULL) : itr->second; torrent::Throttle* throttle = flags & throttle_info_down ? throttles.second : throttles.first; torrent::Throttle* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global(); if (throttle == NULL && name.empty()) throttle = global; if (throttle == NULL) return flags & throttle_info_rate ? (int64_t)0 : (int64_t)-1; else if (!throttle->is_throttled() || !global->is_throttled()) return (int64_t)0; else if (flags & throttle_info_rate) return (int64_t)throttle->rate()->rate(); else return (int64_t)throttle->max_rate(); } torrent::Object apply_address_throttle(const torrent::Object::list_type& args) { if (args.size() < 2 || args.size() > 3) throw torrent::input_error("Incorrect number of arguments."); std::pair range = parse_address_range(args, ++args.begin()); core::ThrottleMap::iterator throttleItr = control->core()->throttles().find(args.begin()->as_string().c_str()); if (throttleItr == control->core()->throttles().end()) throw torrent::input_error("Throttle not found."); control->core()->set_address_throttle(range.first, range.second, throttleItr->second); return torrent::Object(); } torrent::Object throttle_update(const char* variable, int64_t value) { rpc::commands.call_command(variable, value); control->ui()->adjust_up_throttle(0); control->ui()->adjust_down_throttle(0); return torrent::Object(); } void initialize_command_throttle() { CMD2_ANY ("throttle.unchoked_uploads", tr1::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager())); CMD2_ANY ("throttle.unchoked_downloads", tr1::bind(&torrent::ResourceManager::currently_download_unchoked, torrent::resource_manager())); CMD2_VAR_VALUE ("throttle.min_peers.normal", 100); CMD2_VAR_VALUE ("throttle.max_peers.normal", 200); CMD2_VAR_VALUE ("throttle.min_peers.seed", -1); CMD2_VAR_VALUE ("throttle.max_peers.seed", -1); CMD2_VAR_VALUE ("throttle.min_uploads", 0); CMD2_VAR_VALUE ("throttle.max_uploads", 50); CMD2_VAR_VALUE ("throttle.min_downloads", 0); CMD2_VAR_VALUE ("throttle.max_downloads", 50); CMD2_VAR_VALUE ("throttle.max_uploads.div._val", 1); CMD2_VAR_VALUE ("throttle.max_uploads.global._val", 0); CMD2_VAR_VALUE ("throttle.max_downloads.div._val", 1); CMD2_VAR_VALUE ("throttle.max_downloads.global._val", 0); CMD2_REDIRECT_GENERIC("throttle.max_uploads.div", "throttle.max_uploads.div._val"); CMD2_REDIRECT_GENERIC("throttle.max_uploads.global", "throttle.max_uploads.global._val"); CMD2_REDIRECT_GENERIC("throttle.max_downloads.div", "throttle.max_downloads.div._val"); CMD2_REDIRECT_GENERIC("throttle.max_downloads.global", "throttle.max_downloads.global._val"); CMD2_ANY_VALUE ("throttle.max_uploads.div.set", tr1::bind(&throttle_update, "throttle.max_uploads.div._val.set", tr1::placeholders::_2)); CMD2_ANY_VALUE ("throttle.max_uploads.global.set", tr1::bind(&throttle_update, "throttle.max_uploads.global._val.set", tr1::placeholders::_2)); CMD2_ANY_VALUE ("throttle.max_downloads.div.set", tr1::bind(&throttle_update, "throttle.max_downloads.div._val.set", tr1::placeholders::_2)); CMD2_ANY_VALUE ("throttle.max_downloads.global.set", tr1::bind(&throttle_update, "throttle.max_downloads.global._val.set", tr1::placeholders::_2)); // TODO: Move the logic into some libtorrent function. CMD2_ANY ("throttle.global_up.rate", tr1::bind(&torrent::Rate::rate, torrent::up_rate())); CMD2_ANY ("throttle.global_up.total", tr1::bind(&torrent::Rate::total, torrent::up_rate())); CMD2_ANY ("throttle.global_up.max_rate", tr1::bind(&torrent::Throttle::max_rate, torrent::up_throttle_global())); CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", tr1::bind(&ui::Root::set_up_throttle_i64, control->ui(), tr1::placeholders::_2)); CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", tr1::bind(&ui::Root::set_up_throttle_i64, control->ui(), tr1::placeholders::_2)); CMD2_ANY ("throttle.global_down.rate", tr1::bind(&torrent::Rate::rate, torrent::down_rate())); CMD2_ANY ("throttle.global_down.total", tr1::bind(&torrent::Rate::total, torrent::down_rate())); CMD2_ANY ("throttle.global_down.max_rate", tr1::bind(&torrent::Throttle::max_rate, torrent::down_throttle_global())); CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", tr1::bind(&ui::Root::set_down_throttle_i64, control->ui(), tr1::placeholders::_2)); CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", tr1::bind(&ui::Root::set_down_throttle_i64, control->ui(), tr1::placeholders::_2)); // Temporary names, need to change this to accept real rates rather // than kB. CMD2_ANY_LIST ("throttle.up", tr1::bind(&apply_throttle, tr1::placeholders::_2, true)); CMD2_ANY_LIST ("throttle.down", tr1::bind(&apply_throttle, tr1::placeholders::_2, false)); CMD2_ANY_LIST ("throttle.ip", tr1::bind(&apply_address_throttle, tr1::placeholders::_2)); CMD2_ANY_STRING ("throttle.up.max", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_up | throttle_info_max)); CMD2_ANY_STRING ("throttle.up.rate", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_up | throttle_info_rate)); CMD2_ANY_STRING ("throttle.down.max", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_down | throttle_info_max)); CMD2_ANY_STRING ("throttle.down.rate", tr1::bind(&retrieve_throttle_info, tr1::placeholders::_2, throttle_info_down | throttle_info_rate)); } rtorrent-0.9.6/src/command_tracker.cc000066400000000000000000000201061257211462100176340ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "core/download.h" #include "core/manager.h" #include "globals.h" #include "control.h" #include "command_helpers.h" #include "core/dht_manager.h" void tracker_set_enabled(torrent::Tracker* tracker, bool state) { if (state) tracker->enable(); else tracker->disable(); } struct call_add_node_t { call_add_node_t(int port) : m_port(port) { } void operator() (const sockaddr* sa, int err) { if (sa == NULL) { lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host."); } else { torrent::dht_manager()->add_node(sa, m_port); } } int m_port; }; torrent::Object apply_dht_add_node(const std::string& arg) { if (!torrent::dht_manager()->is_valid()) throw torrent::input_error("DHT not enabled."); int port, ret; char dummy; char host[1024]; ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); if (ret == 1) port = 6881; else if (ret != 2) throw torrent::input_error("Could not parse host."); if (port < 1 || port > 65535) throw torrent::input_error("Invalid port number."); torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port)); return torrent::Object(); } torrent::Object apply_enable_trackers(int64_t arg) { for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) { std::for_each((*itr)->tracker_list()->begin(), (*itr)->tracker_list()->end(), arg ? std::mem_fun(&torrent::Tracker::enable) : std::mem_fun(&torrent::Tracker::disable)); if (arg && !rpc::call_command_value("trackers.use_udp")) (*itr)->enable_udp_trackers(false); } return torrent::Object(); } void initialize_command_tracker() { CMD2_TRACKER ("t.is_open", tr1::bind(&torrent::Tracker::is_busy, tr1::placeholders::_1)); CMD2_TRACKER ("t.is_enabled", tr1::bind(&torrent::Tracker::is_enabled, tr1::placeholders::_1)); CMD2_TRACKER ("t.is_usable", tr1::bind(&torrent::Tracker::is_usable, tr1::placeholders::_1)); CMD2_TRACKER ("t.is_busy", tr1::bind(&torrent::Tracker::is_busy, tr1::placeholders::_1)); CMD2_TRACKER ("t.is_extra_tracker", tr1::bind(&torrent::Tracker::is_extra_tracker, tr1::placeholders::_1)); CMD2_TRACKER ("t.can_scrape", tr1::bind(&torrent::Tracker::can_scrape, tr1::placeholders::_1)); CMD2_TRACKER_V ("t.enable", tr1::bind(&torrent::Tracker::enable, tr1::placeholders::_1)); CMD2_TRACKER_V ("t.disable", tr1::bind(&torrent::Tracker::disable, tr1::placeholders::_1)); CMD2_TRACKER_VALUE_V("t.is_enabled.set", tr1::bind(&tracker_set_enabled, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_TRACKER ("t.url", tr1::bind(&torrent::Tracker::url, tr1::placeholders::_1)); CMD2_TRACKER ("t.group", tr1::bind(&torrent::Tracker::group, tr1::placeholders::_1)); CMD2_TRACKER ("t.type", tr1::bind(&torrent::Tracker::type, tr1::placeholders::_1)); CMD2_TRACKER ("t.id", tr1::bind(&torrent::Tracker::tracker_id, tr1::placeholders::_1)); CMD2_TRACKER ("t.latest_event", tr1::bind(&torrent::Tracker::latest_event, tr1::placeholders::_1)); CMD2_TRACKER ("t.latest_new_peers", tr1::bind(&torrent::Tracker::latest_new_peers, tr1::placeholders::_1)); CMD2_TRACKER ("t.latest_sum_peers", tr1::bind(&torrent::Tracker::latest_sum_peers, tr1::placeholders::_1)); // Time since last connection, connection attempt. CMD2_TRACKER ("t.normal_interval", tr1::bind(&torrent::Tracker::normal_interval, tr1::placeholders::_1)); CMD2_TRACKER ("t.min_interval", tr1::bind(&torrent::Tracker::min_interval, tr1::placeholders::_1)); CMD2_TRACKER ("t.activity_time_next", tr1::bind(&torrent::Tracker::activity_time_next, tr1::placeholders::_1)); CMD2_TRACKER ("t.activity_time_last", tr1::bind(&torrent::Tracker::activity_time_last, tr1::placeholders::_1)); CMD2_TRACKER ("t.success_time_next", tr1::bind(&torrent::Tracker::success_time_next, tr1::placeholders::_1)); CMD2_TRACKER ("t.success_time_last", tr1::bind(&torrent::Tracker::success_time_last, tr1::placeholders::_1)); CMD2_TRACKER ("t.success_counter", tr1::bind(&torrent::Tracker::success_counter, tr1::placeholders::_1)); CMD2_TRACKER ("t.failed_time_next", tr1::bind(&torrent::Tracker::failed_time_next, tr1::placeholders::_1)); CMD2_TRACKER ("t.failed_time_last", tr1::bind(&torrent::Tracker::failed_time_last, tr1::placeholders::_1)); CMD2_TRACKER ("t.failed_counter", tr1::bind(&torrent::Tracker::failed_counter, tr1::placeholders::_1)); CMD2_TRACKER ("t.scrape_time_last", tr1::bind(&torrent::Tracker::scrape_time_last, tr1::placeholders::_1)); CMD2_TRACKER ("t.scrape_counter", tr1::bind(&torrent::Tracker::scrape_counter, tr1::placeholders::_1)); CMD2_TRACKER ("t.scrape_complete", tr1::bind(&torrent::Tracker::scrape_complete, tr1::placeholders::_1)); CMD2_TRACKER ("t.scrape_incomplete", tr1::bind(&torrent::Tracker::scrape_incomplete, tr1::placeholders::_1)); CMD2_TRACKER ("t.scrape_downloaded", tr1::bind(&torrent::Tracker::scrape_downloaded, tr1::placeholders::_1)); CMD2_ANY_VALUE ("trackers.enable", tr1::bind(&apply_enable_trackers, int64_t(1))); CMD2_ANY_VALUE ("trackers.disable", tr1::bind(&apply_enable_trackers, int64_t(0))); CMD2_VAR_VALUE ("trackers.numwant", -1); CMD2_VAR_BOOL ("trackers.use_udp", true); CMD2_ANY_STRING_V ("dht.mode.set", tr1::bind(&core::DhtManager::set_mode, control->dht_manager(), tr1::placeholders::_2)); CMD2_VAR_VALUE ("dht.port", int64_t(6881)); CMD2_ANY_STRING ("dht.add_node", tr1::bind(&apply_dht_add_node, tr1::placeholders::_2)); CMD2_ANY ("dht.statistics", tr1::bind(&core::DhtManager::dht_statistics, control->dht_manager())); CMD2_ANY ("dht.throttle.name", tr1::bind(&core::DhtManager::throttle_name, control->dht_manager())); CMD2_ANY_STRING_V ("dht.throttle.name.set", tr1::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), tr1::placeholders::_2)); } rtorrent-0.9.6/src/command_ui.cc000066400000000000000000000505331257211462100166250ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "core/manager.h" #include "core/view_manager.h" #include "ui/root.h" #include "ui/download_list.h" #include "rpc/parse.h" #include "globals.h" #include "control.h" #include "command_helpers.h" typedef void (core::ViewManager::*view_event_slot)(const std::string&, const torrent::Object&); torrent::Object apply_view_filter_on(const torrent::Object::list_type& args) { if (args.size() < 1) throw torrent::input_error("Too few arguments."); const std::string& name = args.front().as_string(); if (name.empty()) throw torrent::input_error("First argument must be a string."); core::ViewManager::filter_args filterArgs; for (torrent::Object::list_const_iterator itr = ++args.begin(), last = args.end(); itr != last; itr++) filterArgs.push_back(itr->as_string()); control->view_manager()->set_filter_on(name, filterArgs); return torrent::Object(); } torrent::Object apply_view_event(view_event_slot viewFilterSlot, const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); (control->view_manager()->*viewFilterSlot)(args.front().as_string(), args.back()); return torrent::Object(); } torrent::Object apply_view_sort(const torrent::Object::list_type& args) { if (args.size() <= 0 || args.size() > 2) throw torrent::input_error("Wrong argument count."); const std::string& name = args.front().as_string(); if (name.empty()) throw torrent::input_error("First argument must be a string."); int32_t value = 0; if (args.size() == 2) value = rpc::convert_to_value(args.back()); control->view_manager()->sort(name, value); return torrent::Object(); } torrent::Object apply_view_list() { torrent::Object rawResult = torrent::Object::create_list(); torrent::Object::list_type& result = rawResult.as_list(); for (core::ViewManager::const_iterator itr = control->view_manager()->begin(), last = control->view_manager()->end(); itr != last; itr++) result.push_back((*itr)->name()); return rawResult; } torrent::Object apply_view_set(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); core::ViewManager::iterator itr = control->view_manager()->find(args.back().as_string()); if (itr == control->view_manager()->end()) throw torrent::input_error("Could not find view \"" + args.back().as_string() + "\"."); // if (args.front().as_string() == "main") // control->ui()->download_list()->set_view(*itr); // else throw torrent::input_error("No such target."); } torrent::Object apply_print(rpc::target_type target, const torrent::Object& rawArgs) { char buffer[1024]; rpc::print_object(buffer, buffer + 1024, &rawArgs, 0); control->core()->push_log(buffer); return torrent::Object(); } torrent::Object apply_cat(rpc::target_type target, const torrent::Object& rawArgs) { std::string result; rpc::print_object_std(&result, &rawArgs, 0); return result; } // Move these boolean operators to a new file. inline bool as_boolean(const torrent::Object& rawArgs) { switch (rawArgs.type()) { case torrent::Object::TYPE_VALUE: return rawArgs.as_value(); case torrent::Object::TYPE_STRING: return !rawArgs.as_string().empty(); // We need to properly handle argument lists that are single-object // at a higher level. case torrent::Object::TYPE_LIST: return !rawArgs.as_list().empty() && as_boolean(rawArgs.as_list().front()); // case torrent::Object::TYPE_MAP: return !rawArgs.as_map().empty(); default: return false; } } torrent::Object apply_not(rpc::target_type target, const torrent::Object& rawArgs) { bool result; if (rawArgs.is_dict_key()) result = as_boolean(rpc::commands.call_command(rawArgs.as_dict_key().c_str(), rawArgs.as_dict_obj(), target)); // TODO: Thus we should clean this up... else if (rawArgs.is_list() && !rawArgs.as_list().empty()) return apply_not(target, rawArgs.as_list().front()); else result = as_boolean(rawArgs); return (int64_t)!result; } torrent::Object apply_false(rpc::target_type target, const torrent::Object& rawArgs) { return (int64_t)0; } torrent::Object apply_and(rpc::target_type target, const torrent::Object& rawArgs) { if (rawArgs.type() != torrent::Object::TYPE_LIST) return as_boolean(rawArgs); for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++) if (itr->is_dict_key()) { if (!as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target))) return (int64_t)false; } else if (itr->is_value()) { if (!itr->as_value()) return (int64_t)false; } else { // TODO: Switch to new versions that only accept the new command syntax. if (!as_boolean(rpc::parse_command_single(target, itr->as_string()))) return (int64_t)false; } return (int64_t)true; } torrent::Object apply_or(rpc::target_type target, const torrent::Object& rawArgs) { if (rawArgs.type() != torrent::Object::TYPE_LIST) return as_boolean(rawArgs); for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++) if (itr->is_dict_key()) { if (as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target))) return (int64_t)true; } else if (itr->is_value()) { if (itr->as_value()) return (int64_t)true; } else { if (as_boolean(rpc::parse_command_single(target, itr->as_string()))) return (int64_t)true; } return (int64_t)false; } torrent::Object apply_cmp(rpc::target_type target, const torrent::Object::list_type& args) { // We only need to check if empty() since if size() == 1 it calls // the same command for both, or if size() == 2 then each side of // the comparison has different commands. if (args.empty()) throw torrent::input_error("Wrong argument count."); // This really should be converted to using args flagged as // commands, so that we can compare commands and statics values. torrent::Object result1; torrent::Object result2; rpc::target_type target1 = rpc::is_target_pair(target) ? rpc::get_target_left(target) : target; rpc::target_type target2 = rpc::is_target_pair(target) ? rpc::get_target_right(target) : target; if (args.front().is_dict_key()) result1 = rpc::commands.call_command(args.front().as_dict_key().c_str(), args.front().as_dict_obj(), target1); else result1 = rpc::parse_command_single(target1, args.front().as_string()); if (args.back().is_dict_key()) result2 = rpc::commands.call_command(args.back().as_dict_key().c_str(), args.back().as_dict_obj(), target2); else result2 = rpc::parse_command_single(target2, args.back().as_string()); if (result1.type() != result2.type()) throw torrent::input_error("Type mismatch."); switch (result1.type()) { case torrent::Object::TYPE_VALUE: return result1.as_value() - result2.as_value(); case torrent::Object::TYPE_STRING: return result1.as_string().compare(result2.as_string()); default: return torrent::Object(); } } torrent::Object apply_less(rpc::target_type target, const torrent::Object::list_type& args) { torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() < 0 : (int64_t)false; } torrent::Object apply_greater(rpc::target_type target, const torrent::Object::list_type& args) { torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() > 0 : (int64_t)false; } torrent::Object apply_equal(rpc::target_type target, const torrent::Object::list_type& args) { torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() == 0 : (int64_t)false; } torrent::Object apply_to_time(const torrent::Object& rawArgs, int flags) { std::tm *u; time_t t = (uint64_t)rawArgs.as_value(); if (flags & 0x1) u = std::localtime(&t); else u = std::gmtime(&t); if (u == NULL) return torrent::Object(); char buffer[11]; if (flags & 0x2) snprintf(buffer, 11, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)); else snprintf(buffer, 9, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec); return std::string(buffer); } torrent::Object apply_to_elapsed_time(const torrent::Object& rawArgs) { uint64_t arg = cachedTime.seconds() - rawArgs.as_value(); char buffer[48]; snprintf(buffer, 48, "%2d:%02d:%02d", (int)(arg / 3600), (int)((arg / 60) % 60), (int)(arg % 60)); return std::string(buffer); } torrent::Object apply_to_kb(const torrent::Object& rawArgs) { char buffer[32]; snprintf(buffer, 32, "%5.1f", (double)rawArgs.as_value() / (1 << 10)); return std::string(buffer); } torrent::Object apply_to_mb(const torrent::Object& rawArgs) { char buffer[32]; snprintf(buffer, 32, "%8.1f", (double)rawArgs.as_value() / (1 << 20)); return std::string(buffer); } torrent::Object apply_to_xb(const torrent::Object& rawArgs) { char buffer[48]; int64_t arg = rawArgs.as_value(); if (arg < (int64_t(1000) << 10)) snprintf(buffer, 48, "%5.1f KB", (double)arg / (int64_t(1) << 10)); else if (arg < (int64_t(1000) << 20)) snprintf(buffer, 48, "%5.1f MB", (double)arg / (int64_t(1) << 20)); else if (arg < (int64_t(1000) << 30)) snprintf(buffer, 48, "%5.1f GB", (double)arg / (int64_t(1) << 30)); else snprintf(buffer, 48, "%5.1f TB", (double)arg / (int64_t(1) << 40)); return std::string(buffer); } torrent::Object apply_to_throttle(const torrent::Object& rawArgs) { int64_t arg = rawArgs.as_value(); if (arg < 0) return "---"; else if (arg == 0) return "off"; char buffer[32]; snprintf(buffer, 32, "%3d", (int)(arg / (1 << 10))); return std::string(buffer); } // A series of if/else statements. Every even arguments are // conditionals and odd arguments are branches to be executed, except // the last one which is always a branch. // // if (cond1) { branch1 } // , // // if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 } // ,,,, torrent::Object apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) { const torrent::Object::list_type& args = rawArgs.as_list(); torrent::Object::list_const_iterator itr = args.begin(); while (itr != args.end() && itr != --args.end()) { torrent::Object tmp; const torrent::Object* conditional; if (flags & 0x1 && itr->is_string()) conditional = &(tmp = rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first); else if (flags & 0x1 && itr->is_dict_key()) conditional = &(tmp = rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)); else conditional = &*itr; bool result; switch (conditional->type()) { case torrent::Object::TYPE_STRING: result = !conditional->as_string().empty(); break; case torrent::Object::TYPE_VALUE: result = conditional->as_value(); break; case torrent::Object::TYPE_NONE: result = false; break; default: throw torrent::input_error("Type not supported by 'if'."); }; itr++; if (result) break; itr++; } if (itr == args.end()) return torrent::Object(); if (flags & 0x1 && itr->is_string()) { return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first; } else if (flags & 0x1 && itr->is_dict_key()) { return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target); } else if (flags & 0x1 && itr->is_list()) { // Move this into a special function or something. Also, might be // nice to have a parse_command function that takes list // iterator... for (torrent::Object::list_type::const_iterator cmdItr = itr->as_list().begin(), last = itr->as_list().end(); cmdItr != last; cmdItr++) if (cmdItr->is_string()) rpc::parse_command(target, cmdItr->as_string().c_str(), cmdItr->as_string().c_str() + cmdItr->as_string().size()); return torrent::Object(); } else { return *itr; } } torrent::Object cmd_view_size(const torrent::Object::string_type& args) { return (*control->view_manager()->find_throw(args))->size_visible(); } torrent::Object cmd_view_size_not_visible(const torrent::Object::string_type& args) { return (*control->view_manager()->find_throw(args))->size_not_visible(); } torrent::Object cmd_view_persistent(const torrent::Object::string_type& args) { core::View* view = *control->view_manager()->find_throw(args); if (!view->get_filter().is_empty() || !view->event_added().is_empty() || !view->event_removed().is_empty()) throw torrent::input_error("Cannot set modified views as persitent."); view->set_filter("d.views.has=" + args); view->set_event_added("d.views.push_back_unique=" + args); view->set_event_removed("d.views.remove=" + args); return torrent::Object(); } // TODO: These don't need wrapper functions anymore... torrent::Object cmd_ui_set_view(const torrent::Object::string_type& args) { control->ui()->download_list()->set_current_view(args); return torrent::Object(); } torrent::Object cmd_ui_unfocus_download(core::Download* download) { control->ui()->download_list()->unfocus_download(download); return torrent::Object(); } torrent::Object cmd_view_filter_download(core::Download* download, const torrent::Object::string_type& args) { (*control->view_manager()->find_throw(args))->filter_download(download); return torrent::Object(); } torrent::Object cmd_view_set_visible(core::Download* download, const torrent::Object::string_type& args) { (*control->view_manager()->find_throw(args))->set_visible(download); return torrent::Object(); } torrent::Object cmd_view_set_not_visible(core::Download* download, const torrent::Object::string_type& args) { (*control->view_manager()->find_throw(args))->set_not_visible(download); return torrent::Object(); } torrent::Object apply_elapsed_less(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); int64_t start_time = rpc::convert_to_value(args.front()); return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time < rpc::convert_to_value(args.back())); } torrent::Object apply_elapsed_greater(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); int64_t start_time = rpc::convert_to_value(args.front()); return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); } void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); CMD2_ANY_STRING("view.add", object_convert_void(tr1::bind(&core::ViewManager::insert_throw, control->view_manager(), tr1::placeholders::_2))); CMD2_ANY_L ("view.list", tr1::bind(&apply_view_list)); CMD2_ANY_LIST("view.set", tr1::bind(&apply_view_set, tr1::placeholders::_2)); CMD2_ANY_LIST("view.filter", tr1::bind(&apply_view_event, &core::ViewManager::set_filter, tr1::placeholders::_2)); CMD2_ANY_LIST("view.filter_on", tr1::bind(&apply_view_filter_on, tr1::placeholders::_2)); CMD2_ANY_LIST("view.sort", tr1::bind(&apply_view_sort, tr1::placeholders::_2)); CMD2_ANY_LIST("view.sort_new", tr1::bind(&apply_view_event, &core::ViewManager::set_sort_new, tr1::placeholders::_2)); CMD2_ANY_LIST("view.sort_current", tr1::bind(&apply_view_event, &core::ViewManager::set_sort_current, tr1::placeholders::_2)); CMD2_ANY_LIST("view.event_added", tr1::bind(&apply_view_event, &core::ViewManager::set_event_added, tr1::placeholders::_2)); CMD2_ANY_LIST("view.event_removed", tr1::bind(&apply_view_event, &core::ViewManager::set_event_removed, tr1::placeholders::_2)); // Cleanup and add . to view. CMD2_ANY_STRING("view.size", tr1::bind(&cmd_view_size, tr1::placeholders::_2)); CMD2_ANY_STRING("view.size_not_visible", tr1::bind(&cmd_view_size_not_visible, tr1::placeholders::_2)); CMD2_ANY_STRING("view.persistent", tr1::bind(&cmd_view_persistent, tr1::placeholders::_2)); CMD2_ANY_STRING_V("view.filter_all", tr1::bind(&core::View::filter, tr1::bind(&core::ViewManager::find_ptr_throw, control->view_manager(), tr1::placeholders::_2))); CMD2_DL_STRING ("view.filter_download", tr1::bind(&cmd_view_filter_download, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_STRING ("view.set_visible", tr1::bind(&cmd_view_set_visible, tr1::placeholders::_1, tr1::placeholders::_2)); CMD2_DL_STRING ("view.set_not_visible", tr1::bind(&cmd_view_set_not_visible, tr1::placeholders::_1, tr1::placeholders::_2)); // Commands that affect the default rtorrent UI. CMD2_DL ("ui.unfocus_download", tr1::bind(&cmd_ui_unfocus_download, tr1::placeholders::_1)); CMD2_ANY_STRING("ui.current_view.set", tr1::bind(&cmd_ui_set_view, tr1::placeholders::_2)); // Move. CMD2_ANY("print", &apply_print); CMD2_ANY("cat", &apply_cat); CMD2_ANY("if", tr1::bind(&apply_if, tr1::placeholders::_1, tr1::placeholders::_2, 0)); CMD2_ANY("not", &apply_not); CMD2_ANY("false", &apply_false); CMD2_ANY("and", &apply_and); CMD2_ANY("or", &apply_or); // A temporary command for handling stuff until we get proper // support for seperation of commands and literals. CMD2_ANY("branch", tr1::bind(&apply_if, tr1::placeholders::_1, tr1::placeholders::_2, 1)); CMD2_ANY_LIST("less", &apply_less); CMD2_ANY_LIST("greater", &apply_greater); CMD2_ANY_LIST("equal", &apply_equal); CMD2_ANY_VALUE("convert.gm_time", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0)); CMD2_ANY_VALUE("convert.gm_date", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x2)); CMD2_ANY_VALUE("convert.time", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x1)); CMD2_ANY_VALUE("convert.date", tr1::bind(&apply_to_time, tr1::placeholders::_2, 0x1 | 0x2)); CMD2_ANY_VALUE("convert.elapsed_time", tr1::bind(&apply_to_elapsed_time, tr1::placeholders::_2)); CMD2_ANY_VALUE("convert.kb", tr1::bind(&apply_to_kb, tr1::placeholders::_2)); CMD2_ANY_VALUE("convert.mb", tr1::bind(&apply_to_mb, tr1::placeholders::_2)); CMD2_ANY_VALUE("convert.xb", tr1::bind(&apply_to_xb, tr1::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", tr1::bind(&apply_to_throttle, tr1::placeholders::_2)); CMD2_ANY_LIST ("elapsed.less", tr1::bind(&apply_elapsed_less, tr1::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", tr1::bind(&apply_elapsed_greater, tr1::placeholders::_2)); } rtorrent-0.9.6/src/control.cc000066400000000000000000000124241257211462100161670ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "core/manager.h" #include "core/download_store.h" #include "core/view_manager.h" #include "core/dht_manager.h" #include "core/http_queue.h" #include "display/canvas.h" #include "display/window.h" #include "display/manager.h" #include "input/manager.h" #include "input/input_event.h" #include "rpc/command_scheduler.h" #include "rpc/parse_commands.h" #include "rpc/scgi.h" #include "rpc/object_storage.h" #include "ui/root.h" #include "control.h" Control::Control() : m_ui(new ui::Root()), m_display(new display::Manager()), m_input(new input::Manager()), m_inputStdin(new input::InputEvent(STDIN_FILENO)), m_commandScheduler(new rpc::CommandScheduler()), m_objectStorage(new rpc::object_storage()), m_tick(0), m_shutdownReceived(false), m_shutdownQuick(false) { m_core = new core::Manager(); m_viewManager = new core::ViewManager(); m_dhtManager = new core::DhtManager(); m_inputStdin->slot_pressed(std::tr1::bind(&input::Manager::pressed, m_input, std::tr1::placeholders::_1)); m_taskShutdown.slot() = std::tr1::bind(&Control::handle_shutdown, this); m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log_std)); } Control::~Control() { delete m_inputStdin; delete m_input; delete m_viewManager; delete m_ui; delete m_display; delete m_core; delete m_dhtManager; delete m_commandScheduler; delete m_objectStorage; } void Control::initialize() { display::Canvas::initialize(); display::Window::slot_schedule(rak::make_mem_fun(m_display, &display::Manager::schedule)); display::Window::slot_unschedule(rak::make_mem_fun(m_display, &display::Manager::unschedule)); display::Window::slot_adjust(rak::make_mem_fun(m_display, &display::Manager::adjust_layout)); m_core->http_stack()->set_user_agent(USER_AGENT); m_core->initialize_second(); m_core->listen_open(); m_core->download_store()->enable(rpc::call_command_value("session.use_lock")); m_core->set_hashing_view(*m_viewManager->find_throw("hashing")); m_ui->init(this); m_inputStdin->insert(torrent::main_thread()->poll()); } void Control::cleanup() { // delete m_scgi; m_scgi = NULL; rpc::xmlrpc.cleanup(); priority_queue_erase(&taskScheduler, &m_taskShutdown); m_inputStdin->remove(torrent::main_thread()->poll()); m_core->download_store()->disable(); m_ui->cleanup(); m_core->cleanup(); display::Canvas::erase_std(); display::Canvas::refresh_std(); display::Canvas::do_update(); display::Canvas::cleanup(); } void Control::cleanup_exception() { // delete m_scgi; m_scgi = NULL; display::Canvas::cleanup(); } bool Control::is_shutdown_completed() { if (!m_shutdownQuick || worker_thread->is_active()) return false; // Tracker requests can be disowned, so wait for these to // finish. The edge case of torrent http downloads may delay // shutdown. if (!core()->http_stack()->empty() || !core()->http_queue()->empty()) return false; return torrent::is_inactive(); } void Control::handle_shutdown() { if (!m_shutdownQuick) { // Temporary hack: if (worker_thread->is_active()) worker_thread->queue_item(&ThreadBase::stop_thread); torrent::connection_manager()->listen_close(); m_core->shutdown(false); if (!m_taskShutdown.is_queued()) priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + rak::timer::from_seconds(5)); } else { // Temporary hack: if (worker_thread->is_active()) worker_thread->queue_item(&ThreadBase::stop_thread); m_core->shutdown(true); } m_shutdownQuick = true; m_shutdownReceived = false; } rtorrent-0.9.6/src/control.h000066400000000000000000000105301257211462100160250ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CONTROL_H #define RTORRENT_CONTROL_H #include #include #include #include #include namespace ui { class Root; } namespace core { class Manager; class ViewManager; class DhtManager; } namespace display { class Manager; } namespace input { class InputEvent; class Manager; } namespace rpc { class CommandScheduler; class XmlRpc; class object_storage; } class Control { public: Control(); ~Control(); bool is_shutdown_completed(); bool is_shutdown_received() { return m_shutdownReceived; } bool is_shutdown_started() { return m_shutdownQuick; } void initialize(); void cleanup(); void cleanup_exception(); void handle_shutdown(); void receive_normal_shutdown() { m_shutdownReceived = true; __sync_synchronize(); } void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; __sync_synchronize(); } core::Manager* core() { return m_core; } core::ViewManager* view_manager() { return m_viewManager; } core::DhtManager* dht_manager() { return m_dhtManager; } ui::Root* ui() { return m_ui; } display::Manager* display() { return m_display; } input::Manager* input() { return m_input; } input::InputEvent* input_stdin() { return m_inputStdin; } rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; } rpc::object_storage* object_storage() { return m_objectStorage; } uint64_t tick() const { return m_tick; } void inc_tick() { m_tick++; } const std::string& working_directory() const { return m_workingDirectory; } void set_working_directory(const std::string& dir); private: Control(const Control&); void operator = (const Control&); core::Manager* m_core; core::ViewManager* m_viewManager; core::DhtManager* m_dhtManager; ui::Root* m_ui; display::Manager* m_display; input::Manager* m_input; input::InputEvent* m_inputStdin; rpc::CommandScheduler* m_commandScheduler; rpc::object_storage* m_objectStorage; uint64_t m_tick; mode_t m_umask; std::string m_workingDirectory; rak::priority_item m_taskShutdown; bool m_shutdownReceived lt_cacheline_aligned; bool m_shutdownQuick lt_cacheline_aligned; }; #endif rtorrent-0.9.6/src/core/000077500000000000000000000000001257211462100151255ustar00rootroot00000000000000rtorrent-0.9.6/src/core/Makefile.am000066400000000000000000000011231257211462100171560ustar00rootroot00000000000000noinst_LIBRARIES = libsub_core.a libsub_core_a_SOURCES = \ curl_get.cc \ curl_get.h \ curl_socket.cc \ curl_socket.h \ curl_stack.cc \ curl_stack.h \ dht_manager.cc \ dht_manager.h \ download.cc \ download.h \ download_factory.cc \ download_factory.h \ download_list.cc \ download_list.h \ download_slot_map.h \ download_store.cc \ download_store.h \ http_queue.cc \ http_queue.h \ manager.cc \ manager.h \ poll_manager.cc \ poll_manager.h \ range_map.h \ view.cc \ view.h \ view_manager.cc \ view_manager.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/core/curl_get.cc000066400000000000000000000102041257211462100172350ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "globals.h" #include "curl_get.h" #include "curl_stack.h" namespace core { size_t curl_get_receive_write(void* data, size_t size, size_t nmemb, void* handle) { if (!((CurlGet*)handle)->stream()->write((const char*)data, size * nmemb).fail()) return size * nmemb; else return 0; } CurlGet::~CurlGet() { close(); } void CurlGet::start() { if (is_busy()) throw torrent::internal_error("Tried to call CurlGet::start on a busy object."); if (m_stream == NULL) throw torrent::internal_error("Tried to call CurlGet::start without a valid output stream."); m_handle = curl_easy_init(); if (m_handle == NULL) throw torrent::internal_error("Call to curl_easy_init() failed."); curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str()); curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &curl_get_receive_write); curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this); if (m_timeout != 0) { curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, (long)60); curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, (long)m_timeout); // Normally libcurl should handle the timeout. But sometimes that doesn't // work right so we do a fallback timeout that just aborts the transfer. m_taskTimeout.slot() = std::tr1::bind(&CurlGet::receive_timeout, this); priority_queue_erase(&taskScheduler, &m_taskTimeout); priority_queue_insert(&taskScheduler, &m_taskTimeout, cachedTime + rak::timer::from_seconds(m_timeout + 5)); } curl_easy_setopt(m_handle, CURLOPT_FORBID_REUSE, (long)1); curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1); curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1); curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5); curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(m_handle, CURLOPT_ENCODING, ""); m_stack->add_get(this); } void CurlGet::close() { priority_queue_erase(&taskScheduler, &m_taskTimeout); if (!is_busy()) return; m_stack->remove_get(this); curl_easy_cleanup(m_handle); m_handle = NULL; } void CurlGet::receive_timeout() { return m_stack->transfer_done(m_handle, "Timed out"); } double CurlGet::size_done() { double d = 0.0; curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD, &d); return d; } double CurlGet::size_total() { double d = 0.0; curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); return d; } } rtorrent-0.9.6/src/core/curl_get.h000066400000000000000000000051751257211462100171120ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_CURL_GET_H #define RTORRENT_CORE_CURL_GET_H #include #include #include #include #include "rak/priority_queue_default.h" namespace core { class CurlStack; class CurlGet : public torrent::Http { public: friend class CurlStack; CurlGet(CurlStack* s) : m_active(false), m_handle(NULL), m_stack(s) {} virtual ~CurlGet(); void start(); void close(); bool is_busy() const { return m_handle; } bool is_active() const { return m_active; } void set_active(bool a) { m_active = a; } double size_done(); double size_total(); CURL* handle() { return m_handle; } private: CurlGet(const CurlGet&); void operator = (const CurlGet&); void receive_timeout(); bool m_active; rak::priority_item m_taskTimeout; CURL* m_handle; CurlStack* m_stack; }; } #endif rtorrent-0.9.6/src/core/curl_socket.cc000066400000000000000000000077101257211462100177560ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2008, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "control.h" #include "curl_socket.h" #include "curl_stack.h" namespace core { int CurlSocket::receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp) { CurlStack* stack = (CurlStack*)userp; CurlSocket* socket = (CurlSocket*)socketp; if (what == CURL_POLL_REMOVE) { // We also probably need the special code here as we're not // guaranteed that the fd will be closed, afaik. if (socket != NULL) socket->close(); // TODO: Consider the possibility that we'll need to set the // fd-associated pointer curl holds to NULL. delete socket; return 0; } if (socket == NULL) { socket = stack->new_socket(fd); torrent::main_thread()->poll()->open(socket); // No interface for libcurl to signal when it's interested in error events. // Assume that hence it must always be interested in them. torrent::main_thread()->poll()->insert_error(socket); } if (what == CURL_POLL_NONE || what == CURL_POLL_OUT) torrent::main_thread()->poll()->remove_read(socket); else torrent::main_thread()->poll()->insert_read(socket); if (what == CURL_POLL_NONE || what == CURL_POLL_IN) torrent::main_thread()->poll()->remove_write(socket); else torrent::main_thread()->poll()->insert_write(socket); return 0; } CurlSocket::~CurlSocket() { if (m_fileDesc != -1) throw torrent::internal_error("CurlSocket::~CurlSocket() m_fileDesc != -1."); } void CurlSocket::close() { if (m_fileDesc == -1) throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1."); torrent::main_thread()->poll()->closed(this); m_fileDesc = -1; } void CurlSocket::event_read() { #if (LIBCURL_VERSION_NUM >= 0x071003) return m_stack->receive_action(this, CURL_CSELECT_IN); #else return m_stack->receive_action(this, 0); #endif } void CurlSocket::event_write() { #if (LIBCURL_VERSION_NUM >= 0x071003) return m_stack->receive_action(this, CURL_CSELECT_OUT); #else return m_stack->receive_action(this, 0); #endif } void CurlSocket::event_error() { #if (LIBCURL_VERSION_NUM >= 0x071003) return m_stack->receive_action(this, CURL_CSELECT_ERR); #else return m_stack->receive_action(this, 0); #endif } } rtorrent-0.9.6/src/core/curl_socket.h000066400000000000000000000045301257211462100176150ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2008, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_CURL_SOCKET_H #define RTORRENT_CORE_CURL_SOCKET_H #include #include "globals.h" namespace core { class CurlStack; class CurlSocket : public torrent::Event { public: CurlSocket(int fd, CurlStack* stack) : m_stack(stack) { m_fileDesc = fd; } ~CurlSocket(); const char* type_name() const { return "curl"; } void close(); static int receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp); private: CurlSocket(const CurlSocket&); void operator = (const CurlSocket&); virtual void event_read(); virtual void event_write(); virtual void event_error(); CurlStack* m_stack; }; } #endif rtorrent-0.9.6/src/core/curl_stack.cc000066400000000000000000000170131257211462100175700ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "rak/functional.h" #include "curl_get.h" #include "curl_socket.h" #include "curl_stack.h" namespace core { CurlStack::CurlStack() : m_handle((void*)curl_multi_init()), m_active(0), m_maxActive(32), m_ssl_verify_peer(true), m_dns_timeout(60) { m_taskTimeout.slot() = std::tr1::bind(&CurlStack::receive_timeout, this); #if (LIBCURL_VERSION_NUM >= 0x071000) curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this); curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout); #endif curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this); curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket); } CurlStack::~CurlStack() { while (!empty()) front()->close(); curl_multi_cleanup((CURLM*)m_handle); priority_queue_erase(&taskScheduler, &m_taskTimeout); } CurlGet* CurlStack::new_object() { return new CurlGet(this); } CurlSocket* CurlStack::new_socket(int fd) { CurlSocket* socket = new CurlSocket(fd, this); curl_multi_assign((CURLM*)m_handle, fd, socket); return socket; } void CurlStack::receive_action(CurlSocket* socket, int events) { CURLMcode code; do { int count; #if (LIBCURL_VERSION_NUM >= 0x071003) code = curl_multi_socket_action((CURLM*)m_handle, socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT, events, &count); #else code = curl_multi_socket((CURLM*)m_handle, socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT, &count); #endif if (code > 0) throw torrent::internal_error("Error calling curl_multi_socket_action."); // Socket might be removed when cleaning handles below, future // calls should not use it. socket = NULL; events = 0; if ((unsigned int)count != size()) { while (process_done_handle()) ; // Do nothing. if (empty()) priority_queue_erase(&taskScheduler, &m_taskTimeout); } } while (code == CURLM_CALL_MULTI_PERFORM); } bool CurlStack::process_done_handle() { int remaining_msgs = 0; CURLMsg* msg = curl_multi_info_read((CURLM*)m_handle, &remaining_msgs); if (msg == NULL) return false; if (msg->msg != CURLMSG_DONE) throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE."); transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result)); return remaining_msgs != 0; } void CurlStack::transfer_done(void* handle, const char* msg) { iterator itr = std::find_if(begin(), end(), rak::equal(handle, std::mem_fun(&CurlGet::handle))); if (itr == end()) throw torrent::internal_error("Could not find CurlGet with the right easy_handle."); if (msg == NULL) (*itr)->trigger_done(); else (*itr)->trigger_failed(msg); } void CurlStack::receive_timeout() { receive_action(NULL, 0); // Sometimes libcurl forgets to reset the timeout. Try to poll the value in that case, or use 10 seconds. if (!empty() && !m_taskTimeout.is_queued()) { long timeout; curl_multi_timeout((CURLM*)m_handle, &timeout); priority_queue_insert(&taskScheduler, &m_taskTimeout, cachedTime + rak::timer::from_milliseconds(std::max(timeout, 10000))); } } void CurlStack::add_get(CurlGet* get) { if (!m_userAgent.empty()) curl_easy_setopt(get->handle(), CURLOPT_USERAGENT, m_userAgent.c_str()); if (!m_httpProxy.empty()) curl_easy_setopt(get->handle(), CURLOPT_PROXY, m_httpProxy.c_str()); if (!m_bindAddress.empty()) curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bindAddress.c_str()); if (!m_httpCaPath.empty()) curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_httpCaPath.c_str()); if (!m_httpCaCert.empty()) curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_httpCaCert.c_str()); curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)m_ssl_verify_peer); curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout); base_type::push_back(get); if (m_active >= m_maxActive) return; m_active++; get->set_active(true); if (curl_multi_add_handle((CURLM*)m_handle, get->handle()) > 0) throw torrent::internal_error("Error calling curl_multi_add_handle."); #if (LIBCURL_VERSION_NUM < 0x071000) receive_timeout(); #endif } void CurlStack::remove_get(CurlGet* get) { iterator itr = std::find(begin(), end(), get); if (itr == end()) throw torrent::internal_error("Could not find CurlGet when calling CurlStack::remove."); base_type::erase(itr); // The CurlGet object was never activated, so we just skip this one. if (!get->is_active()) return; get->set_active(false); if (curl_multi_remove_handle((CURLM*)m_handle, get->handle()) > 0) throw torrent::internal_error("Error calling curl_multi_remove_handle."); if (m_active == m_maxActive && (itr = std::find_if(begin(), end(), std::not1(std::mem_fun(&CurlGet::is_active)))) != end()) { (*itr)->set_active(true); if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0) throw torrent::internal_error("Error calling curl_multi_add_handle."); } else { m_active--; } } void CurlStack::global_init() { curl_global_init(CURL_GLOBAL_ALL); } void CurlStack::global_cleanup() { curl_global_cleanup(); } // TODO: Is this function supposed to set a per-handle timeout, or is // it the shortest timeout amongst all handles? int CurlStack::set_timeout(void* handle, long timeout_ms, void* userp) { CurlStack* stack = (CurlStack*)userp; priority_queue_erase(&taskScheduler, &stack->m_taskTimeout); priority_queue_insert(&taskScheduler, &stack->m_taskTimeout, cachedTime + rak::timer::from_milliseconds(timeout_ms)); return 0; } } rtorrent-0.9.6/src/core/curl_stack.h000066400000000000000000000121171257211462100174320ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_CURL_STACK_H #define RTORRENT_CORE_CURL_STACK_H #include #include #include "rak/priority_queue_default.h" namespace core { class CurlGet; class CurlSocket; // By using a deque instead of vector we allow for cheaper removal of // the oldest elements, those that will be first in the in the // deque. // // This should fit well with the use-case of a http stack, thus // we get most of the cache locality benefits of a vector with fast // removal of elements. class CurlStack : std::deque { public: friend class CurlGet; typedef std::deque base_type; using base_type::value_type; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::back; using base_type::front; using base_type::size; using base_type::empty; CurlStack(); ~CurlStack(); CurlGet* new_object(); CurlSocket* new_socket(int fd); unsigned int active() const { return m_active; } unsigned int max_active() const { return m_maxActive; } void set_max_active(unsigned int a) { m_maxActive = a; } const std::string& user_agent() const { return m_userAgent; } const std::string& http_proxy() const { return m_httpProxy; } const std::string& bind_address() const { return m_bindAddress; } const std::string& http_capath() const { return m_httpCaPath; } const std::string& http_cacert() const { return m_httpCaCert; } void set_user_agent(const std::string& s) { m_userAgent = s; } void set_http_proxy(const std::string& s) { m_httpProxy = s; } void set_bind_address(const std::string& s) { m_bindAddress = s; } void set_http_capath(const std::string& s) { m_httpCaPath = s; } void set_http_cacert(const std::string& s) { m_httpCaCert = s; } bool ssl_verify_peer() const { return m_ssl_verify_peer; } void set_ssl_verify_peer(bool s) { m_ssl_verify_peer = s; } long dns_timeout() const { return m_dns_timeout; } void set_dns_timeout(long timeout) { m_dns_timeout = timeout; } static void global_init(); static void global_cleanup(); void receive_action(CurlSocket* socket, int type); static int set_timeout(void* handle, long timeout_ms, void* userp); void transfer_done(void* handle, const char* msg); protected: void add_get(CurlGet* get); void remove_get(CurlGet* get); private: CurlStack(const CurlStack&); void operator = (const CurlStack&); void receive_timeout(); bool process_done_handle(); void* m_handle; unsigned int m_active; unsigned int m_maxActive; rak::priority_item m_taskTimeout; std::string m_userAgent; std::string m_httpProxy; std::string m_bindAddress; std::string m_httpCaPath; std::string m_httpCaCert; bool m_ssl_verify_peer; long m_dns_timeout; }; } #endif rtorrent-0.9.6/src/core/dht_manager.cc000066400000000000000000000262071257211462100177140ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "globals.h" #include "control.h" #include "dht_manager.h" #include "download.h" #include "download_store.h" #include "manager.h" namespace core { const char* DhtManager::dht_settings[dht_settings_num] = { "disable", "off", "auto", "on" }; DhtManager::~DhtManager() { priority_queue_erase(&taskScheduler, &m_updateTimeout); priority_queue_erase(&taskScheduler, &m_stopTimeout); } void DhtManager::load_dht_cache() { if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) return; torrent::Object cache = torrent::Object::create_map(); std::fstream cache_file((control->core()->download_store()->path() + "rtorrent.dht_cache").c_str(), std::ios::in | std::ios::binary); if (cache_file.is_open()) { cache_file >> cache; // If the cache file is corrupted we will just discard it with an // error message. if (cache_file.fail()) { lt_log_print(torrent::LOG_DHT_WARN, "DHT cache file corrupted, discarding."); cache = torrent::Object::create_map(); } } try { torrent::dht_manager()->initialize(cache); if (m_start == dht_on) start_dht(); } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_DHT_WARN, "DHT failed: %s", e.what()); } } void DhtManager::start_dht() { priority_queue_erase(&taskScheduler, &m_stopTimeout); if (!torrent::dht_manager()->is_valid() || torrent::dht_manager()->is_active()) return; torrent::ThrottlePair throttles = control->core()->get_throttle(m_throttleName); torrent::dht_manager()->set_upload_throttle(throttles.first); torrent::dht_manager()->set_download_throttle(throttles.second); int port = rpc::call_command_value("dht.port"); if (port <= 0) return; lt_log_print(torrent::LOG_DHT_INFO, "Starting DHT server on port %d.", port); try { torrent::dht_manager()->start(port); torrent::dht_manager()->reset_statistics(); m_updateTimeout.slot() = std::tr1::bind(&DhtManager::update, this); priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds()); m_dhtPrevCycle = 0; m_dhtPrevQueriesSent = 0; m_dhtPrevRepliesReceived = 0; m_dhtPrevQueriesReceived = 0; m_dhtPrevBytesUp = 0; m_dhtPrevBytesDown = 0; } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_DHT_ERROR, "DHT start failed: %s", e.what()); m_start = dht_off; } } void DhtManager::stop_dht() { priority_queue_erase(&taskScheduler, &m_updateTimeout); priority_queue_erase(&taskScheduler, &m_stopTimeout); if (torrent::dht_manager()->is_active()) { log_statistics(true); lt_log_print(torrent::LOG_DHT_INFO, "Stopping DHT server."); torrent::dht_manager()->stop(); } } void DhtManager::save_dht_cache() { if (!control->core()->download_store()->is_enabled() || !torrent::dht_manager()->is_valid()) return; std::string filename = control->core()->download_store()->path() + "rtorrent.dht_cache"; std::string filename_tmp = filename + ".new"; std::fstream cache_file(filename_tmp.c_str(), std::ios::out | std::ios::trunc); if (!cache_file.is_open()) return; torrent::Object cache = torrent::Object::create_map(); cache_file << *torrent::dht_manager()->store_cache(&cache); if (!cache_file.good()) return; cache_file.close(); ::rename(filename_tmp.c_str(), filename.c_str()); } void DhtManager::set_mode(const std::string& arg) { int i; for (i = 0; i < dht_settings_num; i++) { if (arg == dht_settings[i]) { m_start = i; break; } } if (i == dht_settings_num) throw torrent::input_error("Invalid argument."); if (m_start == dht_off) stop_dht(); else if (m_start == dht_on) start_dht(); } void DhtManager::update() { if (!torrent::dht_manager()->is_active()) throw torrent::internal_error("DhtManager::update called with DHT inactive."); if (m_start == dht_auto && !m_stopTimeout.is_queued()) { DownloadList::const_iterator itr, end; for (itr = control->core()->download_list()->begin(), end = control->core()->download_list()->end(); itr != end; ++itr) if ((*itr)->download()->info()->is_active() && !(*itr)->download()->info()->is_private()) break; if (itr == end) { m_stopTimeout.slot() = std::tr1::bind(&DhtManager::stop_dht, this); priority_queue_insert(&taskScheduler, &m_stopTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds()); } } // While bootstrapping (log_statistics returns true), check every minute if it completed, otherwise update every 15 minutes. if (log_statistics(false)) priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(60)).round_seconds()); else priority_queue_insert(&taskScheduler, &m_updateTimeout, (cachedTime + rak::timer::from_seconds(15 * 60)).round_seconds()); } bool DhtManager::log_statistics(bool force) { torrent::DhtManager::statistics_type stats = torrent::dht_manager()->get_statistics(); // Check for firewall problems. if (stats.cycle > 2 && stats.queries_sent - m_dhtPrevQueriesSent > 100 && stats.queries_received == m_dhtPrevQueriesReceived) { // We should have had clients ping us at least but have received // nothing, that means the UDP port is probably unreachable. if (torrent::dht_manager()->can_receive_queries()) lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be unreachable, no queries received."); torrent::dht_manager()->set_can_receive(false); } if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) { // No replies to over 20 queries plus two per node we have. Probably firewalled. if (!m_warned) lt_log_print(torrent::LOG_DHT_WARN, "DHT port appears to be firewalled, no replies received."); m_warned = true; return false; } m_warned = false; if (stats.queries_received > m_dhtPrevQueriesReceived) torrent::dht_manager()->set_can_receive(true); // Nothing to log while bootstrapping, but check again every minute. if (stats.cycle <= 1) { m_dhtPrevCycle = stats.cycle; return true; } // If bootstrap completed between now and the previous check, notify user. if (m_dhtPrevCycle == 1) { char buffer[128]; snprintf(buffer, sizeof(buffer), "DHT bootstrap complete, have %d nodes in %d buckets.", stats.num_nodes, stats.num_buckets); control->core()->push_log_complete(buffer); m_dhtPrevCycle = stats.cycle; return false; }; // Standard DHT statistics on first real cycle, and every 8th cycle // afterwards (i.e. every 2 hours), or when forced. if ((force && stats.cycle != m_dhtPrevCycle) || stats.cycle == 3 || stats.cycle > m_dhtPrevCycle + 7) { char buffer[256]; snprintf(buffer, sizeof(buffer), "DHT statistics: %d queries in, %d queries out, %d replies received, %lld bytes read, %lld bytes sent, " "%d known nodes in %d buckets, %d peers (highest: %d) tracked in %d torrents.", stats.queries_received - m_dhtPrevQueriesReceived, stats.queries_sent - m_dhtPrevQueriesSent, stats.replies_received - m_dhtPrevRepliesReceived, (long long unsigned int)(stats.down_rate.total() - m_dhtPrevBytesDown), (long long unsigned int)(stats.up_rate.total() - m_dhtPrevBytesUp), stats.num_nodes, stats.num_buckets, stats.num_peers, stats.max_peers, stats.num_trackers); control->core()->push_log_complete(buffer); m_dhtPrevCycle = stats.cycle; m_dhtPrevQueriesSent = stats.queries_sent; m_dhtPrevRepliesReceived = stats.replies_received; m_dhtPrevQueriesReceived = stats.queries_received; m_dhtPrevBytesUp = stats.up_rate.total(); m_dhtPrevBytesDown = stats.down_rate.total(); } return false; } torrent::Object DhtManager::dht_statistics() { torrent::Object dhtStats = torrent::Object::create_map(); dhtStats.insert_key("dht", dht_settings[m_start]); dhtStats.insert_key("active", torrent::dht_manager()->is_active()); dhtStats.insert_key("throttle", m_throttleName); if (torrent::dht_manager()->is_active()) { torrent::DhtManager::statistics_type stats = torrent::dht_manager()->get_statistics(); dhtStats.insert_key("cycle", stats.cycle); dhtStats.insert_key("queries_received", stats.queries_received); dhtStats.insert_key("queries_sent", stats.queries_sent); dhtStats.insert_key("replies_received", stats.replies_received); dhtStats.insert_key("errors_received", stats.errors_received); dhtStats.insert_key("errors_caught", stats.errors_caught); dhtStats.insert_key("bytes_read", stats.down_rate.total()); dhtStats.insert_key("bytes_written", stats.up_rate.total()); dhtStats.insert_key("nodes", stats.num_nodes); dhtStats.insert_key("buckets", stats.num_buckets); dhtStats.insert_key("peers", stats.num_peers); dhtStats.insert_key("peers_max", stats.max_peers); dhtStats.insert_key("torrents", stats.num_trackers); } return dhtStats; } void DhtManager::set_throttle_name(const std::string& throttleName) { if (torrent::dht_manager()->is_active()) throw torrent::input_error("Cannot set DHT throttle while active."); m_throttleName = throttleName; } } rtorrent-0.9.6/src/core/dht_manager.h000066400000000000000000000062061257211462100175530ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_DHT_MANAGER_H #define RTORRENT_CORE_DHT_MANAGER_H #include #include namespace core { class DhtManager { public: DhtManager() : m_warned(false), m_start(dht_off) { } ~DhtManager(); void load_dht_cache(); void save_dht_cache(); torrent::Object dht_statistics(); void start_dht(); void stop_dht(); void auto_start() { if (m_start == dht_auto) start_dht(); } void set_mode(const std::string& arg); void set_throttle_name(const std::string& throttleName); const std::string& throttle_name() const { return m_throttleName; } private: static const int dht_disable = 0; static const int dht_off = 1; static const int dht_auto = 2; static const int dht_on = 3; static const int dht_settings_num = 4; static const char* dht_settings[dht_settings_num]; void update(); bool log_statistics(bool force); unsigned int m_dhtPrevCycle; unsigned int m_dhtPrevQueriesSent; unsigned int m_dhtPrevRepliesReceived; unsigned int m_dhtPrevQueriesReceived; uint64_t m_dhtPrevBytesUp; uint64_t m_dhtPrevBytesDown; rak::priority_item m_updateTimeout; rak::priority_item m_stopTimeout; bool m_warned; int m_start; std::string m_throttleName; }; } #endif rtorrent-0.9.6/src/core/download.cc000066400000000000000000000134451257211462100172520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "control.h" #include "download.h" #include "manager.h" namespace core { Download::Download(download_type d) : m_download(d), m_hashFailed(false), m_resumeFlags(~uint32_t()), m_group(0) { m_download.info()->signal_tracker_success().push_back(tr1::bind(&Download::receive_tracker_msg, this, "")); m_download.info()->signal_tracker_failed().push_back(tr1::bind(&Download::receive_tracker_msg, this, tr1::placeholders::_1)); } Download::~Download() { if (!m_download.is_valid()) return; m_download = download_type(); } void Download::enable_udp_trackers(bool state) { for (torrent::TrackerList::iterator itr = m_download.tracker_list()->begin(), last = m_download.tracker_list()->end(); itr != last; ++itr) if ((*itr)->type() == torrent::Tracker::TRACKER_UDP) { if (state) (*itr)->enable(); else (*itr)->disable(); } } uint32_t Download::priority() { return bencode()->get_key("rtorrent").get_key_value("priority"); } void Download::set_priority(uint32_t p) { p %= 4; // Seeding torrents get half the priority of unfinished torrents. if (!is_done()) torrent::download_set_priority(m_download, p * p * 2); else torrent::download_set_priority(m_download, p * p); bencode()->get_key("rtorrent").insert_key("priority", (int64_t)p); } uint32_t Download::connection_list_size() const { return m_download.connection_list()->size(); } void Download::receive_tracker_msg(std::string msg) { if (msg.empty()) m_message = ""; else m_message = "Tracker: [" + msg + "]"; } float Download::distributed_copies() const { const uint8_t* avail = m_download.chunks_seen(); const torrent::Bitfield* bitfield = m_download.file_list()->bitfield(); if (avail == NULL) return 0; int minAvail = std::numeric_limits::max(); int num = 0; for (uint32_t i = m_download.file_list()->size_chunks(); i-- > 0; ) { int totAvail = (int)avail[i] + bitfield->get(i); if (totAvail == minAvail) { num++; } else if (totAvail < minAvail) { minAvail = totAvail; num = 1; } } return minAvail + 1 - bitfield->is_all_set() - (float)num / m_download.file_list()->size_chunks(); } void Download::set_throttle_name(const std::string& throttleName) { if (m_download.info()->is_active()) throw torrent::input_error("Cannot set throttle on active download."); torrent::ThrottlePair throttles = control->core()->get_throttle(throttleName); m_download.set_upload_throttle(throttles.first); m_download.set_download_throttle(throttles.second); m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", throttleName); } void Download::set_root_directory(const std::string& path) { // If the download is open, hashed and has completed chunks make // sure to verify that the download files are still present. // // This should ensure that no one tries to set the destination // directory 'after' moving files. In cases where the user wants to // override this behavior the download must first be closed or // 'd.directory_base.set' may be used. rak::file_stat file_stat; torrent::FileList* file_list = m_download.file_list(); if (is_hash_checked() && file_list->completed_chunks() != 0 && (file_list->is_multi_file() ? !file_list->is_root_dir_created() : !file_stat.update(file_list->front()->frozen_path()))) { set_message("Cannot change the directory of an open download after the files have been moved."); rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(this)); control->core()->download_list()->close_directly(this); throw torrent::input_error("Cannot change the directory of an open download atter the files have been moved."); } control->core()->download_list()->close_directly(this); file_list->set_root_dir(rak::path_expand(path)); bencode()->get_key("rtorrent").insert_key("directory", path); } } rtorrent-0.9.6/src/core/download.h000066400000000000000000000151561257211462100171150ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_DOWNLOAD_H #define RTORRENT_CORE_DOWNLOAD_H #include #include #include #include #include #include #include "globals.h" namespace torrent { class PeerList; class TrackerList; } namespace core { class Download { public: typedef torrent::Download download_type; typedef torrent::FileList file_list_type; typedef torrent::PeerList peer_list_type; typedef torrent::TrackerList tracker_list_type; typedef torrent::TrackerController tracker_controller_type; typedef torrent::ConnectionList connection_list_type; typedef download_type::ConnectionType connection_type; static const int variable_hashing_stopped = 0; static const int variable_hashing_initial = 1; static const int variable_hashing_last = 2; static const int variable_hashing_rehash = 3; Download(download_type d); ~Download(); const torrent::DownloadInfo* info() const { return m_download.info(); } const torrent::download_data* data() const { return m_download.data(); } torrent::DownloadMain* main() { return m_download.main(); } bool is_open() const { return m_download.info()->is_open(); } bool is_active() const { return m_download.info()->is_active(); } bool is_done() const { return m_download.file_list()->is_done(); } bool is_downloading() const { return is_active() && !is_done(); } bool is_seeding() const { return is_active() && is_done(); } // FIXME: Fixed a bug in libtorrent that caused is_hash_checked to // return true when the torrent is closed. Remove this redundant // test in the next milestone. bool is_hash_checked() const { return is_open() && m_download.is_hash_checked(); } bool is_hash_checking() const { return m_download.is_hash_checking(); } bool is_hash_failed() const { return m_hashFailed; } void set_hash_failed(bool v) { m_hashFailed = v; } download_type* download() { return &m_download; } const download_type* c_download() const { return &m_download; } file_list_type* file_list() { return m_download.file_list(); } const file_list_type* c_file_list() const { return m_download.file_list(); } peer_list_type* peer_list() { return m_download.peer_list(); } const peer_list_type* c_peer_list() const { return m_download.peer_list(); } torrent::Object* bencode() { return m_download.bencode(); } tracker_list_type* tracker_list() { return m_download.tracker_list(); } uint32_t tracker_list_size() const { return m_download.tracker_list()->size(); } tracker_controller_type* tracker_controller() { return m_download.tracker_controller(); } connection_list_type* connection_list() { return m_download.connection_list(); } uint32_t connection_list_size() const; const std::string& message() const { return m_message; } void set_message(const std::string& msg) { m_message = msg; } void enable_udp_trackers(bool state); uint32_t priority(); void set_priority(uint32_t p); uint32_t resume_flags() { return m_resumeFlags; } void set_resume_flags(uint32_t flags) { m_resumeFlags = flags; } void set_root_directory(const std::string& path); void set_throttle_name(const std::string& throttleName); bool operator == (const std::string& str) const; float distributed_copies() const; // HACK: Choke group setting. unsigned int group() const { return m_group; } void set_group(unsigned int g) { m_group = g; } private: Download(const Download&); void operator () (const Download&); void receive_tracker_msg(std::string msg); void receive_chunk_failed(uint32_t idx); // Store the FileList instance so we can use slots etc on it. download_type m_download; bool m_hashFailed; std::string m_message; uint32_t m_resumeFlags; unsigned int m_group; }; inline bool Download::operator == (const std::string& str) const { return str.size() == torrent::HashString::size_data && *torrent::HashString::cast_from(str) == m_download.info()->hash(); } } #endif rtorrent-0.9.6/src/core/download_factory.cc000066400000000000000000000406051257211462100207770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "curl_get.h" #include "control.h" #include "http_queue.h" #include "globals.h" #include "manager.h" #include "download.h" #include "download_factory.h" #include "download_store.h" namespace core { bool is_network_uri(const std::string& uri) { return std::strncmp(uri.c_str(), "http://", 7) == 0 || std::strncmp(uri.c_str(), "https://", 8) == 0 || std::strncmp(uri.c_str(), "ftp://", 6) == 0; } static bool download_factory_add_stream(torrent::Object* root, const char* key, const char* filename) { std::fstream stream(filename, std::ios::in | std::ios::binary); if (!stream.is_open()) return false; torrent::Object obj; stream >> obj; if (!stream.good()) return false; root->insert_key_move(key, obj); return true; } bool is_magnet_uri(const std::string& uri) { return std::strncmp(uri.c_str(), "magnet:?", 8) == 0; } DownloadFactory::DownloadFactory(Manager* m) : m_manager(m), m_stream(NULL), m_object(NULL), m_commited(false), m_loaded(false), m_session(false), m_start(false), m_printLog(true), m_isFile(false) { m_taskLoad.slot() = std::tr1::bind(&DownloadFactory::receive_load, this); m_taskCommit.slot() = std::tr1::bind(&DownloadFactory::receive_commit, this); // m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech"); // m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed"); m_variables["connection_leech"] = std::string(); m_variables["connection_seed"] = std::string(); m_variables["directory"] = rpc::call_command("directory.default"); m_variables["tied_to_file"] = torrent::Object((int64_t)false); } DownloadFactory::~DownloadFactory() { priority_queue_erase(&taskScheduler, &m_taskLoad); priority_queue_erase(&taskScheduler, &m_taskCommit); delete m_stream; delete m_object; m_stream = NULL; } void DownloadFactory::load(const std::string& uri) { m_uri = uri; priority_queue_insert(&taskScheduler, &m_taskLoad, cachedTime); } // This function must be called before DownloadFactory::commit(). void DownloadFactory::load_raw_data(const std::string& input) { if (m_stream) throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL"); m_stream = new std::stringstream(input); m_loaded = true; } void DownloadFactory::commit() { priority_queue_insert(&taskScheduler, &m_taskCommit, cachedTime); } void DownloadFactory::receive_load() { if (m_stream) throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL"); if (is_network_uri(m_uri)) { // Http handling here. m_stream = new std::stringstream; HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream); (*itr)->signal_done().push_front(std::tr1::bind(&DownloadFactory::receive_loaded, this)); (*itr)->signal_failed().push_front(std::tr1::bind(&DownloadFactory::receive_failed, this, std::tr1::placeholders::_1)); m_variables["tied_to_file"] = (int64_t)false; } else if (is_magnet_uri(m_uri)) { // DEBUG: Use m_object. m_stream = new std::stringstream(); *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e"; m_variables["tied_to_file"] = (int64_t)false; receive_loaded(); } else { std::fstream stream(rak::path_expand(m_uri).c_str(), std::ios::in | std::ios::binary); if (!stream.is_open()) return receive_failed("Could not open file"); m_object = new torrent::Object; stream >> *m_object; if (!stream.good()) return receive_failed("Reading torrent file failed"); m_isFile = true; receive_loaded(); } } void DownloadFactory::receive_loaded() { m_loaded = true; if (m_commited) receive_success(); } void DownloadFactory::receive_commit() { m_commited = true; if (m_loaded) receive_success(); } void DownloadFactory::receive_success() { Download* download = m_stream != NULL ? m_manager->download_list()->create(m_stream, m_printLog) : m_manager->download_list()->create(m_object, m_printLog); m_object = NULL; if (download == NULL) { // core::Manager should already have added the error message to // the log. m_slot_finished(); return; } torrent::Object* root = download->bencode(); if (download->download()->info()->is_meta_download()) { torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map()); meta.insert_key("start", m_start); meta.insert_key("print_log", m_printLog); torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list(); for (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr) commands.push_back(*itr); } if (m_session) { download_factory_add_stream(root, "rtorrent", (rak::path_expand(m_uri) + ".rtorrent").c_str()); download_factory_add_stream(root, "libtorrent_resume", (rak::path_expand(m_uri) + ".libtorrent_resume").c_str()); } else { // We only allow session torrents to keep their // 'rtorrent/libtorrent' sections. The "fast_resume" section // should be safe to keep. root->erase_key("rtorrent"); } torrent::Object* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second; torrent::Object& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second; initialize_rtorrent(download, rtorrent); if (!rtorrent->has_key_string("custom1")) rtorrent->insert_key("custom1", std::string()); if (!rtorrent->has_key_string("custom2")) rtorrent->insert_key("custom2", std::string()); if (!rtorrent->has_key_string("custom3")) rtorrent->insert_key("custom3", std::string()); if (!rtorrent->has_key_string("custom4")) rtorrent->insert_key("custom4", std::string()); if (!rtorrent->has_key_string("custom5")) rtorrent->insert_key("custom5", std::string()); rpc::call_command("d.uploads_min.set", rpc::call_command("throttle.min_uploads"), rpc::make_target(download)); rpc::call_command("d.uploads_max.set", rpc::call_command("throttle.max_uploads"), rpc::make_target(download)); rpc::call_command("d.downloads_min.set", rpc::call_command("throttle.min_downloads"), rpc::make_target(download)); rpc::call_command("d.downloads_max.set", rpc::call_command("throttle.max_downloads"), rpc::make_target(download)); rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.normal"), rpc::make_target(download)); rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.normal"), rpc::make_target(download)); rpc::call_command("d.tracker_numwant.set", rpc::call_command("trackers.numwant"), rpc::make_target(download)); rpc::call_command("d.max_file_size.set", rpc::call_command("system.file.max_size"), rpc::make_target(download)); if (rpc::call_command_value("d.complete", rpc::make_target(download)) != 0) { if (rpc::call_command_value("throttle.min_peers.seed") >= 0) rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.seed"), rpc::make_target(download)); if (rpc::call_command_value("throttle.max_peers.seed") >= 0) rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download)); } if (!rpc::call_command_value("trackers.use_udp")) download->enable_udp_trackers(false); // Check first if we already have these values set in the session // torrent, so that it is safe to change the values. // // Need to also catch the exceptions. if (rpc::call_command_value("system.file.split_size") >= 0) torrent::file_split_all(download->download()->file_list(), rpc::call_command_value("system.file.split_size"), rpc::call_command_string("system.file.split_suffix")); if (!rtorrent->has_key_string("directory")) rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download)); else rpc::call_command("d.directory_base.set", rtorrent->get_key("directory"), rpc::make_target(download)); if (!m_session && m_variables["tied_to_file"].as_value()) rpc::call_command("d.tied_to_file.set", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download)); rpc::call_command("d.peer_exchange.set", rpc::call_command_value("protocol.pex"), rpc::make_target(download)); torrent::resume_load_addresses(*download->download(), resumeObject); torrent::resume_load_file_priorities(*download->download(), resumeObject); torrent::resume_load_tracker_settings(*download->download(), resumeObject); // The action of inserting might cause the torrent to be // opened/started or such. Figure out a nicer way of handling this. if (m_manager->download_list()->insert(download) == m_manager->download_list()->end()) { // ATM doesn't really ever get here. delete download; m_slot_finished(); return; } // Save the info-hash just in case the commands decide to delete it. torrent::HashString infohash = download->info()->hash(); try { if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid()) log_created(download, rtorrent); std::for_each(m_commands.begin(), m_commands.end(), rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_std), rpc::make_target(download))); if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end()) throw torrent::input_error("The newly created download was removed."); if (!m_session) rpc::call_command("d.state.set", (int64_t)m_start, rpc::make_target(download)); rpc::commands.call_catch(m_session ? "event.download.inserted_session" : "event.download.inserted_new", rpc::make_target(download), torrent::Object(), "Download event action failed: "); } catch (torrent::input_error& e) { std::string msg = "Command on torrent creation failed: " + std::string(e.what()); if (m_printLog) m_manager->push_log_std(msg); if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) { // Should stop it, mark it bad. Perhaps even delete it? download->set_hash_failed(true); download->set_message(msg); // m_manager->download_list()->erase(m_manager->download_list()->find(infohash.data())); } } m_slot_finished(); } void DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) { std::stringstream dump; dump << "info_hash = " << torrent::hash_string_to_hex_str(download->info()->hash()) << std::endl; dump << "session = " << (m_session ? "true" : "false") << std::endl; if (download->download()->info()->is_meta_download()) dump << "magnet = true" << std::endl; if (!rtorrent->has_key_string("directory")) dump << "directory = \"" << (m_variables["directory"].is_string() ? m_variables["directory"].as_string() : std::string()) << '"' << std::endl; else dump << "directory_base = \"" << (rtorrent->get_key("directory").is_string() ? rtorrent->get_key("directory").as_string() : std::string()) << '"' << std::endl; dump << "---COMMANDS---" << std::endl; for (command_list_type::const_iterator itr = m_commands.begin(); itr != m_commands.end(); itr++) { dump << *itr << std::endl; } std::string dump_str = dump.str(); lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:"); } void DownloadFactory::receive_failed(const std::string& msg) { // Add message to log. if (m_printLog) m_manager->push_log_std(msg + ": \"" + m_uri + "\""); m_slot_finished(); } void DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) { if (!rtorrent->has_key_value("state") || rtorrent->get_key_value("state") > 1) { rtorrent->insert_key("state", (int64_t)m_start); rtorrent->insert_key("state_changed", cachedTime.seconds()); rtorrent->insert_key("state_counter", int64_t()); } else if (!rtorrent->has_key_value("state_changed") || rtorrent->get_key_value("state_changed") > cachedTime.seconds() || rtorrent->get_key_value("state_changed") == 0 || !rtorrent->has_key_value("state_counter") || (uint64_t)rtorrent->get_key_value("state_counter") > (1 << 20)) { rtorrent->insert_key("state_changed", cachedTime.seconds()); rtorrent->insert_key("state_counter", int64_t()); } rtorrent->insert_preserve_copy("complete", (int64_t)0); rtorrent->insert_preserve_copy("hashing", (int64_t)Download::variable_hashing_stopped); rtorrent->insert_preserve_copy("timestamp.started", (int64_t)0); rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0); rtorrent->insert_preserve_copy("tied_to_file", ""); rtorrent->insert_key("loaded_file", m_isFile ? m_uri : std::string()); if (rtorrent->has_key_value("priority")) rpc::call_command("d.priority.set", rtorrent->get_key_value("priority") % 4, rpc::make_target(download)); else rpc::call_command("d.priority.set", (int64_t)2, rpc::make_target(download)); if (rtorrent->has_key_value("key")) { download->tracker_list()->set_key(rtorrent->get_key_value("key")); } else { download->tracker_list()->set_key(random() % (std::numeric_limits::max() - 1) + 1); rtorrent->insert_key("key", download->tracker_list()->key()); } if (rtorrent->has_key_value("total_uploaded")) download->info()->mutable_up_rate()->set_total(rtorrent->get_key_value("total_uploaded")); if (rtorrent->has_key_value("chunks_done") && rtorrent->has_key_value("chunks_wanted")) download->download()->set_chunks_done(rtorrent->get_key_value("chunks_done"), rtorrent->get_key_value("chunks_wanted")); download->set_throttle_name(rtorrent->has_key_string("throttle_name") ? rtorrent->get_key_string("throttle_name") : std::string()); rtorrent->insert_preserve_copy("ignore_commands", (int64_t)0); rtorrent->insert_preserve_copy("views", torrent::Object::create_list()); rtorrent->insert_preserve_type("connection_leech", m_variables["connection_leech"]); rtorrent->insert_preserve_type("connection_seed", m_variables["connection_seed"]); rtorrent->insert_preserve_copy("choke_heuristics.up.leech", std::string()); rtorrent->insert_preserve_copy("choke_heuristics.up.seed", std::string()); rtorrent->insert_preserve_copy("choke_heuristics.down.leech", std::string()); rtorrent->insert_preserve_copy("choke_heuristics.down.seed", std::string()); } } rtorrent-0.9.6/src/core/download_factory.h000066400000000000000000000102751257211462100206410ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // The DownloadFactory class assures that loading torrents can be done // anywhere in the code by queueing the task. The user may change // settings while, or even after, the torrent is loading. #ifndef RTORRENT_CORE_DOWNLOAD_FACTORY_H #define RTORRENT_CORE_DOWNLOAD_FACTORY_H #include #include #include #include #include "http_queue.h" namespace core { class Manager; class DownloadFactory { public: typedef std::tr1::function slot_void; typedef std::vector command_list_type; // Do not destroy this object while it is in a HttpQueue. DownloadFactory(Manager* m); ~DownloadFactory(); // Calling of receive_load() is delayed so you can change whatever // you want without fear of the slots being triggered as you call // load() or commit(). void load(const std::string& uri); void load_raw_data(const std::string& input); void commit(); command_list_type& commands() { return m_commands; } torrent::Object::map_type& variables() { return m_variables; } bool get_session() const { return m_session; } void set_session(bool v) { m_session = v; } bool get_start() const { return m_start; } void set_start(bool v) { m_start = v; } bool print_log() const { return m_printLog; } void set_print_log(bool v) { m_printLog = v; } void slot_finished(slot_void s) { m_slot_finished = s; } private: void receive_load(); void receive_loaded(); void receive_commit(); void receive_success(); void receive_failed(const std::string& msg); void log_created(Download* download, torrent::Object* rtorrent); void initialize_rtorrent(Download* download, torrent::Object* rtorrent); Manager* m_manager; std::iostream* m_stream; torrent::Object* m_object; bool m_commited; bool m_loaded; std::string m_uri; bool m_session; bool m_start; bool m_printLog; bool m_isFile; command_list_type m_commands; torrent::Object::map_type m_variables; slot_void m_slot_finished; rak::priority_item m_taskLoad; rak::priority_item m_taskCommit; }; bool is_network_uri(const std::string& uri); bool is_magnet_uri(const std::string& uri); } #endif rtorrent-0.9.6/src/core/download_list.cc000066400000000000000000000676521257211462100203160ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "control.h" #include "globals.h" #include "manager.h" #include "view.h" #include "view_manager.h" #include "dht_manager.h" #include "download.h" #include "download_list.h" #include "download_store.h" #define DL_TRIGGER_EVENT(download, event_name) \ rpc::commands.call_catch(event_name, rpc::make_target(download), torrent::Object(), "Event '" event_name "' failed: "); namespace core { inline void DownloadList::check_contains(Download* d) { #ifdef USE_EXTRA_DEBUG if (std::find(begin(), end(), d) == end()) throw torrent::internal_error("DownloadList::check_contains(...) failed."); #endif } void DownloadList::clear() { std::for_each(begin(), end(), std::bind1st(std::mem_fun(&DownloadList::close), this)); std::for_each(begin(), end(), rak::call_delete()); base_type::clear(); } void DownloadList::session_save() { unsigned int c = std::count_if(begin(), end(), std::bind1st(std::mem_fun(&DownloadStore::save_resume), control->core()->download_store())); if (c != size()) lt_log_print(torrent::LOG_ERROR, "Failed to save session torrents."); control->dht_manager()->save_dht_cache(); } DownloadList::iterator DownloadList::find(const torrent::HashString& hash) { return std::find_if(begin(), end(), rak::equal(hash, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash)))); } DownloadList::iterator DownloadList::find_hex(const char* hash) { torrent::HashString key; for (torrent::HashString::iterator itr = key.begin(), last = key.end(); itr != last; itr++, hash += 2) *itr = (rak::hexchar_to_value(*hash) << 4) + rak::hexchar_to_value(*(hash + 1)); return std::find_if(begin(), end(), rak::equal(key, rak::on(std::mem_fun(&Download::info), std::mem_fun(&torrent::DownloadInfo::hash)))); } Download* DownloadList::find_hex_ptr(const char* hash) { iterator itr = find_hex(hash); return itr != end() ? *itr : NULL; } Download* DownloadList::create(torrent::Object* obj, bool printLog) { torrent::Download download; try { download = torrent::download_add(obj); } catch (torrent::local_error& e) { delete obj; if (printLog) lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what()); return NULL; } // There's no non-critical exceptions that should be throwable by // the ctor, so don't catch. return new Download(download); } Download* DownloadList::create(std::istream* str, bool printLog) { torrent::Object* object = new torrent::Object; torrent::Download download; try { *str >> *object; // Don't throw input_error from here as gcc-3.3.5 produces bad // code. if (str->fail()) { delete object; if (printLog) lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent."); return NULL; } download = torrent::download_add(object); } catch (torrent::local_error& e) { delete object; if (printLog) lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what()); return NULL; } // There's no non-critical exceptions that should be throwable by // the ctor, so don't catch. return new Download(download); } DownloadList::iterator DownloadList::insert(Download* download) { iterator itr = base_type::insert(end(), download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download."); try { (*itr)->data()->slot_initial_hash() = tr1::bind(&DownloadList::hash_done, this, download); (*itr)->data()->slot_download_done() = tr1::bind(&DownloadList::received_finished, this, download); // This needs to be separated into two different calls to ensure // the download remains in the view. std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::insert), download)); std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::filter_download), download)); DL_TRIGGER_EVENT(*itr, "event.download.inserted"); } catch (torrent::local_error& e) { // Should perhaps relax this, just print an error and remove the // downloads? throw torrent::internal_error("Caught during DownloadList::insert(...): " + std::string(e.what())); } return itr; } void DownloadList::erase_ptr(Download* download) { erase(std::find(begin(), end(), download)); } DownloadList::iterator DownloadList::erase(iterator itr) { if (itr == end()) throw torrent::internal_error("DownloadList::erase(...) could not find download."); lt_log_print_info(torrent::LOG_TORRENT_INFO, (*itr)->info(), "download_list", "Erasing download."); // Makes sure close doesn't restart hashing of this download. (*itr)->set_hash_failed(true); close(*itr); control->core()->download_store()->remove(*itr); DL_TRIGGER_EVENT(*itr, "event.download.erased"); std::for_each(control->view_manager()->begin(), control->view_manager()->end(), std::bind2nd(std::mem_fun(&View::erase), *itr)); torrent::download_remove(*(*itr)->download()); delete *itr; return base_type::erase(itr); } bool DownloadList::open(Download* download) { try { open_throw(download); return true; } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not open download: %s", e.what()); return false; } } void DownloadList::open_throw(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Opening download."); if (download->download()->info()->is_open()) return; int openFlags = download->resume_flags(); if (rpc::call_command_value("system.file.allocate")) openFlags |= torrent::Download::open_enable_fallocate; download->download()->open(openFlags); DL_TRIGGER_EVENT(download, "event.download.opened"); } void DownloadList::close(Download* download) { try { close_throw(download); } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not close download: %s", e.what()); } } void DownloadList::close_directly(Download* download) { lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download directly."); if (download->download()->info()->is_active()) { download->download()->stop(torrent::Download::stop_skip_tracker); if (torrent::resume_check_target_files(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"))) torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); } if (download->download()->info()->is_open()) download->download()->close(); } void DownloadList::close_quick(Download* download) { lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download quickly."); close(download); // Make sure we cancel any tracker requests. This should rather be // handled by some parameter to the close function, or some other // way of giving the client more control of when STOPPED requests // are sent. download->download()->manual_cancel(); } void DownloadList::close_throw(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download with throw."); // When pause gets called it will clear the initial hash check state // and set hash failed. This should ensure hashing doesn't restart // until resume gets called. pause(download); // Check for is_open after pause due to hashing. if (!download->is_open()) return; // Save the torrent on close, this covers shutdown and if a torrent // is manually closed which would clear the progress data. For // better crash protection, save regulary in addition to this. // // Used to be in pause, but this was wrong for rehashing etc. // // Reconsider this save. Should be done explicitly when shutting down. //control->core()->download_store()->save(download); download->download()->close(); if (!download->is_hash_failed() && rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped) throw torrent::internal_error("DownloadList::close_throw(...) called but we're going into a hashing loop."); DL_TRIGGER_EVENT(download, "event.download.hash_removed"); DL_TRIGGER_EVENT(download, "event.download.closed"); } void DownloadList::resume(Download* download, int flags) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Resuming download: flags:%0x.", flags); try { if (download->download()->info()->is_active()) return; rpc::parse_command_single(rpc::make_target(download), "view.set_visible=active"); // We need to make sure the flags aren't reset if someone decideds // to call resume() while it is hashing, etc. if (download->resume_flags() == ~uint32_t()) download->set_resume_flags(flags); // Manual or end-of-download rehashing clears the resume data so // we can just start the hashing again without clearing it again. // // It is also assumed the is_hash_checked flag gets cleared when // 'hashing' was set. if (!download->is_hash_checked()) { // If the hash failed flag wasn't cleared then hashing won't be // initiated. if (download->is_hash_failed()) return; if (rpc::call_command_value("d.hashing", rpc::make_target(download)) == Download::variable_hashing_stopped) rpc::call_command("d.hashing.set", Download::variable_hashing_initial, rpc::make_target(download)); DL_TRIGGER_EVENT(download, "event.download.hash_queued"); return; } // This will never actually do anything due to the above hash check. // open_throw(download); rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download)); rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)) + 1, rpc::make_target(download)); if (download->is_done()) { torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download)); torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download)); torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download)); if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download)); if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download)); if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download)); rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download)); rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download)); rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download)); } else { torrent::Object conn_current = rpc::call_command("d.connection_leech", torrent::Object(), rpc::make_target(download)); torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.leech", torrent::Object(), rpc::make_target(download)); torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.leech", torrent::Object(), rpc::make_target(download)); if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.leech", torrent::Object(), rpc::make_target(download)); if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.leech", torrent::Object(), rpc::make_target(download)); if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.leech", torrent::Object(), rpc::make_target(download)); rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download)); rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download)); rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download)); // For the moment, clear the resume data so we force hash-check // on non-complete downloads after a crash. This shouldn't be // needed, but for some reason linux 2.6 is very lazy about // updating mtime. // // Disabling this due to the new resume code. // torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"), true); } // If the DHT server is set to auto, start it now. if (!download->download()->info()->is_private()) control->dht_manager()->auto_start(); // Update the priority to ensure it has the correct // seeding/unfinished modifiers. download->set_priority(download->priority()); download->download()->start(download->resume_flags()); download->set_resume_flags(~uint32_t()); DL_TRIGGER_EVENT(download, "event.download.resumed"); } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not resume download: %s", e.what()); } } void DownloadList::pause(Download* download, int flags) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Pausing download: flags:%0x.", flags); try { download->set_resume_flags(~uint32_t()); rpc::parse_command_single(rpc::make_target(download), "view.set_not_visible=active"); // Always clear hashing on pause. When a hashing request is added, // it should have cleared the hash resume data. if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped) { download->download()->hash_stop(); rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_stopped, rpc::make_target(download)); DL_TRIGGER_EVENT(download, "event.download.hash_removed"); } if (!download->download()->info()->is_active()) return; download->download()->stop(flags); torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); // TODO: This is actually for pause, not stop... And doesn't get // called when the download isn't active, but was in the 'started' // view. DL_TRIGGER_EVENT(download, "event.download.paused"); rpc::call_command("d.state_changed.set", cachedTime.seconds(), rpc::make_target(download)); rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)), rpc::make_target(download)); // If initial seeding is complete, don't try it again when restarting. if (download->is_done() && rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)).as_string() == "initial_seed") rpc::call_command("d.connection_seed.set", rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)), rpc::make_target(download)); // Save the state after all the slots, etc have been called so we // include the modifications they may make. //control->core()->download_store()->save(download); } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not pause download: %s", e.what()); } } void DownloadList::check_hash(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Checking hash."); try { if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped) return; hash_queue(download, Download::variable_hashing_rehash); } catch (torrent::local_error& e) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not check hash: %s", e.what()); } } void DownloadList::hash_done(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash done."); if (download->is_hash_checking() || download->is_active()) throw torrent::internal_error("DownloadList::hash_done(...) download in invalid state."); if (!download->is_hash_checked()) { download->set_hash_failed(true); DL_TRIGGER_EVENT(download, "event.download.hash_failed"); return; } // Need to find some sane conditional here. Can we check the total // downloaded to ensure something was transferred, thus we didn't // just hash an already completed torrent with lacking session data? // // Perhaps we should use a seperate variable or state, and check // that. Thus we can bork the download if the hash check doesn't // confirm all the data, avoiding large BW usage on f.ex. the // ReiserFS bug with >4GB files. int64_t hashing = rpc::call_command_value("d.hashing", rpc::make_target(download)); rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_stopped, rpc::make_target(download)); if (download->is_done() && download->download()->info()->is_meta_download()) return process_meta_download(download); switch (hashing) { case Download::variable_hashing_initial: case Download::variable_hashing_rehash: // Normal re/hashing. // If the download was previously completed but the files were // f.ex deleted, then we clear the state and complete. if (rpc::call_command_value("d.complete", rpc::make_target(download)) && !download->is_done()) { rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(download)); download->set_message("Download registered as completed, but hash check returned unfinished chunks."); } // Save resume data so we update time-stamps and priorities if // they were invalid/changed while loading/hashing. rpc::call_command("d.complete.set", (int64_t)download->is_done(), rpc::make_target(download)); torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1) resume(download, download->resume_flags()); break; case Download::variable_hashing_last: if (download->is_done()) { confirm_finished(download); } else { download->set_message("Hash check on download completion found bad chunks, consider using \"safe_sync\"."); lt_log_print(torrent::LOG_TORRENT_ERROR, "Hash check on download completion found bad chunks, consider using \"safe_sync\"."); DL_TRIGGER_EVENT(download, "event.download.hash_final_failed"); } // TODO: Should we skip the 'hash_done' event here? return; case Download::variable_hashing_stopped: default: // Either an error or someone wrote to the hashing variable... download->set_message("Hash check completed but the \"hashing\" variable is in an invalid state."); return; } DL_TRIGGER_EVENT(download, "event.download.hash_done"); } void DownloadList::hash_queue(Download* download, int type) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Hash queue."); if (rpc::call_command_value("d.hashing", rpc::make_target(download)) != Download::variable_hashing_stopped) throw torrent::internal_error("DownloadList::hash_queue(...) hashing already queued."); // HACK if (download->is_open()) { pause(download, torrent::Download::stop_skip_tracker); download->download()->close(); DL_TRIGGER_EVENT(download, "event.download.hash_removed"); DL_TRIGGER_EVENT(download, "event.download.closed"); } torrent::resume_clear_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); download->set_hash_failed(false); rpc::call_command_set_value("d.hashing.set", type, rpc::make_target(download)); if (download->is_open()) throw torrent::internal_error("DownloadList::hash_clear(...) download still open."); // If any more stuff is added here, make sure resume etc are still // correct. DL_TRIGGER_EVENT(download, "event.download.hash_queued"); } void DownloadList::received_finished(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Received finished."); if (rpc::call_command_value("pieces.hash.on_completion")) // Set some 'checking_finished_thingie' variable to make hash_done // trigger correctly, also so it can bork on missing data. hash_queue(download, Download::variable_hashing_last); else confirm_finished(download); } // The download must be open when we call this function. void DownloadList::confirm_finished(Download* download) { check_contains(download); lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Confirming finished."); if (download->download()->info()->is_meta_download()) return process_meta_download(download); rpc::call_command("d.complete.set", (int64_t)1, rpc::make_target(download)); // Clean up these settings: torrent::Object conn_current = rpc::call_command("d.connection_seed", torrent::Object(), rpc::make_target(download)); torrent::Object choke_up = rpc::call_command("d.up.choke_heuristics.seed", torrent::Object(), rpc::make_target(download)); torrent::Object choke_down = rpc::call_command("d.down.choke_heuristics.seed", torrent::Object(), rpc::make_target(download)); if (conn_current.is_string_empty()) conn_current = rpc::call_command("protocol.connection.seed", torrent::Object(), rpc::make_target(download)); if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download)); if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download)); rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download)); rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download)); rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download)); download->set_priority(download->priority()); if (rpc::call_command_value("d.peers_min", rpc::make_target(download)) == rpc::call_command_value("throttle.min_peers.normal") && rpc::call_command_value("throttle.min_peers.seed") >= 0) rpc::call_command("d.peers_min.set", rpc::call_command("throttle.min_peers.seed"), rpc::make_target(download)); if (rpc::call_command_value("d.peers_max", rpc::make_target(download)) == rpc::call_command_value("throttle.max_peers.normal") && rpc::call_command_value("throttle.max_peers.seed") >= 0) rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download)); // Do this before the slots are called in case one of them closes // the download. // // Obsolete. if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0) { // torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); control->core()->download_store()->save_resume(download); } // Send the completed request before resuming so we don't reset the // up/downloaded baseline. download->download()->send_completed(); // Save the hash in case the finished event erases it. torrent::HashString infohash = download->info()->hash(); DL_TRIGGER_EVENT(download, "event.download.finished"); if (find(infohash) == end()) return; // if (download->resume_flags() != ~uint32_t()) // throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t()."); // See #1292. // // Just reset the value for the moment. If a torrent finishes while // others are hashing, or some other situtation that causes resume // flag to change could cause the state to be invalid. // // TODO: Add a check when setting the flags to see if the torrent is // being hashed. download->set_resume_flags(~uint32_t()); if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1) resume(download, torrent::Download::start_no_create | torrent::Download::start_skip_tracker | torrent::Download::start_keep_baseline); } void DownloadList::process_meta_download(Download* download) { lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Processing meta download."); rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download)); rpc::call_command("d.close", torrent::Object(), rpc::make_target(download)); std::string metafile = (*download->file_list()->begin())->frozen_path(); std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary); if (!file.is_open()) { lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not read download metadata."); return; } torrent::Object* bencode = new torrent::Object(torrent::Object::create_map()); file >> bencode->insert_key("info", torrent::Object()); if (file.fail()) { delete bencode; lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent."); return; } file.close(); // Steal the keys we still need. The old download has no use for them. bencode->insert_key("rtorrent_meta_download", torrent::Object()).swap(download->bencode()->get_key("rtorrent_meta_download")); if (download->bencode()->has_key("announce")) bencode->insert_key("announce", torrent::Object()).swap(download->bencode()->get_key("announce")); if (download->bencode()->has_key("announce-list")) bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list")); erase_ptr(download); control->core()->try_create_download_from_meta_download(bencode, metafile); } } rtorrent-0.9.6/src/core/download_list.h000066400000000000000000000124531257211462100201450ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_DOWNLOAD_LIST_H #define RTORRENT_CORE_DOWNLOAD_LIST_H #include #include #include namespace torrent { class HashString; } namespace core { class Download; // Container for all downloads. Add slots to the slot maps to cause // some action to be taken when the torrent changes states. Don't // change the states from outside of core. // // Fix apply_on_ratio if the base_type is changed. class DownloadList : private std::list { public: typedef std::list base_type; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::value_type; using base_type::pointer; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::size; DownloadList() { } void clear(); void session_save(); iterator find(const torrent::HashString& hash); iterator find_hex(const char* hash); Download* find_hex_ptr(const char* hash); // Might move this to DownloadFactory. Download* create(std::istream* str, bool printLog); Download* create(torrent::Object* obj, bool printLog); iterator insert(Download* d); void erase_ptr(Download* d); iterator erase(iterator itr); //void save(Download* d); bool open(Download* d); void open_throw(Download* d); void close(Download* d); void close_directly(Download* d); void close_quick(Download* d); void close_throw(Download* d); void resume(Download* d, int flags = 0); void pause(Download* d, int flags = 0); void resume_default(Download* d) { resume(d); } void pause_default(Download* d) { pause(d); } void check_hash(Download* d); enum { D_SLOTS_INSERT, D_SLOTS_ERASE, D_SLOTS_OPEN, D_SLOTS_CLOSE, D_SLOTS_START, D_SLOTS_STOP, D_SLOTS_HASH_QUEUED, D_SLOTS_HASH_REMOVED, D_SLOTS_HASH_DONE, D_SLOTS_FINISHED, SLOTS_MAX_SIZE }; static const char* slot_name(int m) { switch(m) { case D_SLOTS_INSERT: return "event.download.inserted"; case D_SLOTS_ERASE: return "event.download.erased"; case D_SLOTS_OPEN: return "event.download.opened"; case D_SLOTS_CLOSE: return "event.download.closed"; case D_SLOTS_START: return "event.download.resumed"; case D_SLOTS_STOP: return "event.download.paused"; case D_SLOTS_HASH_QUEUED: return "event.download.hash_queued"; case D_SLOTS_HASH_REMOVED: return "event.download.hash_removed"; case D_SLOTS_HASH_DONE: return "event.download.hash_done"; case D_SLOTS_FINISHED: return "event.download.finished"; default: return "BORK"; } } // The finished slots will be called when an active download with // "finished" == 0 performs a hash check which returns a done // torrent. // // But how to avoid sending 'completed' messages to the tracker? // Also we need to handle cases when a hashing torrent starts up // after a shutdown. private: DownloadList(const DownloadList&); void operator = (const DownloadList&); void hash_done(Download* d); void hash_queue(Download* d, int type); inline void check_contains(Download* d); void received_finished(Download* d); void confirm_finished(Download* d); void process_meta_download(Download* d); }; } #endif rtorrent-0.9.6/src/core/download_slot_map.h000066400000000000000000000046221257211462100210070ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H #define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H #include #include #include #include "download.h" namespace core { class DownloadSlotMap : public std::map > { public: typedef std::tr1::function slot_download; typedef std::map Base; void insert(const std::string& key, slot_download s) { Base::operator[](key) = s; } void erase(const std::string& key) { Base::erase(key); } void for_each(Download* d); }; inline void DownloadSlotMap::for_each(Download* d) { for (iterator itr = begin(), last = end(); itr != last; ++itr) itr->second(d); } } #endif rtorrent-0.9.6/src/core/download_store.cc000066400000000000000000000156221257211462100204650ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // DownloadStore handles the saving and listing of session torrents. #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "utils/directory.h" #include "download.h" #include "download_store.h" namespace core { void DownloadStore::enable(bool lock) { if (is_enabled()) throw torrent::input_error("Session directory already enabled."); if (m_path.empty()) return; if (lock) m_lockfile.set_path(m_path + "rtorrent.lock"); else m_lockfile.set_path(std::string()); if (!m_lockfile.try_lock()) { if (rak::error_number::current().is_bad_path()) throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", " + rak::error_number::current().c_str()); else throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by_as_string() + "\"."); } } void DownloadStore::disable() { if (!is_enabled()) return; m_lockfile.unlock(); } void DownloadStore::set_path(const std::string& path) { if (is_enabled()) throw torrent::input_error("Tried to change session directory while it is enabled."); if (!path.empty() && *path.rbegin() != '/') m_path = rak::path_expand(path + '/'); else m_path = rak::path_expand(path); } bool DownloadStore::write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask) { torrent::Object tmp; std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc); if (!output.is_open()) goto download_store_save_error; torrent::object_write_bencode(&output, &obj, skip_mask); if (!output.good()) goto download_store_save_error; output.close(); // Test the new file, to ensure it is a valid bencode string. output.open(filename.c_str(), std::ios::in); output >> tmp; if (!output.good()) goto download_store_save_error; output.close(); return true; download_store_save_error: output.close(); return false; } bool DownloadStore::save(Download* d, int flags) { if (!is_enabled()) return true; torrent::Object* resume_base = &d->download()->bencode()->get_key("libtorrent_resume"); torrent::Object* rtorrent_base = &d->download()->bencode()->get_key("rtorrent"); // Move this somewhere else? rtorrent_base->insert_key("chunks_done", d->download()->file_list()->completed_chunks()); rtorrent_base->insert_key("chunks_wanted", d->download()->data()->wanted_chunks()); rtorrent_base->insert_key("total_uploaded", d->info()->up_rate()->total()); // Don't save for completed torrents when we've cleared the uncertain_pieces. torrent::resume_save_progress(*d->download(), *resume_base); torrent::resume_save_uncertain_pieces(*d->download(), *resume_base); torrent::resume_save_addresses(*d->download(), *resume_base); torrent::resume_save_file_priorities(*d->download(), *resume_base); torrent::resume_save_tracker_settings(*d->download(), *resume_base); // Temp fixing of all flags, move to a better place: resume_base->set_flags(torrent::Object::flag_session_data); rtorrent_base->set_flags(torrent::Object::flag_session_data); std::string base_filename = create_filename(d); if (!write_bencode(base_filename + ".libtorrent_resume.new", *resume_base, 0) || !write_bencode(base_filename + ".rtorrent.new", *rtorrent_base, 0)) return false; ::rename((base_filename + ".libtorrent_resume.new").c_str(), (base_filename + ".libtorrent_resume").c_str()); ::rename((base_filename + ".rtorrent.new").c_str(), (base_filename + ".rtorrent").c_str()); if (!(flags & flag_skip_static) && write_bencode(base_filename + ".new", *d->bencode(), torrent::Object::flag_session_data)) ::rename((base_filename + ".new").c_str(), base_filename.c_str()); return true; } void DownloadStore::remove(Download* d) { if (!is_enabled()) return; ::unlink((create_filename(d) + ".libtorrent_resume").c_str()); ::unlink((create_filename(d) + ".rtorrent").c_str()); ::unlink(create_filename(d).c_str()); } // This also needs to check that it isn't a directory. bool not_correct_format(const utils::directory_entry& entry) { return !DownloadStore::is_correct_format(entry.d_name); } utils::Directory DownloadStore::get_formated_entries() { if (!is_enabled()) return utils::Directory(); utils::Directory d(m_path); if (!d.update(utils::Directory::update_hide_dot)) throw torrent::storage_error("core::DownloadStore::update() could not open directory \"" + m_path + "\""); d.erase(std::remove_if(d.begin(), d.end(), std::ptr_fun(¬_correct_format)), d.end()); return d; } bool DownloadStore::is_correct_format(const std::string& f) { if (f.size() != 48 || f.substr(40) != ".torrent") return false; for (std::string::const_iterator itr = f.begin(); itr != f.end() - 8; ++itr) if (!(*itr >= '0' && *itr <= '9') && !(*itr >= 'A' && *itr <= 'F')) return false; return true; } std::string DownloadStore::create_filename(Download* d) { return m_path + rak::transform_hex(d->info()->hash().begin(), d->info()->hash().end()) + ".torrent"; } } rtorrent-0.9.6/src/core/download_store.h000066400000000000000000000055371257211462100203330ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_DOWNLOAD_STORE_H #define RTORRENT_CORE_DOWNLOAD_STORE_H #include #include "utils/lockfile.h" namespace utils { class Directory; } namespace core { class Download; class DownloadStore { public: static const int flag_skip_static = 0x1; bool is_enabled() { return m_lockfile.is_locked(); } void enable(bool lock); void disable(); const std::string& path() const { return m_path; } void set_path(const std::string& path); bool save(Download* d, int flags); bool save_full(Download* d) { return save(d, 0); } bool save_resume(Download* d) { return save(d, flag_skip_static); } void remove(Download* d); // Currently shows all entries in the correct format. utils::Directory get_formated_entries(); static bool is_correct_format(const std::string& f); private: std::string create_filename(Download* d); bool write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask); std::string m_path; utils::Lockfile m_lockfile; }; } #endif rtorrent-0.9.6/src/core/http_queue.cc000066400000000000000000000053521257211462100176240ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "rak/functional.h" #include "http_queue.h" #include "curl_get.h" namespace core { HttpQueue::iterator HttpQueue::insert(const std::string& url, std::iostream* s) { std::auto_ptr h(m_slot_factory()); h->set_url(url); h->set_stream(s); h->set_timeout(5 * 60); iterator signal_itr = base_type::insert(end(), h.get()); h->signal_done().push_back(std::tr1::bind(&HttpQueue::erase, this, signal_itr)); h->signal_failed().push_back(std::tr1::bind(&HttpQueue::erase, this, signal_itr)); (*signal_itr)->start(); h.release(); for (signal_curl_get::iterator itr = m_signal_insert.begin(), last = m_signal_insert.end(); itr != last; itr++) (*itr)(*signal_itr); return signal_itr; } void HttpQueue::erase(iterator signal_itr) { for (signal_curl_get::iterator itr = m_signal_erase.begin(), last = m_signal_erase.end(); itr != last; itr++) (*itr)(*signal_itr); delete *signal_itr; base_type::erase(signal_itr); } void HttpQueue::clear() { while (!empty()) erase(begin()); base_type::clear(); } } rtorrent-0.9.6/src/core/http_queue.h000066400000000000000000000061051257211462100174630ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_HTTP_QUEUE_H #define RTORRENT_CORE_HTTP_QUEUE_H #include #include #include namespace core { class CurlGet; class HttpQueue : private std::list { public: typedef std::list base_type; typedef std::tr1::function slot_factory; typedef std::tr1::function slot_curl_get; typedef std::list signal_curl_get; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::size; HttpQueue() {} ~HttpQueue() { clear(); } // Note that any slots connected to the CurlGet signals must be // pushed in front of the erase slot added by HttpQueue::insert. // // Consider adding a flag to indicate whetever HttpQueue should // delete the stream. iterator insert(const std::string& url, std::iostream* s); void erase(iterator itr); void clear(); void set_slot_factory(slot_factory s) { m_slot_factory = s; } signal_curl_get& signal_insert() { return m_signal_insert; } signal_curl_get& signal_erase() { return m_signal_erase; } private: slot_factory m_slot_factory; signal_curl_get m_signal_insert; signal_curl_get m_signal_erase; }; } #endif rtorrent-0.9.6/src/core/manager.cc000066400000000000000000000402011257211462100170430ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "utils/directory.h" #include "utils/file_status_cache.h" #include "globals.h" #include "curl_get.h" #include "control.h" #include "download.h" #include "download_factory.h" #include "download_store.h" #include "http_queue.h" #include "manager.h" #include "poll_manager.h" #include "view.h" namespace core { void Manager::push_log(const char* msg) { m_log_important->lock_and_push_log(msg, strlen(msg), 0); m_log_complete->lock_and_push_log(msg, strlen(msg), 0); } Manager::Manager() : m_hashingView(NULL), m_log_important(torrent::log_open_log_buffer("important")), m_log_complete(torrent::log_open_log_buffer("complete")) { m_downloadStore = new DownloadStore(); m_downloadList = new DownloadList(); m_fileStatusCache = new FileStatusCache(); m_httpQueue = new HttpQueue(); m_httpStack = new CurlStack(); torrent::Throttle* unthrottled = torrent::Throttle::create_throttle(); unthrottled->set_max_rate(0); m_throttles["NULL"] = std::make_pair(unthrottled, unthrottled); } Manager::~Manager() { torrent::Throttle::destroy_throttle(m_throttles["NULL"].first); delete m_downloadList; // TODO: Clean up logs objects. delete m_downloadStore; delete m_httpQueue; delete m_fileStatusCache; } void Manager::set_hashing_view(View* v) { if (v == NULL || m_hashingView != NULL) throw torrent::internal_error("Manager::set_hashing_view(...) received NULL or is already set."); m_hashingView = v; m_hashingView->signal_changed().push_back(std::tr1::bind(&Manager::receive_hashing_changed, this)); } torrent::ThrottlePair Manager::get_throttle(const std::string& name) { ThrottleMap::const_iterator itr = m_throttles.find(name); torrent::ThrottlePair throttles = (itr == m_throttles.end() ? torrent::ThrottlePair(NULL, NULL) : itr->second); if (throttles.first == NULL) throttles.first = torrent::up_throttle_global(); if (throttles.second == NULL) throttles.second = torrent::down_throttle_global(); return throttles; } void Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles) { m_addressThrottles.set_merge(begin, end, throttles); torrent::connection_manager()->address_throttle() = tr1::bind(&core::Manager::get_address_throttle, control->core(), tr1::placeholders::_1); } torrent::ThrottlePair Manager::get_address_throttle(const sockaddr* addr) { return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(NULL, NULL)); } // Most of this should be possible to move out. void Manager::initialize_second() { torrent::Http::slot_factory() = std::tr1::bind(&CurlStack::new_object, m_httpStack); m_httpQueue->set_slot_factory(std::tr1::bind(&CurlStack::new_object, m_httpStack)); CurlStack::global_init(); } void Manager::cleanup() { // Need to disconnect log signals? Not really since we won't receive // any more. m_downloadList->clear(); // When we implement asynchronous DNS lookups, we need to cancel them // here before the torrent::* objects are deleted. torrent::cleanup(); delete m_httpStack; CurlStack::global_cleanup(); } void Manager::shutdown(bool force) { if (!force) std::for_each(m_downloadList->begin(), m_downloadList->end(), std::bind1st(std::mem_fun(&DownloadList::pause_default), m_downloadList)); else std::for_each(m_downloadList->begin(), m_downloadList->end(), std::bind1st(std::mem_fun(&DownloadList::close_quick), m_downloadList)); } void Manager::listen_open() { // This stuff really should be moved outside of manager, make it // part of the init script. if (!rpc::call_command_value("network.port_open")) return; int portFirst, portLast; torrent::Object portRange = rpc::call_command("network.port_range"); if (portRange.is_string()) { if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2) throw torrent::input_error("Invalid port_range argument."); // } else if (portRange.is_list()) { } else { throw torrent::input_error("Invalid port_range argument."); } if (portFirst > portLast || portLast >= (1 << 16)) throw torrent::input_error("Invalid port range."); if (rpc::call_command_value("network.port_random")) { int boundary = portFirst + random() % (portLast - portFirst + 1); if (torrent::connection_manager()->listen_open(boundary, portLast) || torrent::connection_manager()->listen_open(portFirst, boundary)) return; } else { if (torrent::connection_manager()->listen_open(portFirst, portLast)) return; } throw torrent::input_error("Could not open/bind port for listening: " + std::string(rak::error_number::current().c_str())); } std::string Manager::bind_address() const { return rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->address_str(); } void Manager::set_bind_address(const std::string& addr) { int err; rak::address_info* ai; if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + "."); try { if (torrent::connection_manager()->listen_port() != 0) { torrent::connection_manager()->listen_close(); torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr()); listen_open(); } else { torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr()); } m_httpStack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string()); rak::address_info::free_address_info(ai); } catch (torrent::input_error& e) { rak::address_info::free_address_info(ai); throw e; } } std::string Manager::local_address() const { return rak::socket_address::cast_from(torrent::connection_manager()->local_address())->address_str(); } void Manager::set_local_address(const std::string& addr) { int err; rak::address_info* ai; if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + "."); try { torrent::connection_manager()->set_local_address(ai->address()->c_sockaddr()); rak::address_info::free_address_info(ai); } catch (torrent::input_error& e) { rak::address_info::free_address_info(ai); throw e; } } std::string Manager::proxy_address() const { return rak::socket_address::cast_from(torrent::connection_manager()->proxy_address())->address_str(); } void Manager::set_proxy_address(const std::string& addr) { int port; rak::address_info* ai; char buf[addr.length() + 1]; int err = std::sscanf(addr.c_str(), "%[^:]:%i", buf, &port); if (err <= 0) throw torrent::input_error("Could not parse proxy address."); if (err == 1) port = 80; if ((err = rak::address_info::get_address_info(buf, PF_INET, SOCK_STREAM, &ai)) != 0) throw torrent::input_error("Could not set proxy address: " + std::string(rak::address_info::strerror(err)) + "."); try { ai->address()->set_port(port); torrent::connection_manager()->set_proxy_address(ai->address()->c_sockaddr()); rak::address_info::free_address_info(ai); } catch (torrent::input_error& e) { rak::address_info::free_address_info(ai); throw e; } } void Manager::receive_http_failed(std::string msg) { push_log_std("Http download error: \"" + msg + "\""); } void Manager::try_create_download(const std::string& uri, int flags, const command_list_type& commands) { // If the path was attempted loaded before, skip it. if ((flags & create_tied) && !(flags & create_raw_data) && !is_network_uri(uri) && !is_magnet_uri(uri) && !file_status_cache()->insert(uri, 0)) return; // Adding download. DownloadFactory* f = new DownloadFactory(this); f->variables()["tied_to_file"] = (int64_t)(bool)(flags & create_tied); f->commands().insert(f->commands().end(), commands.begin(), commands.end()); f->set_start(flags & create_start); f->set_print_log(!(flags & create_quiet)); f->slot_finished(std::tr1::bind(&rak::call_delete_func, f)); if (flags & create_raw_data) f->load_raw_data(uri); else f->load(uri); f->commit(); } void Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) { DownloadFactory* f = new DownloadFactory(this); f->variables()["tied_to_file"] = (int64_t)true; f->variables()["tied_file"] = metafile; torrent::Object& meta = bencode->get_key("rtorrent_meta_download"); torrent::Object::list_type& commands = meta.get_key_list("commands"); for (torrent::Object::list_type::const_iterator itr = commands.begin(); itr != commands.end(); ++itr) f->commands().insert(f->commands().end(), itr->as_string()); f->set_start(meta.get_key_value("start")); f->set_print_log(meta.get_key_value("print_log")); f->slot_finished(std::tr1::bind(&rak::call_delete_func, f)); // Bit of a waste to create the bencode repesentation here // only to have the DownloadFactory decode it. std::stringstream s; s.imbue(std::locale::classic()); s << *bencode; f->load_raw_data(s.str()); f->commit(); } utils::Directory path_expand_transform(std::string path, const utils::directory_entry& entry) { return path + entry.d_name; } // Move this somewhere better. void path_expand(std::vector* paths, const std::string& pattern) { std::vector currentCache; std::vector nextCache; rak::split_iterator_t first = rak::split_iterator(pattern, '/'); rak::split_iterator_t last = rak::split_iterator(pattern); if (first == last) return; // Check for initial '/' that indicates the root. if ((*first).empty()) { currentCache.push_back(utils::Directory("/")); ++first; } else if (rak::trim(*first) == "~") { currentCache.push_back(utils::Directory("~")); ++first; } else { currentCache.push_back(utils::Directory(".")); } // Might be an idea to use depth-first search instead. for (; first != last; ++first) { rak::regex r(*first); if (r.pattern().empty()) continue; // Special case for ".."? for (std::vector::iterator itr = currentCache.begin(); itr != currentCache.end(); ++itr) { // Only include filenames starting with '.' if the pattern // starts with the same. itr->update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0); itr->erase(std::remove_if(itr->begin(), itr->end(), rak::on(rak::mem_ref(&utils::directory_entry::d_name), std::not1(r))), itr->end()); std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + "/")); } currentCache.clear(); currentCache.swap(nextCache); } std::transform(currentCache.begin(), currentCache.end(), std::back_inserter(*paths), std::mem_fun_ref(&utils::Directory::path)); } bool manager_equal_tied(const std::string& path, Download* download) { return path == rpc::call_command_string("d.tied_to_file", rpc::make_target(download)); } void Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) { if (flags & create_raw_data) { try_create_download(uri, flags, commands); return; } std::vector paths; paths.reserve(256); path_expand(&paths, uri); if (!paths.empty()) for (std::vector::iterator itr = paths.begin(); itr != paths.end(); ++itr) try_create_download(*itr, flags, commands); else try_create_download(uri, flags, commands); } // DownloadList's hashing related functions don't actually start the // hashing, it only reacts to events. This functions checks the // hashing view and starts hashing if nessesary. void Manager::receive_hashing_changed() { bool foundHashing = std::find_if(m_hashingView->begin_visible(), m_hashingView->end_visible(), std::mem_fun(&Download::is_hash_checking)) != m_hashingView->end_visible(); // Try quick hashing all those with hashing == initial, set them to // something else when failed. for (View::iterator itr = m_hashingView->begin_visible(), last = m_hashingView->end_visible(); itr != last; ++itr) { if ((*itr)->is_hash_checked()) throw torrent::internal_error("core::Manager::receive_hashing_changed() (*itr)->is_hash_checked()."); if ((*itr)->is_hash_checking() || (*itr)->is_hash_failed()) continue; bool tryQuick = rpc::call_command_value("d.hashing", rpc::make_target(*itr)) == Download::variable_hashing_initial && (*itr)->download()->file_list()->bitfield()->empty(); if (!tryQuick && foundHashing) continue; try { m_downloadList->open_throw(*itr); // Since the bitfield is allocated on loading of resume load or // hash start, and unallocated on close, we know that if it it // not empty then we have already loaded any existing resume // data. if ((*itr)->download()->file_list()->bitfield()->empty()) torrent::resume_load_progress(*(*itr)->download(), (*itr)->download()->bencode()->get_key("libtorrent_resume")); if (tryQuick) { if ((*itr)->download()->hash_check(true)) continue; (*itr)->download()->hash_stop(); if (foundHashing) { rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_rehash, rpc::make_target(*itr)); continue; } } (*itr)->download()->hash_check(false); foundHashing = true; } catch (torrent::local_error& e) { if (tryQuick) { // Make sure we don't repeat the quick hashing. rpc::call_command_set_value("d.hashing.set", Download::variable_hashing_rehash, rpc::make_target(*itr)); } else { (*itr)->set_hash_failed(true); lt_log_print(torrent::LOG_TORRENT_ERROR, "Hashing failed: %s", e.what()); } } } } } rtorrent-0.9.6/src/core/manager.h000066400000000000000000000137311257211462100167150ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_MANAGER_H #define RTORRENT_CORE_MANAGER_H #include #include #include #include #include "download_list.h" #include "poll_manager.h" #include "range_map.h" namespace torrent { class Bencode; } namespace utils { class FileStatusCache; } namespace core { class DownloadStore; class HttpQueue; typedef std::map ThrottleMap; class View; class Manager { public: typedef DownloadList::iterator DListItr; typedef utils::FileStatusCache FileStatusCache; // typedef std::tr1::function slot_ready; // typedef std::tr1::function slot_void; Manager(); ~Manager(); DownloadList* download_list() { return m_downloadList; } DownloadStore* download_store() { return m_downloadStore; } FileStatusCache* file_status_cache() { return m_fileStatusCache; } HttpQueue* http_queue() { return m_httpQueue; } CurlStack* http_stack() { return m_httpStack; } View* hashing_view() { return m_hashingView; } void set_hashing_view(View* v); torrent::log_buffer* log_important() { return m_log_important; } torrent::log_buffer* log_complete() { return m_log_complete; } ThrottleMap& throttles() { return m_throttles; } torrent::ThrottlePair get_throttle(const std::string& name); // Use custom throttle for the given range of IP addresses. void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles); torrent::ThrottlePair get_address_throttle(const sockaddr* addr); // Really should find a more descriptive name. void initialize_second(); void cleanup(); void listen_open(); std::string bind_address() const; void set_bind_address(const std::string& addr); std::string local_address() const; void set_local_address(const std::string& addr); std::string proxy_address() const; void set_proxy_address(const std::string& addr); void shutdown(bool force); void push_log(const char* msg); void push_log_std(const std::string& msg) { m_log_important->lock_and_push_log(msg.c_str(), msg.size(), 0); m_log_complete->lock_and_push_log(msg.c_str(), msg.size(), 0); } void push_log_complete(const std::string& msg) { m_log_complete->lock_and_push_log(msg.c_str(), msg.size(), 0); } void handshake_log(const sockaddr* sa, int msg, int err, const torrent::HashString* hash); static const int create_start = 0x1; static const int create_tied = 0x2; static const int create_quiet = 0x4; static const int create_raw_data = 0x8; typedef std::vector command_list_type; // Temporary, find a better place for this. void try_create_download(const std::string& uri, int flags, const command_list_type& commands); void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type()); void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile); private: typedef RangeMap AddressThrottleMap; void create_http(const std::string& uri); void create_final(std::istream* s); void initialize_bencode(Download* d); void receive_http_failed(std::string msg); void receive_hashing_changed(); DownloadList* m_downloadList; DownloadStore* m_downloadStore; FileStatusCache* m_fileStatusCache; HttpQueue* m_httpQueue; CurlStack* m_httpStack; View* m_hashingView; ThrottleMap m_throttles; AddressThrottleMap m_addressThrottles; torrent::log_buffer* m_log_important; torrent::log_buffer* m_log_complete; }; // Meh, cleanup. extern void receive_tracker_dump(const std::string& url, const char* data, size_t size); } #endif rtorrent-0.9.6/src/core/poll_manager.cc000066400000000000000000000061211257211462100200740ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "globals.h" #include "control.h" #include "manager.h" #include "poll_manager.h" namespace core { torrent::Poll* create_poll() { const char* poll_name = getenv("RTORRENT_POLL"); int maxOpen = sysconf(_SC_OPEN_MAX); torrent::Poll* poll = NULL; if (poll_name != NULL) { if (!strcmp(poll_name, "epoll")) poll = torrent::PollEPoll::create(maxOpen); else if (!strcmp(poll_name, "kqueue")) poll = torrent::PollKQueue::create(maxOpen); else if (!strcmp(poll_name, "select")) poll = torrent::PollSelect::create(maxOpen); if (poll == NULL) control->core()->push_log_std(std::string("Cannot enable '") + poll_name + "' based polling."); } if (poll != NULL) control->core()->push_log_std(std::string("Using '") + poll_name + "' based polling."); else if ((poll = torrent::PollEPoll::create(maxOpen)) != NULL) control->core()->push_log_std("Using 'epoll' based polling."); else if ((poll = torrent::PollKQueue::create(maxOpen)) != NULL) control->core()->push_log_std("Using 'kqueue' based polling."); else if ((poll = torrent::PollSelect::create(maxOpen)) != NULL) control->core()->push_log_std("Using 'select' based polling."); else throw torrent::internal_error("Could not create any Poll object."); return poll; } } rtorrent-0.9.6/src/core/poll_manager.h000066400000000000000000000034641257211462100177450ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_POLL_MANAGER_H #define RTORRENT_CORE_POLL_MANAGER_H #include "curl_stack.h" namespace torrent { class Poll; } namespace core { torrent::Poll* create_poll(); } #endif rtorrent-0.9.6/src/core/range_map.h000066400000000000000000000161651257211462100172400ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2008, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_RANGE_MAP_H #define RTORRENT_CORE_RANGE_MAP_H #include #include namespace core { // Associate values with a range of keys, and retrieve for any key in the range. // The template arguments have the same semantics as std::map. // Exception: if set_merge is used, the value type must have a defined operator ==. template, typename Alloc = std::allocator > > class RangeMap : private std::map, Compare, typename Alloc::template rebind > >::other> { typedef std::map, Compare, typename Alloc::template rebind > >::other> base_type; public: RangeMap() {} RangeMap(const Compare& c) : base_type(c) {} typedef typename base_type::iterator iterator; typedef typename base_type::reverse_iterator reverse_iterator; typedef typename base_type::const_iterator const_iterator; typedef typename base_type::const_reverse_iterator const_reverse_iterator; // using typename base_type::const_iterator; // using typename base_type::const_reverse_iterator; using base_type::clear; using base_type::swap; using base_type::size; using base_type::empty; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::key_comp; using base_type::value_comp; // Store a value for the range [begin, end). Returns iterator for the range. const_iterator set_range(const Key& begin, const Key& end, const T& value); // Same, but merge adjacent ranges having the same value. Returns iterator for the merged range. const_iterator set_merge(Key begin, const Key& end, const T& value); // Find range containing the given key, or end(). const_iterator find(const Key& key) const; // Retrieve value for key in a range, throw std::out_of_range if range does not exist. const T& get(const Key& key) const; // Retrieve value for key in a range, return def if range does not exist. T get(const Key& key, T def) const; private: iterator crop_overlap(const Key& begin, const Key& end); }; // Semantics of an entry: // .first End of range (exclusive), map key. // .second.first Beginning of range. // .second.second Value. template inline typename RangeMap::iterator RangeMap::crop_overlap(const Key& _begin, const Key& _end) { typename RangeMap::iterator itr = base_type::upper_bound(_begin); while (itr != end() && key_comp()(itr->second.first, _end)) { // There's a subrange before the new begin: need new entry (new range end means new key). if (key_comp()(itr->second.first, _begin)) base_type::insert(itr, typename RangeMap::value_type(_begin, itr->second)); // Old end is within our range: erase entry. if (!key_comp()(_end, itr->first)) { base_type::erase(itr++); // Otherwise simply set the new begin of the old range. } else { itr->second.first = _end; ++itr; } } return itr; } template inline typename RangeMap::const_iterator RangeMap::set_merge(Key _begin, const Key& _end, const T& value) { if (!key_comp()(_begin, _end)) return end(); // Crop overlapping ranges and return iterator to first range after the one we're inserting. typename RangeMap::iterator itr = crop_overlap(_begin, _end); // Check if range before new one is adjacent and has same value: if so erase it and use its beginning. if (itr != begin()) { typename RangeMap::iterator prev = itr; if (!key_comp()((--prev)->first, _begin) && prev->second.second == value) { _begin = prev->second.first; base_type::erase(prev); } } // Range after new one is adjacent and has same value: set new beginning. if (itr != end() && !key_comp()(_end, itr->second.first) && itr->second.second == value) { itr->second.first = _begin; return itr; } // Otherwise, this range isn't mergeable, make new entry. return base_type::insert(itr, typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value))); } template inline typename RangeMap::const_iterator RangeMap::set_range(const Key& _begin, const Key& _end, const T& value) { if (!key_comp()(_begin, _end)) return end(); return base_type::insert(crop_overlap(_begin, _end), typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value))); } template inline typename RangeMap::const_iterator RangeMap::find(const Key& key) const { typename RangeMap::const_iterator itr = base_type::upper_bound(key); if (itr != end() && key_comp()(key, itr->second.first)) itr = end(); return itr; } template inline const T& RangeMap::get(const Key& key) const { typename RangeMap::const_iterator itr = find(key); if (itr == end()) throw std::out_of_range("RangeMap::get"); return itr->second.second; } template inline T RangeMap::get(const Key& key, T def) const { typename RangeMap::const_iterator itr = find(key); return (itr == end() ? def : itr->second.second); } } #endif rtorrent-0.9.6/src/core/view.cc000066400000000000000000000260701257211462100164130ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "rpc/parse_commands.h" #include "rpc/object_storage.h" #include "control.h" #include "download.h" #include "download_list.h" #include "manager.h" #include "view.h" namespace core { // Also add focus thingie here? struct view_downloads_compare : std::binary_function { view_downloads_compare(const torrent::Object& cmd) : m_command(cmd) {} bool operator () (Download* d1, Download* d2) const { try { if (m_command.is_empty()) return false; if (!m_command.is_dict_key()) return rpc::parse_command_single(rpc::make_target_pair(d1, d2), m_command.as_string()).as_value(); // torrent::Object tmp_command = m_command; // uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; // tmp_command.unset_flags(torrent::Object::mask_function); // tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function); // rpc::parse_command_execute(rpc::make_target_pair(d1, d2), &tmp_command); // return rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), // rpc::make_target_pair(d1, d2)).as_value(); return rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target_pair(d1, d2)).as_value(); } catch (torrent::input_error& e) { control->core()->push_log(e.what()); return false; } } const torrent::Object& m_command; }; struct view_downloads_filter : std::unary_function { view_downloads_filter(const torrent::Object& cmd) : m_command(cmd) {} bool operator () (Download* d1) const { if (m_command.is_empty()) return true; try { torrent::Object result; if (m_command.is_dict_key()) { // torrent::Object tmp_command = m_command; // uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; // tmp_command.unset_flags(torrent::Object::mask_function); // tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function); // rpc::parse_command_execute(rpc::make_target(d1), &tmp_command); // result = rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), // rpc::make_target(d1)); result = rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target(d1)); } else { result = rpc::parse_command_single(rpc::make_target(d1), m_command.as_string()); } switch (result.type()) { // case torrent::Object::TYPE_RAW_BENCODE: return !result.as_raw_bencode().empty(); case torrent::Object::TYPE_VALUE: return result.as_value(); case torrent::Object::TYPE_STRING: return !result.as_string().empty(); case torrent::Object::TYPE_LIST: return !result.as_list().empty(); case torrent::Object::TYPE_MAP: return !result.as_map().empty(); default: return false; } // The default filter action is to return true, to not filter // the download out. return true; } catch (torrent::input_error& e) { control->core()->push_log(e.what()); return false; } } const torrent::Object& m_command; }; void View::emit_changed() { priority_queue_erase(&taskScheduler, &m_delayChanged); priority_queue_insert(&taskScheduler, &m_delayChanged, cachedTime); } void View::emit_changed_now() { for (signal_void::iterator itr = m_signal_changed.begin(), last = m_signal_changed.end(); itr != last; itr++) (*itr)(); } View::~View() { if (m_name.empty()) return; clear_filter_on(); priority_queue_erase(&taskScheduler, &m_delayChanged); } void View::initialize(const std::string& name) { if (!m_name.empty()) throw torrent::internal_error("View::initialize(...) called on an already initialized view."); if (name.empty()) throw torrent::internal_error("View::initialize(...) called with an empty name."); core::DownloadList* dlist = control->core()->download_list(); m_name = name; // Urgh, wrong. No filtering being done. std::for_each(dlist->begin(), dlist->end(), rak::bind1st(std::mem_fun(&View::push_back), this)); m_size = base_type::size(); m_focus = 0; set_last_changed(rak::timer()); m_delayChanged.slot() = std::tr1::bind(&View::emit_changed_now, this); } void View::erase(Download* download) { iterator itr = std::find(base_type::begin(), base_type::end(), download); if (itr >= end_visible()) { erase_internal(itr); } else { erase_internal(itr); rpc::call_object_nothrow(m_event_removed, rpc::make_target(download)); } } void View::set_visible(Download* download) { iterator itr = std::find(begin_filtered(), end_filtered(), download); if (itr == end_filtered()) return; // Don't optimize erase since we want to keep the order of the // non-visible elements. base_type::erase(itr); insert_visible(download); rpc::call_object_nothrow(m_event_added, rpc::make_target(download)); } void View::set_not_visible(Download* download) { iterator itr = std::find(begin_visible(), end_visible(), download); if (itr == end_visible()) return; m_size--; m_focus -= (m_focus > position(itr)); // Don't optimize erase since we want to keep the order of the // non-visible elements. base_type::erase(itr); base_type::push_back(download); rpc::call_object_nothrow(m_event_removed, rpc::make_target(download)); } void View::next_focus() { if (empty()) return; m_focus = (m_focus + 1) % (size() + 1); emit_changed(); } void View::prev_focus() { if (empty()) return; m_focus = (m_focus - 1 + size() + 1) % (size() + 1); emit_changed(); } void View::sort() { Download* curFocus = focus() != end_visible() ? *focus() : NULL; // Don't go randomly switching around equivalent elements. std::stable_sort(begin(), end_visible(), view_downloads_compare(m_sortCurrent)); m_focus = position(std::find(begin(), end_visible(), curFocus)); emit_changed(); } void View::filter() { // Parition the list in two steps so we know which elements changed. iterator splitVisible = std::stable_partition(begin_visible(), end_visible(), view_downloads_filter(m_filter)); iterator splitFiltered = std::stable_partition(begin_filtered(), end_filtered(), view_downloads_filter(m_filter)); base_type changed(splitVisible, splitFiltered); iterator splitChanged = changed.begin() + std::distance(splitVisible, end_visible()); m_size = std::distance(begin(), std::copy(splitChanged, changed.end(), splitVisible)); std::copy(changed.begin(), splitChanged, begin_filtered()); // Fix this... m_focus = std::min(m_focus, m_size); // The commands are allowed to remove itself from or change View // sorting since the commands are being called on the 'changed' // vector. But this will cause undefined behavior if elements are // removed. // // Consider if View should lock itself (and throw) if erase events // are triggered on a Download in the 'changed' list. This can be // done by using a base_type* member variable, and making sure we // set the elements to NULL as we trigger commands on them. Or // perhaps always clear them, thus not throwing anything. if (!m_event_removed.is_empty()) std::for_each(changed.begin(), splitChanged, tr1::bind(&rpc::call_object_d_nothrow, m_event_removed, tr1::placeholders::_1)); if (!m_event_added.is_empty()) std::for_each(changed.begin(), splitChanged, tr1::bind(&rpc::call_object_d_nothrow, m_event_added, tr1::placeholders::_1)); emit_changed(); } void View::filter_download(core::Download* download) { iterator itr = std::find(base_type::begin(), base_type::end(), download); if (itr == base_type::end()) throw torrent::internal_error("View::filter_download(...) could not find download."); if (view_downloads_filter(m_filter)(download)) { if (itr >= end_visible()) { erase_internal(itr); insert_visible(download); rpc::call_object_nothrow(m_event_added, rpc::make_target(download)); } else { // This makes sure the download is sorted even if it is // already visible. // // Consider removing this. erase_internal(itr); insert_visible(download); } } else { if (itr >= end_visible()) return; erase_internal(itr); base_type::push_back(download); rpc::call_object_nothrow(m_event_removed, rpc::make_target(download)); } emit_changed(); } void View::set_filter_on_event(const std::string& event) { control->object_storage()->set_str_multi_key(event, "!view." + m_name, "view.filter_download=" + m_name); } void View::clear_filter_on() { control->object_storage()->rlookup_clear("!view." + m_name); } inline void View::insert_visible(Download* d) { iterator itr = std::find_if(begin_visible(), end_visible(), std::bind1st(view_downloads_compare(m_sortNew), d)); m_size++; m_focus += (m_focus >= position(itr)); base_type::insert(itr, d); } inline void View::erase_internal(iterator itr) { if (itr == end_filtered()) throw torrent::internal_error("View::erase_visible(...) iterator out of range."); m_size -= (itr < end_visible()); m_focus -= (m_focus > position(itr)); base_type::erase(itr); } } rtorrent-0.9.6/src/core/view.h000066400000000000000000000162371257211462100162610ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // Provides a filtered and sorted list of downloads that can be // updated auto-magically. // // We don't worry about std::vector's insert/erase performance as the // elements get accessed often but not modified, better with cache // locality. // // View::m_size indicates the number of Download's that // remain visible, e.g. has not been filtered out. The Download's that // were filtered are still in the underlying vector, but cannot be // accessed through the normal stl container functions. #ifndef RTORRENT_CORE_VIEW_DOWNLOADS_H #define RTORRENT_CORE_VIEW_DOWNLOADS_H #include #include #include #include #include #include "globals.h" namespace core { class Download; class View : private std::vector { public: typedef std::vector base_type; typedef std::tr1::function slot_void; typedef std::list signal_void; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::size_type; View() {} ~View(); void initialize(const std::string& name); const std::string& name() const { return m_name; } bool empty_visible() const { return m_size == 0; } size_type size() const { return m_size; } size_type size_visible() const { return m_size; } size_type size_not_visible() const { return base_type::size() - m_size; } // Perhaps this should be renamed? iterator begin_visible() { return begin(); } const_iterator begin_visible() const { return begin(); } iterator end_visible() { return begin() + m_size; } const_iterator end_visible() const { return begin() + m_size; } iterator begin_filtered() { return begin() + m_size; } const_iterator begin_filtered() const { return begin() + m_size; } iterator end_filtered() { return base_type::end(); } const_iterator end_filtered() const { return base_type::end(); } iterator focus() { return begin() + m_focus; } const_iterator focus() const { return begin() + m_focus; } void set_focus(iterator itr) { m_focus = position(itr); emit_changed(); } void insert(Download* download) { base_type::push_back(download); } void erase(Download* download); void set_visible(Download* download); void set_not_visible(Download* download); void next_focus(); void prev_focus(); void sort(); void set_sort_new(const torrent::Object& s) { m_sortNew = s; } void set_sort_current(const torrent::Object& s) { m_sortCurrent = s; } // Need to explicity trigger filtering. void filter(); void filter_download(core::Download* download); const torrent::Object& get_filter() const { return m_filter; } void set_filter(const torrent::Object& s) { m_filter = s; } void set_filter_on_event(const std::string& event); void clear_filter_on(); const torrent::Object& event_added() const { return m_event_added; } const torrent::Object& event_removed() const { return m_event_removed; } void set_event_added(const torrent::Object& cmd) { m_event_added = cmd; } void set_event_removed(const torrent::Object& cmd) { m_event_removed = cmd; } // The time of the last change to the view, semantics of this is // user-dependent. Used by f.ex. ViewManager to decide if it should // sort and/or filter a view. // // Currently initialized to rak::timer(), though perhaps we should // use cachedTimer. rak::timer last_changed() const { return m_lastChanged; } void set_last_changed(const rak::timer& t = ::cachedTime) { m_lastChanged = t; } // Don't connect any slots until after initialize else it get's // triggered when adding the Download's in DownloadList. signal_void& signal_changed() { return m_signal_changed; } private: View(const View&); void operator = (const View&); void push_back(Download* d) { base_type::push_back(d); } inline void insert_visible(Download* d); inline void erase_internal(iterator itr); void emit_changed(); void emit_changed_now(); size_type position(const_iterator itr) const { return itr - begin(); } // An received thing for changed status so we can sort and filter. std::string m_name; size_type m_size; size_type m_focus; // These should be replaced by a faster non-string command type. torrent::Object m_sortNew; torrent::Object m_sortCurrent; torrent::Object m_filter; torrent::Object m_event_added; torrent::Object m_event_removed; rak::timer m_lastChanged; signal_void m_signal_changed; rak::priority_item m_delayChanged; }; } #endif rtorrent-0.9.6/src/core/view_manager.cc000066400000000000000000000071761257211462100201130ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "globals.h" #include "control.h" #include "rpc/parse_commands.h" #include "download.h" #include "download_list.h" #include "manager.h" #include "view.h" #include "view_manager.h" namespace core { void ViewManager::clear() { std::for_each(begin(), end(), rak::call_delete()); base_type::clear(); } ViewManager::iterator ViewManager::insert(const std::string& name) { if (name.empty()) throw torrent::input_error("View with empty name not supported."); if (find(name) != end()) throw torrent::input_error("View with same name already inserted."); View* view = new View(); view->initialize(name); return base_type::insert(end(), view); } ViewManager::iterator ViewManager::find(const std::string& name) { return std::find_if(begin(), end(), rak::equal(name, std::mem_fun(&View::name))); } ViewManager::iterator ViewManager::find_throw(const std::string& name) { iterator itr = std::find_if(begin(), end(), rak::equal(name, std::mem_fun(&View::name))); if (itr == end()) throw torrent::input_error("Could not find view: " + name); return itr; } void ViewManager::sort(const std::string& name, uint32_t timeout) { iterator viewItr = find_throw(name); if ((*viewItr)->last_changed() + rak::timer::from_seconds(timeout) > cachedTime) return; // Should we rename sort, or add a seperate function? (*viewItr)->filter(); (*viewItr)->sort(); } void ViewManager::set_filter(const std::string& name, const torrent::Object& cmd) { iterator viewItr = find_throw(name); (*viewItr)->set_filter(cmd); (*viewItr)->filter(); } void ViewManager::set_filter_on(const std::string& name, const filter_args& args) { iterator viewItr = find_throw(name); (*viewItr)->clear_filter_on(); // TODO: Ensure the filter keys are rlookup. for (filter_args::const_iterator itr = args.begin(); itr != args.end(); ++itr) (*viewItr)->set_filter_on_event(*itr); } } rtorrent-0.9.6/src/core/view_manager.h000066400000000000000000000075611257211462100177530ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_CORE_VIEW_MANAGER_H #define RTORRENT_CORE_VIEW_MANAGER_H #include #include #include "view.h" namespace core { class ViewManager : public rak::unordered_vector { public: typedef rak::unordered_vector base_type; typedef std::list filter_args; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::size_type; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::size; ViewManager() {} ~ViewManager() { clear(); } // Ffff... Just throwing together an interface, need to think some // more on this. void clear(); iterator insert(const std::string& name); void insert_throw(const std::string& name) { insert(name); } // When erasing, just 'disable' the view so that the users won't // suddenly find their pointer dangling? iterator find(const std::string& name); iterator find_throw(const std::string& name); View* find_ptr_throw(const std::string& name) { return *find_throw(name); } // If View::last_changed() is less than 'timeout' seconds ago, don't // sort. // // Find a better name for 'timeout'. void sort(const std::string& name, uint32_t timeout = 0); // These could be moved to where the command is implemented. void set_sort_new(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_new(cmd); } void set_sort_current(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_current(cmd); } void set_filter(const std::string& name, const torrent::Object& cmd); void set_filter_on(const std::string& name, const filter_args& args); void set_event_added(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_event_added(cmd); } void set_event_removed(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_event_removed(cmd); } }; } #endif rtorrent-0.9.6/src/display/000077500000000000000000000000001257211462100156425ustar00rootroot00000000000000rtorrent-0.9.6/src/display/Makefile.am000066400000000000000000000022031257211462100176730ustar00rootroot00000000000000noinst_LIBRARIES = libsub_display.a libsub_display_a_SOURCES = \ attributes.h \ canvas.cc \ canvas.h \ frame.cc \ frame.h \ manager.cc \ manager.h \ utils.cc \ utils.h \ text_element.h \ text_element_list.cc \ text_element_list.h \ text_element_string.cc \ text_element_string.h \ text_element_value.cc \ text_element_value.h \ window.cc \ window.h \ window_download_chunks_seen.cc \ window_download_chunks_seen.h \ window_download_list.cc \ window_download_list.h \ window_download_statusbar.cc \ window_download_statusbar.h \ window_download_transfer_list.cc \ window_download_transfer_list.h \ window_file_list.cc \ window_file_list.h \ window_http_queue.cc \ window_http_queue.h \ window_input.cc \ window_input.h \ window_log.cc \ window_log.h \ window_log_complete.cc \ window_log_complete.h \ window_peer_list.cc \ window_peer_list.h \ window_statusbar.cc \ window_statusbar.h \ window_string_list.cc \ window_string_list.h \ window_text.cc \ window_text.h \ window_title.cc \ window_title.h \ window_tracker_list.cc \ window_tracker_list.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/display/attributes.h000066400000000000000000000064771257211462100202170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_ATTRIBUTES_H #define RTORRENT_DISPLAY_ATTRIBUTES_H #include #include #if defined(HAVE_NCURSESW_CURSES_H) #include #elif defined(HAVE_NCURSESW_H) #include #elif defined(HAVE_NCURSES_CURSES_H) #include #elif defined(HAVE_NCURSES_H) #include #elif defined(HAVE_CURSES_H) #include #else #error "SysV or X/Open-compatible Curses header file required" #endif // Let us hail the creators of curses for being idiots. The only // clever move they made was in the naming. #undef timeout #undef move namespace display { class Attributes { public: static const int a_invalid = ~int(); static const int a_normal = A_NORMAL; static const int a_bold = A_BOLD; static const int a_reverse = A_REVERSE; static const int color_invalid = ~int(); static const int color_default = 0; Attributes() {} Attributes(const char* pos, int attr, int col) : m_position(pos), m_attributes(attr), m_colors(col) {} Attributes(const char* pos, const Attributes& old) : m_position(pos), m_attributes(old.m_attributes), m_colors(old.m_colors) {} const char* position() const { return m_position; } void set_position(const char* pos) { m_position = pos; } int attributes() const { return m_attributes; } void set_attributes(int attr) { m_attributes = attr; } int colors() const { return m_colors; } void set_colors(int col) { m_colors = col; } private: const char* m_position; int m_attributes; int m_colors; }; } #endif rtorrent-0.9.6/src/display/canvas.cc000066400000000000000000000066201257211462100174300ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "canvas.h" namespace display { bool Canvas::m_isInitialized = false; Canvas::Canvas(int x, int y, int width, int height) : m_window(newwin(height, width, y, x)) { if (m_window == NULL) throw torrent::internal_error("Could not allocate ncurses canvas."); } void Canvas::resize(int x, int y, int w, int h) { wresize(m_window, h, w); mvwin(m_window, y, x); } void Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes) { move(x, y); attr_t org_attr; short org_pair; wattr_get(m_window, &org_attr, &org_pair, NULL); attributes_list::const_iterator attrItr = attributes->begin(); wattr_set(m_window, Attributes::a_normal, Attributes::color_default, NULL); while (first != last) { const char* next = last; if (attrItr != attributes->end()) { next = attrItr->position(); if (first >= next) { wattr_set(m_window, attrItr->attributes(), attrItr->colors(), NULL); ++attrItr; } } print("%.*s", next - first, first); first = next; } // Reset the color. wattr_set(m_window, org_attr, org_pair, NULL); } void Canvas::initialize() { if (m_isInitialized) return; m_isInitialized = true; initscr(); raw(); noecho(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); curs_set(0); } void Canvas::cleanup() { if (!m_isInitialized) return; m_isInitialized = false; noraw(); endwin(); } std::pair Canvas::term_size() { struct winsize ws; if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) return std::pair(ws.ws_col, ws.ws_row); else return std::pair(80, 24); } } rtorrent-0.9.6/src/display/canvas.h000066400000000000000000000140071257211462100172700ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_CANVAS_H #define RTORRENT_DISPLAY_CANVAS_H #include #include #include "attributes.h" namespace display { class Canvas { public: typedef std::vector attributes_list; Canvas(int x = 0, int y = 0, int width = 0, int height = 0); ~Canvas() { delwin(m_window); } void refresh() { wnoutrefresh(m_window); } static void refresh_std() { wnoutrefresh(stdscr); } void redraw() { redrawwin(m_window); } static void redraw_std() { redrawwin(stdscr); } void resize(int w, int h) { wresize(m_window, h, w); } void resize(int x, int y, int w, int h); static void resize_term(int x, int y) { resizeterm(y, x); } static void resize_term(std::pair dim) { resizeterm(dim.second, dim.first); } unsigned int get_x() { int x, __UNUSED y; getyx(m_window, y, x); return x; } unsigned int get_y() { int x, y; getyx(m_window, y, x); return y; } unsigned int width() { int x, __UNUSED y; getmaxyx(m_window, y, x); return x; } unsigned int height() { int x, y; getmaxyx(m_window, y, x); return y; } void move(unsigned int x, unsigned int y) { wmove(m_window, y, x); } chtype get_background() { return getbkgd(m_window); } void set_background(chtype c) { return wbkgdset(m_window, c); } void erase() { werase(m_window); } static void erase_std() { werase(stdscr); } void print_border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, chtype bl, chtype br) { wborder(m_window, ls, rs, ts, bs, tl, tr, bl, br); } // The format string is non-const, but that will not be a problem // since the string shall always be a C string choosen at // compiletime. Might cause extra copying of the string? void print(const char* str, ...); void print(unsigned int x, unsigned int y, const char* str, ...); void print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes); void print_char(const chtype ch) { waddch(m_window, ch); } void print_char(unsigned int x, unsigned int y, const chtype ch) { mvwaddch(m_window, y, x, ch); } void set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) { mvwchgat(m_window, y, x, n, attr, color, NULL); } void set_default_attributes(int attr) { (void)wattrset(m_window, attr); } // Initialize stdscr. static void initialize(); static void cleanup(); static int get_screen_width() { int x, __UNUSED y; getmaxyx(stdscr, y, x); return x; } static int get_screen_height() { int x, y; getmaxyx(stdscr, y, x); return y; } static std::pair term_size(); static void do_update() { doupdate(); } private: Canvas(const Canvas&); void operator = (const Canvas&); static bool m_isInitialized; WINDOW* m_window; }; inline void Canvas::print(const char* str, ...) { va_list arglist; va_start(arglist, str); vw_printw(m_window, const_cast(str), arglist); va_end(arglist); } inline void Canvas::print(unsigned int x, unsigned int y, const char* str, ...) { va_list arglist; va_start(arglist, str); wmove(m_window, y, x); vw_printw(m_window, const_cast(str), arglist); va_end(arglist); } } #endif rtorrent-0.9.6/src/display/frame.cc000066400000000000000000000330341257211462100172460ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "frame.h" #include "window.h" namespace display { Frame::Frame() : m_type(TYPE_NONE), m_positionX(0), m_positionY(0), m_width(0), m_height(0) { } bool Frame::is_width_dynamic() const { switch (m_type) { case TYPE_NONE: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_width_dynamic(); case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->is_width_dynamic()) return true; return false; } return false; } bool Frame::is_height_dynamic() const { switch (m_type) { case TYPE_NONE: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_height_dynamic(); case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->is_height_dynamic()) return true; return false; } return false; } bool Frame::has_left_frame() const { switch (m_type) { case TYPE_NONE: case TYPE_ROW: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_left(); case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->has_left_frame()) return true; return false; } return false; } bool Frame::has_bottom_frame() const { switch (m_type) { case TYPE_NONE: case TYPE_COLUMN: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_bottom(); case TYPE_ROW: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->has_bottom_frame()) return true; return false; } return false; } Frame::bounds_type Frame::preferred_size() const { switch (m_type) { case TYPE_NONE: return bounds_type(0, 0, 0, 0); case TYPE_WINDOW: if (m_window->is_active()) return bounds_type(m_window->min_width(), m_window->min_height(), m_window->max_width(), m_window->max_height()); else return bounds_type(0, 0, 0, 0); case TYPE_ROW: case TYPE_COLUMN: { bounds_type accum(0, 0, 0, 0); for (size_type i = 0; i < m_containerSize; ++i) { bounds_type p = m_container[i]->preferred_size(); accum.minWidth += p.minWidth; accum.minHeight += p.minHeight; if (p.maxWidth == Window::extent_full || accum.maxWidth == Window::extent_full) accum.maxWidth = Window::extent_full; else accum.maxWidth += p.maxWidth; if (p.maxHeight == Window::extent_full || accum.maxHeight == Window::extent_full) accum.maxHeight = Window::extent_full; else accum.maxHeight += p.maxHeight; } return accum; } } return bounds_type(0, 0, 0, 0); } void Frame::set_container_size(size_type size) { if ((m_type != TYPE_ROW && m_type != TYPE_COLUMN) || size >= max_size) throw torrent::internal_error("Frame::set_container_size(...) Bad state."); while (m_containerSize > size) { delete m_container[--m_containerSize]; m_container[m_containerSize] = NULL; } while (m_containerSize < size) { m_container[m_containerSize++] = new Frame(); } } void Frame::initialize_window(Window* window) { if (m_type != TYPE_NONE) throw torrent::internal_error("Frame::initialize_window(...) m_type != TYPE_NONE."); m_type = TYPE_WINDOW; m_window = window; } void Frame::initialize_row(size_type size) { if (m_type != TYPE_NONE) throw torrent::internal_error("Frame::initialize_container(...) Invalid state."); if (size > max_size) throw torrent::internal_error("Frame::initialize_container(...) size >= max_size."); m_type = TYPE_ROW; m_containerSize = size; for (size_type i = 0; i < m_containerSize; ++i) m_container[i] = new Frame(); } void Frame::initialize_column(size_type size) { if (m_type != TYPE_NONE) throw torrent::internal_error("Frame::initialize_container(...) Invalid state."); if (size > max_size) throw torrent::internal_error("Frame::initialize_container(...) size >= max_size."); m_type = TYPE_COLUMN; m_containerSize = size; for (size_type i = 0; i < m_containerSize; ++i) m_container[i] = new Frame(); } void Frame::clear() { switch (m_type) { case TYPE_WINDOW: if (m_window != NULL) m_window->set_offscreen(true); break; case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) { m_container[i]->clear(); delete m_container[i]; } break; default: break; } m_type = TYPE_NONE; } void Frame::refresh() { switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: if (m_window->is_active() && !m_window->is_offscreen()) m_window->refresh(); break; case TYPE_ROW: case TYPE_COLUMN: for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) (*itr)->refresh(); break; } } void Frame::redraw() { switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: if (m_window->is_active() && !m_window->is_offscreen()) m_window->redraw(); break; case TYPE_ROW: case TYPE_COLUMN: for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) (*itr)->redraw(); break; } } void Frame::balance(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { m_positionX = x; m_positionY = y; m_width = width; m_height = height; switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: balance_window(x, y, width, height); break; case TYPE_ROW: balance_row(x, y, width, height); break; case TYPE_COLUMN: balance_column(x, y, width, height); break; } } inline void Frame::balance_window(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Ensure that we don't draw windows that are offscreen or have // zero extent. if (width == 0 || height == 0 || !m_window->is_active()) { m_window->set_offscreen(true); return; } if (width > m_window->max_width()) { if (m_window->is_left()) x += width - m_window->max_width(); width = m_window->max_width(); } if (height > m_window->max_height()) { if (m_window->is_bottom()) y += height - m_window->max_height(); height = m_window->max_height(); } m_window->set_offscreen(false); m_window->resize(x, y, width, height); m_window->mark_dirty(); } inline Frame::extent_type dynamic_min_height(const Frame::dynamic_type& value) { return value.second.min_height(); } inline Frame::extent_type dynamic_min_width(const Frame::dynamic_type& value) { return value.second.min_width(); } inline void Frame::balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Find the size of the static frames. The dynamic frames are added // to a temporary list for the second pass. Each frame uses the // m_width and m_height as temporary storage for width and height in // this algorithm. size_type dynamicSize = 0; dynamic_type dynamicFrames[max_size]; int remaining = height; for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { bounds_type bounds = (*itr)->preferred_size(); if ((*itr)->is_height_dynamic()) { (*itr)->m_height = 0; dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds); } else { (*itr)->m_height = bounds.minHeight; remaining -= bounds.minHeight; } } // Sort the dynamic frames by the min size in the direction we are // interested in. Then try to satisfy the largest first, and if we // have any remaining space we can use that to extend it and any // following frames. // // Else if we're short, only give each what they require. std::stable_sort(dynamicFrames, dynamicFrames + dynamicSize, std::tr1::bind(std::greater(), std::tr1::bind(&dynamic_min_height, std::tr1::placeholders::_1), std::tr1::bind(&dynamic_min_height, std::tr1::placeholders::_2))); bool retry; do { retry = false; for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) { uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last); adjust += itr->first->m_height; adjust = std::max(adjust, itr->second.minHeight); adjust = std::min(adjust, itr->second.maxHeight); remaining -= adjust - itr->first->m_height; retry = retry || itr->first->m_height != adjust; itr->first->m_height = adjust; } } while (retry && remaining > 0); // Use the pre-calculated frame sizes to balance the sub-frames. If // the frame is too small, it will set the remaining windows to zero // extent which will flag them as offscreen. for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { // If there is any remaining space, check if we want to shift // the subsequent frames to the other side of this frame. if (remaining > 0 && (*itr)->has_bottom_frame()) { (*itr)->m_height += remaining; remaining = 0; } (*itr)->balance(x, y, m_width, std::min((*itr)->m_height, height)); y += (*itr)->m_height; height -= (*itr)->m_height; } } inline void Frame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Find the size of the static frames. The dynamic frames are added // to a temporary list for the second pass. Each frame uses the // m_width and m_height as temporary storage for width and height in // this algorithm. size_type dynamicSize = 0; dynamic_type dynamicFrames[max_size]; int remaining = width; for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { bounds_type bounds = (*itr)->preferred_size(); if ((*itr)->is_width_dynamic()) { (*itr)->m_width = 0; dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds); } else { (*itr)->m_width = bounds.minWidth; remaining -= bounds.minWidth; } } // Sort the dynamic frames by the min size in the direction we are // interested in. Then try to satisfy the largest first, and if we // have any remaining space we can use that to extend it and any // following frames. // // Else if we're short, only give each what they require. std::stable_sort(dynamicFrames, dynamicFrames + dynamicSize, std::tr1::bind(std::greater(), std::tr1::bind(&dynamic_min_width, std::tr1::placeholders::_1), std::tr1::bind(&dynamic_min_width, std::tr1::placeholders::_2))); bool retry; do { retry = false; for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) { uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last); adjust += itr->first->m_width; adjust = std::max(adjust, itr->second.minWidth); adjust = std::min(adjust, itr->second.maxWidth); remaining -= adjust - itr->first->m_width; retry = retry || itr->first->m_width != adjust; itr->first->m_width = adjust; } } while (retry && remaining > 0); // Use the pre-calculated frame sizes to balance the sub-frames. If // the frame is too small, it will set the remaining windows to zero // extent which will flag them as offscreen. for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { // If there is any remaining space, check if we want to shift // the subsequent frames to the other side of this frame. if (remaining > 0 && (*itr)->has_left_frame()) { (*itr)->m_width += remaining; remaining = 0; } (*itr)->balance(x, y, std::min((*itr)->m_width, width), m_height); x += (*itr)->m_width; width -= (*itr)->m_width; } } } rtorrent-0.9.6/src/display/frame.h000066400000000000000000000106261257211462100171120ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_FRAME_H #define RTORRENT_DISPLAY_FRAME_H #include namespace display { class Window; class Frame { public: typedef uint32_t extent_type; typedef uint32_t size_type; enum Type { TYPE_NONE, TYPE_WINDOW, TYPE_ROW, TYPE_COLUMN }; struct bounds_type { bounds_type() {} bounds_type(extent_type minW, extent_type minH, extent_type maxW, extent_type maxH) : minWidth(minW), minHeight(minH), maxWidth(maxW), maxHeight(maxH) {} extent_type min_width() const { return minWidth; } extent_type min_height() const { return minHeight; } extent_type minWidth; extent_type minHeight; extent_type maxWidth; extent_type maxHeight; }; typedef std::pair dynamic_type; static const size_type max_size = 5; Frame(); bool is_width_dynamic() const; bool is_height_dynamic() const; bool has_left_frame() const; bool has_bottom_frame() const; bounds_type preferred_size() const; uint32_t position_x() const { return m_positionX; } uint32_t position_y() const { return m_positionY; } uint32_t width() const { return m_width; } uint32_t height() const { return m_height; } Type get_type() const { return m_type; } void set_type(Type t); Window* window() const { return m_window; } Frame* frame(size_type idx) { return m_container[idx]; } size_type container_size() const { return m_containerSize; } void set_container_size(size_type size); void initialize_window(Window* window); void initialize_row(size_type size); void initialize_column(size_type size); void clear(); void refresh(); void redraw(); void balance(uint32_t x, uint32_t y, uint32_t width, uint32_t height); private: inline void balance_window(uint32_t x, uint32_t y, uint32_t width, uint32_t height); inline void balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height); inline void balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height); Type m_type; uint32_t m_positionX; uint32_t m_positionY; uint32_t m_width; uint32_t m_height; union { Window* m_window; struct { size_type m_containerSize; Frame* m_container[max_size]; }; }; }; } #endif rtorrent-0.9.6/src/display/manager.cc000066400000000000000000000066301257211462100175700ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "canvas.h" #include "globals.h" #include "manager.h" #include "window.h" namespace display { Manager::Manager() : m_forceRedraw(false) { m_taskUpdate.slot() = std::tr1::bind(&Manager::receive_update, this); } Manager::~Manager() { priority_queue_erase(&taskScheduler, &m_taskUpdate); } void Manager::force_redraw() { m_forceRedraw = true; } void Manager::schedule(Window* w, rak::timer t) { rak::priority_queue_erase(&m_scheduler, w->task_update()); rak::priority_queue_insert(&m_scheduler, w->task_update(), t); schedule_update(50000); } void Manager::unschedule(Window* w) { rak::priority_queue_erase(&m_scheduler, w->task_update()); schedule_update(50000); } void Manager::adjust_layout() { Canvas::redraw_std(); m_rootFrame.balance(0, 0, Canvas::get_screen_width(), Canvas::get_screen_height()); schedule_update(0); } void Manager::receive_update() { if (m_forceRedraw) { m_forceRedraw = false; display::Canvas::resize_term(display::Canvas::term_size()); Canvas::redraw_std(); adjust_layout(); m_rootFrame.redraw(); } Canvas::refresh_std(); rak::priority_queue_perform(&m_scheduler, cachedTime); m_rootFrame.refresh(); Canvas::do_update(); m_timeLastUpdate = cachedTime; schedule_update(50000); } void Manager::schedule_update(uint32_t minInterval) { if (m_scheduler.empty()) { rak::priority_queue_erase(&taskScheduler, &m_taskUpdate); return; } if (!m_taskUpdate.is_queued() || m_taskUpdate.time() > m_scheduler.top()->time()) { rak::priority_queue_erase(&taskScheduler, &m_taskUpdate); rak::priority_queue_insert(&taskScheduler, &m_taskUpdate, std::max(m_scheduler.top()->time(), m_timeLastUpdate + minInterval)); } } } rtorrent-0.9.6/src/display/manager.h000066400000000000000000000046771257211462100174430ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_MANAGER_H #define RTORRENT_DISPLAY_MANAGER_H #include #include #include "frame.h" namespace display { class Window; class Manager { public: Manager(); ~Manager(); void force_redraw(); void schedule(Window* w, rak::timer t); void unschedule(Window* w); void adjust_layout(); void receive_update(); // New interface. Frame* root_frame() { return &m_rootFrame; } private: void schedule_update(uint32_t minInterval); bool m_forceRedraw; rak::timer m_timeLastUpdate; rak::priority_queue_default m_scheduler; rak::priority_item m_taskUpdate; // New interface. Frame m_rootFrame; }; } #endif rtorrent-0.9.6/src/display/text_element.h000066400000000000000000000050031257211462100205060ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_TEXT_ELEMENT_H #define RTORRENT_DISPLAY_TEXT_ELEMENT_H #include #include #include "display/canvas.h" #include "rpc/command_map.h" namespace display { class TextElement { public: typedef uint32_t extent_type; static const extent_type extent_full = ~extent_type(); TextElement() {} virtual ~TextElement() {} // The last element must point to a valid memory location into which // the caller must write a '\0' to terminate the c string. The // attributes must contain at least one attribute. virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target) = 0; virtual extent_type max_length() = 0; static void push_attribute(Canvas::attributes_list* attributes, Attributes value); private: TextElement(const TextElement&); void operator = (const TextElement&); }; } #endif rtorrent-0.9.6/src/display/text_element_list.cc000066400000000000000000000063151257211462100217060ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "text_element_list.h" namespace display { void TextElementList::clear() { std::for_each(begin(), end(), rak::call_delete()); base_type::clear(); } char* TextElementList::print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target) { int column = m_columnWidth != NULL ? m_column : 0; // Call print for each element even if first == last so that any // attributes gets added to the list. for (iterator itr = begin(); itr != end(); ++itr) if (column-- > 0) { char* columnEnd = std::min(last, first + *m_columnWidth); if (columnEnd < first || columnEnd > last) throw torrent::internal_error("TextElementList::print(...) columnEnd < first || columnEnd > last."); first = (*itr)->print(first, columnEnd, attributes, target); if (first > columnEnd) throw torrent::internal_error("TextElementList::print(...) first > columnEnd."); std::memset(first, ' ', columnEnd - first); first = columnEnd; } else { first = (*itr)->print(first, last, attributes, target); } return first; } TextElementList::extent_type TextElementList::max_length() { extent_type length = 0; int column = m_columnWidth != NULL ? m_column : 0; for (iterator itr = begin(); itr != end(); ++itr) { extent_type l = column-- > 0 ? std::min((*itr)->max_length(), *m_columnWidth) : (*itr)->max_length(); if (l == extent_full) return extent_full; length += l; } return length; } } rtorrent-0.9.6/src/display/text_element_list.h000066400000000000000000000055431257211462100215520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_TEXT_ELEMENT_LIST_H #define RTORRENT_DISPLAY_TEXT_ELEMENT_LIST_H #include "text_element.h" namespace display { class TextElementList : public TextElement, public std::vector { public: typedef std::vector base_type; typedef base_type::value_type value_type; typedef base_type::reference reference; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; typedef base_type::reverse_iterator reverse_iterator; using base_type::empty; using base_type::size; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::push_back; TextElementList() : m_column(0), m_columnWidth(0) {} virtual ~TextElementList() { clear(); } void clear(); void set_column(unsigned int column) { m_column = column; } void set_column_width(extent_type* width) { m_columnWidth = width; } virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target); virtual extent_type max_length(); private: unsigned int m_column; extent_type* m_columnWidth; }; } #endif rtorrent-0.9.6/src/display/text_element_string.cc000066400000000000000000000105401257211462100222340ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "rpc/parse_commands.h" #include "text_element_string.h" namespace display { char* TextElementStringBase::print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target) { Attributes baseAttribute = attributes->back(); push_attribute(attributes, Attributes(first, m_attributes, Attributes::color_invalid)); if (first == last) return first; if (m_flags & flag_escape_hex) { char buffer[last - first]; char* bufferLast = copy_string(buffer, buffer + (last - first), target); first = rak::transform_hex(buffer, bufferLast, first, last); } else if (m_flags & flag_escape_html) { char buffer[last - first]; char* bufferLast = copy_string(buffer, buffer + (last - first), target); first = rak::copy_escape_html(buffer, bufferLast, first, last); } else { first = copy_string(first, last, target); } push_attribute(attributes, Attributes(first, baseAttribute)); return first; } char* TextElementString::copy_string(char* first, char* last, rpc::target_type target) { extent_type length = std::min(last - first, m_string.size()); std::memcpy(first, m_string.c_str(), length); return first + length; } char* TextElementCString::copy_string(char* first, char* last, rpc::target_type target) { extent_type length = std::min(last - first, m_length); std::memcpy(first, m_string, length); return first + length; } char* TextElementCommand::print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target) { Attributes baseAttribute = attributes->back(); push_attribute(attributes, Attributes(first, m_attributes, Attributes::color_invalid)); torrent::Object result = rpc::parse_command(target, m_command, m_commandEnd).first; if (first == last) return first; switch (result.type()) { case torrent::Object::TYPE_STRING: { const std::string& str = result.as_string(); if (m_flags & flag_escape_hex) { first = rak::transform_hex(str.c_str(), str.c_str() + str.size(), first, last); } else if (m_flags & flag_escape_html) { first = rak::copy_escape_html(str.c_str(), str.c_str() + str.size(), first, last); } else { size_t length = std::min(str.size(), std::distance(first, last)); std::memcpy(first, str.c_str(), length); first += std::min(str.size(), length); } break; } case torrent::Object::TYPE_VALUE: { first += std::min(std::max(snprintf(first, last - first + 1, "%lld", (long long int)result.as_value()), 0), last - first + 1); break; } default: return first; } push_attribute(attributes, Attributes(first, baseAttribute)); return first; } } rtorrent-0.9.6/src/display/text_element_string.h000066400000000000000000000157711257211462100221110ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_TEXT_ELEMENT_STRING_H #define RTORRENT_DISPLAY_TEXT_ELEMENT_STRING_H #include #include #include #include "text_element.h" namespace display { class TextElementStringBase : public TextElement { public: static const int flag_normal = 0; static const int flag_escape_hex = (1 << 0); static const int flag_escape_html = (1 << 1); static const int flag_fixed_width = (1 << 8); int flags() const { return m_flags; } void set_flags(int flags) { m_flags = flags; } int attributes() const { return m_attributes; } void set_attributes(int a) { m_attributes = a; } virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target); protected: virtual char* copy_string(char* first, char* last, rpc::target_type target) = 0; int m_flags; int m_attributes; }; class TextElementString : public TextElementStringBase { public: TextElementString(const std::string& s, int flags = flag_normal, int attributes = Attributes::a_invalid) : m_string(s) { m_flags = flags; m_attributes = attributes; } const std::string& str() const { return m_string; } void set_str(const std::string& s) { m_string = s; } virtual extent_type max_length() { return m_string.size(); } private: virtual char* copy_string(char* first, char* last, rpc::target_type target); std::string m_string; }; class TextElementCString : public TextElementStringBase { public: TextElementCString(const char* s, int flags = flag_normal, int attributes = Attributes::a_invalid) : m_length(std::strlen(s)), m_string(s) { m_flags = flags; m_attributes = attributes; } virtual extent_type max_length() { return m_length; } private: virtual char* copy_string(char* first, char* last, rpc::target_type target); extent_type m_length; const char* m_string; }; template class TextElementStringSlot : public TextElementStringBase { public: typedef typename slot_type::argument_type arg1_type; typedef typename slot_type::result_type result_type; TextElementStringSlot(const slot_type& slot, int flags, int attributes, extent_type length) : m_length(length), m_slot(slot) { m_flags = flags; m_attributes = attributes; } virtual extent_type max_length() { return m_length; } private: virtual char* copy_string(char* first, char* last, rpc::target_type target) { if (target.second == NULL) return first; result_type result = m_slot(reinterpret_cast(target.second)); extent_type length = std::min(result_length(&result), last - first); std::memcpy(first, result_buffer(&result), length); return first + length; } template extent_type result_length(Result* result) { return std::min(result->size(), m_length); } extent_type result_length(const char** result) { if (m_flags & flag_fixed_width) return m_length; else return std::min(std::strlen(*result), m_length); } template const char* result_buffer(Result* result) { return result->c_str(); } const char* result_buffer(const char** result) { return *result; } extent_type m_length; slot_type m_slot; }; template inline TextElementStringSlot* text_element_string_slot(const slot_type& slot, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid, TextElement::extent_type length = TextElement::extent_full) { return new TextElementStringSlot(slot, flags, attributes, length); } // // New TE's for calling commands directly. Move to a better place. // class TextElementCommand : public TextElement { public: static const int flag_normal = 0; static const int flag_escape_hex = (1 << 0); static const int flag_escape_html = (1 << 1); static const int flag_fixed_width = (1 << 8); TextElementCommand(const char* command, int flags, int attributes, extent_type length) : m_flags(flags), m_attributes(attributes), m_length(length), m_command(command), m_commandEnd(command + std::strlen(command)) {} int flags() const { return m_flags; } void set_flags(int flags) { m_flags = flags; } int attributes() const { return m_attributes; } void set_attributes(int a) { m_attributes = a; } virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target); virtual extent_type max_length() { return m_length; } protected: int m_flags; int m_attributes; extent_type m_length; const char* m_command; const char* m_commandEnd; }; namespace helpers { inline TextElementCommand* te_command(const char* command, int flags = TextElementCommand::flag_normal, int attributes = Attributes::a_invalid) { return new TextElementCommand(command, flags, attributes, TextElementCommand::extent_full); } } } #endif rtorrent-0.9.6/src/display/text_element_value.cc000066400000000000000000000123271257211462100220470ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "globals.h" #include "text_element_value.h" namespace display { // Should be in text_element.cc. void TextElement::push_attribute(Canvas::attributes_list* attributes, Attributes value) { Attributes base = attributes->back(); if (value.colors() == Attributes::color_invalid) value.set_colors(base.colors()); if (value.attributes() == Attributes::a_invalid) value.set_attributes(base.attributes()); if (base.position() == value.position()) attributes->back() = value; else if (base.colors() != value.colors() || base.attributes() != value.attributes()) attributes->push_back(value); } char* TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target) { Attributes baseAttribute = attributes->back(); push_attribute(attributes, Attributes(first, m_attributes, Attributes::color_invalid)); int64_t val = value(target.second); // Transform the value if needed. if (m_flags & flag_elapsed) val = cachedTime.seconds() - val; else if (m_flags & flag_remaining) val = val - cachedTime.seconds(); if (m_flags & flag_usec) val = rak::timer(val).seconds(); // Print the value. if (first == last) { // Do nothing, but ensure that the last attributes are set. } else if (m_flags & flag_kb) { // Just use a default width of 5 for now. first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f", (double)val / (1 << 10)), 0), last - first + 1); } else if (m_flags & flag_mb) { // Just use a default width of 8 for now. first += std::min(std::max(snprintf(first, last - first + 1, "%8.1f", (double)val / (1 << 20)), 0), last - first + 1); } else if (m_flags & flag_xb) { if (val < (int64_t(1000) << 10)) first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f KB", (double)val / (int64_t(1) << 10)), 0), last - first + 1); else if (val < (int64_t(1000) << 20)) first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f MB", (double)val / (int64_t(1) << 20)), 0), last - first + 1); else if (val < (int64_t(1000) << 30)) first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f GB", (double)val / (int64_t(1) << 30)), 0), last - first + 1); else first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f TB", (double)val / (int64_t(1) << 40)), 0), last - first + 1); } else if (m_flags & flag_timer) { if (val == 0) first += std::min(std::max(snprintf(first, last - first + 1, "--:--:--"), 0), last - first + 1); else first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", (int)(val / 3600), (int)((val / 60) % 60), (int)(val % 60)), 0), last - first + 1); } else if (m_flags & flag_date) { time_t t = val; std::tm *u = std::gmtime(&t); if (u == NULL) return first; first += std::min(std::max(snprintf(first, last - first + 1, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)), 0), last - first + 1); } else if (m_flags & flag_time) { time_t t = val; std::tm *u = std::gmtime(&t); if (u == NULL) return first; first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec), 0), last - first + 1); } else { first += std::min(std::max(snprintf(first, last - first + 1, "%lld", (long long int)val), 0), last - first + 1); } push_attribute(attributes, Attributes(first, baseAttribute)); return first; } } rtorrent-0.9.6/src/display/text_element_value.h000066400000000000000000000121011257211462100216770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_TEXT_ELEMENT_VALUE_H #define RTORRENT_DISPLAY_TEXT_ELEMENT_VALUE_H #include #include #include "text_element.h" namespace display { class TextElementValueBase : public TextElement { public: static const int flag_normal = 0; static const int flag_timer = (1 << 0); static const int flag_date = (1 << 1); static const int flag_time = (1 << 2); static const int flag_kb = (1 << 3); static const int flag_mb = (1 << 4); static const int flag_xb = (1 << 5); static const int flag_elapsed = (1 << 8); static const int flag_remaining = (1 << 9); static const int flag_usec = (1 << 10); int flags() const { return m_flags; } void set_flags(int flags) { m_flags = flags; } int attributes() const { return m_attributes; } void set_attributes(int a) { m_attributes = a; } virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, rpc::target_type target); protected: virtual int64_t value(void* object) = 0; int m_flags; int m_attributes; }; class TextElementValue : public TextElementValueBase { public: TextElementValue(int64_t value, int flags = flag_normal, int attributes = Attributes::a_invalid) : m_value(value) { m_flags = flags; m_attributes = attributes; } int64_t value() const { return m_value; } void set_value(int64_t v) { m_value = v; } virtual extent_type max_length() { return 12; } private: virtual int64_t value(void* object) { return m_value; } int64_t m_value; }; template class TextElementValueSlot0 : public TextElementValueBase { public: typedef typename slot_type::result_type result_type; TextElementValueSlot0(const slot_type& slot, int flags = flag_normal, int attributes = Attributes::a_invalid) : m_slot(slot) { m_flags = flags; m_attributes = attributes; } virtual extent_type max_length() { return 12; } private: virtual int64_t value(void* object) { return m_slot(); } slot_type m_slot; }; template class TextElementValueSlot : public TextElementValueBase { public: typedef typename slot_type::argument_type arg1_type; typedef typename slot_type::result_type result_type; TextElementValueSlot(const slot_type& slot, int flags = flag_normal, int attributes = Attributes::a_invalid) : m_slot(slot) { m_flags = flags; m_attributes = attributes; } virtual extent_type max_length() { return 12; } private: virtual int64_t value(void* object) { if (object == NULL) return 0; return m_slot(reinterpret_cast(object)); } slot_type m_slot; }; template inline TextElementValueSlot0* text_element_value_void(const slot_type& slot, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { return new TextElementValueSlot0(slot, flags, attributes); } template inline TextElementValueSlot* text_element_value_slot(const slot_type& slot, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { return new TextElementValueSlot(slot, flags, attributes); } } #endif rtorrent-0.9.6/src/display/utils.cc000066400000000000000000000272531257211462100173220ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/manager.h" #include "rpc/parse_commands.h" #include "control.h" #include "globals.h" #include "utils.h" namespace display { char* print_string(char* first, char* last, char* str) { if (first == last) return first; // We don't have any nice simple functions for copying strings that // return the end address. while (first + 1 != last && *str != '\0') *(first++) = *(str++); *first = '\0'; return first; } char* print_hhmmss(char* first, char* last, time_t t) { return print_buffer(first, last, "%2d:%02d:%02d", (int)t / 3600, ((int)t / 60) % 60, (int)t % 60); } char* print_hhmmss_local(char* first, char* last, time_t t) { std::tm *u = std::localtime(&t); if (u == NULL) //return "inv_time"; throw torrent::internal_error("print_hhmmss_local(...) failed."); return print_buffer(first, last, "%2u:%02u:%02u", u->tm_hour, u->tm_min, u->tm_sec); } char* print_ddhhmm(char* first, char* last, time_t t) { if (t / (24 * 3600) < 100) return print_buffer(first, last, "%2id %2i:%02i", (int)t / (24 * 3600), ((int)t / 3600) % 24, ((int)t / 60) % 60); else return print_buffer(first, last, "--d --:--"); } char* print_ddmmyyyy(char* first, char* last, time_t t) { std::tm *u = std::gmtime(&t); if (u == NULL) //return "inv_time"; throw torrent::internal_error("print_ddmmyyyy(...) failed."); return print_buffer(first, last, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)); } char* print_address(char* first, char* last, const rak::socket_address* sa) { if (!sa->address_c_str(first, last - first)) return first; return std::find(first, last, '\0'); } inline char* print_address(char* first, char* last, const sockaddr* sa) { return print_address(first, last, rak::socket_address::cast_from(sa)); } char* print_download_title(char* first, char* last, core::Download* d) { return print_buffer(first, last, " %s", d->info()->name().c_str()); } char* print_download_info(char* first, char* last, core::Download* d) { if (!d->download()->info()->is_open()) first = print_buffer(first, last, "[CLOSED] "); else if (!d->download()->info()->is_active()) first = print_buffer(first, last, "[OPEN] "); else first = print_buffer(first, last, " "); if (d->is_done()) first = print_buffer(first, last, "done %10.1f MB", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); else first = print_buffer(first, last, "%6.1f / %6.1f MB", (double)d->download()->bytes_done() / (double)(1 << 20), (double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); first = print_buffer(first, last, " Rate: %5.1f / %5.1f KB Uploaded: %7.1f MB", (double)d->info()->up_rate()->rate() / (1 << 10), (double)d->info()->down_rate()->rate() / (1 << 10), (double)d->info()->up_rate()->total() / (1 << 20)); if (d->download()->info()->is_active() && !d->is_done()) { first = print_buffer(first, last, " "); first = print_download_percentage_done(first, last, d); first = print_buffer(first, last, " "); first = print_download_time_left(first, last, d); } else { first = print_buffer(first, last, " "); } first = print_buffer(first, last, " [%c%c R: %4.2f", rpc::call_command_string("d.tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T', rpc::call_command_value("d.ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I', (double)rpc::call_command_value("d.ratio", rpc::make_target(d)) / 1000.0); if (d->priority() != 2) first = print_buffer(first, last, " %s", rpc::call_command_string("d.priority_str", rpc::make_target(d)).c_str()); if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty()) first = print_buffer(first, last , " %s", rpc::call_command_string("d.throttle_name", rpc::make_target(d)).c_str()); first = print_buffer(first, last , "]"); if (first > last) throw torrent::internal_error("print_download_info(...) wrote past end of the buffer."); return first; } char* print_download_status(char* first, char* last, core::Download* d) { if (d->is_active()) ; else if (rpc::call_command_value("d.hashing", rpc::make_target(d)) != 0) first = print_buffer(first, last, "Hashing: "); else if (!d->is_active()) first = print_buffer(first, last, "Inactive: "); if (d->is_hash_checking()) { first = print_buffer(first, last, "Checking hash [%2i%%]", (d->download()->chunks_hashed() * 100) / d->download()->file_list()->size_chunks()); } else if (d->tracker_list()->has_active_not_scrape()) { torrent::TrackerList::iterator itr = std::find_if(d->tracker_list()->begin(), d->tracker_list()->end(), std::mem_fun(&torrent::Tracker::is_busy_not_scrape)); char status[128]; (*itr)->get_status(status, sizeof(status)); first = print_buffer(first, last, "Tracker[%i:%i]: Connecting to %s %s", (*itr)->group(), std::distance(d->tracker_list()->begin(), itr), (*itr)->url().c_str(), status); } else if (!d->message().empty()) { first = print_buffer(first, last, "%s", d->message().c_str()); } else { *first = '\0'; } if (first > last) throw torrent::internal_error("print_download_status(...) wrote past end of the buffer."); return first; } char* print_download_time_left(char* first, char* last, core::Download* d) { uint32_t rate = d->info()->down_rate()->rate(); if (rate < 512) return print_buffer(first, last, "--d --:--"); time_t remaining = (d->download()->file_list()->size_bytes() - d->download()->bytes_done()) / (rate & ~(uint32_t)(512 - 1)); return print_ddhhmm(first, last, remaining); } char* print_download_percentage_done(char* first, char* last, core::Download* d) { if (!d->is_open() || d->is_done()) //return print_buffer(first, last, "[--%%]"); return print_buffer(first, last, " "); else return print_buffer(first, last, "[%2u%%]", (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks()); } char* print_client_version(char* first, char* last, const torrent::ClientInfo& clientInfo) { switch (torrent::ClientInfo::version_size(clientInfo.type())) { case 4: return print_buffer(first, last, "%s %hhu.%hhu.%hhu.%hhu", clientInfo.short_description(), clientInfo.version()[0], clientInfo.version()[1], clientInfo.version()[2], clientInfo.version()[3]); case 3: return print_buffer(first, last, "%s %hhu.%hhu.%hhu", clientInfo.short_description(), clientInfo.version()[0], clientInfo.version()[1], clientInfo.version()[2]); default: return print_buffer(first, last, "%s", clientInfo.short_description()); } } char* print_status_info(char* first, char* last) { if (!torrent::up_throttle_global()->is_throttled()) first = print_buffer(first, last, "[Throttle off"); else first = print_buffer(first, last, "[Throttle %3i", torrent::up_throttle_global()->max_rate() / 1024); if (!torrent::down_throttle_global()->is_throttled()) first = print_buffer(first, last, "/off KB]"); else first = print_buffer(first, last, "/%3i KB]", torrent::down_throttle_global()->max_rate() / 1024); first = print_buffer(first, last, " [Rate %5.1f/%5.1f KB]", (double)torrent::up_rate()->rate() / 1024.0, (double)torrent::down_rate()->rate() / 1024.0); first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::connection_manager()->listen_port()); if (!rak::socket_address::cast_from(torrent::connection_manager()->local_address())->is_address_any()) { first = print_buffer(first, last, " [Local "); first = print_address(first, last, torrent::connection_manager()->local_address()); first = print_buffer(first, last, "]"); } if (first > last) throw torrent::internal_error("print_status_info(...) wrote past end of the buffer."); if (!rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->is_address_any()) { first = print_buffer(first, last, " [Bind "); first = print_address(first, last, torrent::connection_manager()->bind_address()); first = print_buffer(first, last, "]"); } return first; } char* print_status_extra(char* first, char* last) { first = print_buffer(first, last, " [U %i/%i]", torrent::resource_manager()->currently_upload_unchoked(), torrent::resource_manager()->max_upload_unchoked()); first = print_buffer(first, last, " [D %i/%i]", torrent::resource_manager()->currently_download_unchoked(), torrent::resource_manager()->max_download_unchoked()); first = print_buffer(first, last, " [H %u/%u]", control->core()->http_stack()->active(), control->core()->http_stack()->max_active()); first = print_buffer(first, last, " [S %i/%i/%i]", torrent::total_handshakes(), torrent::connection_manager()->size(), torrent::connection_manager()->max_size()); first = print_buffer(first, last, " [F %i/%i]", torrent::file_manager()->open_files(), torrent::file_manager()->max_open_files()); return first; } } rtorrent-0.9.6/src/display/utils.h000066400000000000000000000130221257211462100171510ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_UTILS_H #define RTORRENT_DISPLAY_UTILS_H #include #include #include namespace core { class Download; } namespace utils { class Timer; } namespace torrent { class ClientInfo; class Entry; } class Control; namespace display { char* print_string(char* first, char* last, char* str); char* print_hhmmss(char* first, char* last, time_t t); char* print_hhmmss_local(char* first, char* last, time_t t); char* print_ddhhmm(char* first, char* last, time_t t); char* print_ddmmyyyy(char* first, char* last, time_t t); char* print_download_title(char* first, char* last, core::Download* d); char* print_download_info(char* first, char* last, core::Download* d); char* print_download_status(char* first, char* last, core::Download* d); char* print_download_time_left(char* first, char* last, core::Download* d); char* print_download_percentage_done(char* first, char* last, core::Download* d); char* print_client_version(char* first, char* last, const torrent::ClientInfo& clientInfo); char* print_entry_tags(char* first, char* last); char* print_entry_file(char* first, char* last, const torrent::Entry& entry); char* print_status_info(char* first, char* last); char* print_status_extra(char* first, char* last); inline char* print_buffer(char* first, char* last, const char* format) { if (first >= last) return first; // Adding 'i' format to suppress a GCC warning. int s = snprintf(first, last - first, format, 0); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1, const Arg2& arg2) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1, arg2); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1, arg2, arg3); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1, arg2, arg3, arg4); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1, arg2, arg3, arg4, arg5); if (s < 0) return first; else return std::min(first + s, last); } template inline char* print_buffer(char* first, char* last, const char* format, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, const Arg6& arg6) { if (first >= last) return first; int s = snprintf(first, last - first, format, arg1, arg2, arg3, arg4, arg5, arg6); if (s < 0) return first; else return std::min(first + s, last); } } #endif rtorrent-0.9.6/src/display/window.cc000066400000000000000000000057471257211462100174750ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "window.h" namespace display { Window::SlotTimer Window::m_slotSchedule; Window::SlotWindow Window::m_slotUnschedule; Window::Slot Window::m_slotAdjust; // When constructing the window we set flag_offscreen so that redraw // doesn't get triggered until after a successful Frame::balance call. Window::Window(Canvas* canvas, int flags, extent_type minWidth, extent_type minHeight, extent_type maxWidth, extent_type maxHeight) : m_canvas(canvas), m_flags(flags | flag_offscreen), m_minWidth(minWidth), m_minHeight(minHeight), m_maxWidth(maxWidth), m_maxHeight(maxHeight) { m_taskUpdate.slot() = std::tr1::bind(&Window::redraw, this); } Window::~Window() { if (is_active()) m_slotUnschedule(this); delete m_canvas; } void Window::set_active(bool state) { if (state == is_active()) return; if (state) { // Set offscreen so we don't try rendering before Frame::balance // has been called. m_flags |= flag_active | flag_offscreen; mark_dirty(); } else { m_flags &= ~flag_active; m_slotUnschedule(this); } } void Window::resize(int x, int y, int w, int h) { if (x < 0 || y < 0) throw std::logic_error("Window::resize(...) bad x or y position"); if (w <= 0 || h <= 0) throw std::logic_error("Window::resize(...) bad size"); m_canvas->resize(x, y, w, h); } } rtorrent-0.9.6/src/display/window.h000066400000000000000000000131721257211462100173260ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_WINDOW_BASE_H #define RTORRENT_WINDOW_BASE_H #include #include #include "canvas.h" #include "globals.h" namespace display { class Canvas; class Manager; class Window { public: typedef uint32_t extent_type; typedef rak::mem_fun0 Slot; typedef rak::mem_fun1 SlotWindow; typedef rak::mem_fun2 SlotTimer; static const int flag_active = (1 << 0); static const int flag_offscreen = (1 << 1); static const int flag_focused = (1 << 2); static const int flag_left = (1 << 3); static const int flag_bottom = (1 << 4); static const extent_type extent_static = extent_type(); static const extent_type extent_full = ~extent_type(); Window(Canvas* canvas, int flags, extent_type minWidth, extent_type minHeight, extent_type maxWidth, extent_type maxHeight); virtual ~Window(); bool is_active() const { return m_flags & flag_active; } void set_active(bool state); bool is_offscreen() const { return m_flags & flag_offscreen; } void set_offscreen(bool state) { if (state) m_flags |= flag_offscreen; else m_flags &= ~flag_offscreen; } bool is_focused() const { return m_flags & flag_focused; } void set_focused(bool state) { if (state) m_flags |= flag_focused; else m_flags &= ~flag_focused; } bool is_left() const { return m_flags & flag_left; } void set_left(bool state) { if (state) m_flags |= flag_left; else m_flags &= ~flag_left; } bool is_bottom() const { return m_flags & flag_bottom; } void set_bottom(bool state) { if (state) m_flags |= flag_bottom; else m_flags &= ~flag_bottom; } bool is_width_dynamic() const { return m_maxWidth > m_minWidth; } bool is_height_dynamic() const { return m_maxHeight > m_minHeight; } // Do not call mark_dirty() from withing redraw() as it may cause // infinite looping in the display scheduler. bool is_dirty() { return m_taskUpdate.is_queued(); } void mark_dirty() { if (!is_active()) return; m_slotSchedule(this, cachedTime); } extent_type min_width() const { return m_minWidth; } extent_type min_height() const { return m_minHeight; } extent_type max_width() const { return std::max(m_maxWidth, m_minWidth); } extent_type max_height() const { return std::max(m_maxHeight, m_minHeight); } extent_type width() const { return m_canvas->width(); } extent_type height() const { return m_canvas->height(); } void refresh() { m_canvas->refresh(); } void resize(int x, int y, int w, int h); virtual void redraw() = 0; rak::priority_item* task_update() { return &m_taskUpdate; } // Slot for adjust and refresh. static void slot_schedule(SlotTimer s) { m_slotSchedule = s; } static void slot_unschedule(SlotWindow s) { m_slotUnschedule = s; } static void slot_adjust(Slot s) { m_slotAdjust = s; } protected: Window(const Window&); void operator = (const Window&); static SlotTimer m_slotSchedule; static SlotWindow m_slotUnschedule; static Slot m_slotAdjust; Canvas* m_canvas; int m_flags; extent_type m_minWidth; extent_type m_minHeight; extent_type m_maxWidth; extent_type m_maxHeight; rak::priority_item m_taskUpdate; }; } #endif rtorrent-0.9.6/src/display/window_download_chunks_seen.cc000066400000000000000000000122361257211462100237400ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include "core/download.h" #include "window_download_chunks_seen.h" namespace display { WindowDownloadChunksSeen::WindowDownloadChunksSeen(core::Download* d, unsigned int *focus) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_download(d), m_focus(focus) { } void WindowDownloadChunksSeen::redraw() { // TODO: Make this depend on tracker signal. m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds()); m_canvas->erase(); if (m_canvas->height() < 3 || m_canvas->width() < 18) return; m_canvas->print(2, 0, "Chunks seen: [C/A/D %i/%i/%.2f]", (int)m_download->download()->peers_complete() + m_download->download()->file_list()->is_done(), (int)m_download->download()->peers_accounted(), std::floor(m_download->distributed_copies() * 100.0f) / 100.0f); const uint8_t* seen = m_download->download()->chunks_seen(); if (seen == NULL || m_download->download()->file_list()->bitfield()->empty()) { m_canvas->print(2, 2, "Not available."); return; } if (!m_download->is_done()) { m_canvas->print(36, 0, "X downloaded missing queued downloading"); m_canvas->print_char(50, 0, 'X' | A_BOLD); m_canvas->print_char(61, 0, 'X' | A_BOLD | A_UNDERLINE); m_canvas->print_char(71, 0, 'X' | A_REVERSE); } *m_focus = std::min(*m_focus, max_focus()); const uint8_t* chunk = seen + *m_focus * chunks_per_row(); const uint8_t* last = seen + m_download->download()->file_list()->size_chunks(); const torrent::Bitfield* bitfield = m_download->download()->file_list()->bitfield(); const torrent::TransferList* transfers = m_download->download()->transfer_list(); std::vector transferChunks(transfers->size(), 0); std::copy(transfers->begin(), transfers->end(), transferChunks.begin()); std::sort(transferChunks.begin(), transferChunks.end(), rak::less2(std::mem_fun(&torrent::BlockList::index), std::mem_fun(&torrent::BlockList::index))); std::vector::const_iterator itrTransfer = transferChunks.begin(); while (itrTransfer != transferChunks.end() && (uint32_t)(chunk - seen) > (*itrTransfer)->index()) itrTransfer++; for (unsigned int y = 1; y < m_canvas->height() && chunk < last; ++y) { m_canvas->print(0, y, "%5u ", (int)(chunk - seen)); while (chunk < last) { chtype attr; if (bitfield->get(chunk - seen)) { attr = A_NORMAL; } else if (itrTransfer != transferChunks.end() && (uint32_t)(chunk - seen) == (*itrTransfer)->index()) { if (std::find_if((*itrTransfer)->begin(), (*itrTransfer)->end(), std::mem_fun_ref(&torrent::Block::is_transfering)) != (*itrTransfer)->end()) attr = A_REVERSE; else attr = A_BOLD | A_UNDERLINE; itrTransfer++; } else { attr = A_BOLD; } m_canvas->print_char(attr | rak::value_to_hexchar<0>(std::min(*chunk, 0xF))); chunk++; if ((chunk - seen) % 10 == 0) { if (m_canvas->get_x() + 12 > m_canvas->width()) break; m_canvas->print_char(' '); } } } } unsigned int WindowDownloadChunksSeen::rows() const { if (m_canvas->width() < 18) return 0; return (m_download->download()->file_list()->size_chunks() + chunks_per_row() - 1) / chunks_per_row(); } } rtorrent-0.9.6/src/display/window_download_chunks_seen.h000066400000000000000000000044101257211462100235750ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_DOWNLOAD_CHUNKS_SEEN_H #define RTORRENT_DISPLAY_WINDOW_DOWNLOAD_CHUNKS_SEEN_H #include #include "window.h" namespace core { class Download; } namespace display { class WindowDownloadChunksSeen : public Window { public: WindowDownloadChunksSeen(core::Download* d, unsigned int* focus); virtual void redraw(); unsigned int rows() const; unsigned int chunks_per_row() const { return (width() - 6) / 11 * 10; } unsigned int max_focus() const { return std::max(rows() - height() / 2 + 1, 0); } private: core::Download* m_download; unsigned int* m_focus; }; } #endif rtorrent-0.9.6/src/display/window_download_list.cc000066400000000000000000000076671257211462100224220ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "core/download.h" #include "core/view.h" #include "canvas.h" #include "globals.h" #include "utils.h" #include "window_download_list.h" namespace display { WindowDownloadList::WindowDownloadList() : Window(new Canvas, 0, 120, 1, extent_full, extent_full), m_view(NULL) { } WindowDownloadList::~WindowDownloadList() { if (m_view != NULL) m_view->signal_changed().erase(m_changed_itr); m_view = NULL; } void WindowDownloadList::set_view(core::View* l) { if (m_view != NULL) m_view->signal_changed().erase(m_changed_itr); m_view = l; if (m_view != NULL) m_changed_itr = m_view->signal_changed().insert(m_view->signal_changed().begin(), std::tr1::bind(&Window::mark_dirty, this)); } void WindowDownloadList::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); if (m_view == NULL) return; m_canvas->print(0, 0, "%s", ("[View: " + m_view->name() + "]").c_str()); if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2) return; typedef std::pair Range; Range range = rak::advance_bidirectional(m_view->begin_visible(), m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(), m_view->end_visible(), m_canvas->height() / 3); // Make sure we properly fill out the last lines so it looks like // there are more torrents, yet don't hide it if we got the last one // in focus. if (range.second != m_view->end_visible()) ++range.second; int pos = 1; while (range.first != range.second) { char buffer[m_canvas->width() + 1]; char* last = buffer + m_canvas->width() - 2 + 1; print_download_title(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); print_download_info(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); print_download_status(buffer, last, *range.first); m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer); ++range.first; } } } rtorrent-0.9.6/src/display/window_download_list.h000066400000000000000000000042041257211462100222440ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_DOWNLOAD_LIST_H #define RTORRENT_DISPLAY_WINDOW_DOWNLOAD_LIST_H #include "window.h" #include "core/download_list.h" #include "core/view.h" namespace display { class WindowDownloadList : public Window { public: typedef core::View::signal_void::iterator signal_void_itr; WindowDownloadList(); ~WindowDownloadList(); virtual void redraw(); void set_view(core::View* l); private: core::View* m_view; signal_void_itr m_changed_itr; }; } #endif rtorrent-0.9.6/src/display/window_download_statusbar.cc000066400000000000000000000075271257211462100234520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "canvas.h" #include "globals.h" #include "utils.h" #include "window_download_statusbar.h" #include "core/download.h" namespace display { WindowDownloadStatusbar::WindowDownloadStatusbar(core::Download* d) : Window(new Canvas, 0, 0, 3, extent_full, extent_static), m_download(d) { } void WindowDownloadStatusbar::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); char buffer[m_canvas->width()]; char* last = buffer + m_canvas->width() - 2; print_download_info(buffer, last, m_download); m_canvas->print(0, 0, "%s", buffer); snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Slots: U:%i/%i D:%i/%i U/I/C/A: %i/%i/%i/%i Unchoked: %u/%u Failed: %i", (int)m_download->download()->connection_list()->size(), (int)m_download->download()->peer_list()->available_list_size(), (int)m_download->download()->connection_list()->min_size(), (int)m_download->download()->connection_list()->max_size(), (int)m_download->download()->uploads_min(), (int)m_download->download()->uploads_max(), (int)m_download->download()->downloads_min(), (int)m_download->download()->downloads_max(), (int)m_download->download()->peers_currently_unchoked(), (int)m_download->download()->peers_currently_interested(), (int)m_download->download()->peers_complete(), (int)m_download->download()->peers_accounted(), (int)m_download->info()->upload_unchoked(), (int)m_download->info()->download_unchoked(), (int)m_download->download()->transfer_list()->failed_count()); m_canvas->print(0, 1, "%s", buffer); print_download_status(buffer, last, m_download); m_canvas->print(0, 2, "[%c:%i] %s", m_download->tracker_list()->has_active() ? 'C' : ' ', (int)(m_download->download()->tracker_controller()->seconds_to_next_timeout()), buffer); } } rtorrent-0.9.6/src/display/window_download_statusbar.h000066400000000000000000000037261257211462100233110ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_WINDOW_DOWNLOAD_STATUSBAR_H #define RTORRENT_WINDOW_DOWNLOAD_STATUSBAR_H #include "window.h" namespace core { class Download; } namespace display { class WindowDownloadStatusbar : public Window { public: WindowDownloadStatusbar(core::Download* d); virtual void redraw(); private: core::Download* m_download; }; } #endif rtorrent-0.9.6/src/display/window_download_transfer_list.cc000066400000000000000000000115461257211462100243150ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/download.h" #include "window_download_transfer_list.h" namespace display { WindowDownloadTransferList::WindowDownloadTransferList(core::Download* d, unsigned int *focus) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_download(d) { } void WindowDownloadTransferList::redraw() { // TODO: Make this depend on tracker signal. m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); if (m_canvas->height() < 3 || m_canvas->width() < 18) return; const torrent::TransferList* transfers = m_download->download()->transfer_list(); m_canvas->print(2, 0, "Transfer list: [Size %i]", transfers->size()); torrent::TransferList::const_iterator itr = transfers->begin(); // This is just for testing and the layout and included information // is just something i threw in there, someone really should // prettify this. (This is a very subtle hint) for (unsigned int y = 1; y < m_canvas->height() && itr != transfers->end(); ++y, ++itr) { m_canvas->print(0, y, "%5u [P: %u F: %u]", (*itr)->index(), (*itr)->priority(), (*itr)->failed()); // Handle window size. for (torrent::BlockList::const_iterator bItr = (*itr)->begin(), bLast = (*itr)->end(); bItr != bLast; ++bItr) { if (m_canvas->get_x() >= m_canvas->width() - 1) { if (++y >= m_canvas->height()) break; m_canvas->move(17, y); } char id; chtype attr = A_NORMAL; if (bItr->is_finished()) { attr = A_REVERSE; id = key_id(bItr->leader()->const_peer_info()); } else if (bItr->is_transfering()) { attr = A_BOLD; id = key_id(bItr->leader()->const_peer_info()); } else if (bItr->queued()->size() >= 1) { id = std::tolower(key_id(bItr->queued()->back()->const_peer_info())); } else { id = '.'; } if (bItr->size_all() > 1) attr |= A_UNDERLINE; m_canvas->print_char(attr | id); } } } unsigned int WindowDownloadTransferList::rows() const { if (m_canvas->width() < 18) return 0; // return (m_download->download()->chunks_total() + chunks_per_row() - 1) / chunks_per_row(); return 0; } char WindowDownloadTransferList::key_id(torrent::BlockTransfer::key_type key) { uint32_t oldestTime = cachedTime.seconds(); assigned_vector::iterator oldestItr = m_assigned.begin(); for (assigned_vector::iterator itr = m_assigned.begin(), last = m_assigned.end(); itr != last; ++itr) { if (itr->m_key == key) { itr->m_last = cachedTime.seconds(); return itr->m_id; } if (itr->m_last < oldestTime) { oldestTime = itr->m_last; oldestItr = itr; } } if (oldestItr == m_assigned.end() || cachedTime.seconds() - oldestTime <= 60) { // We didn't find any previously used id's to take over. // Return 'f' when we run out of characters. if (m_assigned.size() >= ('Z' - 'A')) return 'Z'; char id = 'A' + m_assigned.size(); m_assigned.push_back(assigned_type(key, cachedTime.seconds(), id)); return id; } else { return oldestItr->m_id; } } } rtorrent-0.9.6/src/display/window_download_transfer_list.h000066400000000000000000000051421257211462100241520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_DOWNLOAD_TRANSFER_LIST_H #define RTORRENT_DISPLAY_WINDOW_DOWNLOAD_TRANSFER_LIST_H #include #include #include "window.h" namespace core { class Download; } namespace display { class WindowDownloadTransferList : public Window { public: struct assigned_type { assigned_type(torrent::BlockTransfer::key_type key, uint32_t last, char id) : m_key(key), m_last(last), m_id(id) { } torrent::BlockTransfer::key_type m_key; uint32_t m_last; char m_id; }; typedef std::vector assigned_vector; WindowDownloadTransferList(core::Download* d, unsigned int* focus); virtual void redraw(); unsigned int rows() const; unsigned int max_focus() const { return std::max(rows() - height() + 1, 0); } private: char key_id(torrent::BlockTransfer::key_type key); core::Download* m_download; assigned_vector m_assigned; }; } #endif rtorrent-0.9.6/src/display/window_file_list.cc000066400000000000000000000154651257211462100215250ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/download.h" #include "ui/element_file_list.h" #include "window_file_list.h" namespace display { // Don't really like the direction of the element dependency, but // don't really feel like making a seperate class for containing the // necessary information. WindowFileList::WindowFileList(const ui::ElementFileList* element) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_element(element) { } // Convert std::string to std::wstring of given width (in screen positions), // taking into account that some characters may be occupying two screen positions. std::wstring wstring_width(const std::string& i_str, int width) { wchar_t result[width + 1]; size_t length = std::mbstowcs(result, i_str.c_str(), width); // If not valid UTF-8 encoding, at least copy the printable characters. if (length == (size_t)-1) { wchar_t* out = result; for (std::string::const_iterator itr = i_str.begin(); out != result + width && itr != i_str.end(); ++itr) if (!std::isprint(*itr, std::locale::classic())) *out++ = '?'; else *out++ = *itr; *out = 0; } int swidth = wcswidth(result, width); // Limit to width if it's too wide already. if (swidth == -1 || swidth > width) { length = swidth = 0; while (result[length]) { int next = ::wcwidth(result[length]); // Unprintable character? if (next == -1) { result[length] = '?'; next = 1; } if (swidth + next > width) { result[length] = 0; break; } length++; swidth += next; } } // Pad with spaces to given width. while (swidth < width && length <= (unsigned int)width) { result[length++] = ' '; swidth++; } result[length] = 0; return result; } void WindowFileList::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds()); m_canvas->erase(); torrent::FileList* fl = m_element->download()->download()->file_list(); if (fl->size_files() == 0 || m_canvas->height() < 2) return; std::vector entries(m_canvas->height() - 1); unsigned int last = 0; for (iterator itr = m_element->selected(); last != m_canvas->height() - 1; ) { if (m_element->is_collapsed()) itr.forward_current_depth(); else ++itr; entries[last++] = itr; if (itr == iterator(fl->end())) break; } unsigned int first = m_canvas->height() - 1; for (iterator itr = m_element->selected(); first >= last || first > (m_canvas->height() - 1) / 2; ) { entries[--first] = itr; if (itr == iterator(fl->begin())) break; if (m_element->is_collapsed()) itr.backward_current_depth(); else --itr; } unsigned int pos = 0; int filenameWidth = m_canvas->width() - 16; m_canvas->print(0, pos++, "Cmp Pri Size Filename"); while (pos != m_canvas->height()) { iterator itr = entries[first]; if (itr == iterator(fl->end())) break; m_canvas->set_default_attributes(itr == m_element->selected() ? is_focused() ? A_REVERSE : A_BOLD : A_NORMAL); if (itr.is_empty()) { m_canvas->print(0, pos, "%*c%-*s", 16, ' ', filenameWidth, "EMPTY"); } else if (itr.is_entering()) { m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\', itr.depth() < (*itr)->path()->size() ? wstring_width((*itr)->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN"); } else if (itr.is_leaving()) { m_canvas->print(0, pos, "%*c %-*s", 16 + (itr.depth() - 1), '/', filenameWidth - (itr.depth() - 1), ""); } else if (itr.is_file()) { torrent::File* e = *itr; const char* priority; switch (e->priority()) { case torrent::PRIORITY_OFF: priority = "off"; break; case torrent::PRIORITY_NORMAL: priority = " "; break; case torrent::PRIORITY_HIGH: priority = "hig"; break; default: priority = "BUG"; break; }; m_canvas->print(0, pos, "%3d %s ", done_percentage(e), priority); int64_t val = e->size_bytes(); if (val < (int64_t(1000) << 10)) m_canvas->print(8, pos, "%5.1f K", (double)val / (int64_t(1) << 10)); else if (val < (int64_t(1000) << 20)) m_canvas->print(8, pos, "%5.1f M", (double)val / (int64_t(1) << 20)); else if (val < (int64_t(1000) << 30)) m_canvas->print(8, pos, "%5.1f G", (double)val / (int64_t(1) << 30)); else m_canvas->print(8, pos, "%5.1f T", (double)val / (int64_t(1) << 40)); m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|', itr.depth() < (*itr)->path()->size() ? wstring_width((*itr)->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN"); } else { m_canvas->print(0, pos, "BORK BORK"); } m_canvas->set_default_attributes(A_NORMAL); pos++; first = (first + 1) % (m_canvas->height() - 1); } } int WindowFileList::done_percentage(torrent::File* e) { int chunks = e->range().second - e->range().first; return chunks ? (e->completed_chunks() * 100) / chunks : 100; } } rtorrent-0.9.6/src/display/window_file_list.h000066400000000000000000000043661257211462100213650ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_FILE_LIST_H #define RTORRENT_DISPLAY_FILE_LIST_H #include "window.h" namespace ui { class ElementFileList; } namespace torrent { class File; class FileListIterator; class file_list_collapsed_iterator; } namespace display { class WindowFileList : public Window { public: typedef torrent::FileListIterator iterator; typedef torrent::file_list_collapsed_iterator collapsed_iterator; WindowFileList(const ui::ElementFileList* element); virtual void redraw(); private: int done_percentage(torrent::File* e); const ui::ElementFileList* m_element; }; } #endif rtorrent-0.9.6/src/display/window_http_queue.cc000066400000000000000000000117211257211462100217250ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "core/curl_get.h" #include "core/http_queue.h" #include "canvas.h" #include "rak/functional.h" #include "window_http_queue.h" namespace display { WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) : Window(new Canvas, 0, 0, 1, extent_full, 1), m_queue(q) { set_active(false); m_connInsert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), std::tr1::bind(&WindowHttpQueue::receive_insert, this, std::tr1::placeholders::_1)); m_connErase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), std::tr1::bind(&WindowHttpQueue::receive_erase, this, std::tr1::placeholders::_1)); } void WindowHttpQueue::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); cleanup_list(); if (m_container.empty()) { set_active(false); m_slotAdjust(); return; } m_canvas->erase(); m_canvas->print(0, 0, "Http [%i]", m_queue->size()); unsigned int pos = 10; Container::iterator itr = m_container.begin(); while (itr != m_container.end() && pos + 20 < m_canvas->width()) { if (itr->m_http == NULL) m_canvas->print(pos, 0, "%s done", itr->m_name.c_str()); else if (itr->m_http->size_total() == 0) m_canvas->print(pos, 0, "%s ---%%", itr->m_name.c_str()); else m_canvas->print(pos, 0, "%s %3i%%", itr->m_name.c_str(), (int)(100.0 * itr->m_http->size_done() / itr->m_http->size_total())); pos += itr->m_name.size() + 6; ++itr; } } void WindowHttpQueue::cleanup_list() { for (Container::iterator itr = m_container.begin(); itr != m_container.end();) if (itr->m_http == NULL && itr->m_timer < cachedTime) itr = m_container.erase(itr); else ++itr; // Bad, can't have this here as it is called from redraw(). // mark_dirty(); } std::string WindowHttpQueue::create_name(core::CurlGet* h) { size_t p = h->url().rfind('/', h->url().size() - std::min(10, h->url().size())); std::string n = p != std::string::npos ? h->url().substr(p) : h->url(); if (n.empty()) throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string"); if (n.size() > 2 && n[0] == '/') n = n.substr(1); if (n.size() > 9 && (n.substr(n.size() - 8) == ".torrent" || n.substr(n.size() - 8) == ".TORRENT")) n = n.substr(0, n.size() - 8); if (n.size() > 30) n = n.substr(0, 30); return n; } void WindowHttpQueue::receive_insert(core::CurlGet* h) { m_container.push_back(Node(h, create_name(h))); if (!is_active()) { set_active(true); m_slotAdjust(); } mark_dirty(); } void WindowHttpQueue::receive_erase(core::CurlGet* h) { Container::iterator itr = std::find_if(m_container.begin(), m_container.end(), rak::equal(h, std::mem_fun_ref(&Node::get_http))); if (itr == m_container.end()) throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have"); itr->m_http = NULL; itr->m_timer = cachedTime + rak::timer::from_seconds(1); mark_dirty(); } } rtorrent-0.9.6/src/display/window_http_queue.h000066400000000000000000000053221257211462100215670ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H #define RTORRENT_DISPLAY_WINDOW_HTTP_QUEUE_H #include #include "window.h" namespace core { class CurlGet; class HttpQueue; } namespace display { class WindowHttpQueue : public Window { public: typedef std::tr1::function slot_curl_get; typedef std::list signal_curl_get; WindowHttpQueue(core::HttpQueue* q); virtual void redraw(); private: struct Node { Node(core::CurlGet* h, const std::string& n) : m_http(h), m_name(n) {} core::CurlGet* get_http() { return m_http; } core::CurlGet* m_http; std::string m_name; rak::timer m_timer; }; typedef std::list Container; void cleanup_list(); void receive_insert(core::CurlGet* h); void receive_erase(core::CurlGet* h); static std::string create_name(core::CurlGet* h); core::HttpQueue* m_queue; Container m_container; signal_curl_get::iterator m_connInsert; signal_curl_get::iterator m_connErase; }; } #endif rtorrent-0.9.6/src/display/window_input.cc000066400000000000000000000037651257211462100207120ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "canvas.h" #include "window_input.h" #include "input/text_input.h" namespace display { void WindowInput::redraw() { m_canvas->erase(); m_canvas->print(0, 0, "%s> %s", m_title.c_str(), m_input != NULL ? m_input->c_str() : ""); if (m_focus) m_canvas->set_attr(m_input->get_pos() + 2 + m_title.size(), 0, 1, A_REVERSE, COLOR_PAIR(0)); } } rtorrent-0.9.6/src/display/window_input.h000066400000000000000000000051041257211462100205410ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_INPUT_H #define RTORRENT_DISPLAY_WINDOW_INPUT_H #include #include "window.h" namespace input { class TextInput; } namespace display { class WindowInput : public Window { public: WindowInput() : Window(new Canvas, 0, 0, 1, extent_full, 1), m_input(NULL), m_focus(false) {} input::TextInput* input() { return m_input; } void set_input(input::TextInput* input) { m_input = input; } const std::string& title() const { return m_title; } void set_title(const std::string& str) { m_title = str; } bool focus() const { return m_focus; } void set_focus(bool f) { m_focus = f; if (is_active()) mark_dirty(); } virtual void redraw(); private: input::TextInput* m_input; std::string m_title; bool m_focus; }; } #endif rtorrent-0.9.6/src/display/window_log.cc000066400000000000000000000067741257211462100203370ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "canvas.h" #include "utils.h" #include "window_log.h" namespace display { WindowLog::WindowLog(torrent::log_buffer* l) : Window(new Canvas, 0, 0, 0, extent_full, extent_static), m_log(l) { m_taskUpdate.slot() = std::tr1::bind(&WindowLog::receive_update, this); unsigned int signal_index = torrent::main_thread()->signal_bitfield()->add_signal(std::tr1::bind(&WindowLog::receive_update, this)); m_log->lock_and_set_update_slot(std::tr1::bind(&torrent::thread_base::send_event_signal, torrent::main_thread(), signal_index, false)); } WindowLog::~WindowLog() { priority_queue_erase(&taskScheduler, &m_taskUpdate); } WindowLog::iterator WindowLog::find_older() { return m_log->find_older(cachedTime.seconds() - 60); // return m_log->begin(); } void WindowLog::redraw() { m_canvas->erase(); int pos = m_canvas->height(); for (iterator itr = m_log->end(), last = find_older(); itr != last && pos > 0; --pos) { itr--; char buffer[16]; print_hhmmss_local(buffer, buffer + 16, static_cast(itr->timestamp)); m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.c_str()); } } // When WindowLog is activated, call receive_update() to ensure it // gets updated. void WindowLog::receive_update() { if (!is_active()) return; iterator itr = find_older(); extent_type height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits::difference_type)10); if (height != m_maxHeight) { m_minHeight = height != 0 ? 1 : 0; m_maxHeight = height; mark_dirty(); m_slotAdjust(); } else { mark_dirty(); } priority_queue_erase(&taskScheduler, &m_taskUpdate); if (height != 0) priority_queue_insert(&taskScheduler, &m_taskUpdate, (cachedTime + rak::timer::from_seconds(5)).round_seconds()); } } rtorrent-0.9.6/src/display/window_log.h000066400000000000000000000041621257211462100201660ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_LOG_H #define RTORRENT_DISPLAY_WINDOW_LOG_H #include #include "window.h" namespace display { class WindowLog : public Window { public: typedef torrent::log_buffer::const_iterator iterator; WindowLog(torrent::log_buffer* l); ~WindowLog(); virtual void redraw(); void receive_update(); private: inline iterator find_older(); torrent::log_buffer* m_log; rak::priority_item m_taskUpdate; }; } #endif rtorrent-0.9.6/src/display/window_log_complete.cc000066400000000000000000000061371257211462100222200ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "canvas.h" #include "utils.h" #include "window_log_complete.h" namespace display { WindowLogComplete::WindowLogComplete(torrent::log_buffer* l) : Window(new Canvas, 0, 30, 1, extent_full, extent_full), m_log(l) { } WindowLogComplete::~WindowLogComplete() { } WindowLogComplete::iterator WindowLogComplete::find_older() { return m_log->find_older(cachedTime.seconds() - 60); } void WindowLogComplete::redraw() { m_canvas->erase(); if (m_canvas->width() < 16) return; int pos = m_canvas->height(); for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && pos > 0; ) { itr--; char buffer[16]; // Use an arbitrary min width of 60 for allowing multiple // lines. This should ensure we don't mess up the display when the // screen is shrunk too much. unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast(itr->timestamp)) - buffer; unsigned int logWidth = m_canvas->width() > 60 ? (m_canvas->width() - timeWidth) : (60 - timeWidth); unsigned int logHeight = (itr->message.size() + logWidth - 1) / logWidth; for (unsigned int j = logHeight; j > 0 && pos > 0; --j, --pos) if (j == 1) m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.substr(0, m_canvas->width() - timeWidth).c_str()); else m_canvas->print(timeWidth, pos - 1, "%s", itr->message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str()); } } } rtorrent-0.9.6/src/display/window_log_complete.h000066400000000000000000000041101257211462100220470ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_LOG_COMPLETE_H #define RTORRENT_DISPLAY_WINDOW_LOG_COMPLETE_H #include #include "window.h" namespace display { class WindowLogComplete : public Window { public: typedef torrent::log_buffer::const_iterator iterator; WindowLogComplete(torrent::log_buffer* l); ~WindowLogComplete(); virtual void redraw(); private: inline iterator find_older(); torrent::log_buffer* m_log; }; } #endif rtorrent-0.9.6/src/display/window_peer_list.cc000066400000000000000000000127221257211462100215320ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "core/download.h" #include "rak/algorithm.h" #include "canvas.h" #include "utils.h" #include "window_peer_list.h" namespace display { WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_download(d), m_list(l), m_focus(f) { } void WindowPeerList::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); int x = 2; int y = 0; m_canvas->print(x, y, "IP"); x += 16; m_canvas->print(x, y, "UP"); x += 7; m_canvas->print(x, y, "DOWN"); x += 7; m_canvas->print(x, y, "PEER"); x += 7; m_canvas->print(x, y, "CT/RE/LO"); x += 10; m_canvas->print(x, y, "QS"); x += 6; m_canvas->print(x, y, "DONE"); x += 6; m_canvas->print(x, y, "REQ"); x += 6; m_canvas->print(x, y, "SNUB"); x += 6; m_canvas->print(x, y, "FAILED"); ++y; if (m_list->empty()) return; typedef std::pair Range; Range range = rak::advance_bidirectional(m_list->begin(), *m_focus != m_list->end() ? *m_focus : m_list->begin(), m_list->end(), m_canvas->height() - y); if (m_download->download()->file_list()->size_chunks() <= 0) throw std::logic_error("WindowPeerList::redraw() m_slotChunksTotal() returned invalid value"); while (range.first != range.second) { torrent::Peer* p = *range.first; x = 0; m_canvas->print(x, y, "%c %s", range.first == *m_focus ? '*' : ' ', rak::socket_address::cast_from(p->address())->address_str().c_str()); x += 18; m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p->peer_rate()->rate() / 1024); x += 7; char remoteChoked; char peerType; if (!p->is_down_choked_limited()) remoteChoked = 'U'; else if (p->is_down_queued()) remoteChoked = 'Q'; else remoteChoked = 'C'; if (p->peer_info()->is_blocked()) peerType = 'u'; else if (p->peer_info()->is_preferred()) peerType = 'p'; else peerType = ' '; m_canvas->print(x, y, "%c%c/%c%c/%c%c", p->is_encrypted() ? (p->is_incoming() ? 'R' : 'L') : (p->is_incoming() ? 'r' : 'l'), peerType, p->is_down_choked() ? std::tolower(remoteChoked) : remoteChoked, p->is_down_interested() ? 'i' : 'n', p->is_up_choked() ? 'c' : 'u', p->is_up_interested() ? 'i' : 'n'); x += 10; m_canvas->print(x, y, "%i/%i", p->outgoing_queue_size(), p->incoming_queue_size()); x += 6; m_canvas->print(x, y, "%3i", done_percentage(*range.first)); x += 6; const torrent::BlockTransfer* transfer = p->transfer(); if (transfer != NULL) m_canvas->print(x, y, "%i", transfer->index()); x += 6; if (p->is_snubbed()) m_canvas->print(x, y, "*"); x += 6; if (p->failed_counter() != 0) m_canvas->print(x, y, "%u", p->failed_counter()); x += 7; char buf[128]; print_client_version(buf, buf + 128, p->peer_info()->client_info()); m_canvas->print(x, y, "%s", buf); ++y; ++range.first; } } int WindowPeerList::done_percentage(torrent::Peer* p) { int chunks = m_download->download()->file_list()->size_chunks(); return chunks ? (100 * p->chunks_done()) / chunks : 0; } } rtorrent-0.9.6/src/display/window_peer_list.h000066400000000000000000000042371257211462100213760ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_PEER_LIST_H #define RTORRENT_DISPLAY_PEER_LIST_H #include #include #include "window.h" namespace core { class Download; } namespace display { class WindowPeerList : public Window { public: typedef std::list PList; WindowPeerList(core::Download* d, PList* l, PList::iterator* f); virtual void redraw(); private: int done_percentage(torrent::Peer* p); core::Download* m_download; PList* m_list; PList::iterator* m_focus; }; } #endif rtorrent-0.9.6/src/display/window_statusbar.cc000066400000000000000000000046141257211462100215550ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include "control.h" #include "canvas.h" #include "utils.h" #include "window_statusbar.h" namespace display { void WindowStatusbar::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); // TODO: Make a buffer with size = get_width? char buffer[m_canvas->width() + 1]; char* position; char* last = buffer + m_canvas->width(); position = print_status_info(buffer, last); m_canvas->print(0, 0, "%s", buffer); last = last - (position - buffer); if (last > buffer) { position = print_status_extra(buffer, last); m_canvas->print(m_canvas->width() - (position - buffer), 0, "%s", buffer); } m_lastTick = control->tick(); } } rtorrent-0.9.6/src/display/window_statusbar.h000066400000000000000000000037651257211462100214250ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_STATUSBAR_H #define RTORRENT_DISPLAY_WINDOW_STATUSBAR_H #include #include "window.h" namespace display { class WindowStatusbar : public Window { public: WindowStatusbar() : Window(new Canvas, 0, 0, 1, extent_full, extent_static), m_lastTick(0) {} virtual void redraw(); private: uint64_t m_lastTick; }; } #endif rtorrent-0.9.6/src/display/window_string_list.cc000066400000000000000000000050001257211462100220740ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "canvas.h" #include "utils.h" #include "window_string_list.h" namespace display { WindowStringList::WindowStringList() : Window(new Canvas, 0, 0, 0, extent_full, extent_full) { } WindowStringList::~WindowStringList() { } void WindowStringList::redraw() { m_canvas->erase(); size_t ypos = 0; size_t xpos = 1; size_t width = 0; iterator itr = m_first; while (itr != m_last) { if (ypos == (size_t)m_canvas->height()) { ypos = 0; xpos += width + 2; if (xpos + 20 >= (size_t)m_canvas->width()) break; width = 0; } width = std::max(itr->size(), width); if (xpos + itr->size() <= (size_t)m_canvas->width()) m_canvas->print(xpos, ypos++, "%s", itr->c_str()); else m_canvas->print(xpos, ypos++, "%s", itr->substr(0, m_canvas->width() - xpos).c_str()); ++itr; } m_drawEnd = itr; } } rtorrent-0.9.6/src/display/window_string_list.h000066400000000000000000000043761257211462100217550ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_STRING_LIST_H #define RTORRENT_DISPLAY_WINDOW_STRING_LIST_H #include #include #include "window.h" namespace display { class WindowStringList : public Window { public: typedef std::list::iterator iterator; WindowStringList(); ~WindowStringList(); iterator get_draw_end() { return m_drawEnd; } void set_range(iterator first, iterator last) { m_first = m_drawEnd = first; m_last = last; } virtual void redraw(); private: iterator m_first; iterator m_last; iterator m_drawEnd; }; } #endif rtorrent-0.9.6/src/display/window_text.cc000066400000000000000000000072771257211462100205410ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include "canvas.h" #include "utils.h" #include "window_text.h" namespace display { WindowText::WindowText(rpc::target_type target, extent_type margin) : Window(new Canvas, 0, 0, 0, extent_static, extent_static), m_target(target), m_errorHandler(NULL), m_margin(margin), m_interval(0) { } void WindowText::clear() { std::for_each(begin(), end(), rak::call_delete()); base_type::clear(); delete m_errorHandler; m_errorHandler = NULL; } void WindowText::push_back(TextElement* element) { base_type::push_back(element); // m_minHeight = size(); m_maxHeight = size(); if (element != NULL) { extent_type width = element->max_length(); if (width == extent_full) m_maxWidth = extent_full; else m_maxWidth = std::max(m_maxWidth, element->max_length() + m_margin); } // Check if active, if so do the update thingie. Or be lazy? } void WindowText::redraw() { if (m_interval != 0) m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(m_interval)).round_seconds()); m_canvas->erase(); unsigned int position = 0; if (m_canvas->height() == 0) return; if (m_errorHandler != NULL && m_target.second == NULL) { char buffer[m_canvas->width() + 1]; Canvas::attributes_list attributes; attributes.push_back(Attributes(buffer, Attributes::a_normal, Attributes::color_default)); char* last = m_errorHandler->print(buffer, buffer + m_canvas->width(), &attributes, m_target); m_canvas->print_attributes(0, position, buffer, last, &attributes); return; } for (iterator itr = begin(); itr != end() && position < m_canvas->height(); ++itr, ++position) { if (*itr == NULL) continue; char buffer[m_canvas->width() + 1]; Canvas::attributes_list attributes; attributes.push_back(Attributes(buffer, Attributes::a_normal, Attributes::color_default)); char* last = (*itr)->print(buffer, buffer + m_canvas->width(), &attributes, m_target); m_canvas->print_attributes(0, position, buffer, last, &attributes); } } } rtorrent-0.9.6/src/display/window_text.h000066400000000000000000000063021257211462100203670ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_TEXT_H #define RTORRENT_DISPLAY_WINDOW_TEXT_H #include #include "text_element.h" #include "window.h" namespace display { class WindowText : public Window, public std::vector { public: typedef std::vector base_type; typedef base_type::value_type value_type; typedef base_type::reference reference; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; typedef base_type::reverse_iterator reverse_iterator; using base_type::empty; using base_type::size; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; WindowText(rpc::target_type target = rpc::make_target(), extent_type margin = 0); ~WindowText() { clear(); } void clear(); rpc::target_type target() const { return m_target; } void set_target(rpc::target_type target) { m_target = target; } uint32_t interval() const { return m_interval; } void set_interval(uint32_t i) { m_interval = i; } void push_back(TextElement* element); // Set an error handler if targets pointing to NULL elements should // be handled separately to avoid throwing errors. void set_error_handler(TextElement* element) { m_errorHandler = element; } virtual void redraw(); private: rpc::target_type m_target; TextElement* m_errorHandler; extent_type m_margin; uint32_t m_interval; }; } #endif rtorrent-0.9.6/src/display/window_title.cc000066400000000000000000000037431257211462100206700ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "canvas.h" #include "window_title.h" namespace display { void WindowTitle::redraw() { m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds()); m_canvas->erase(); m_canvas->print(std::max(0, ((int)m_canvas->width() - (int)m_title.size()) / 2 - 4), 0, "*** %s ***", m_title.c_str()); } } rtorrent-0.9.6/src/display/window_title.h000066400000000000000000000041741257211462100205310ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_WINDOW_TITLE_H #define RTORRENT_DISPLAY_WINDOW_TITLE_H #include #include "window.h" namespace display { class WindowTitle : public Window { public: WindowTitle() : Window(new Canvas, 0, 0, 1, extent_full, extent_static) {} const std::string& title() const { return m_title; } void set_title(const std::string& title) { m_title = title; mark_dirty(); } virtual void redraw(); private: std::string m_title; }; } #endif rtorrent-0.9.6/src/display/window_tracker_list.cc000066400000000000000000000114371257211462100222340ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "core/download.h" #include "window_tracker_list.h" namespace display { WindowTrackerList::WindowTrackerList(core::Download* d, unsigned int* focus) : Window(new Canvas, 0, 0, 0, extent_full, extent_full), m_download(d), m_focus(focus) { } void WindowTrackerList::redraw() { // TODO: Make this depend on tracker signal. m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds()); m_canvas->erase(); unsigned int pos = 0; torrent::TrackerList* tl = m_download->tracker_list(); torrent::TrackerController* tc = m_download->tracker_controller(); m_canvas->print(2, pos, "Trackers: [Key: %08x] [%s %s %s]", tl->key(), tc->is_requesting() ? "req" : " ", tc->is_promiscuous_mode() ? "prom" : " ", tc->is_failure_mode() ? "fail" : " "); ++pos; if (tl->size() == 0 || *m_focus >= tl->size()) return; typedef std::pair Range; Range range = rak::advance_bidirectional(0, *m_focus, tl->size(), (m_canvas->height() - 1) / 2); unsigned int group = tl->at(range.first)->group(); while (range.first != range.second) { torrent::Tracker* tracker = tl->at(range.first); if (tracker->group() == group) m_canvas->print(0, pos, "%2i:", group++); m_canvas->print(4, pos++, "%s", tracker->url().c_str()); if (pos < m_canvas->height()) { const char* state; if (tracker->is_busy_not_scrape()) state = "req "; else if (tracker->is_busy()) state = "scr "; else state = " "; m_canvas->print(0, pos++, "%s Id: %s Counters: %uf / %us (%u) %s S/L/D: %u/%u/%u (%u/%u)", state, rak::copy_escape_html(tracker->tracker_id()).c_str(), tracker->failed_counter(), tracker->success_counter(), tracker->scrape_counter(), tracker->is_usable() ? " on" : tracker->is_enabled() ? "err" : "off", tracker->scrape_complete(), tracker->scrape_incomplete(), tracker->scrape_downloaded(), tracker->latest_new_peers(), tracker->latest_sum_peers()); } if (range.first == *m_focus) { m_canvas->set_attr(4, pos - 2, m_canvas->width(), is_focused() ? A_REVERSE : A_BOLD, COLOR_PAIR(0)); m_canvas->set_attr(4, pos - 1, m_canvas->width(), is_focused() ? A_REVERSE : A_BOLD, COLOR_PAIR(0)); } if (tracker->is_busy()) { m_canvas->set_attr(0, pos - 2, 4, A_REVERSE, COLOR_PAIR(0)); m_canvas->set_attr(0, pos - 1, 4, A_REVERSE, COLOR_PAIR(0)); } range.first++; // If we're at the end of the range, check if we can // show one more line for the following tracker. if (range.first == range.second && pos < m_canvas->height() && range.first < tl->size()) range.second++; } } } rtorrent-0.9.6/src/display/window_tracker_list.h000066400000000000000000000037641257211462100221020ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_DISPLAY_TRACKER_LIST_H #define RTORRENT_DISPLAY_TRACKER_LIST_H #include "window.h" namespace core { class Download; } namespace display { class WindowTrackerList : public Window { public: WindowTrackerList(core::Download* d, unsigned int* focus); virtual void redraw(); private: core::Download* m_download; unsigned int* m_focus; }; } #endif rtorrent-0.9.6/src/globals.cc000066400000000000000000000035671257211462100161420ustar00rootroot00000000000000// rTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "globals.h" rak::priority_queue_default taskScheduler; rak::timer cachedTime; rpc::ip_table_list ip_tables; Control* control = NULL; ThreadWorker* worker_thread = NULL; rtorrent-0.9.6/src/globals.h000066400000000000000000000044661257211462100160030ustar00rootroot00000000000000// rTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef TORRENT_GLOBALS_H #define TORRENT_GLOBALS_H #include #include #include "thread_base.h" #include "thread_worker.h" #include "rpc/ip_table_list.h" class Control; // The cachedTime timer should only be updated by the main thread to // avoid potential problems in timing calculations. Code really should // be reviewed and fixed in order to avoid any potential problems, and // then made updates properly sync'ed with memory barriers. extern rak::priority_queue_default taskScheduler; extern rak::timer cachedTime; extern rpc::ip_table_list ip_tables; extern Control* control; extern ThreadWorker* worker_thread; #endif rtorrent-0.9.6/src/input/000077500000000000000000000000001257211462100153345ustar00rootroot00000000000000rtorrent-0.9.6/src/input/Makefile.am000066400000000000000000000004231257211462100173670ustar00rootroot00000000000000noinst_LIBRARIES = libsub_input.a libsub_input_a_SOURCES = \ bindings.cc \ bindings.h \ input_event.cc \ input_event.h \ manager.cc \ manager.h \ path_input.cc \ path_input.h \ text_input.cc \ text_input.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/input/bindings.cc000066400000000000000000000035751257211462100174520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "bindings.h" namespace input { bool Bindings::pressed(int key) { if (!m_enabled) return false; const_iterator itr = find(key); if (itr == end()) return false; itr->second(); return true; } } rtorrent-0.9.6/src/input/bindings.h000066400000000000000000000051421257211462100173040ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_INPUT_BINDINGS_H #define RTORRENT_INPUT_BINDINGS_H #include #include #include "display/attributes.h" namespace input { class Bindings : private std::map > { public: typedef std::tr1::function slot_void; typedef std::map base_type; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::find; using base_type::erase; using base_type::operator[]; Bindings() : m_enabled(true) {} void enable() { m_enabled = true; } void disable() { m_enabled = false; } bool pressed(int key); void ignore(int key) { (*this)[key] = slot_void(); } private: bool m_enabled; }; } #endif rtorrent-0.9.6/src/input/input_event.cc000066400000000000000000000041611257211462100202050ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "input_event.h" //ncurses.h must be included last since sys/mman.h on Solaris munges ERR. #include namespace input { void InputEvent::insert(torrent::Poll* p) { p->open(this); p->insert_read(this); } void InputEvent::remove(torrent::Poll* p) { p->remove_read(this); p->close(this); } void InputEvent::event_read() { int c; while ((c = getch()) != ERR) m_slotPressed(c); } void InputEvent::event_write() { } void InputEvent::event_error() { } } rtorrent-0.9.6/src/input/input_event.h000066400000000000000000000044051257211462100200500ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_INPUT_INPUT_EVENT_H #define RTORRENT_INPUT_INPUT_EVENT_H #include #include #include namespace input { class InputEvent : public torrent::Event { public: typedef std::tr1::function slot_int; InputEvent(int fd) { m_fileDesc = fd; } void insert(torrent::Poll* p); void remove(torrent::Poll* p); void event_read(); void event_write(); void event_error(); void slot_pressed(slot_int s) { m_slotPressed = s; } private: slot_int m_slotPressed; }; } #endif rtorrent-0.9.6/src/input/manager.cc000066400000000000000000000043671257211462100172670ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "manager.h" #include "bindings.h" #include "text_input.h" namespace input { void Manager::erase(Bindings* b) { iterator itr = std::find(begin(), end(), b); if (itr == end()) return; Base::erase(itr); if (std::find(begin(), end(), b) != end()) throw torrent::internal_error("Manager::erase(...) found duplicate bindings."); } void Manager::pressed(int key) { if (m_textInput != NULL) m_textInput->pressed(key); else std::find_if(rbegin(), rend(), std::bind2nd(std::mem_fun(&Bindings::pressed), key)); } } rtorrent-0.9.6/src/input/manager.h000066400000000000000000000044341257211462100171240ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_INPUT_MANAGER_H #define RTORRENT_INPUT_MANAGER_H #include namespace input { class Bindings; class TextInput; class Manager : private std::vector { public: typedef std::vector Base; using Base::iterator; using Base::const_iterator; using Base::reverse_iterator; using Base::const_reverse_iterator; using Base::begin; using Base::end; using Base::rbegin; using Base::rend; using Base::push_back; Manager() : m_textInput(NULL) {} void erase(Bindings* b); void pressed(int key); void set_text_input(TextInput* input = NULL) { m_textInput = input; } private: TextInput* m_textInput; }; } #endif rtorrent-0.9.6/src/input/path_input.cc000066400000000000000000000111761257211462100200240ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include "path_input.h" namespace input { PathInput::PathInput() : m_showNext(false) { } bool PathInput::pressed(int key) { // Consider binding tab in m_bindings instead. if (key != '\t') { m_showNext = false; return TextInput::pressed(key); } else if (m_showNext) { for (signal_void::iterator itr = m_signal_show_next.begin(), last = m_signal_show_next.end(); itr != last; itr++) (*itr)(); } else { receive_do_complete(); } return true; } struct _transform_filename { void operator () (utils::directory_entry& entry) { if (entry.d_type == DT_DIR) entry.d_name += '/'; } }; void PathInput::receive_do_complete() { lt_log_print(torrent::LOG_UI_EVENTS, "path_input: received completion"); size_type dirEnd = find_last_delim(); utils::Directory dir(dirEnd != 0 ? str().substr(0, dirEnd) : "./"); if (!dir.update(utils::Directory::update_sort | utils::Directory::update_hide_dot) || dir.empty()) { mark_dirty(); return; } std::for_each(dir.begin(), dir.end(), _transform_filename()); range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos())); if (r.first == r.second) return; // Show some nice colors here. std::string base = rak::make_base(r.first, r.second, rak::const_mem_ref(&utils::directory_entry::d_name)); // Clear the path after the cursor to make this code cleaner. It's // not really nessesary to add the complexity just because someone // might start tab-completeing in the middle of a path. str().resize(dirEnd); str().insert(dirEnd, base); set_pos(dirEnd + base.size()); mark_dirty(); // Only emit if there are more than one option. m_showNext = ++utils::Directory::iterator(r.first) != r.second; if (m_showNext) { lt_log_print(torrent::LOG_UI_EVENTS, "path_input: show next page"); for (signal_itr_itr::iterator itr = m_signal_show_range.begin(), last = m_signal_show_range.end(); itr != last; itr++) (*itr)(r.first, r.second); } } PathInput::size_type PathInput::find_last_delim() { size_type r = str().rfind('/', get_pos()); if (r == npos) return 0; else if (r == size()) return r; else return r + 1; } inline bool find_complete_compare(const utils::directory_entry& complete, const std::string& base) { return complete.d_name.compare(0, base.size(), base); } inline bool find_complete_not_compare(const utils::directory_entry& complete, const std::string& base) { return !complete.d_name.compare(0, base.size(), base); } PathInput::range_type PathInput::find_incomplete(utils::Directory& d, const std::string& f) { range_type r; r.first = std::find_if(d.begin(), d.end(), rak::bind2nd(std::ptr_fun(&find_complete_not_compare), f)); r.second = std::find_if(r.first, d.end(), rak::bind2nd(std::ptr_fun(&find_complete_compare), f)); return r; } } rtorrent-0.9.6/src/input/path_input.h000066400000000000000000000054731257211462100176710ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_INPUT_PATH_INPUT_H #define RTORRENT_INPUT_PATH_INPUT_H #include #include #include "utils/directory.h" #include "text_input.h" namespace input { class PathInput : public TextInput { public: typedef utils::Directory::iterator directory_itr; typedef std::pair range_type; typedef std::tr1::function slot_void; typedef std::tr1::function slot_itr_itr; typedef std::list signal_void; typedef std::list signal_itr_itr; PathInput(); virtual ~PathInput() {} signal_void& signal_show_next() { return m_signal_show_next; } signal_itr_itr& signal_show_range() { return m_signal_show_range; } virtual bool pressed(int key); private: void receive_do_complete(); size_type find_last_delim(); range_type find_incomplete(utils::Directory& d, const std::string& f); bool m_showNext; signal_void m_signal_show_next; signal_itr_itr m_signal_show_range; }; } #endif rtorrent-0.9.6/src/input/text_input.cc000066400000000000000000000056771257211462100200650ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "display/attributes.h" #include "text_input.h" namespace input { bool TextInput::pressed(int key) { if (m_bindings.pressed(key)) { return true; } else if (m_alt) { m_alt = false; switch (key) { // case 'b': // Base::insert(m_pos, "M^b"); // break; // case 'f': // Base::insert(m_pos, "M^f"); // break; default: return false; } } else if (key >= 0x20 && key < 0x7F) { Base::insert(m_pos++, 1, key); } else { switch (key) { case 0x7F: case 'h' - 'a' + 1: // ^H case KEY_BACKSPACE: if (m_pos != 0) Base::erase(--m_pos, 1); break; case KEY_DC: if (m_pos != size()) Base::erase(m_pos, 1); break; case 0x02: case KEY_LEFT: if (m_pos != 0) --m_pos; break; case 0x06: case KEY_RIGHT: if (m_pos != size()) ++m_pos; break; case KEY_HOME: m_pos = 0; break; case KEY_END: m_pos = size(); break; case 'u' - 'a' + 1: // ^U Base::erase(0, m_pos); m_pos = 0; break; case 'k' - 'a' + 1: // ^K Base::erase(m_pos, size()-m_pos); break; case 0x1B: m_alt = true; break; default: return false; } } mark_dirty(); return true; } } rtorrent-0.9.6/src/input/text_input.h000066400000000000000000000054121257211462100177120ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_INPUT_TEXT_INPUT_H #define RTORRENT_INPUT_TEXT_INPUT_H #include #include "bindings.h" namespace input { class TextInput : private std::string { public: typedef std::string Base; typedef std::tr1::function slot_void; using Base::c_str; using Base::empty; using Base::size; using Base::size_type; using Base::npos; TextInput() : m_pos(0), m_alt(false) {} virtual ~TextInput() {} size_type get_pos() { return m_pos; } void set_pos(size_type pos) { m_pos = pos; } virtual bool pressed(int key); void clear() { m_pos = 0; m_alt = false; Base::clear(); } void slot_dirty(slot_void s) { m_slot_dirty = s; } void mark_dirty() { if (m_slot_dirty) m_slot_dirty(); } std::string& str() { return *this; } Bindings& bindings() { return m_bindings; } private: size_type m_pos; bool m_alt; slot_void m_slot_dirty; Bindings m_bindings; }; } #endif rtorrent-0.9.6/src/main.cc000066400000000000000000001347251257211462100154440ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_EXECINFO #include #endif #include "core/dht_manager.h" #include "core/download.h" #include "core/download_factory.h" #include "core/download_store.h" #include "core/manager.h" #include "display/canvas.h" #include "display/window.h" #include "display/manager.h" #include "input/bindings.h" #include "rpc/command_scheduler.h" #include "rpc/command_scheduler_item.h" #include "rpc/parse_commands.h" #include "utils/directory.h" #include "control.h" #include "command_helpers.h" #include "globals.h" #include "signal_handler.h" #include "option_parser.h" #include "thread_worker.h" void handle_sigbus(int signum, siginfo_t* sa, void* ptr); void do_panic(int signum); void print_help(); void initialize_commands(); void do_nothing() {} void do_nothing_str(const std::string&) {} int parse_options(Control* c, int argc, char** argv) { try { OptionParser optionParser; // Converted. optionParser.insert_flag('h', std::tr1::bind(&print_help)); optionParser.insert_flag('n', std::tr1::bind(&do_nothing_str, std::tr1::placeholders::_1)); optionParser.insert_flag('D', std::tr1::bind(&do_nothing_str, std::tr1::placeholders::_1)); optionParser.insert_flag('I', std::tr1::bind(&do_nothing_str, std::tr1::placeholders::_1)); optionParser.insert_flag('K', std::tr1::bind(&do_nothing_str, std::tr1::placeholders::_1)); optionParser.insert_option('b', std::tr1::bind(&rpc::call_command_set_string, "network.bind_address.set", std::tr1::placeholders::_1)); optionParser.insert_option('d', std::tr1::bind(&rpc::call_command_set_string, "directory.default.set", std::tr1::placeholders::_1)); optionParser.insert_option('i', std::tr1::bind(&rpc::call_command_set_string, "ip", std::tr1::placeholders::_1)); optionParser.insert_option('p', std::tr1::bind(&rpc::call_command_set_string, "network.port_range.set", std::tr1::placeholders::_1)); optionParser.insert_option('s', std::tr1::bind(&rpc::call_command_set_string, "session", std::tr1::placeholders::_1)); optionParser.insert_option('O', std::tr1::bind(&rpc::parse_command_single_std, std::tr1::placeholders::_1)); optionParser.insert_option_list('o', std::tr1::bind(&rpc::call_command_set_std_string, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); return optionParser.process(argc, argv); } catch (torrent::input_error& e) { throw torrent::input_error("Failed to parse command line option: " + std::string(e.what())); } } void load_session_torrents(Control* c) { utils::Directory entries = c->core()->download_store()->get_formated_entries(); for (utils::Directory::const_iterator first = entries.begin(), last = entries.end(); first != last; ++first) { // We don't really support session torrents that are links. These // would be overwritten anyway on exit, and thus not really be // useful. if (!first->is_file()) continue; core::DownloadFactory* f = new core::DownloadFactory(c->core()); // Replace with session torrent flag. f->set_session(true); f->slot_finished(std::tr1::bind(&rak::call_delete_func, f)); f->load(entries.path() + first->d_name); f->commit(); } } void load_arg_torrents(Control* c, char** first, char** last) { //std::for_each(begin, end, std::bind1st(std::mem_fun(&core::Manager::insert), &c->get_core())); for (; first != last; ++first) { core::DownloadFactory* f = new core::DownloadFactory(c->core()); // Replace with session torrent flag. f->set_start(true); f->slot_finished(std::tr1::bind(&rak::call_delete_func, f)); f->load(*first); f->commit(); } } static uint64_t client_next_timeout(Control* c) { if (taskScheduler.empty()) return (c->is_shutdown_started() ? rak::timer::from_milliseconds(100) : rak::timer::from_seconds(60)).usec(); else if (taskScheduler.top()->time() <= cachedTime) return 0; else return (taskScheduler.top()->time() - cachedTime).usec(); } static void client_perform() { // Use throw exclusively. if (control->is_shutdown_completed()) throw torrent::shutdown_exception(); if (control->is_shutdown_received()) control->handle_shutdown(); control->inc_tick(); cachedTime = rak::timer::current(); rak::priority_queue_perform(&taskScheduler, cachedTime); } int main(int argc, char** argv) { try { // Temporary. setlocale(LC_ALL, ""); cachedTime = rak::timer::current(); // Initialize logging: torrent::log_initialize(); control = new Control; srandom(cachedTime.usec() ^ (getpid() << 16) ^ getppid()); srand48(cachedTime.usec() ^ (getpid() << 16) ^ getppid()); SignalHandler::set_ignore(SIGPIPE); SignalHandler::set_handler(SIGINT, std::tr1::bind(&Control::receive_normal_shutdown, control)); SignalHandler::set_handler(SIGTERM, std::tr1::bind(&Control::receive_quick_shutdown, control)); SignalHandler::set_handler(SIGWINCH, std::tr1::bind(&display::Manager::force_redraw, control->display())); SignalHandler::set_handler(SIGSEGV, std::tr1::bind(&do_panic, SIGSEGV)); SignalHandler::set_handler(SIGILL, std::tr1::bind(&do_panic, SIGILL)); SignalHandler::set_handler(SIGFPE, std::tr1::bind(&do_panic, SIGFPE)); SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus); // SIGUSR1 is used for interrupting polling, forcing the target // thread to process new non-socket events. // // LibTorrent uses sockets for this purpose on Solaris and other // platforms that do not properly pass signals to the target // threads. Use '--enable-interrupt-socket' when configuring // LibTorrent to enable this workaround. if (torrent::thread_base::should_handle_sigusr1()) SignalHandler::set_handler(SIGUSR1, std::tr1::bind(&do_nothing)); torrent::log_add_group_output(torrent::LOG_NOTICE, "important"); torrent::log_add_group_output(torrent::LOG_INFO, "complete"); torrent::Poll::slot_create_poll() = std::tr1::bind(&core::create_poll); torrent::initialize(); torrent::main_thread()->slot_do_work() = tr1::bind(&client_perform); torrent::main_thread()->slot_next_timeout() = tr1::bind(&client_next_timeout, control); worker_thread = new ThreadWorker(); worker_thread->init_thread(); // Initialize option handlers after libtorrent to ensure // torrent::ConnectionManager* are valid etc. initialize_commands(); if (OptionParser::has_flag('D', argc, argv)) { rpc::call_command_set_value("method.use_deprecated.set", false); lt_log_print(torrent::LOG_WARN, "Disabled deprecated commands."); } if (OptionParser::has_flag('I', argc, argv)) { rpc::call_command_set_value("method.use_intermediate.set", 0); lt_log_print(torrent::LOG_WARN, "Disabled intermediate commands."); } if (OptionParser::has_flag('K', argc, argv)) { rpc::call_command_set_value("method.use_intermediate.set", 2); lt_log_print(torrent::LOG_WARN, "Allowing intermediate commands without xmlrpc."); } rpc::parse_command_multiple (rpc::make_target(), "method.insert = event.download.inserted,multi|rlookup|static\n" "method.insert = event.download.inserted_new,multi|rlookup|static\n" "method.insert = event.download.inserted_session,multi|rlookup|static\n" "method.insert = event.download.erased,multi|rlookup|static\n" "method.insert = event.download.opened,multi|rlookup|static\n" "method.insert = event.download.closed,multi|rlookup|static\n" "method.insert = event.download.resumed,multi|rlookup|static\n" "method.insert = event.download.paused,multi|rlookup|static\n" "method.insert = event.download.finished,multi|rlookup|static\n" "method.insert = event.download.hash_done,multi|rlookup|static\n" "method.insert = event.download.hash_failed,multi|rlookup|static\n" "method.insert = event.download.hash_final_failed,multi|rlookup|static\n" "method.insert = event.download.hash_removed,multi|rlookup|static\n" "method.insert = event.download.hash_queued,multi|rlookup|static\n" "method.set_key = event.download.inserted, 1_send_scrape, ((d.tracker.send_scrape,30))\n" "method.set_key = event.download.inserted_new, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) ),(d.save_full_session)}\n" "method.set_key = event.download.inserted_session, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) )}\n" "method.set_key = event.download.inserted, 1_prioritize_toc, \"branch=file.prioritize_toc=,{\\\"f.multicall=(file.prioritize_toc.first),f.prioritize_first.enable=\\\",\\\"f.multicall=(file.prioritize_toc.last),f.prioritize_last.enable=\\\",d.update_priorities=}\"\n" "method.set_key = event.download.erased, !_download_list, ui.unfocus_download=\n" "method.set_key = event.download.erased, ~_delete_tied, d.delete_tied=\n" "method.set_key = event.download.resumed, !_timestamp, ((d.timestamp.started.set_if_z, ((system.time)) ))\n" "method.set_key = event.download.finished, !_timestamp, ((d.timestamp.finished.set_if_z, ((system.time)) ))\n" "method.insert.c_simple = group.insert_persistent_view," "((view.add,((argument.0)))),((view.persistent,((argument.0)))),((group.insert,((argument.0)),((argument.0))))\n" "file.prioritize_toc.first.set = {*.avi,*.mp4,*.mkv,*.gz}\n" "file.prioritize_toc.last.set = {*.zip}\n" // Allow setting 'group2.view' as constant, so that we can't // modify the value. And look into the possibility of making // 'const' use non-heap memory, as we know they can't be // erased. // TODO: Remember to ensure it doesn't get restarted by watch // dir, etc. Set ignore commands, or something. "group.insert = seeding,seeding\n" "session.name.set = (cat,(system.hostname),:,(system.pid))\n" // Currently not doing any sorting on main. "view.add = main\n" "view.add = default\n" "view.add = name\n" "view.sort_new = name,((less,((d.name))))\n" "view.sort_current = name,((less,((d.name))))\n" "view.add = active\n" "view.filter = active,((false))\n" "view.add = started\n" "view.filter = started,((false))\n" "view.event_added = started,{(view.set_not_visible,stopped),(d.state.set,1),(scheduler.simple.added)}\n" "view.event_removed = started,{(view.set_visible,stopped),(scheduler.simple.removed)}\n" "view.add = stopped\n" "view.filter = stopped,((false))\n" "view.event_added = stopped,{(d.state.set,0),(view.set_not_visible,started)}\n" "view.event_removed = stopped,((view.set_visible,started))\n" "view.add = complete\n" "view.filter = complete,((d.complete))\n" "view.filter_on = complete,event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed,event.download.finished\n" "view.add = incomplete\n" "view.filter = incomplete,((not,((d.complete))))\n" "view.filter_on = incomplete,event.download.hash_done,event.download.hash_failed," "event.download.hash_final_failed,event.download.finished\n" // The hashing view does not include stopped torrents. "view.add = hashing\n" "view.filter = hashing,((d.hashing))\n" "view.filter_on = hashing,event.download.hash_queued,event.download.hash_removed," "event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed,event.download.finished\n" "view.add = seeding\n" "view.filter = seeding,((and,((d.state)),((d.complete))))\n" "view.filter_on = seeding,event.download.resumed,event.download.paused,event.download.finished\n" "view.add = leeching\n" "view.filter = leeching,((and,((d.state)),((not,((d.complete))))))\n" "view.filter_on = leeching,event.download.resumed,event.download.paused,event.download.finished\n" "schedule2 = view.main,10,10,((view.sort,main,20))\n" "schedule2 = view.name,10,10,((view.sort,name,20))\n" "schedule2 = session_save,1200,1200,((session.save))\n" "schedule2 = low_diskspace,5,60,((close_low_diskspace,500M))\n" "schedule2 = prune_file_status,3600,86400,((system.file_status_cache.prune))\n" "protocol.encryption.set=allow_incoming,prefer_plaintext,enable_retry\n" ); // Functions that might not get depracted as they are nice for // configuration files, and thus might do with just some // cleanup. CMD2_REDIRECT_GENERIC("upload_rate", "throttle.global_up.max_rate.set_kb"); CMD2_REDIRECT_GENERIC("download_rate", "throttle.global_down.max_rate.set_kb"); CMD2_REDIRECT_GENERIC("ratio.enable", "group.seeding.ratio.enable"); CMD2_REDIRECT_GENERIC("ratio.disable", "group.seeding.ratio.disable"); CMD2_REDIRECT_GENERIC("ratio.min", "group2.seeding.ratio.min"); CMD2_REDIRECT_GENERIC("ratio.max", "group2.seeding.ratio.max"); CMD2_REDIRECT_GENERIC("ratio.upload", "group2.seeding.ratio.upload"); CMD2_REDIRECT_GENERIC("ratio.min.set", "group2.seeding.ratio.min.set"); CMD2_REDIRECT_GENERIC("ratio.max.set", "group2.seeding.ratio.max.set"); CMD2_REDIRECT_GENERIC("ratio.upload.set", "group2.seeding.ratio.upload.set"); CMD2_REDIRECT_GENERIC("encryption", "protocol.encryption.set"); CMD2_REDIRECT_GENERIC("encoding_list", "encoding.add"); CMD2_REDIRECT_GENERIC("connection_leech", "protocol.connection.leech.set"); CMD2_REDIRECT_GENERIC("connection_seed", "protocol.connection.seed.set"); CMD2_REDIRECT ("min_peers", "throttle.min_peers.normal.set"); CMD2_REDIRECT ("max_peers", "throttle.max_peers.normal.set"); CMD2_REDIRECT ("min_peers_seed", "throttle.min_peers.seed.set"); CMD2_REDIRECT ("max_peers_seed", "throttle.max_peers.seed.set"); CMD2_REDIRECT ("min_uploads", "throttle.min_uploads.set"); CMD2_REDIRECT ("max_uploads", "throttle.max_uploads.set"); CMD2_REDIRECT ("min_downloads", "throttle.min_downloads.set"); CMD2_REDIRECT ("max_downloads", "throttle.max_downloads.set"); CMD2_REDIRECT ("max_uploads_div", "throttle.max_uploads.div.set"); CMD2_REDIRECT ("max_uploads_global", "throttle.max_uploads.global.set"); CMD2_REDIRECT ("max_downloads_div", "throttle.max_downloads.div.set"); CMD2_REDIRECT ("max_downloads_global", "throttle.max_downloads.global.set"); CMD2_REDIRECT_GENERIC("max_memory_usage", "pieces.memory.max.set"); CMD2_REDIRECT ("bind", "network.bind_address.set"); CMD2_REDIRECT ("ip", "network.local_address.set"); CMD2_REDIRECT ("port_range", "network.port_range.set"); CMD2_REDIRECT_GENERIC("dht", "dht.mode.set"); CMD2_REDIRECT_GENERIC("dht_port", "dht.port.set"); CMD2_REDIRECT ("port_random", "network.port_random.set"); CMD2_REDIRECT ("proxy_address", "network.proxy_address.set"); CMD2_REDIRECT_GENERIC("directory", "directory.default.set"); CMD2_REDIRECT_GENERIC("session", "session.path.set"); CMD2_REDIRECT ("key_layout", "keys.layout.set"); // Deprecated commands. Don't use these anymore. if (rpc::call_command_value("method.use_intermediate") == 1) { CMD2_REDIRECT_GENERIC("execute", "execute2"); CMD2_REDIRECT_GENERIC("schedule", "schedule2"); CMD2_REDIRECT_GENERIC("schedule_remove", "schedule_remove2"); } else if (rpc::call_command_value("method.use_intermediate") == 2) { // Allow for use in config files, etc, just don't export it. CMD2_REDIRECT_GENERIC_NO_EXPORT("execute", "execute2"); CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule", "schedule2"); CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule_remove", "schedule_remove2"); } #if LT_SLIM_VERSION != 1 if (rpc::call_command_value("method.use_deprecated")) { // Deprecated in 0.7.0: CMD2_REDIRECT_GENERIC("system.method.insert", "method.insert"); CMD2_REDIRECT_GENERIC("system.method.erase", "method.erase"); CMD2_REDIRECT_GENERIC("system.method.get", "method.get"); CMD2_REDIRECT_GENERIC("system.method.set", "method.set"); CMD2_REDIRECT_GENERIC("system.method.list_keys", "method.list_keys"); CMD2_REDIRECT_GENERIC("system.method.has_key", "method.has_key"); CMD2_REDIRECT_GENERIC("system.method.set_key", "method.set_key"); CMD2_REDIRECT ("get_directory", "directory.default"); CMD2_REDIRECT_GENERIC("set_directory", "directory.default.set"); CMD2_REDIRECT ("get_session", "session.path"); CMD2_REDIRECT_GENERIC("set_session", "session.path.set"); CMD2_REDIRECT ("session_save", "session.save"); CMD2_REDIRECT ("get_name", "session.name"); CMD2_REDIRECT_GENERIC("set_name", "session.name.set"); CMD2_REDIRECT ("system.file_allocate", "system.file.allocate"); CMD2_REDIRECT ("system.file_allocate.set", "system.file.allocate.set"); CMD2_REDIRECT ("get_max_file_size", "system.file.max_size"); CMD2_REDIRECT_GENERIC("set_max_file_size", "system.file.max_size.set"); CMD2_REDIRECT ("get_split_file_size", "system.file.split_size"); CMD2_REDIRECT_GENERIC("set_split_file_size", "system.file.split_size.set"); CMD2_REDIRECT ("get_split_suffix", "system.file.split_suffix"); CMD2_REDIRECT_GENERIC("set_split_suffix", "system.file.split_suffix.set"); CMD2_REDIRECT ("get_timeout_sync", "pieces.sync.timeout"); CMD2_REDIRECT_GENERIC("set_timeout_sync", "pieces.sync.timeout.set"); CMD2_REDIRECT ("get_timeout_safe_sync", "pieces.sync.timeout_safe"); CMD2_REDIRECT_GENERIC("set_timeout_safe_sync", "pieces.sync.timeout_safe.set"); CMD2_REDIRECT_GENERIC("get_preload_type", "pieces.preload.type"); CMD2_REDIRECT_GENERIC("get_preload_min_size", "pieces.preload.min_size"); CMD2_REDIRECT_GENERIC("get_preload_required_rate", "pieces.preload.min_rate"); CMD2_REDIRECT_GENERIC("set_preload_type", "pieces.preload.type.set"); CMD2_REDIRECT_GENERIC("set_preload_min_size", "pieces.preload.min_size.set"); CMD2_REDIRECT_GENERIC("set_preload_required_rate", "pieces.preload.min_rate.set"); CMD2_REDIRECT_GENERIC("get_stats_preloaded", "pieces.stats_preloaded"); CMD2_REDIRECT_GENERIC("get_stats_not_preloaded", "pieces.stats_not_preloaded"); CMD2_REDIRECT_GENERIC("get_safe_sync", "pieces.sync.always_safe"); CMD2_REDIRECT_GENERIC("set_safe_sync", "pieces.sync.always_safe.set"); CMD2_REDIRECT ("get_memory_usage", "pieces.memory.current"); CMD2_REDIRECT_GENERIC("get_max_memory_usage", "pieces.memory.max"); CMD2_REDIRECT_GENERIC("set_max_memory_usage", "pieces.memory.max.set"); CMD2_REDIRECT_GENERIC("load", "load.normal"); CMD2_REDIRECT_GENERIC("load_verbose", "load.verbose"); CMD2_REDIRECT_GENERIC("load_start", "load.start"); CMD2_REDIRECT_GENERIC("load_start_verbose", "load.start_verbose"); CMD2_REDIRECT_GENERIC("load_raw", "load.raw"); CMD2_REDIRECT_GENERIC("load_raw_start", "load.raw_start"); CMD2_REDIRECT_GENERIC("load_raw_verbose", "load.raw_verbose"); CMD2_REDIRECT_GENERIC("get_connection_leech", "protocol.connection.leech"); CMD2_REDIRECT_GENERIC("get_connection_seed", "protocol.connection.seed"); CMD2_REDIRECT_GENERIC("set_connection_leech", "protocol.connection.leech.set"); CMD2_REDIRECT_GENERIC("set_connection_seed", "protocol.connection.seed.set"); // // Throttle: // CMD2_REDIRECT_GENERIC("throttle_up", "throttle.up"); CMD2_REDIRECT_GENERIC("throttle_down", "throttle.down"); CMD2_REDIRECT_GENERIC("throttle_ip", "throttle.ip"); CMD2_REDIRECT_GENERIC("get_throttle_up_max", "throttle.up.max"); CMD2_REDIRECT_GENERIC("get_throttle_up_rate", "throttle.up.rate"); CMD2_REDIRECT_GENERIC("get_throttle_down_max", "throttle.down.max"); CMD2_REDIRECT_GENERIC("get_throttle_down_rate", "throttle.down.rate"); CMD2_REDIRECT_GENERIC("set_min_peers", "throttle.min_peers.normal.set"); CMD2_REDIRECT_GENERIC("set_max_peers", "throttle.max_peers.normal.set"); CMD2_REDIRECT_GENERIC("set_min_peers_seed", "throttle.min_peers.seed.set"); CMD2_REDIRECT_GENERIC("set_max_peers_seed", "throttle.max_peers.seed.set"); CMD2_REDIRECT_GENERIC("set_max_uploads", "throttle.max_uploads.set"); CMD2_REDIRECT_GENERIC("set_max_uploads_div", "throttle.max_uploads.div.set"); CMD2_REDIRECT_GENERIC("set_max_uploads_global", "throttle.max_uploads.global.set"); CMD2_REDIRECT_GENERIC("set_max_downloads_div", "throttle.max_downloads.div.set"); CMD2_REDIRECT_GENERIC("set_max_downloads_global", "throttle.max_downloads.global.set"); CMD2_REDIRECT ("get_min_peers", "throttle.min_peers.normal"); CMD2_REDIRECT ("get_max_peers", "throttle.max_peers.normal"); CMD2_REDIRECT ("get_min_peers_seed", "throttle.min_peers.seed"); CMD2_REDIRECT ("get_max_peers_seed", "throttle.max_peers.seed"); CMD2_REDIRECT ("get_max_uploads", "throttle.max_uploads"); CMD2_REDIRECT ("get_max_uploads_div", "throttle.max_uploads.div"); CMD2_REDIRECT ("get_max_uploads_global", "throttle.max_uploads.global"); CMD2_REDIRECT ("get_max_downloads_div", "throttle.max_downloads.div"); CMD2_REDIRECT ("get_max_downloads_global", "throttle.max_downloads.global"); CMD2_REDIRECT ("get_up_rate", "throttle.global_up.rate"); CMD2_REDIRECT ("get_up_total", "throttle.global_up.total"); CMD2_REDIRECT ("get_upload_rate", "throttle.global_up.max_rate"); CMD2_REDIRECT_GENERIC("set_upload_rate", "throttle.global_up.max_rate.set"); CMD2_REDIRECT ("get_down_rate", "throttle.global_down.rate"); CMD2_REDIRECT ("get_down_total", "throttle.global_down.total"); CMD2_REDIRECT ("get_download_rate", "throttle.global_down.max_rate"); CMD2_REDIRECT_GENERIC("set_download_rate", "throttle.global_down.max_rate.set"); // // Network: // CMD2_REDIRECT ("get_send_buffer_size", "network.send_buffer.size"); CMD2_REDIRECT_GENERIC("set_send_buffer_size", "network.send_buffer.size.set"); CMD2_REDIRECT ("get_receive_buffer_size", "network.receive_buffer.size"); CMD2_REDIRECT_GENERIC("set_receive_buffer_size", "network.receive_buffer.size.set"); CMD2_REDIRECT_GENERIC("set_bind", "network.bind_address.set"); CMD2_REDIRECT ("get_bind", "network.bind_address"); CMD2_REDIRECT_GENERIC("set_ip", "network.local_address.set"); CMD2_REDIRECT ("get_ip", "network.local_address"); CMD2_REDIRECT ("get_port_range", "network.port_range"); CMD2_REDIRECT_GENERIC("set_port_range", "network.port_range.set"); CMD2_REDIRECT ("get_port_random", "network.port_random"); CMD2_REDIRECT_GENERIC("set_port_random", "network.port_random.set"); CMD2_REDIRECT ("port_open", "network.port_open.set"); CMD2_REDIRECT ("get_port_open", "network.port_open"); CMD2_REDIRECT_GENERIC("set_port_open", "network.port_open.set"); CMD2_REDIRECT_GENERIC("set_proxy_address", "network.proxy_address.set"); CMD2_REDIRECT ("get_proxy_address", "network.proxy_address"); CMD2_REDIRECT ("scgi_port", "network.scgi.open_port"); CMD2_REDIRECT ("scgi_local", "network.scgi.open_local"); CMD2_REDIRECT ("scgi_dont_route", "network.scgi.dont_route.set"); CMD2_REDIRECT_GENERIC("set_scgi_dont_route", "network.scgi.dont_route.set"); CMD2_REDIRECT ("get_scgi_dont_route", "network.scgi.dont_route"); CMD2_REDIRECT ("get_max_open_sockets", "network.max_open_sockets"); CMD2_REDIRECT ("get_max_open_files", "network.max_open_files"); CMD2_REDIRECT_GENERIC("set_max_open_files", "network.max_open_files.set"); // // XMLRPC stuff: // CMD2_REDIRECT_GENERIC("xmlrpc_dialect", "network.xmlrpc.dialect.set"); CMD2_REDIRECT_GENERIC("set_xmlrpc_dialect", "network.xmlrpc.dialect.set"); CMD2_REDIRECT_GENERIC("xmlrpc_size_limit", "network.xmlrpc.size_limit.set"); CMD2_REDIRECT ("get_xmlrpc_size_limit", "network.xmlrpc.size_limit"); CMD2_REDIRECT_GENERIC("set_xmlrpc_size_limit", "network.xmlrpc.size_limit.set"); // // HTTP stuff: // CMD2_REDIRECT_GENERIC("http_capath", "network.http.capath.set"); CMD2_REDIRECT ("get_http_capath", "network.http.capath"); CMD2_REDIRECT_GENERIC("set_http_capath", "network.http.capath.set"); CMD2_REDIRECT_GENERIC("http_cacert", "network.http.cacert.set"); CMD2_REDIRECT ("get_http_cacert", "network.http.cacert"); CMD2_REDIRECT_GENERIC("set_http_cacert", "network.http.cacert.set"); CMD2_REDIRECT ("get_max_open_http", "network.http.max_open"); CMD2_REDIRECT_GENERIC("set_max_open_http", "network.http.max_open.set"); CMD2_REDIRECT_GENERIC("http_proxy", "network.http.proxy_address.set"); CMD2_REDIRECT ("get_http_proxy", "network.http.proxy_address"); CMD2_REDIRECT_GENERIC("set_http_proxy", "network.http.proxy_address.set"); CMD2_REDIRECT ("peer_exchange", "protocol.pex.set"); CMD2_REDIRECT ("get_peer_exchange", "protocol.pex"); CMD2_REDIRECT_GENERIC("set_peer_exchange", "protocol.pex.set"); // // Trackers: // CMD2_REDIRECT ("tracker_numwant", "trackers.numwant.set"); CMD2_REDIRECT ("get_tracker_numwant", "trackers.numwant"); CMD2_REDIRECT_GENERIC("set_tracker_numwant", "trackers.numwant.set"); CMD2_REDIRECT ("use_udp_trackers", "trackers.use_udp.set"); CMD2_REDIRECT ("get_use_udp_trackers", "trackers.use_udp"); CMD2_REDIRECT_GENERIC("set_use_udp_trackers", "trackers.use_udp.set"); // // DHT stuff // CMD2_REDIRECT ("dht_add_node", "dht.add_node"); CMD2_REDIRECT ("dht_statistics", "dht.statistics"); CMD2_REDIRECT ("get_dht_port", "dht.port"); CMD2_REDIRECT_GENERIC("set_dht_port", "dht.port.set"); CMD2_REDIRECT ("get_dht_throttle", "dht.throttle.name"); CMD2_REDIRECT_GENERIC("set_dht_throttle", "dht.throttle.name.set"); // // Various system stuff: // CMD2_REDIRECT ("get_session_lock", "session.use_lock"); CMD2_REDIRECT_GENERIC("set_session_lock", "session.use_lock.set"); CMD2_REDIRECT ("get_session_on_completion", "session.on_completion"); CMD2_REDIRECT_GENERIC("set_session_on_completion", "session.on_completion.set"); CMD2_REDIRECT ("check_hash", "pieces.hash.on_completion.set"); CMD2_REDIRECT ("get_check_hash", "pieces.hash.on_completion"); CMD2_REDIRECT_GENERIC("set_check_hash", "pieces.hash.on_completion.set"); // // Download: // CMD2_REDIRECT ("d.get_hash", "d.hash"); CMD2_REDIRECT ("d.get_local_id", "d.local_id"); CMD2_REDIRECT ("d.get_local_id_html", "d.local_id_html"); CMD2_REDIRECT ("d.get_bitfield", "d.bitfield"); CMD2_REDIRECT ("d.get_base_path", "d.base_path"); CMD2_REDIRECT ("d.get_base_filename", "d.base_filename"); CMD2_REDIRECT ("d.get_name", "d.name"); CMD2_REDIRECT ("d.get_creation_date", "d.creation_date"); CMD2_REDIRECT ("d.get_peer_exchange", "d.peer_exchange"); CMD2_REDIRECT ("d.get_up_rate", "d.up.rate"); CMD2_REDIRECT ("d.get_up_total", "d.up.total"); CMD2_REDIRECT ("d.get_down_rate", "d.down.rate"); CMD2_REDIRECT ("d.get_down_total", "d.down.total"); CMD2_REDIRECT ("d.get_skip_rate", "d.skip.rate"); CMD2_REDIRECT ("d.get_skip_total", "d.skip.total"); // CMD2_REDIRECT ("d.get_bytes_done", "d.bytes_done"); CMD2_REDIRECT ("d.get_chunk_size", "d.chunk_size"); CMD2_REDIRECT ("d.get_chunks_hashed", "d.chunks_hashed"); CMD2_REDIRECT ("d.get_complete", "d.complete"); CMD2_REDIRECT ("d.get_completed_bytes", "d.completed_bytes"); CMD2_REDIRECT ("d.get_completed_chunks", "d.completed_chunks"); CMD2_REDIRECT ("d.get_connection_current", "d.connection_current"); CMD2_REDIRECT ("d.get_connection_leech", "d.connection_leech"); CMD2_REDIRECT ("d.get_connection_seed", "d.connection_seed"); CMD2_REDIRECT ("d.get_custom", "d.custom"); CMD2_REDIRECT ("d.get_custom1", "d.custom1"); CMD2_REDIRECT ("d.get_custom2", "d.custom2"); CMD2_REDIRECT ("d.get_custom3", "d.custom3"); CMD2_REDIRECT ("d.get_custom4", "d.custom4"); CMD2_REDIRECT ("d.get_custom5", "d.custom5"); CMD2_REDIRECT ("d.get_custom_throw", "d.custom_throw"); CMD2_REDIRECT ("d.get_directory", "d.directory"); CMD2_REDIRECT ("d.get_directory_base", "d.directory_base"); CMD2_REDIRECT ("d.get_free_diskspace", "d.free_diskspace"); CMD2_REDIRECT ("d.get_hashing", "d.hashing"); CMD2_REDIRECT ("d.get_hashing_failed", "d.hashing_failed"); CMD2_REDIRECT ("d.get_ignore_commands", "d.ignore_commands"); CMD2_REDIRECT ("d.get_left_bytes", "d.left_bytes"); CMD2_REDIRECT ("d.get_loaded_file", "d.loaded_file"); CMD2_REDIRECT ("d.get_max_file_size", "d.max_file_size"); CMD2_REDIRECT ("d.get_max_size_pex", "d.max_size_pex"); CMD2_REDIRECT ("d.get_message", "d.message"); CMD2_REDIRECT ("d.get_mode", "d.mode"); CMD2_REDIRECT ("d.get_peers_accounted", "d.peers_accounted"); CMD2_REDIRECT ("d.get_peers_complete", "d.peers_complete"); CMD2_REDIRECT ("d.get_peers_connected", "d.peers_connected"); CMD2_REDIRECT ("d.get_peers_max", "d.peers_max"); CMD2_REDIRECT ("d.get_peers_min", "d.peers_min"); CMD2_REDIRECT ("d.get_peers_not_connected", "d.peers_not_connected"); CMD2_REDIRECT ("d.get_priority", "d.priority"); CMD2_REDIRECT ("d.get_priority_str", "d.priority_str"); CMD2_REDIRECT ("d.get_ratio", "d.ratio"); CMD2_REDIRECT ("d.get_size_bytes", "d.size_bytes"); CMD2_REDIRECT ("d.get_size_chunks", "d.size_chunks"); CMD2_REDIRECT ("d.get_size_files", "d.size_files"); CMD2_REDIRECT ("d.get_size_pex", "d.size_pex"); CMD2_REDIRECT ("d.get_state", "d.state"); CMD2_REDIRECT ("d.get_state_changed", "d.state_changed"); CMD2_REDIRECT ("d.get_state_counter", "d.state_counter"); CMD2_REDIRECT ("d.get_throttle_name", "d.throttle_name"); CMD2_REDIRECT ("d.get_tied_to_file", "d.tied_to_file"); CMD2_REDIRECT ("d.get_tracker_focus", "d.tracker_focus"); CMD2_REDIRECT ("d.get_tracker_numwant", "d.tracker_numwant"); CMD2_REDIRECT ("d.get_tracker_size", "d.tracker_size"); CMD2_REDIRECT ("d.get_uploads_max", "d.uploads_max"); CMD2_REDIRECT ("d.set_connection_current", "d.connection_current.set"); CMD2_REDIRECT ("d.set_custom", "d.custom.set"); CMD2_REDIRECT ("d.set_custom1", "d.custom1.set"); CMD2_REDIRECT ("d.set_custom2", "d.custom2.set"); CMD2_REDIRECT ("d.set_custom3", "d.custom3.set"); CMD2_REDIRECT ("d.set_custom4", "d.custom4.set"); CMD2_REDIRECT ("d.set_custom5", "d.custom5.set"); CMD2_REDIRECT ("d.set_directory", "d.directory.set"); CMD2_REDIRECT ("d.set_directory_base", "d.directory_base.set"); CMD2_REDIRECT ("d.set_hashing_failed", "d.hashing_failed.set"); CMD2_REDIRECT ("d.set_ignore_commands", "d.ignore_commands.set"); CMD2_REDIRECT ("d.set_max_file_size", "d.max_file_size.set"); CMD2_REDIRECT ("d.set_message", "d.message.set"); CMD2_REDIRECT ("d.set_peers_max", "d.peers_max.set"); CMD2_REDIRECT ("d.set_peers_min", "d.peers_min.set"); CMD2_REDIRECT ("d.set_priority", "d.priority.set"); CMD2_REDIRECT ("d.set_throttle_name", "d.throttle_name.set"); CMD2_REDIRECT ("d.set_tied_to_file", "d.tied_to_file.set"); CMD2_REDIRECT ("d.set_tracker_numwant", "d.tracker_numwant.set"); CMD2_REDIRECT ("d.set_uploads_max", "d.uploads_max.set"); CMD2_REDIRECT ("create_link", "d.create_link"); CMD2_REDIRECT ("delete_link", "d.delete_link"); CMD2_REDIRECT ("delete_tied", "d.delete_tied"); // // Tracker: // CMD2_REDIRECT_TRACKER("t.get_group", "t.group"); CMD2_REDIRECT_TRACKER("t.get_id", "t.id"); CMD2_REDIRECT_TRACKER("t.get_min_interval", "t.min_interval"); CMD2_REDIRECT_TRACKER("t.get_normal_interval", "t.normal_interval"); CMD2_REDIRECT_TRACKER("t.get_scrape_complete", "t.scrape_complete"); CMD2_REDIRECT_TRACKER("t.get_scrape_downloaded", "t.scrape_downloaded"); CMD2_REDIRECT_TRACKER("t.get_scrape_incomplete", "t.scrape_incomplete"); CMD2_REDIRECT_TRACKER("t.get_scrape_time_last", "t.scrape_time_last"); CMD2_REDIRECT_TRACKER("t.get_type", "t.type"); CMD2_REDIRECT_TRACKER("t.get_url", "t.url"); CMD2_REDIRECT_TRACKER("t.set_enabled", "t.is_enabled.set"); // // File: // CMD2_REDIRECT_FILE ("f.get_completed_chunks", "f.completed_chunks"); CMD2_REDIRECT_FILE ("f.get_frozen_path", "f.frozen_path"); CMD2_REDIRECT_FILE ("f.get_last_touched", "f.last_touched"); CMD2_REDIRECT_FILE ("f.get_match_depth_next", "f.match_depth_next"); CMD2_REDIRECT_FILE ("f.get_match_depth_prev", "f.match_depth_prev"); CMD2_REDIRECT_FILE ("f.get_offset", "f.offset"); CMD2_REDIRECT_FILE ("f.get_path", "f.path"); CMD2_REDIRECT_FILE ("f.get_path_components", "f.path_components"); CMD2_REDIRECT_FILE ("f.get_path_depth", "f.path_depth"); CMD2_REDIRECT_FILE ("f.get_priority", "f.priority"); CMD2_REDIRECT_FILE ("f.get_range_first", "f.range_first"); CMD2_REDIRECT_FILE ("f.get_range_second", "f.range_second"); CMD2_REDIRECT_FILE ("f.get_size_bytes", "f.size_bytes"); CMD2_REDIRECT_FILE ("f.get_size_chunks", "f.size_chunks"); CMD2_REDIRECT_FILE ("f.set_priority", "f.priority.set"); CMD2_REDIRECT_FILE ("fi.get_filename_last", "fi.filename_last"); // // Peer: // CMD2_REDIRECT ("p.get_address", "p.address"); CMD2_REDIRECT ("p.get_client_version", "p.client_version"); CMD2_REDIRECT ("p.get_completed_percent", "p.completed_percent"); CMD2_REDIRECT ("p.get_down_rate", "p.down_rate"); CMD2_REDIRECT ("p.get_down_total", "p.down_total"); CMD2_REDIRECT ("p.get_id", "p.id"); CMD2_REDIRECT ("p.get_id_html", "p.id_html"); CMD2_REDIRECT ("p.get_options_str", "p.options_str"); CMD2_REDIRECT ("p.get_peer_rate", "p.peer_rate"); CMD2_REDIRECT ("p.get_peer_total", "p.peer_total"); CMD2_REDIRECT ("p.get_port", "p.port"); CMD2_REDIRECT ("p.get_up_rate", "p.up_rate"); CMD2_REDIRECT ("p.get_up_total", "p.up_total"); // // View: // CMD2_REDIRECT_GENERIC("view_add", "view.add"); CMD2_REDIRECT_GENERIC("view_filter", "view.filter"); CMD2_REDIRECT_GENERIC("view_filter_on", "view.filter_on"); CMD2_REDIRECT_GENERIC("view_list", "view.list"); CMD2_REDIRECT_GENERIC("view_set", "view.set"); CMD2_REDIRECT_GENERIC("view_sort", "view.sort"); CMD2_REDIRECT_GENERIC("view_sort_current", "view.sort_current"); CMD2_REDIRECT_GENERIC("view_sort_new", "view.sort_new"); // Rename these to avoid conflicts with old style. CMD2_REDIRECT_GENERIC("d.multicall", "d.multicall2"); CMD2_REDIRECT_GENERIC("to_gm_time", "convert.gm_time"); CMD2_REDIRECT_GENERIC("to_gm_date", "convert.gm_date"); CMD2_REDIRECT_GENERIC("to_time", "convert.time"); CMD2_REDIRECT_GENERIC("to_date", "convert.date"); CMD2_REDIRECT_GENERIC("to_elapsed_time", "convert.elapsed_time"); CMD2_REDIRECT_GENERIC("to_kb", "convert.kb"); CMD2_REDIRECT_GENERIC("to_mb", "convert.mb"); CMD2_REDIRECT_GENERIC("to_xb", "convert.xb"); CMD2_REDIRECT_GENERIC("to_throttle", "convert.throttle"); CMD2_REDIRECT_GENERIC("execute_throw", "execute.throw"); CMD2_REDIRECT_GENERIC("execute_nothrow", "execute.nothrow"); CMD2_REDIRECT_GENERIC("execute_raw", "execute.raw"); CMD2_REDIRECT_GENERIC("execute_raw_nothrow", "execute.raw_nothrow"); CMD2_REDIRECT_GENERIC("execute_capture", "execute.capture"); CMD2_REDIRECT_GENERIC("execute_capture_nothrow", "execute.capture_nothrow"); } #endif int firstArg = parse_options(control, argc, argv); if (OptionParser::has_flag('n', argc, argv)) { lt_log_print(torrent::LOG_WARN, "Ignoring ~/.rtorrent.rc."); } else { rpc::parse_command_single(rpc::make_target(), "try_import = ~/.rtorrent.rc"); } control->initialize(); // Load session torrents and perform scheduled tasks to ensure // session torrents are loaded before arg torrents. control->dht_manager()->load_dht_cache(); load_session_torrents(control); rak::priority_queue_perform(&taskScheduler, cachedTime); load_arg_torrents(control, argv + firstArg, argv + argc); // Make sure we update the display before any scheduled tasks can // run, so that loading of torrents doesn't look like it hangs on // startup. control->display()->adjust_layout(); control->display()->receive_update(); worker_thread->start_thread(); torrent::thread_base::event_loop(torrent::main_thread()); control->core()->download_list()->session_save(); control->cleanup(); } catch (torrent::internal_error& e) { control->cleanup_exception(); std::cout << "Caught internal_error: " << e.what() << std::endl << e.backtrace(); lt_log_print_dump(torrent::LOG_CRITICAL, e.backtrace().c_str(), e.backtrace().size(), "Caught internal_error: '%s'.", e.what()); return -1; } catch (std::exception& e) { control->cleanup_exception(); std::cout << "rtorrent: " << e.what() << std::endl; lt_log_print(torrent::LOG_CRITICAL, "Caught exception: '%s'.", e.what()); return -1; } torrent::log_cleanup(); delete control; delete worker_thread; return 0; } void handle_sigbus(int signum, siginfo_t* sa, void* ptr) { if (signum != SIGBUS) do_panic(signum); SignalHandler::set_default(signum); display::Canvas::cleanup(); std::stringstream output; output << "Caught SIGBUS, dumping stack:" << std::endl; #ifdef USE_EXECINFO void* stackPtrs[20]; // Print the stack and exit. int stackSize = backtrace(stackPtrs, 20); char** stackStrings = backtrace_symbols(stackPtrs, stackSize); for (int i = 0; i < stackSize; ++i) output << stackStrings[i] << std::endl; #else output << "Stack dump not enabled." << std::endl; #endif output << std::endl << "Error: " << rak::error_number(sa->si_errno).c_str() << std::endl; const char* signal_reason; switch (sa->si_code) { case BUS_ADRALN: signal_reason = "Invalid address alignment."; break; case BUS_ADRERR: signal_reason = "Non-existent physical address."; break; case BUS_OBJERR: signal_reason = "Object specific hardware error."; break; default: if (sa->si_code <= 0) signal_reason = "User-generated signal."; else signal_reason = "Unknown."; break; }; output << "Signal code '" << sa->si_code << "': " << signal_reason << std::endl; output << "Fault address: " << sa->si_addr << std::endl; // New code for finding the location of the SIGBUS signal, and using // that to figure out how to recover. torrent::chunk_info_result result = torrent::chunk_list_address_info(sa->si_addr); if (!result.download.is_valid()) { output << "The fault address is not part of any chunk." << std::endl; goto handle_sigbus_exit; } output << "Torrent name: " << result.download.info()->name().c_str() << std::endl; output << "File name: " << result.file_path << std::endl; output << "File offset: " << result.file_offset << std::endl; output << "Chunk index: " << result.chunk_index << std::endl; output << "Chunk offset: " << result.chunk_offset << std::endl; handle_sigbus_exit: std::cout << output.rdbuf(); if (lt_log_is_valid(torrent::LOG_CRITICAL)) { std::string dump = output.str(); lt_log_print_dump(torrent::LOG_CRITICAL, dump.c_str(), dump.size(), "Caught signal: '%s'.", signal_reason); } torrent::log_cleanup(); std::abort(); } void do_panic(int signum) { // Use the default signal handler in the future to avoid infinit // loops. SignalHandler::set_default(signum); display::Canvas::cleanup(); std::stringstream output; output << "Caught " << SignalHandler::as_string(signum) << ", dumping stack:" << std::endl; #ifdef USE_EXECINFO void* stackPtrs[20]; // Print the stack and exit. int stackSize = backtrace(stackPtrs, 20); char** stackStrings = backtrace_symbols(stackPtrs, stackSize); for (int i = 0; i < stackSize; ++i) output << stackStrings[i] << std::endl; #else output << "Stack dump not enabled." << std::endl; #endif if (signum == SIGBUS) output << "A bus error probably means you ran out of diskspace." << std::endl; std::cout << output.rdbuf(); if (lt_log_is_valid(torrent::LOG_CRITICAL)) { std::string dump = output.str(); lt_log_print_dump(torrent::LOG_CRITICAL, dump.c_str(), dump.size(), "Caught signal: '%s.", strsignal(signum)); } torrent::log_cleanup(); std::abort(); } void print_help() { std::cout << "Rakshasa's BitTorrent client version " VERSION "." << std::endl; std::cout << std::endl; std::cout << "All value pairs (f.ex rate and queue size) will be in the UP/DOWN" << std::endl; std::cout << "order. Use the up/down/left/right arrow keys to move between screens." << std::endl; std::cout << std::endl; std::cout << "Usage: rtorrent [OPTIONS]... [FILE]... [URL]..." << std::endl; std::cout << " -h Display this very helpful text" << std::endl; std::cout << " -n Don't try to load ~/.rtorrent.rc on startup" << std::endl; std::cout << " -b Bind the listening socket to this IP" << std::endl; std::cout << " -i Change the IP that is sent to the tracker" << std::endl; std::cout << " -p - Set port range for incoming connections" << std::endl; std::cout << " -d Save torrents to this directory by default" << std::endl; std::cout << " -s Set the session directory" << std::endl; std::cout << " -o key=opt,... Set options, see 'rtorrent.rc' file" << std::endl; std::cout << std::endl; std::cout << "Main view keys:" << std::endl; std::cout << " backspace Add a torrent url or path" << std::endl; std::cout << " ^s Start torrent" << std::endl; std::cout << " ^d Stop torrent or delete a stopped torrent" << std::endl; std::cout << " ^r Manually initiate hash checking" << std::endl; std::cout << " ^q Initiate shutdown or skip shutdown process" << std::endl; std::cout << " a,s,d,z,x,c Adjust upload throttle" << std::endl; std::cout << " A,S,D,Z,X,C Adjust download throttle" << std::endl; std::cout << " I Toggle whether torrent ignores ratio settings" << std::endl; std::cout << " right View torrent" << std::endl; std::cout << std::endl; std::cout << "Download view keys:" << std::endl; std::cout << " spacebar Depends on the current view" << std::endl; std::cout << " 1,2 Adjust max uploads" << std::endl; std::cout << " 3,4,5,6 Adjust min/max connected peers" << std::endl; std::cout << " t/T Query tracker for more peers / Force query" << std::endl; std::cout << " * Snub peer" << std::endl; std::cout << " right View files" << std::endl; std::cout << " p View peer information" << std::endl; std::cout << " o View trackers" << std::endl; std::cout << std::endl; std::cout << "Report bugs to ." << std::endl; exit(0); } rtorrent-0.9.6/src/option_parser.cc000066400000000000000000000105471257211462100173770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "option_parser.h" void OptionParser::insert_flag(char c, slot_string s) { m_container[c].m_slot = s; m_container[c].m_useOption = false; } void OptionParser::insert_option(char c, slot_string s) { m_container[c].m_slot = s; m_container[c].m_useOption = true; } void OptionParser::insert_option_list(char c, slot_string_pair s) { m_container[c].m_slot = std::tr1::bind(&OptionParser::call_option_list, s, std::tr1::placeholders::_1); m_container[c].m_useOption = true; } void OptionParser::insert_int_pair(char c, slot_int_pair s) { m_container[c].m_slot = std::tr1::bind(&OptionParser::call_int_pair, s, std::tr1::placeholders::_1); m_container[c].m_useOption = true; } int OptionParser::process(int argc, char** argv) { int c; std::string optString = create_optstring(); while ((c = getopt(argc, argv, optString.c_str())) != -1) if (c == '?') throw std::runtime_error("Invalid/unknown option flag \"-" + std::string(1, (char)optopt) + "\". See rtorrent -h for more information."); else call(c, optarg ? optarg : ""); return optind; } bool OptionParser::has_flag(char flag, int argc, char** argv) { char options[3] = { '-', flag, '\0' }; return std::find_if(argv, argv + argc, std::not1(std::bind1st(std::ptr_fun(&std::strcmp), options))) != argv + argc; } std::string OptionParser::create_optstring() { std::string s; for (Container::iterator itr = m_container.begin(); itr != m_container.end(); ++itr) { s += itr->first; if (itr->second.m_useOption) s += ':'; } return s; } void OptionParser::call(char c, const std::string& arg) { Container::iterator itr = m_container.find(c); if (itr == m_container.end()) throw std::logic_error("OptionParser::call_flag(...) could not find the flag"); itr->second.m_slot(arg); } void OptionParser::call_option_list(slot_string_pair slot, const std::string& arg) { std::string::const_iterator itr = arg.begin(); while (itr != arg.end()) { std::string::const_iterator last = std::find(itr, arg.end(), ','); std::string::const_iterator opt = std::find(itr, last, '='); if (opt == itr || opt == last) throw std::logic_error("Invalid argument, \"" + arg + "\" should be \"key1=opt1,key2=opt2,...\""); slot(std::string(itr, opt), std::string(opt + 1, last)); if (last == arg.end()) break; itr = ++last; } } void OptionParser::call_int_pair(slot_int_pair slot, const std::string& arg) { int a, b; if (std::sscanf(arg.c_str(), "%u-%u", &a, &b) != 2) throw std::runtime_error("Invalid argument, \"" + arg + "\" should be \"a-b\""); slot(a, b); } rtorrent-0.9.6/src/option_parser.h000066400000000000000000000057551257211462100172460ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_OPTION_PARSER_H #define RTORRENT_OPTION_PARSER_H #include #include #include // Throws std::runtime_error upon receiving bad input. class OptionParser { public: typedef std::tr1::function slot_string; typedef std::tr1::function slot_string_pair; typedef std::tr1::function slot_int_pair; void insert_flag(char c, slot_string s); void insert_option(char c, slot_string s); void insert_option_list(char c, slot_string_pair s); void insert_int_pair(char c, slot_int_pair s); // Returns the index of the first non-option argument. int process(int argc, char** argv); static bool has_flag(char flag, int argc, char** argv); private: std::string create_optstring(); void call(char c, const std::string& arg); static void call_option_list(slot_string_pair slot, const std::string& arg); static void call_int_pair(slot_int_pair slot, const std::string& arg); // Use pair instead? struct Node { slot_string m_slot; bool m_useOption; }; typedef std::map Container; Container m_container; }; #endif rtorrent-0.9.6/src/rpc/000077500000000000000000000000001257211462100147615ustar00rootroot00000000000000rtorrent-0.9.6/src/rpc/Makefile.am000066400000000000000000000010411257211462100170110ustar00rootroot00000000000000noinst_LIBRARIES = libsub_rpc.a libsub_rpc_a_SOURCES = \ command.h \ command.cc \ command_impl.h \ command_map.cc \ command_map.h \ command_scheduler.cc \ command_scheduler.h \ command_scheduler_item.cc \ command_scheduler_item.h \ exec_file.cc \ exec_file.h \ fixed_key.h \ ip_table_list.h \ object_storage.cc \ object_storage.h \ parse.cc \ parse.h \ parse_commands.cc \ parse_commands.h \ scgi.cc \ scgi.h \ scgi_task.cc \ scgi_task.h \ xmlrpc.h \ xmlrpc.cc AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/rpc/command.cc000066400000000000000000000132111257211462100167040ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "core/download.h" #include "parse.h" #include "command.h" #define COMMAND_BASE_TEMPLATE_DEFINE(func_name) \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); namespace rpc { template const torrent::Object command_base_call(command_base* rawCommand, target_type target, const torrent::Object& args) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type to command."); return command_base::_call::type, T>(rawCommand, target, args); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call); template const torrent::Object command_base_call_value_base(command_base* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type to command."); const torrent::Object& arg = convert_to_single_argument(rawArgs); if (arg.type() == torrent::Object::TYPE_STRING) { torrent::Object::value_type val; if (!parse_whole_value_nothrow(arg.as_string().c_str(), &val, base, unit)) throw torrent::input_error("Not a value."); return command_base::_call::type, T>(rawCommand, target, val); } return command_base::_call::type, T>(rawCommand, target, arg.as_value()); } template const torrent::Object command_base_call_value(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { return command_base_call_value_base(rawCommand, target, rawArgs, 0, 1); } template const torrent::Object command_base_call_value_kb(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { return command_base_call_value_base(rawCommand, target, rawArgs, 0, 1024); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value); COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value_kb); template const torrent::Object command_base_call_string(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type to command."); const torrent::Object& arg = convert_to_single_argument(rawArgs); if (arg.type() == torrent::Object::TYPE_RAW_STRING) return command_base::_call::type, T>(rawCommand, target, arg.as_raw_string().as_string()); return command_base::_call::type, T>(rawCommand, target, arg.as_string()); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_string); template const torrent::Object command_base_call_list(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { if (!is_target_compatible(target)) throw torrent::input_error("Target of wrong type to command."); if (rawArgs.type() != torrent::Object::TYPE_LIST) { torrent::Object::list_type arg; if (!rawArgs.is_empty()) arg.push_back(rawArgs); return command_base::_call::type, T>(rawCommand, target, arg); } return command_base::_call::type, T>(rawCommand, target, rawArgs.as_list()); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_list); } rtorrent-0.9.6/src/rpc/command.h000066400000000000000000000307731257211462100165620ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_COMMAND_H #define RTORRENT_RPC_COMMAND_H #include #include #include #include #include #include #include // Move into config.h or something. namespace tr1 { using namespace std::tr1; } namespace core { class Download; } namespace torrent { class File; class FileListIterator; class Peer; class Tracker; } namespace rpc { template struct target_wrapper { typedef Target target_type; typedef Target cleaned_type; }; template <> struct target_wrapper { struct no_type {}; typedef void target_type; typedef no_type* cleaned_type; }; // Since c++0x isn't out yet... template struct rt_triple : private std::pair { typedef std::pair base_type; typedef T3 third_type; using base_type::first; using base_type::second; using typename base_type::first_type; using typename base_type::second_type; T3 third; rt_triple() : base_type(), third() {} rt_triple(const T1& a, const T2& b) : base_type(a, b), third() {} rt_triple(const T1& a, const T2& b, const T3& c) : base_type(a, b), third(c) {} rt_triple(const base_type& b) : base_type(b), third() {} rt_triple(const rt_triple& src) : base_type(src.first, src.second), third(src.third) {} }; // Since it gets used so many places we might as well put it in the // rpc namespace. //typedef std::pair target_type; typedef rt_triple target_type; class command_base; typedef const torrent::Object (*command_base_call_type)(command_base*, target_type, const torrent::Object&); typedef tr1::function base_function; template struct command_base_is_valid {}; template struct command_base_is_type {}; class command_base { public: typedef torrent::Object::value_type value_type; typedef torrent::Object::string_type string_type; typedef torrent::Object::list_type list_type; typedef torrent::Object::map_type map_type; typedef torrent::Object::key_type key_type; typedef const torrent::Object (*generic_slot) (command_base*, const torrent::Object&); typedef const torrent::Object (*cleaned_slot) (command_base*, target_wrapper::cleaned_type, const torrent::Object&); typedef const torrent::Object (*any_slot) (command_base*, target_type, const torrent::Object&); typedef const torrent::Object (*download_slot) (command_base*, core::Download*, const torrent::Object&); typedef const torrent::Object (*file_slot) (command_base*, torrent::File*, const torrent::Object&); typedef const torrent::Object (*file_itr_slot) (command_base*, torrent::FileListIterator*, const torrent::Object&); typedef const torrent::Object (*peer_slot) (command_base*, torrent::Peer*, const torrent::Object&); typedef const torrent::Object (*tracker_slot) (command_base*, torrent::Tracker*, const torrent::Object&); typedef const torrent::Object (*download_pair_slot) (command_base*, core::Download*, core::Download*, const torrent::Object&); static const int target_generic = 0; static const int target_any = 1; static const int target_download = 2; static const int target_peer = 3; static const int target_tracker = 4; static const int target_file = 5; static const int target_file_itr = 6; static const int target_download_pair = 7; static const unsigned int max_arguments = 10; struct stack_type { torrent::Object* begin() { return reinterpret_cast(buffer); } torrent::Object* end() { return reinterpret_cast(buffer) + max_arguments; } const torrent::Object* begin() const { return reinterpret_cast(buffer); } const torrent::Object* end() const { return reinterpret_cast(buffer) + max_arguments; } torrent::Object& operator [] (unsigned int idx) { return *(begin() + idx); } const torrent::Object& operator [] (unsigned int idx) const { return *(begin() + idx); } static stack_type* from_data(char* data) { return reinterpret_cast(data); } char buffer[sizeof(torrent::Object) * max_arguments]; }; command_base() { new (&_pod()) base_function(); } command_base(const command_base& src) { new (&_pod()) base_function(src._pod()); } ~command_base() { _pod().~base_function(); } static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; } static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); } static stack_type current_stack; static torrent::Object* stack_begin() { return current_stack.begin(); } static torrent::Object* stack_end() { return current_stack.end(); } static torrent::Object* push_stack(const torrent::Object::list_type& args, stack_type* stack); static torrent::Object* push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack); static void pop_stack(stack_type* stack, torrent::Object* last_stack); template void set_function(T s, int value = command_base_is_valid::value) { _pod() = s; } template void set_function_2(typename command_base_is_type::type s, int value = command_base_is_valid::type>::value) { _pod::type>() = s; } // The std::function object in GCC is castable between types with a // pointer to a struct of ctor/dtor/calls for non-POD slots. As such // it should be safe to cast between different std::function // template types, yet what the C++0x standard will say about this I // have no idea atm. template tmpl& _pod() { return reinterpret_cast(t_pod); } template const tmpl& _pod() const { return reinterpret_cast(t_pod); } template static const torrent::Object _call(command_base* cmd, target_type target, Args args); command_base& operator = (const command_base& src) { _pod() = src._pod(); return *this; } protected: // For use by functions that need to use placeholders to arguments // within commands. E.d. callable command strings where one of the // arguments within the command needs to be supplied by the caller. #ifdef HAVE_CXX11 union { base_function t_pod; // char t_pod[sizeof(base_function)]; }; #else union { char t_pod[sizeof(base_function)]; }; #endif }; template struct target_type_id { // Nothing here, so we cause an error. }; template inline bool is_target_compatible(const target_type& target) { return target.first == target_type_id::value; } // Splitting pairs into separate targets. inline bool is_target_pair(const target_type& target) { return target.first >= command_base::target_download_pair; } template inline T get_target_cast(target_type target, int type = target_type_id::value) { return (T)target.second; } inline target_type get_target_left(const target_type& target) { return target_type(target.first - 5, target.second); } inline target_type get_target_right(const target_type& target) { return target_type(target.first - 5, target.third); } } #include "command_impl.h" namespace rpc { template inline const torrent::Object command_base::_call(command_base* cmd, target_type target, Args args) { return static_cast(cmd)->_pod()(get_target_cast(target), args); } #define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \ template ::proper_type> struct func_type { typedef tr1::function type; }; \ \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; // template struct command_base_is_valid::type > { static const int value = 1; }; COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&)); COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&)); COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&)); COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const torrent::Object::list_type&)); #define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; COMMAND_BASE_TEMPLATE_CALL(command_base_call, command_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_value, command_value_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_value_kb, command_value_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_string, command_string_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_list, command_list_function); } #endif rtorrent-0.9.6/src/rpc/command_impl.h000066400000000000000000000131211257211462100175670ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_COMMAND_IMPL_H #define RTORRENT_RPC_COMMAND_IMPL_H namespace rpc { //template <> struct target_type_id { static const int value = command_base::target_generic; }; template <> struct target_type_id { static const int value = command_base::target_generic; }; template <> struct target_type_id { static const int value = command_base::target_any; }; template <> struct target_type_id { static const int value = command_base::target_download; }; template <> struct target_type_id { static const int value = command_base::target_peer; }; template <> struct target_type_id { static const int value = command_base::target_tracker; }; template <> struct target_type_id { static const int value = command_base::target_file; }; template <> struct target_type_id { static const int value = command_base::target_file_itr; }; template <> struct target_type_id { static const int value = command_base::target_download_pair; }; template <> struct target_type_id<> { static const int value = command_base::target_generic; }; template <> struct target_type_id { static const int value = command_base::target_any; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_download; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_peer; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_tracker; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_file; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_file_itr; static const int proper_type = 1; }; template <> struct target_type_id { static const int value = command_base::target_download_pair; }; template <> inline bool is_target_compatible(const target_type& target) { return true; } template <> inline bool is_target_compatible(const target_type& target) { return target.first == command_base::target_file || command_base::target_file_itr; } template <> inline target_type get_target_cast(target_type target, int type) { return target; } template <> inline torrent::File* get_target_cast(target_type target, int type) { if (target.first == command_base::target_file_itr) return static_cast(target.second)->file(); else return static_cast(target.second); } inline torrent::Object* command_base::push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack) { unsigned int idx = 0; while (first_arg != last_arg && idx < command_base::max_arguments) { new (&(*stack)[idx]) torrent::Object(*first_arg++); (*stack)[idx].swap(*command_base::argument(idx)); idx++; } return stack->begin() + idx; } inline torrent::Object* command_base::push_stack(const torrent::Object::list_type& args, stack_type* stack) { return push_stack(args.data(), args.data() + args.size(), stack); } inline void command_base::pop_stack(stack_type* stack, torrent::Object* last_stack) { while (last_stack-- != stack->begin()) { last_stack->swap(*command_base::argument(std::distance(stack->begin(), last_stack))); last_stack->~Object(); // To ensure we catch errors: std::memset(last_stack, 0xAA, sizeof(torrent::Object)); } } } #endif rtorrent-0.9.6/src/rpc/command_map.cc000066400000000000000000000146121257211462100175470ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include // Get better logging... #include "globals.h" #include "control.h" #include "core/manager.h" #include "command.h" #include "command_map.h" // For XMLRPC stuff, clean up. #include "xmlrpc.h" #include "parse_commands.h" namespace rpc { command_base::stack_type command_base::current_stack; CommandMap::~CommandMap() { std::vector keys; for (iterator itr = base_type::begin(), last = base_type::end(); itr != last; itr++) { // if (!(itr->second.m_flags & flag_dont_delete)) // delete itr->second.m_variable; if (itr->second.m_flags & flag_delete_key) keys.push_back(itr->first); } for (std::vector::iterator itr = keys.begin(), last = keys.end(); itr != last; itr++) delete [] *itr; } CommandMap::iterator CommandMap::insert(key_type key, int flags, const char* parm, const char* doc) { iterator itr = base_type::find(key); if (itr != base_type::end()) throw torrent::internal_error("CommandMap::insert(...) tried to insert an already existing key."); // TODO: This is not honoring the public_xmlrpc flags!!! if (rpc::xmlrpc.is_valid() && (flags & flag_public_xmlrpc)) // if (rpc::xmlrpc.is_valid()) rpc::xmlrpc.insert_command(key, parm, doc); return base_type::insert(itr, value_type(key, command_map_data_type(flags, parm, doc))); } // void // CommandMap::insert(key_type key, const command_map_data_type src) { // iterator itr = base_type::find(key); // if (itr != base_type::end()) // throw torrent::internal_error("CommandMap::insert(...) tried to insert an already existing key."); // itr = base_type::insert(itr, value_type(key, command_map_data_type(src.m_variable, src.m_flags | flag_dont_delete, src.m_parm, src.m_doc))); // // We can assume all the slots are the same size. // itr->second.m_anySlot = src.m_anySlot; // } void CommandMap::erase(iterator itr) { if (itr == end()) return; // TODO: Remove the redirects instead... if (itr->second.m_flags & flag_has_redirects) throw torrent::input_error("Can't erase a command that has redirects."); // if (!(itr->second.m_flags & flag_dont_delete)) // delete itr->second.m_variable; const char* key = itr->second.m_flags & flag_delete_key ? itr->first : NULL; base_type::erase(itr); delete [] key; } void CommandMap::create_redirect(key_type key_new, key_type key_dest, int flags) { iterator new_itr = base_type::find(key_new); iterator dest_itr = base_type::find(key_dest); if (dest_itr == base_type::end()) throw torrent::input_error("Tried to redirect to a key that doesn't exist: '" + std::string(key_dest) + "'."); if (new_itr != base_type::end()) throw torrent::input_error("Tried to create a redirect key that already exists: '" + std::string(key_new) + "'."); if (dest_itr->second.m_flags & flag_is_redirect) throw torrent::input_error("Tried to redirect to a key that is not marked 'flag_is_redirect': '" + std::string(key_dest) + "'."); dest_itr->second.m_flags |= flag_has_redirects; flags |= dest_itr->second.m_flags & ~(flag_delete_key | flag_has_redirects | flag_public_xmlrpc); // TODO: This is not honoring the public_xmlrpc flags!!! if (rpc::xmlrpc.is_valid() && (flags & flag_public_xmlrpc)) rpc::xmlrpc.insert_command(key_new, dest_itr->second.m_parm, dest_itr->second.m_doc); iterator itr = base_type::insert(base_type::end(), value_type(key_new, command_map_data_type(flags, dest_itr->second.m_parm, dest_itr->second.m_doc))); // We can assume all the slots are the same size. itr->second.m_variable = dest_itr->second.m_variable; itr->second.m_anySlot = dest_itr->second.m_anySlot; } const CommandMap::mapped_type CommandMap::call_catch(key_type key, target_type target, const mapped_type& args, const char* err) { try { return call_command(key, args, target); } catch (torrent::input_error& e) { control->core()->push_log((err + std::string(e.what())).c_str()); return torrent::Object(); } } const CommandMap::mapped_type CommandMap::call_command(key_type key, const mapped_type& arg, target_type target) { iterator itr = base_type::find(key); if (itr == base_type::end()) throw torrent::input_error("Command \"" + std::string(key) + "\" does not exist."); return itr->second.m_anySlot(&itr->second.m_variable, target, arg); } const CommandMap::mapped_type CommandMap::call_command(iterator itr, const mapped_type& arg, target_type target) { return itr->second.m_anySlot(&itr->second.m_variable, target, arg); } } rtorrent-0.9.6/src/rpc/command_map.h000066400000000000000000000167061257211462100174170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_COMMAND_MAP_H #define RTORRENT_RPC_COMMAND_MAP_H #include #include #include #include #include "command.h" namespace rpc { struct command_map_comp : public std::binary_function { bool operator () (const char* arg1, const char* arg2) const { return std::strcmp(arg1, arg2) < 0; } }; struct command_map_data_type { // Some commands will need to share data, like get/set a variable. So // instead of using a single virtual member function, each command // will register a member function pointer to be used instead. // // The any_slot should perhaps replace generic_slot? command_map_data_type(int flags, const char* parm, const char* doc) : m_flags(flags), m_parm(parm), m_doc(doc) {} command_map_data_type(const command_map_data_type& src) : m_variable(src.m_variable), m_anySlot(src.m_anySlot), m_flags(src.m_flags), m_parm(src.m_parm), m_doc(src.m_doc) {} command_base m_variable; command_base::any_slot m_anySlot; int m_flags; const char* m_parm; const char* m_doc; }; class CommandMap : public std::map { public: typedef std::map base_type; typedef torrent::Object mapped_type; typedef mapped_type::value_type mapped_value_type; using base_type::iterator; using base_type::const_iterator; using base_type::key_type; using base_type::value_type; using base_type::begin; using base_type::end; using base_type::find; static const int flag_dont_delete = 0x1; static const int flag_delete_key = 0x2; static const int flag_public_xmlrpc = 0x4; static const int flag_modifiable = 0x10; static const int flag_is_redirect = 0x20; static const int flag_has_redirects = 0x40; static const int flag_no_target = 0x100; static const int flag_file_target = 0x200; static const int flag_tracker_target = 0x400; CommandMap() {} ~CommandMap(); bool has(const char* key) const { return base_type::find(key) != base_type::end(); } bool has(const std::string& key) const { return has(key.c_str()); } bool is_modifiable(const_iterator itr) { return itr != end() && (itr->second.m_flags & flag_modifiable); } iterator insert(key_type key, int flags, const char* parm, const char* doc); template void insert_slot(key_type key, Slot variable, command_base::any_slot targetSlot, int flags, const char* parm, const char* doc) { iterator itr = insert(key, flags, parm, doc); itr->second.m_variable.set_function(variable); itr->second.m_anySlot = targetSlot; } // void insert(key_type key, const command_map_data_type src); void erase(iterator itr); void create_redirect(key_type key_new, key_type key_dest, int flags); const mapped_type call(key_type key, const mapped_type& args = mapped_type()); const mapped_type call(key_type key, target_type target, const mapped_type& args = mapped_type()) { return call_command(key, args, target); } const mapped_type call_catch(key_type key, target_type target, const mapped_type& args = mapped_type(), const char* err = "Command failed: "); const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); const mapped_type call_command (iterator itr, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); const mapped_type call_command_d(key_type key, core::Download* download, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_download, download)); } const mapped_type call_command_p(key_type key, torrent::Peer* peer, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_peer, peer)); } const mapped_type call_command_t(key_type key, torrent::Tracker* tracker, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_tracker, tracker)); } const mapped_type call_command_f(key_type key, torrent::File* file, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_file, file)); } private: CommandMap(const CommandMap&); void operator = (const CommandMap&); }; inline target_type make_target() { return target_type((int)command_base::target_generic, NULL); } inline target_type make_target(int type, void* target) { return target_type(type, target); } inline target_type make_target(int type, void* target1, void* target2) { return target_type(type, target1, target2); } template inline target_type make_target(T target) { return target_type((int)target_type_id::value, target); } template inline target_type make_target_pair(T target1, T target2) { return target_type((int)target_type_id::value, target1, target2); } // TODO: Helper-functions that really should be in the // torrent/object.h header. inline torrent::Object create_object_list(const torrent::Object& o1, const torrent::Object& o2) { torrent::Object tmp = torrent::Object::create_list(); tmp.as_list().push_back(o1); tmp.as_list().push_back(o2); return tmp; } inline torrent::Object create_object_list(const torrent::Object& o1, const torrent::Object& o2, const torrent::Object& o3) { torrent::Object tmp = torrent::Object::create_list(); tmp.as_list().push_back(o1); tmp.as_list().push_back(o2); tmp.as_list().push_back(o3); return tmp; } inline const CommandMap::mapped_type CommandMap::call(key_type key, const mapped_type& args) { return call_command(key, args, make_target()); } } #endif rtorrent-0.9.6/src/rpc/command_scheduler.cc000066400000000000000000000135631257211462100207540ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "command_scheduler.h" #include "command_scheduler_item.h" #include "parse_commands.h" namespace rpc { CommandScheduler::~CommandScheduler() { std::for_each(begin(), end(), rak::call_delete()); } CommandScheduler::iterator CommandScheduler::find(const std::string& key) { return std::find_if(begin(), end(), rak::equal(key, std::mem_fun(&CommandSchedulerItem::key))); } CommandScheduler::iterator CommandScheduler::insert(const std::string& key) { if (key.empty()) throw torrent::input_error("Scheduler received an empty key."); iterator itr = find(key); if (itr == end()) itr = base_type::insert(end(), NULL); else delete *itr; *itr = new CommandSchedulerItem(key); (*itr)->slot() = std::tr1::bind(&CommandScheduler::call_item, this, *itr); return itr; } void CommandScheduler::erase(iterator itr) { if (itr == end()) return; delete *itr; base_type::erase(itr); } void CommandScheduler::call_item(value_type item) { if (item->is_queued()) throw torrent::internal_error("CommandScheduler::call_item(...) called but item is still queued."); if (std::find(begin(), end(), item) == end()) throw torrent::internal_error("CommandScheduler::call_item(...) called but the item isn't in the scheduler."); // Remove the item before calling the command if it should be // removed. try { rpc::call_object(item->command()); } catch (torrent::input_error& e) { if (m_slotErrorMessage.is_valid()) m_slotErrorMessage("Scheduled command failed: " + item->key() + ": " + e.what()); } // Still schedule if we caught a torrrent::input_error? rak::timer next = item->next_time_scheduled(); if (next == rak::timer()) { // Remove from scheduler? return; } if (next <= cachedTime) throw torrent::internal_error("CommandScheduler::call_item(...) tried to schedule a zero interval item."); item->enable(next); } void CommandScheduler::parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const torrent::Object& command) { if (!command.is_string() && !command.is_dict_key()) throw torrent::bencode_error("Invalid type passed to command scheduler."); uint32_t absolute = parse_absolute(bufAbsolute.c_str()); uint32_t interval = parse_interval(bufInterval.c_str()); CommandSchedulerItem* item = *insert(key); item->command() = command; item->set_interval(interval); item->enable((cachedTime + rak::timer::from_seconds(absolute)).round_seconds()); } uint32_t CommandScheduler::parse_absolute(const char* str) { Time result = parse_time(str); time_t t; // Do the local time thing. struct tm local; switch (result.first) { case 1: return result.second; case 2: t = cachedTime.tval().tv_sec; if (localtime_r(&t, &local) == NULL) throw torrent::input_error("Could not convert unix time to local time."); return (result.second + 3600 - 60 * local.tm_min - local.tm_sec) % 3600; case 3: t = cachedTime.tval().tv_sec; if (localtime_r(&t, &local) == NULL) throw torrent::input_error("Could not convert unix time to local time."); return (result.second + 24 * 3600 - 3600 * local.tm_hour - 60 * local.tm_min - local.tm_sec) % (24 * 3600); case 0: default: throw torrent::input_error("Could not parse interval."); } } uint32_t CommandScheduler::parse_interval(const char* str) { Time result = parse_time(str); if (result.first == 0) throw torrent::input_error("Could not parse interval."); return result.second; } CommandScheduler::Time CommandScheduler::parse_time(const char* str) { Time result(0, 0); while (true) { char* pos; result.first++; result.second += strtol(str, &pos, 10); if (pos == str || result.second < 0) return Time(0, 0); while (std::isspace(*pos)) ++pos; if (*pos == '\0') return result; if (*pos != ':' || result.first > 3) return Time(0, 0); if (result.first < 3) result.second *= 60; else result.second *= 24; str = pos + 1; } } } rtorrent-0.9.6/src/rpc/command_scheduler.h000066400000000000000000000062411257211462100206110ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_COMMAND_SCHEDULER_H #define RTORRENT_COMMAND_SCHEDULER_H #include #include #include #include namespace torrent { class Object; } namespace rpc { class CommandSchedulerItem; class CommandScheduler : public std::vector { public: typedef rak::function1 SlotString; typedef std::pair Time; typedef std::vector base_type; using base_type::value_type; using base_type::begin; using base_type::end; CommandScheduler() {} ~CommandScheduler(); void set_slot_error_message(SlotString::base_type* s) { m_slotErrorMessage.set(s); } // slot_error_message or something. iterator find(const std::string& key); // If the key already exists then the old item is deleted. It is // safe to call erase on end(). iterator insert(const std::string& key); void erase(iterator itr); void erase_str(const std::string& key) { erase(find(key)); } void parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const torrent::Object& command); static uint32_t parse_absolute(const char* str); static uint32_t parse_interval(const char* str); static Time parse_time(const char* str); private: void call_item(value_type item); SlotString m_slotErrorMessage; }; } #endif rtorrent-0.9.6/src/rpc/command_scheduler_item.cc000066400000000000000000000055111257211462100217640ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "command_scheduler_item.h" namespace rpc { CommandSchedulerItem::~CommandSchedulerItem() { priority_queue_erase(&taskScheduler, &m_task); } void CommandSchedulerItem::enable(rak::timer t) { if (t == rak::timer()) throw torrent::internal_error("CommandSchedulerItem::enable() t == rak::timer()."); if (is_queued()) disable(); // If 'first' is zero then we execute the task // immediately. ''interval()'' will not return zero so we never end // up in an infinit loop. m_timeScheduled = t; priority_queue_insert(&taskScheduler, &m_task, t); } void CommandSchedulerItem::disable() { m_timeScheduled = rak::timer(); priority_queue_erase(&taskScheduler, &m_task); } rak::timer CommandSchedulerItem::next_time_scheduled() const { if (m_interval == 0) return rak::timer(); if (m_timeScheduled == rak::timer()) throw torrent::internal_error("CommandSchedulerItem::next_time_scheduled() m_timeScheduled == rak::timer()."); rak::timer next = m_timeScheduled; // This should be done in a non-looping manner. do { next += rak::timer::from_seconds(m_interval); } while (next <= cachedTime.round_seconds()); return next; } } rtorrent-0.9.6/src/rpc/command_scheduler_item.h000066400000000000000000000060011257211462100216210ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_COMMAND_SCHEDULER_ITEM_H #define RTORRENT_COMMAND_SCHEDULER_ITEM_H #include "globals.h" #include #include namespace rpc { class CommandSchedulerItem { public: typedef std::tr1::function slot_void; CommandSchedulerItem(const std::string& key) : m_key(key), m_interval(0) {} ~CommandSchedulerItem(); bool is_queued() const { return m_task.is_queued(); } void enable(rak::timer t); void disable(); const std::string& key() const { return m_key; } torrent::Object& command() { return m_command; } // 'interval()' should in the future return some more dynamic values. uint32_t interval() const { return m_interval; } void set_interval(uint32_t v) { m_interval = v; } rak::timer time_scheduled() const { return m_timeScheduled; } rak::timer next_time_scheduled() const; slot_void& slot() { return m_task.slot(); } private: CommandSchedulerItem(const CommandSchedulerItem&); void operator = (const CommandSchedulerItem&); std::string m_key; torrent::Object m_command; uint32_t m_interval; rak::timer m_timeScheduled; rak::priority_item m_task; // Flags for various things. }; } #endif rtorrent-0.9.6/src/rpc/exec_file.cc000066400000000000000000000151631257211462100172210ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "exec_file.h" #include "parse.h" #include "thread_base.h" namespace rpc { // Close m_logFd. int ExecFile::execute(const char* file, char* const* argv, int flags) { // Write the execued command and its parameters to the log fd. int __UNUSED result; if (m_logFd != -1) { for (char* const* itr = argv; *itr != NULL; itr++) { if (itr == argv) result = write(m_logFd, "\n---\n", sizeof("\n---\n")); else result = write(m_logFd, " ", 1); result = write(m_logFd, *itr, std::strlen(*itr)); } result = write(m_logFd, "\n---\n", sizeof("\n---\n")); } int pipeFd[2]; if ((flags & flag_capture) && pipe(pipeFd)) throw torrent::input_error("ExecFile::execute(...) Pipe creation failed."); pid_t childPid = fork(); if (childPid == -1) throw torrent::input_error("ExecFile::execute(...) Fork failed."); if (childPid == 0) { if (flags & flag_background) { pid_t detached_pid = fork(); if (detached_pid == -1) _exit(-1); if (detached_pid != 0) { if (m_logFd != -1) result = write(m_logFd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n")); _exit(0); } m_logFd = -1; flags &= ~flag_capture; } int devNull = open("/dev/null", O_RDWR); if (devNull != -1) dup2(devNull, 0); else ::close(0); if (flags & flag_capture) dup2(pipeFd[1], 1); else if (m_logFd != -1) dup2(m_logFd, 1); else if (devNull != -1) dup2(devNull, 1); else ::close(1); if (m_logFd != -1) dup2(m_logFd, 2); else if (devNull != -1) dup2(devNull, 2); else ::close(2); // Close all fd's. for (int i = 3, last = sysconf(_SC_OPEN_MAX); i != last; i++) ::close(i); int result = execvp(file, argv); _exit(result); } // We yield the global lock when waiting for the executed command to // finish so that XMLRPC and other threads can continue working. ThreadBase::release_global_lock(); if (flags & flag_capture) { m_capture = std::string(); ::close(pipeFd[1]); char buffer[4096]; ssize_t length; do { length = read(pipeFd[0], buffer, sizeof(buffer)); if (length > 0) m_capture += std::string(buffer, length); } while (length > 0); ::close(pipeFd[0]); if (m_logFd != -1) { result = write(m_logFd, "Captured output:\n", sizeof("Captured output:\n")); result = write(m_logFd, m_capture.data(), m_capture.length()); } } int status; int wpid; do { wpid = waitpid(childPid, &status, 0); } while (wpid == -1 && rak::error_number::current().value() == rak::error_number::e_intr); ThreadBase::acquire_global_lock(); if (wpid != childPid) throw torrent::internal_error("ExecFile::execute(...) waitpid failed."); // Check return value? if (m_logFd != -1) { if (status == 0) result = write(m_logFd, "\n--- Success ---\n", sizeof("\n--- Success ---\n")); else result = write(m_logFd, "\n--- Error ---\n", sizeof("\n--- Error ---\n")); } return status; } torrent::Object ExecFile::execute_object(const torrent::Object& rawArgs, int flags) { char* argsBuffer[max_args]; char** argsCurrent = argsBuffer; // Size of value strings are less than 24. char valueBuffer[buffer_size]; char* valueCurrent = valueBuffer; if (rawArgs.is_list()) { const torrent::Object::list_type& args = rawArgs.as_list(); if (args.empty()) throw torrent::input_error("Too few arguments."); for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++, argsCurrent++) { if (argsCurrent == argsBuffer + max_args - 1) throw torrent::input_error("Too many arguments."); if (itr->is_string() && (!(flags & flag_expand_tilde) || *itr->as_string().c_str() != '~')) { *argsCurrent = const_cast(itr->as_string().c_str()); } else { *argsCurrent = valueCurrent; valueCurrent = print_object(valueCurrent, valueBuffer + buffer_size, &*itr, flags) + 1; if (valueCurrent >= valueBuffer + buffer_size) throw torrent::input_error("Overflowed execute arg buffer."); } } } else { const torrent::Object::string_type& args = rawArgs.as_string(); if ((flags & flag_expand_tilde) && args.c_str()[0] == '~') { *argsCurrent = valueCurrent; valueCurrent = print_object(valueCurrent, valueBuffer + buffer_size, &rawArgs, flags) + 1; } else { *argsCurrent = const_cast(args.c_str()); } argsCurrent++; } *argsCurrent = NULL; int status = execute(argsBuffer[0], argsBuffer, flags); if ((flags & flag_throw) && status != 0) throw torrent::input_error("Bad return code."); if (flags & flag_capture) return m_capture; return torrent::Object((int64_t)status); } } rtorrent-0.9.6/src/rpc/exec_file.h000066400000000000000000000046441257211462100170650ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_EXEC_FILE_H #define RTORRENT_RPC_EXEC_FILE_H #include namespace rpc { class ExecFile { public: static const unsigned int max_args = 128; static const unsigned int buffer_size = 4096; static const int flag_expand_tilde = 0x1; static const int flag_throw = 0x2; static const int flag_capture = 0x4; static const int flag_background = 0x8; ExecFile() : m_logFd(-1) {} int log_fd() const { return m_logFd; } void set_log_fd(int fd) { m_logFd = fd; } int execute(const char* file, char* const* argv, int flags); torrent::Object execute_object(const torrent::Object& rawArgs, int flags); private: int m_logFd; std::string m_capture; }; } #endif rtorrent-0.9.6/src/rpc/fixed_key.h000066400000000000000000000114101257211462100170760ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_FIXED_KEY_H #define RTORRENT_RPC_FIXED_KEY_H #include namespace rpc { // The key size should be such that the value type size which includes // the next-pointer. template class fixed_key_type { public: typedef char value_type; typedef const char* iterator; typedef const char* const_iterator; typedef uint32_t size_type; static const size_type max_size = MaxSize - 1; fixed_key_type() : m_size(0) { m_data[0] = '\0'; } fixed_key_type(const fixed_key_type& k) : m_size(k.m_size) { std::memcpy(m_data, k.m_data, k.m_size + 1); } fixed_key_type(const value_type* src_data, size_type src_size) { set_data(src_data, src_size); } static fixed_key_type from_c_str(const char* str) { fixed_key_type k; k.set_c_str(str); return k; } static fixed_key_type from_string(const std::string& str) { fixed_key_type k; k.set_c_str(str.c_str(), str.size()); return k; } static fixed_key_type from_raw_string(const torrent::raw_string& str) { fixed_key_type k; k.set_data(str.data(), str.size()); return k; } bool empty() const { return m_size == 0; } size_type size() const { return m_size; } iterator begin() const { return m_data; } iterator end() const { return m_data + m_size; } value_type* data() { return m_data; } const value_type* data() const { return m_data; } const char* c_str() const { return m_data; } void set_data(const value_type* src_data, size_type src_size); void set_c_str(const value_type* src_data); void set_c_str(const value_type* src_data, size_type src_size); bool operator == (const fixed_key_type& rhs) const { return m_size == rhs.m_size && std::memcmp(m_data, rhs.m_data, m_size) == 0; } bool operator != (const fixed_key_type& rhs) const { return m_size != rhs.m_size || std::memcmp(m_data, rhs.m_data, m_size) != 0; } bool operator == (const torrent::raw_string& rhs) const { return m_size == rhs.size() && std::memcmp(m_data, rhs.data(), m_size) == 0; } bool operator != (const torrent::raw_string& rhs) const { return m_size != rhs.size() || std::memcmp(m_data, rhs.data(), m_size) != 0; } bool operator == (const std::string& rhs) const { return m_size == rhs.size() && std::memcmp(m_data, rhs.data(), m_size) == 0; } private: size_type m_size; char m_data[max_size]; }; struct hash_fixed_key_type { template inline std::size_t operator () (const fixed_key_type& p) const { return hash(p.data()); } static inline std::size_t hash(const char* data) { std::size_t result = 0; while (*data != '\0') result = (result * 131) + *data++; return result; } static inline std::size_t hash(const char* data, uint32_t size) { std::size_t result = 0; while (size--) result = (result * 131) + *data++; return result; } }; template bool operator == (const torrent::raw_string& lhs, const fixed_key_type& rhs) { return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; } } #endif rtorrent-0.9.6/src/rpc/ip_table_list.h000066400000000000000000000053561257211462100177550ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_IP_TABLE_LISTS_H #define RTORRENT_RPC_IP_TABLE_LISTS_H #include #include #include #include #include namespace rpc { typedef torrent::extents ipv4_table; struct ip_table_node { std::string name; ipv4_table table; bool equal_name(const std::string& str) const { return str == name; } }; class ip_table_list : private std::vector { public: typedef std::vector base_type; using base_type::iterator; using base_type::const_iterator; using base_type::value_type; using base_type::begin; using base_type::end; iterator insert(const std::string& name); iterator find(const std::string& name); }; inline ip_table_list::iterator ip_table_list::insert(const std::string& name) { ip_table_node tmp = { name }; return base_type::insert(end(), tmp); } inline ip_table_list::iterator ip_table_list::find(const std::string& name) { for (iterator itr = begin(), last = end(); itr != last; itr++) if (itr->equal_name(name)) return itr; return end(); } } #endif rtorrent-0.9.6/src/rpc/object_storage.cc000066400000000000000000000221241257211462100202630ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "object_storage.h" #include "rak/functional.h" #include "parse.h" #include "parse_commands.h" namespace rpc { object_storage::local_iterator object_storage::find_local(const torrent::raw_string& key) { std::size_t n = hash_fixed_key_type::hash(key.data(), key.size()) % bucket_count(); for (local_iterator itr = begin(n), last = end(n); itr != last; itr++) if (itr->first.size() == key.size() && std::memcmp(itr->first.data(), key.data(), key.size()) == 0) return itr; return end(bucket_count()); } object_storage::local_iterator object_storage::find_local_const(const torrent::raw_string& key, unsigned int type) { local_iterator itr = find_local(key); if (itr == end(bucket_count())) throw torrent::input_error("Key not found."); if ((type != 0 && (itr->second.flags & mask_type) != type)) throw torrent::input_error("Object is wrong type or const."); return itr; } object_storage::local_iterator object_storage::find_local_mutable(const torrent::raw_string& key, unsigned int type) { local_iterator itr = find_local(key); if (itr == end(bucket_count())) throw torrent::input_error("Key not found."); if ((type != 0 && (itr->second.flags & mask_type) != type) || itr->second.flags & flag_constant) throw torrent::input_error("Object is wrong type or const."); return itr; } object_storage::iterator object_storage::insert(const char* key_data, uint32_t key_size, const torrent::Object& rawObject, unsigned int flags) { if (std::find(key_data, key_data + key_size, '\0') != key_data + key_size) throw torrent::input_error("Found nul-char in string."); // Check for size > key_size. // Check for empty string. bool use_raw = false; torrent::Object object; switch (flags & mask_type) { case flag_bool_type: object = !!convert_to_value(rawObject); break; case flag_value_type: object = convert_to_value(rawObject); break; case flag_string_type: object = convert_to_string(rawObject); break; case flag_list_type: use_raw = true; break; case flag_function_type: use_raw = true; break; case flag_multi_type: object = torrent::Object::create_map(); break; } if (!(flags & mask_type)) throw torrent::input_error("No type flags set when calling object_storage::insert."); if ((flags & flag_rlookup) && (!(flags & flag_static) || !(flags & flag_multi_type))) throw torrent::input_error("Cannot insert non-static or non-multi-type object with rlookup enabled."); std::pair result = base_type::insert(std::make_pair(key_type(key_data, key_size), object_storage_node())); if (!result.second) throw torrent::input_error("Key already exists in object_storage."); result.first->second.flags = flags; result.first->second.object = use_raw ? rawObject : object; return result.first; } bool object_storage::has_flag(const torrent::raw_string& key, unsigned int flag) { local_iterator itr = find_local_const(key); return itr->second.flags & flag; } void object_storage::enable_flag(const torrent::raw_string& key, unsigned int flag) { local_iterator itr = find_local_mutable(key); itr->second.flags |= (flag & (flag_constant)); } const torrent::Object& object_storage::get(const torrent::raw_string& key) { local_iterator itr = find_local_const(key); return itr->second.object; } const torrent::Object& object_storage::set_bool(const torrent::raw_string& key, int64_t object) { local_iterator itr = find_local_mutable(key, flag_bool_type); return itr->second.object = !!object; } const torrent::Object& object_storage::set_value(const torrent::raw_string& key, int64_t object) { local_iterator itr = find_local_mutable(key, flag_value_type); return itr->second.object = object; } const torrent::Object& object_storage::set_string(const torrent::raw_string& key, const std::string& object) { local_iterator itr = find_local_mutable(key, flag_string_type); return itr->second.object = object; } const torrent::Object& object_storage::set_list(const torrent::raw_string& key, const torrent::Object::list_type& object) { local_iterator itr = find_local_mutable(key, flag_list_type); return itr->second.object = torrent::Object::create_list_range(object.begin(), object.end()); } void object_storage::list_push_back(const torrent::raw_string& key, const torrent::Object& object) { local_iterator itr = find_local_mutable(key, flag_list_type); itr->second.object.as_list().push_back(object); } const torrent::Object& object_storage::set_function(const torrent::raw_string& key, const std::string& object) { local_iterator itr = find_local_mutable(key, flag_function_type); return itr->second.object = object; } torrent::Object object_storage::call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object) { local_iterator itr = find_local_const(key); switch (itr->second.flags & mask_type) { case flag_function_type: case flag_multi_type: return command_function_call_object(itr->second.object, target, object); default: throw torrent::input_error("Key not found or wrong type."); } } bool object_storage::has_multi_key(const torrent::raw_string& key, const std::string& cmd_key) { local_iterator itr = find_local_const(key, flag_multi_type); return itr->second.object.has_key(cmd_key); } void object_storage::erase_multi_key(const torrent::raw_string& key, const std::string& cmd_key) { local_iterator itr = find_local_mutable(key, flag_multi_type); itr->second.object.erase_key(cmd_key); if (!(itr->second.flags & flag_rlookup)) return; // Remove the rlookup entry. rlookup_iterator r_itr = m_rlookup.find(cmd_key); if (r_itr == m_rlookup.end()) return; rlookup_mapped_iterator rm_itr = std::find_if(r_itr->second.begin(), r_itr->second.end(), rak::equal(key, rak::mem_ptr(&value_type::first))); if (rm_itr != r_itr->second.end()) r_itr->second.erase(rm_itr); } void object_storage::set_multi_key_obj(const torrent::raw_string& key, const std::string& cmd_key, const torrent::Object& object) { if (!object.is_string() && !object.is_dict_key() && !object.is_list()) throw torrent::input_error("Object is wrong type."); local_iterator itr = find_local_mutable(key, flag_multi_type); if (itr->second.flags & flag_rlookup) { rlookup_iterator r_itr = m_rlookup.find(cmd_key); if (r_itr == m_rlookup.end()) r_itr = m_rlookup.insert(std::make_pair(cmd_key, rlookup_type::mapped_type())).first; if (std::find_if(r_itr->second.begin(), r_itr->second.end(), rak::equal(key, rak::mem_ptr(&value_type::first))) == r_itr->second.end()) r_itr->second.push_back(&*itr); } itr->second.object.insert_key(cmd_key, object); } torrent::Object::list_type object_storage::rlookup_list(const std::string& cmd_key) { torrent::Object::list_type result; rlookup_iterator r_itr = m_rlookup.find(cmd_key); if (r_itr != m_rlookup.end()) std::transform(r_itr->second.begin(), r_itr->second.end(), std::back_inserter(result), std::tr1::bind(&key_type::c_str, std::tr1::bind(rak::mem_ptr(&value_type::first), std::tr1::placeholders::_1))); return result; } void object_storage::rlookup_clear(const std::string& cmd_key) { rlookup_iterator r_itr = m_rlookup.find(cmd_key); if (r_itr == m_rlookup.end()) return; for (rlookup_mapped_iterator first = r_itr->second.begin(), last = r_itr->second.end(); first != last; first++) (*first)->second.object.erase_key(cmd_key); r_itr->second.clear(); } } rtorrent-0.9.6/src/rpc/object_storage.h000066400000000000000000000271621257211462100201340ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // The object_storage type is responsible for storing variables, // commands, command lists and other types encoded in torrent::Object // format. #ifndef RTORRENT_RPC_OBJECT_STORAGE_H #define RTORRENT_RPC_OBJECT_STORAGE_H #include #include #include #include "rak/unordered_vector.h" #include "command.h" #include "fixed_key.h" namespace rpc { struct object_storage_node { torrent::Object object; char flags; }; typedef std::tr1::unordered_map, object_storage_node, hash_fixed_key_type> object_storage_base_type; class object_storage : private object_storage_base_type { public: // Should really change rlookup_type into a set with pair values. typedef object_storage_base_type base_type; typedef std::map > rlookup_type; using base_type::key_type; using base_type::value_type; using base_type::iterator; using base_type::const_iterator; using base_type::local_iterator; using base_type::const_local_iterator; typedef rlookup_type::iterator rlookup_iterator; typedef rlookup_type::mapped_type::iterator rlookup_mapped_iterator; using base_type::begin; using base_type::end; using base_type::size; using base_type::empty; using base_type::key_eq; using base_type::bucket; using base_type::bucket_count; using base_type::max_bucket_count; using base_type::load_factor; // Verify rlookup is static / const. using base_type::clear; using base_type::find; using base_type::erase; static const unsigned int flag_generic_type = 0x1; static const unsigned int flag_bool_type = 0x2; static const unsigned int flag_value_type = 0x3; static const unsigned int flag_string_type = 0x4; static const unsigned int flag_list_type = 0x5; static const unsigned int flag_function_type = 0x6; static const unsigned int flag_multi_type = 0x7; static const unsigned int mask_type = 0xf; static const unsigned int flag_constant = 0x10; static const unsigned int flag_static = 0x20; static const unsigned int flag_private = 0x40; static const unsigned int flag_rlookup = 0x80; static const size_t key_size = key_type::max_size; local_iterator find_local(const torrent::raw_string& key); local_iterator find_local_const(const torrent::raw_string& key, unsigned int type = 0); local_iterator find_local_mutable(const torrent::raw_string& key, unsigned int type = 0); iterator insert(const char* key_data, uint32_t key_size, const torrent::Object& object, unsigned int flags); iterator insert_c_str(const char* key, const torrent::Object& object, unsigned int flags) { return insert(key, std::strlen(key), object, flags); } iterator insert(const char* key, const torrent::Object& object, unsigned int flags); iterator insert(const torrent::raw_string& key, const torrent::Object& object, unsigned int flags); iterator insert_str(const std::string& key, const torrent::Object& object, unsigned int flags); bool has_flag(const torrent::raw_string& key, unsigned int flag); bool has_flag_str(const std::string& key, unsigned int flag) { return has_flag(torrent::raw_string::from_string(key), flag); } void enable_flag(const torrent::raw_string& key, unsigned int flag); void enable_flag_str(const std::string& key, unsigned int flag) { enable_flag(torrent::raw_string::from_string(key), flag); } // Access functions that throw on error. const torrent::Object& get(const torrent::raw_string& key); const torrent::Object& get_c_str(const char* str) { return get(torrent::raw_string(str, std::strlen(str))); } const torrent::Object& get_str(const std::string& str) { return get(torrent::raw_string(str.data(), str.size())); } const torrent::Object& set_bool(const torrent::raw_string& key, int64_t object); const torrent::Object& set_c_str_bool(const char* str, int64_t object) { return set_bool(torrent::raw_string::from_c_str(str), object); } const torrent::Object& set_str_bool(const std::string& str, int64_t object) { return set_bool(torrent::raw_string::from_string(str), object); } const torrent::Object& set_value(const torrent::raw_string& key, int64_t object); const torrent::Object& set_c_str_value(const char* str, int64_t object) { return set_value(torrent::raw_string::from_string(str), object); } const torrent::Object& set_str_value(const std::string& str, int64_t object) { return set_value(torrent::raw_string::from_string(str), object); } const torrent::Object& set_string(const torrent::raw_string& key, const std::string& object); const torrent::Object& set_c_str_string(const char* str, const std::string& object) { return set_string(torrent::raw_string::from_c_str(str), object); } const torrent::Object& set_str_string(const std::string& str, const std::string& object) { return set_string(torrent::raw_string::from_string(str), object); } const torrent::Object& set_list(const torrent::raw_string& key, const torrent::Object::list_type& object); const torrent::Object& set_c_str_list(const char* str, const torrent::Object::list_type& object) { return set_list(torrent::raw_string::from_c_str(str), object); } const torrent::Object& set_str_list(const std::string& str, const torrent::Object::list_type& object) { return set_list(torrent::raw_string::from_string(str), object); } void list_push_back(const torrent::raw_string& key, const torrent::Object& object); void list_push_back_str(const std::string& str, const torrent::Object& object) { list_push_back(torrent::raw_string::from_string(str), object); } // Functions callers: torrent::Object call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object); torrent::Object call_function_str(const std::string& key, target_type target, const torrent::Object& object); // Single-command function: const torrent::Object& set_function(const torrent::raw_string& key, const std::string& object); const torrent::Object& set_str_function(const std::string& key, const std::string& object); // Multi-command function: bool has_multi_key(const torrent::raw_string& key, const std::string& cmd_key); void erase_multi_key(const torrent::raw_string& key, const std::string& cmd_key); void set_multi_key_obj(const torrent::raw_string& key, const std::string& cmd_key, const torrent::Object& object); void set_multi_key(const torrent::raw_string& key, const std::string& cmd_key, const std::string& object) { set_multi_key_obj(key, cmd_key, object); } bool has_str_multi_key(const std::string& key, const std::string& cmd_key); void erase_str_multi_key(const std::string& key, const std::string& cmd_key); void set_str_multi_key(const std::string& key, const std::string& cmd_key, const std::string& object); void set_str_multi_key_obj(const std::string& key, const std::string& cmd_key, const torrent::Object& object); torrent::Object::list_type rlookup_list(const std::string& cmd_key); torrent::Object rlookup_obj_list(const std::string& cmd_key) { return torrent::Object::from_list(rlookup_list(cmd_key)); } void rlookup_clear(const std::string& cmd_key); private: rlookup_type m_rlookup; }; // // Implementation: // template inline void fixed_key_type::set_data(const value_type* src_data, size_type src_size) { if (src_size >= max_size) { new (this) fixed_key_type(); return; } m_size = src_size; std::memcpy(m_data, src_data, m_size); m_data[m_size] = '\0'; } template inline void fixed_key_type::set_c_str(const value_type* src_data) { value_type* itr = m_data; const value_type* last = m_data + max_size; while (itr != last && *src_data != '\0') *itr++ = *src_data++; *itr = '\0'; m_size = std::distance(m_data, itr); } template inline void fixed_key_type::set_c_str(const value_type* src_data, size_type src_size) { if (src_size >= max_size) { new (this) fixed_key_type(); return; } m_size = src_size; std::memcpy(m_data, src_data, m_size + 1); } inline object_storage::iterator object_storage::insert(const char* key, const torrent::Object& object, unsigned int flags) { return insert(key, std::strlen(key), object, flags); } inline object_storage::iterator object_storage::insert(const torrent::raw_string& key, const torrent::Object& object, unsigned int flags) { return insert(key.data(), key.size(), object, flags); } inline object_storage::iterator object_storage::insert_str(const std::string& key, const torrent::Object& object, unsigned int flags) { return insert(key.data(), key.size(), object, flags); } inline torrent::Object object_storage::call_function_str(const std::string& key, target_type target, const torrent::Object& object) { return call_function(torrent::raw_string::from_string(key), target, object); } inline const torrent::Object& object_storage::set_str_function(const std::string& key, const std::string& object) { return set_function(torrent::raw_string::from_string(key), object); } inline bool object_storage::has_str_multi_key(const std::string& key, const std::string& cmd_key) { return has_multi_key(torrent::raw_string::from_string(key), cmd_key); } inline void object_storage::erase_str_multi_key(const std::string& key, const std::string& cmd_key) { erase_multi_key(torrent::raw_string::from_string(key), cmd_key); } inline void object_storage::set_str_multi_key(const std::string& key, const std::string& cmd_key, const std::string& object) { return set_multi_key_obj(torrent::raw_string::from_string(key), cmd_key, object); } inline void object_storage::set_str_multi_key_obj(const std::string& key, const std::string& cmd_key, const torrent::Object& object) { return set_multi_key_obj(torrent::raw_string::from_string(key), cmd_key, object); } } #endif rtorrent-0.9.6/src/rpc/parse.cc000066400000000000000000000342331257211462100164070ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "parse.h" namespace rpc { const char* parse_skip_wspace(const char* first, const char* last) { while (first != last && parse_is_space(*first)) first++; return first; } const char* parse_skip_wspace(const char* first) { while (parse_is_space(*first)) first++; return first; } const char* parse_string(const char* first, const char* last, std::string* dest, bool (*delim)(const char)) { if (first == last) return first; if (parse_is_quote(*first)) { first++; while (first != last) { if (parse_is_quote(*first)) return ++first; if (parse_is_escape(*first) && ++first == last) throw torrent::input_error("Escape character at end of input."); dest->push_back(*first++); } throw torrent::input_error("Missing closing quote."); } else { while (first != last) { if (delim(*first)) return first; if (parse_is_escape(*first) && ++first == last) throw torrent::input_error("Escape character at end of input."); dest->push_back(*first++); } return first; } } void parse_whole_string(const char* first, const char* last, std::string* dest) { first = parse_skip_wspace(first, last); first = parse_string(first, last, dest); first = parse_skip_wspace(first, last); if (first != last) throw torrent::input_error("Junk at end of input."); } const char* parse_value(const char* src, int64_t* value, int base, int unit) { const char* last = parse_value_nothrow(src, value, base, unit); if (last == src) throw torrent::input_error("Could not convert string to value."); return last; } void parse_whole_value(const char* src, int64_t* value, int base, int unit) { const char* last = parse_value_nothrow(src, value, base, unit); if (last == src || *parse_skip_wspace(last) != '\0') throw torrent::input_error("Could not convert string to value."); } bool parse_whole_value_nothrow(const char* src, int64_t* value, int base, int unit) { const char* last = parse_value_nothrow(src, value, base, unit); if (last == src || *parse_skip_wspace(last) != '\0') return false; return true; } const char* parse_value_nothrow(const char* src, int64_t* value, int base, int unit) { if (unit <= 0) throw torrent::input_error("Command::string_to_value_unit(...) received unit <= 0."); char* last; *value = strtoll(src, &last, base); if (last == src) { if (strcasecmp(src, "no") == 0) { *value = 0; return src + strlen("no"); } if (strcasecmp(src, "yes") == 0) { *value = 1; return src + strlen("yes"); } if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); } if (strcasecmp(src, "false") == 0) { *value = 0; return src + strlen("false"); } return src; } switch (*last) { case 'b': case 'B': ++last; break; case 'k': case 'K': *value = *value << 10; ++last; break; case 'm': case 'M': *value = *value << 20; ++last; break; case 'g': case 'G': *value = *value << 30; ++last; break; // case ' ': // case '\0': *value = *value * unit; break; // default: throw torrent::input_error("Could not parse value."); default: *value = *value * unit; break; } return last; } // Somewhat ugly... const char* parse_object(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) { if (*first == '{') { *dest = torrent::Object::create_list(); first = parse_list(first + 1, last, dest, &parse_is_delim_block); first = parse_skip_wspace(first, last); if (first == last || *first != '}') throw torrent::input_error("Could not find closing '}'."); return ++first; } else if (*first == '(') { int32_t depth = 1; while (first + 1 != last && *(first + 1) == '(') { first++; depth++; } if (depth > 3) throw torrent::input_error("Max 3 parantheses per object allowed."); *dest = torrent::Object::create_dict_key(); dest->set_flags(torrent::Object::flag_function << (depth - 1)); first = parse_string(first + 1, last, &dest->as_dict_key(), &parse_is_delim_func); first = parse_skip_wspace(first, last); if (first == last || !parse_is_delim_func(*first)) throw torrent::input_error("Could not find closing ')'."); if (*first == ',') { // This will always create a list even for single argument functions... dest->as_dict_obj() = torrent::Object::create_list(); first = parse_list(first + 1, last, &dest->as_dict_obj(), &parse_is_delim_func); first = parse_skip_wspace(first, last); } while (depth != 0 && first != last && *first == ')') { first++; depth--; } if (depth != 0) throw torrent::input_error("Parantheses mismatch."); return first; } else { *dest = std::string(); return parse_string(first, last, &dest->as_string(), delim); } } const char* parse_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) { if (!dest->is_list()) throw torrent::internal_error("parse_list(...) !dest->is_list()."); while (true) { torrent::Object tmp; first = parse_skip_wspace(first, last); first = parse_object(first, last, &tmp, delim); first = parse_skip_wspace(first, last); dest->as_list().push_back(tmp); if (first == last || !parse_is_seperator(*first)) break; first++; } return first; } const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) { first = parse_skip_wspace(first, last); first = parse_object(first, last, dest, delim); first = parse_skip_wspace(first, last); if (first != last && parse_is_seperator(*first)) { torrent::Object tmp = torrent::Object::create_list(); tmp.swap(*dest); dest->as_list().push_back(tmp); first = parse_list(++first, last, dest, delim); } return first; } std::string convert_to_string(const torrent::Object& rawSrc) { const torrent::Object& src = convert_to_single_argument(rawSrc); switch (src.type()) { case torrent::Object::TYPE_VALUE: { char buffer[64]; snprintf(buffer, 64, "%lli", (long long int)src.as_value()); return std::string(buffer); } case torrent::Object::TYPE_STRING: return src.as_string(); case torrent::Object::TYPE_NONE: return std::string(); case torrent::Object::TYPE_RAW_BENCODE: if (src.as_raw_bencode().is_empty()) return std::string(); if (src.as_raw_bencode().is_raw_string()) return src.as_raw_bencode().as_raw_string().as_string(); if (src.as_raw_bencode().is_value()) return src.as_raw_bencode().as_value_string(); default: throw torrent::input_error("Not a string."); } } std::string convert_list_to_string(const torrent::Object& src) { if (!src.is_list()) throw torrent::internal_error("convert_list_to_string(...) !src->is_list()."); return convert_list_to_string(src.as_list().begin(), src.as_list().end()); } std::string convert_list_to_string(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) { std::string dest; while (first != last) { if (!first->is_string()) throw torrent::input_error("Could not convert non-string list element to string."); // Meh. if (!dest.empty()) dest += ",\""; else dest += '"'; std::string::size_type quoteItr = dest.size(); dest += first->as_string(); // Finding a quote inside the string should be relatively rare, so // use something that is fast in the general case and ignore the // cost of the unusual one. while (quoteItr != dest.size()) { if (dest[quoteItr] == '"' || dest[quoteItr] == '\\') dest.insert(quoteItr++, 1, '\\'); quoteItr++; } dest += '"'; first++; } return dest; } std::string convert_list_to_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) { if (first == last) throw torrent::input_error("Too few arguments."); std::string dest = (first++)->as_string(); std::string::size_type quoteItr = dest.find('='); if (quoteItr == std::string::npos) throw torrent::input_error("Could not find '=' in command."); // We should only escape backslash, not quote here as the string // will start with the command name which isn't quoted. while ((quoteItr = dest.find('\\', quoteItr + 1)) != std::string::npos) dest.insert(quoteItr++, 1, '\\'); while (first != last) { if (!first->is_string()) throw torrent::input_error("Could not convert non-string list element to string."); dest += ",\""; std::string::size_type quoteItr = dest.size(); dest += first->as_string(); // Finding a quote inside the string should be relatively rare, so // use something that is fast in the general case and ignore the // cost of the unusual one. while (quoteItr != dest.size()) { if (dest[quoteItr] == '"' || dest[quoteItr] == '\\') dest.insert(quoteItr++, 1, '\\'); quoteItr++; } dest += '"'; first++; } return dest; } int64_t convert_to_value(const torrent::Object& src, int base, int unit) { int64_t value; if (!convert_to_value_nothrow(src, &value, base, unit)) throw torrent::input_error("Not convertible to a value."); return value; } bool convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, int unit) { const torrent::Object& unpacked = (src.is_list() && src.as_list().size() == 1) ? src.as_list().front() : src; switch (unpacked.type()) { case torrent::Object::TYPE_VALUE: *value = unpacked.as_value(); break; case torrent::Object::TYPE_STRING: return parse_skip_wspace(parse_value(unpacked.as_string().c_str(), value, base, unit), unpacked.as_string().c_str() + unpacked.as_string().size()) == unpacked.as_string().c_str() + unpacked.as_string().size(); case torrent::Object::TYPE_RAW_STRING: { const torrent::raw_string& str = src.as_raw_string(); char buffer[str.size() + 1]; std::memcpy(buffer, str.data(), str.size()); buffer[str.size()] = '\0'; return parse_skip_wspace(parse_value(buffer, value, base, unit), buffer + str.size()) == buffer + str.size(); } case torrent::Object::TYPE_NONE: *value = 0; break; default: return false; } return true; } char* print_object(char* first, char* last, const torrent::Object* src, int flags) { switch (src->type()) { case torrent::Object::TYPE_STRING: { const std::string& str = src->as_string(); if ((flags & print_expand_tilde) && *str.c_str() == '~') { return rak::path_expand(str.c_str(), first, last); } else { if (first == last) return first; size_t n = std::min(str.size(), std::distance(first, last) - 1); std::memcpy(first, str.c_str(), n); *(first += n) = '\0'; return first; } } case torrent::Object::TYPE_VALUE: return std::min(first + snprintf(first, std::distance(first, last), "%lli", (long long int)src->as_value()), last); case torrent::Object::TYPE_LIST: if (first != last) *first = '\0'; for (torrent::Object::list_const_iterator itr = src->as_list().begin(), itrEnd = src->as_list().end(); itr != itrEnd; itr++) { first = print_object(first, last, &*itr, flags); // Don't expand tilde after the first element in the list. flags &= ~print_expand_tilde; } return first; case torrent::Object::TYPE_NONE: if (first != last) *first = '\0'; return first; default: throw torrent::input_error("Invalid type."); } } void print_object_std(std::string* dest, const torrent::Object* src, int flags) { switch (src->type()) { case torrent::Object::TYPE_STRING: { const std::string& str = src->as_string(); if ((flags & print_expand_tilde) && *str.c_str() == '~') *dest += rak::path_expand(str); else *dest += str; return; } case torrent::Object::TYPE_VALUE: { char buffer[64]; snprintf(buffer, 64, "%lli", (long long int)src->as_value()); *dest += buffer; return; } case torrent::Object::TYPE_LIST: for (torrent::Object::list_const_iterator itr = src->as_list().begin(), itrEnd = src->as_list().end(); itr != itrEnd; itr++) { print_object_std(dest, &*itr, flags); // Don't expand tilde after the first element in the list. flags &= ~print_expand_tilde; } return; case torrent::Object::TYPE_NONE: return; default: throw torrent::input_error("Invalid type."); } } } rtorrent-0.9.6/src/rpc/parse.h000066400000000000000000000124751257211462100162550ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_PARSE_H #define RTORRENT_RPC_PARSE_H #include #include #include namespace rpc { // parse_* functions do the bare minimum necessary to parse what was // asked for. If a whitespace is found, it will be treated as empty // input rather than skipped. // // parse_whole_* functions allow for whitespaces and throw an // exception if there is any garbage at the end of the input. inline bool parse_is_quote(const char c) { return c == '"'; } inline bool parse_is_escape(const char c) { return c == '\\'; } inline bool parse_is_seperator(const char c) { return c == ','; } inline bool parse_is_space(const char c) { return c == ' ' || c == '\t'; } // The block delim is used in {} blocks to contain code. Since it // doesn't check for isspace, it will include useless characters but // that is the price for sane syntax. inline bool parse_is_delim_default(const char c) { return parse_is_seperator(c) || std::isspace(c); } inline bool parse_is_delim_list(const char c) { return parse_is_seperator(c) || c == '}' || std::isspace(c); } inline bool parse_is_delim_command(const char c) { return parse_is_seperator(c) || c == ';' || std::isspace(c); } // inline bool parse_is_delim_block(const char c) { return c == ';' || c == '}'; } inline bool parse_is_delim_block(const char c) { return parse_is_seperator(c) || c == '}'; } inline bool parse_is_delim_func(const char c) { return parse_is_seperator(c) || c == ')'; } const char* parse_skip_wspace(const char* first); const char* parse_skip_wspace(const char* first, const char* last); const char* parse_string(const char* first, const char* last, std::string* dest, bool (*delim)(const char) = &parse_is_delim_default); void parse_whole_string(const char* first, const char* last, std::string* dest); const char* parse_value(const char* src, int64_t* value, int base = 0, int unit = 1); const char* parse_value_nothrow(const char* src, int64_t* value, int base = 0, int unit = 1); const char* parse_value_nothrow(const char* first, const char* last, int64_t* value, int base = 0, int unit = 0); void parse_whole_value(const char* src, int64_t* value, int base = 0, int unit = 1); bool parse_whole_value_nothrow(const char* src, int64_t* value, int base = 0, int unit = 1); const char* parse_object (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default); const char* parse_list (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default); const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default); std::string convert_to_string(const torrent::Object& src); std::string convert_list_to_string(const torrent::Object& src); std::string convert_list_to_string(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last); std::string convert_list_to_command(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last); int64_t convert_to_value(const torrent::Object& src, int base = 0, int unit = 1); bool convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base = 0, int unit = 1); inline const torrent::Object& convert_to_single_argument(const torrent::Object& args) { if (args.type() == torrent::Object::TYPE_LIST && args.as_list().size() == 1) return args.as_list().front(); else return args; } static const int print_expand_tilde = 0x1; char* print_object(char* first, char* last, const torrent::Object* src, int flags); void print_object_std(std::string* dest, const torrent::Object* src, int flags); } #endif rtorrent-0.9.6/src/rpc/parse_commands.cc000066400000000000000000000234121257211462100202650ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "parse.h" #include "parse_commands.h" namespace rpc { CommandMap commands; XmlRpc xmlrpc; ExecFile execFile; struct command_map_is_space : std::unary_function { bool operator () (char c) const { return c == ' ' || c == '\t'; } }; struct command_map_is_newline : std::unary_function { bool operator () (char c) const { return c == '\n' || c == '\0' || c == ';'; } }; // Only escape eol on odd number of escape characters. We know that // there can't be any characters in between, so this should work for // all cases. int parse_count_escaped(const char* first, const char* last) { int escaped = 0; while (last != first && *--last == '\\') escaped++; return escaped; } // Replace any strings starting with '$' with the result of the // result of the command. // // Find a better name. void parse_command_execute(target_type target, torrent::Object* object) { if (object->is_list()) { // For now, until we can flag the lists we want executed and those // we can't, disable recursion completely. for (torrent::Object::list_iterator itr = object->as_list().begin(), last = object->as_list().end(); itr != last; itr++) { if (itr->is_list()) continue; parse_command_execute(target, &*itr); } } else if (object->is_dict_key()) { parse_command_execute(target, &object->as_dict_obj()); if (object->flags() & torrent::Object::flag_function) { *object = rpc::commands.call_command(object->as_dict_key().c_str(), object->as_dict_obj(), target); } else { uint32_t flags = object->flags() & torrent::Object::mask_function; object->unset_flags(torrent::Object::mask_function); object->set_flags((flags >> 1) & torrent::Object::mask_function); } } else if (object->is_string() && *object->as_string().c_str() == '$') { const std::string& str = object->as_string(); *object = parse_command(target, str.c_str() + 1, str.c_str() + str.size()).first; } } // Use a static length buffer for dest. inline const char* parse_command_name(const char* first, const char* last, char* dest_first, char* dest_last) { if (first == last || !std::isalpha(*first)) throw torrent::input_error("Invalid start of command name."); last = first + std::min(std::distance(first, last), std::distance(dest_first, dest_last) - 1); while (first != last && (std::isalnum(*first) || *first == '_' || *first == '.')) *dest_first++ = *first++; *dest_first = '\0'; return first; } // Set 'download' to NULL to call the generic functions, thus reusing // the code below for both cases. parse_command_type parse_command(target_type target, const char* first, const char* last) { first = std::find_if(first, last, std::not1(command_map_is_space())); if (first == last || *first == '#') return std::make_pair(torrent::Object(), first); char key[128]; first = parse_command_name(first, last, key, key + 128); first = std::find_if(first, last, std::not1(command_map_is_space())); if (first == last || *first != '=') throw torrent::input_error("Could not find '='."); torrent::Object args; first = parse_whole_list(first + 1, last, &args, &parse_is_delim_command); // Find the last character that is part of this command, skipping // the whitespace at the end. This ensures us that the caller // doesn't need to do this nor check for junk at the end. first = std::find_if(first, last, std::not1(command_map_is_space())); if (first != last) { if (*first != '\n' && *first != ';' && *first != '\0') throw torrent::input_error("Junk at end of input."); first++; } // Replace any strings starting with '$' with the result of the // following command. parse_command_execute(target, &args); return std::make_pair(commands.call_command(key, args, target), first); } torrent::Object parse_command_multiple(target_type target, const char* first, const char* last) { parse_command_type result; while (first != last) { // Should we check the return value? Probably not necessary as // parse_args throws on unquoted multi-word input. result = parse_command(target, first, last); first = result.second; } return result.first; } bool parse_command_file(const std::string& path) { std::fstream file(rak::path_expand(path).c_str(), std::ios::in); if (!file.is_open()) return false; unsigned int lineNumber = 0; char buffer[4096]; try { unsigned int getCount = 0; while (file.good() && !file.getline(buffer + getCount, 4096 - getCount).fail()) { if (file.gcount() == 0) throw torrent::internal_error("parse_command_file(...) file.gcount() == 0."); int lineLength = file.gcount() - 1; // In case we are at the end of the file and the last character is // not a line feed, we'll just increase the read character count so // that the last would also be included in option line. if (file.eof() && file.get() != '\n') lineLength++; int escaped = parse_count_escaped(buffer + getCount, buffer + getCount + lineLength); lineNumber++; getCount += lineLength; if (getCount == 4096 - 1) throw torrent::input_error("Exceeded max line length."); if (escaped & 0x1) { // Remove the escape characters and continue reading. getCount -= escaped; continue; } // Would be nice to make this zero-copy. parse_command(make_target(), buffer, buffer + getCount); getCount = 0; } } catch (torrent::input_error& e) { snprintf(buffer, 2048, "Error in option file: %s:%u: %s", path.c_str(), lineNumber, e.what()); throw torrent::input_error(buffer); } return true; } torrent::Object call_object(const torrent::Object& command, target_type target) { switch (command.type()) { case torrent::Object::TYPE_RAW_STRING: return parse_command_multiple(target, command.as_raw_string().begin(), command.as_raw_string().end()); case torrent::Object::TYPE_STRING: return parse_command_multiple(target, command.as_string().c_str(), command.as_string().c_str() + command.as_string().size()); case torrent::Object::TYPE_LIST: { torrent::Object result; for (torrent::Object::list_const_iterator itr = command.as_list().begin(), last = command.as_list().end(); itr != last; itr++) result = call_object(*itr, target); return result; } case torrent::Object::TYPE_MAP: { for (torrent::Object::map_const_iterator itr = command.as_map().begin(), last = command.as_map().end(); itr != last; itr++) call_object(itr->second, target); return torrent::Object(); } case torrent::Object::TYPE_DICT_KEY: { // This can/should be optimized... torrent::Object tmp_command = command; // Unquote the root function object so 'parse_command_execute' // doesn't end up calling it. // // TODO: Only call this if mask_function is set? uint32_t flags = tmp_command.flags() & torrent::Object::mask_function; tmp_command.unset_flags(torrent::Object::mask_function); tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function); parse_command_execute(target, &tmp_command); return commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(), target); } default: return torrent::Object(); } } // // // const torrent::Object command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args) { rpc::command_base::stack_type stack; torrent::Object* last_stack; if (args.is_list()) last_stack = rpc::command_base::push_stack(args.as_list(), &stack); else if (args.type() != torrent::Object::TYPE_NONE) last_stack = rpc::command_base::push_stack(&args, &args + 1, &stack); else last_stack = rpc::command_base::push_stack(NULL, NULL, &stack); try { torrent::Object result = call_object(cmd, target); rpc::command_base::pop_stack(&stack, last_stack); return result; } catch (torrent::bencode_error& e) { rpc::command_base::pop_stack(&stack, last_stack); throw e; } } } rtorrent-0.9.6/src/rpc/parse_commands.h000066400000000000000000000140541257211462100201310ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_PARSE_COMMANDS_H #define RTORRENT_RPC_PARSE_COMMANDS_H #include #include #include "command_map.h" #include "exec_file.h" #include "xmlrpc.h" namespace core { class Download; } namespace rpc { // Move to another file? extern CommandMap commands; extern XmlRpc xmlrpc; extern ExecFile execFile; typedef std::pair parse_command_type; // The generic parse command function, used by the rest. At some point // the 'download' parameter should be replaced by a more generic one. parse_command_type parse_command(target_type target, const char* first, const char* last); torrent::Object parse_command_multiple(target_type target, const char* first, const char* last); void parse_command_execute(target_type target, torrent::Object* object); inline torrent::Object parse_command_single(target_type target, const char* first) { return parse_command(target, first, first + std::strlen(first)).first; } inline torrent::Object parse_command_multiple(target_type target, const char* first) { return parse_command_multiple(target, first, first + std::strlen(first)); } bool parse_command_file(const std::string& path); const char* parse_command_name(const char* first, const char* last, std::string* dest); inline torrent::Object parse_command_single(target_type target, const std::string& cmd) { return parse_command(target, cmd.c_str(), cmd.c_str() + cmd.size()).first; } inline torrent::Object parse_command_multiple_std(const std::string& cmd, target_type target = rpc::make_target()) { return parse_command_multiple(target, cmd.c_str(), cmd.c_str() + cmd.size()); } inline void parse_command_single_std(const std::string& cmd) { parse_command(make_target(), cmd.c_str(), cmd.c_str() + cmd.size()); } inline torrent::Object parse_command_multiple_d_nothrow(core::Download* download, const std::string& cmd) { try { return parse_command_multiple(make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()); } catch (torrent::input_error& e) { // Log? return torrent::Object(); } } inline torrent::Object call_command (const char* key, const torrent::Object& obj = torrent::Object(), target_type target = make_target()) { return commands.call_command(key, obj, target); } inline std::string call_command_string(const char* key, target_type target = make_target()) { return commands.call_command(key, torrent::Object(), target).as_string(); } inline int64_t call_command_value (const char* key, target_type target = make_target()) { return commands.call_command(key, torrent::Object(), target).as_value(); } inline void call_command_set_string(const char* key, const std::string& arg) { commands.call_command(key, torrent::Object(arg)); } inline void call_command_set_std_string(const std::string& key, const std::string& arg) { commands.call_command(key.c_str(), torrent::Object(arg)); } inline void call_command_set_value(const char* key, int64_t arg, target_type target = make_target()) { commands.call_command(key, torrent::Object(arg), target); } inline torrent::Object call_command_d_range(const char* key, core::Download* download, torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last) { // Change to using range ctor. torrent::Object rawArgs = torrent::Object::create_list(); torrent::Object::list_type& args = rawArgs.as_list(); while (first != last) args.push_back(*first++); return commands.call_command_d(key, download, rawArgs); } torrent::Object call_object(const torrent::Object& command, target_type target = make_target()); inline torrent::Object call_object_nothrow(const torrent::Object& command, target_type target = make_target()) { try { return call_object(command, target); } catch (torrent::input_error& e) { return torrent::Object(); } } inline torrent::Object call_object_d_nothrow(const torrent::Object& command, core::Download* download) { try { return call_object(command, make_target(download)); } catch (torrent::input_error& e) { return torrent::Object(); } } // // // const torrent::Object command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args); inline const torrent::Object command_function_call_str(const std::string& cmd, target_type target, const torrent::Object& args) { return command_function_call_object(torrent::Object(cmd), target, args); } } #endif rtorrent-0.9.6/src/rpc/scgi.cc000066400000000000000000000120541257211462100162170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include "utils/socket_fd.h" #include "control.h" #include "globals.h" #include "scgi.h" #include "parse_commands.h" namespace rpc { SCgi::~SCgi() { if (!get_fd().is_valid()) return; for (SCgiTask* itr = m_task, *last = m_task + max_tasks; itr != last; ++itr) if (itr->is_open()) itr->close(); deactivate(); torrent::connection_manager()->dec_socket_count(); get_fd().close(); get_fd().clear(); if (!m_path.empty()) ::unlink(m_path.c_str()); } void SCgi::open_port(void* sa, unsigned int length, bool dontRoute) { if (!get_fd().open_stream() || (dontRoute && !get_fd().set_dont_route(true))) throw torrent::resource_error("Could not open socket for listening: " + std::string(rak::error_number::current().c_str())); open(sa, length); } void SCgi::open_named(const std::string& filename) { if (filename.empty() || filename.size() > 4096) throw torrent::resource_error("Invalid filename length."); char buffer[sizeof(sockaddr_un) + filename.size()]; sockaddr_un* sa = reinterpret_cast(buffer); #ifdef __sun__ sa->sun_family = AF_UNIX; #else sa->sun_family = AF_LOCAL; #endif std::memcpy(sa->sun_path, filename.c_str(), filename.size() + 1); if (!get_fd().open_local()) throw torrent::resource_error("Could not open socket for listening."); open(sa, offsetof(struct sockaddr_un, sun_path) + filename.size() + 1); m_path = filename; } void SCgi::open(void* sa, unsigned int length) { try { if (!get_fd().set_nonblock() || !get_fd().set_reuse_address(true) || !get_fd().bind(*reinterpret_cast(sa), length) || !get_fd().listen(max_tasks)) throw torrent::resource_error("Could not prepare socket for listening: " + std::string(rak::error_number::current().c_str())); torrent::connection_manager()->inc_socket_count(); } catch (torrent::resource_error& e) { get_fd().close(); get_fd().clear(); throw e; } } void SCgi::activate() { worker_thread->poll()->open(this); worker_thread->poll()->insert_read(this); worker_thread->poll()->insert_error(this); } void SCgi::deactivate() { worker_thread->poll()->remove_read(this); worker_thread->poll()->remove_error(this); worker_thread->poll()->close(this); } void SCgi::event_read() { rak::socket_address sa; utils::SocketFd fd; while ((fd = get_fd().accept(&sa)).is_valid()) { SCgiTask* task = std::find_if(m_task, m_task + max_tasks, std::mem_fun_ref(&SCgiTask::is_available)); if (task == m_task + max_tasks) { // Ergh... just closing for now. fd.close(); continue; } task->open(this, fd.get_fd()); } } void SCgi::event_write() { throw torrent::internal_error("Listener does not support write()."); } void SCgi::event_error() { throw torrent::internal_error("SCGI listener port received an error event."); } bool SCgi::receive_call(SCgiTask* task, const char* buffer, uint32_t length) { slot_write slotWrite; slotWrite.set(rak::mem_fn(task, &SCgiTask::receive_write)); torrent::thread_base::acquire_global_lock(); torrent::main_thread()->interrupt(); bool result = xmlrpc.process(buffer, length, slotWrite); torrent::thread_base::release_global_lock(); return result; } } rtorrent-0.9.6/src/rpc/scgi.h000066400000000000000000000057771257211462100160770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_SCGI_H #define RTORRENT_RPC_SCGI_H #include #include #include #include "scgi_task.h" namespace utils { class SocketFd; } namespace rpc { class lt_cacheline_aligned SCgi : public torrent::Event { public: typedef rak::function2 slot_write; static const int max_tasks = 100; // Global lock: SCgi() : m_logFd(-1) {} virtual ~SCgi(); const char* type_name() const { return "scgi"; } void open_port(void* sa, unsigned int length, bool dontRoute); void open_named(const std::string& filename); void activate(); void deactivate(); const std::string& path() const { return m_path; } int log_fd() const { return m_logFd; } void set_log_fd(int fd) { m_logFd = fd; } // Thread local: virtual void event_read(); virtual void event_write(); virtual void event_error(); bool receive_call(SCgiTask* task, const char* buffer, uint32_t length); utils::SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } private: void open(void* sa, unsigned int length); std::string m_path; int m_logFd; SCgiTask m_task[max_tasks]; }; } #endif rtorrent-0.9.6/src/rpc/scgi_task.cc000066400000000000000000000167021257211462100172450ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include "utils/socket_fd.h" #include "control.h" #include "globals.h" #include "scgi.h" // Test: // #include "core/manager.h" // #include // static rak::timer scgiTimer; namespace rpc { // If bufferSize is zero then memcpy won't do anything. inline void SCgiTask::realloc_buffer(uint32_t size, const char* buffer, uint32_t bufferSize) { char* tmp = rak::cacheline_allocator::alloc_size(size); std::memcpy(tmp, buffer, bufferSize); ::free(m_buffer); m_buffer = tmp; } void SCgiTask::open(SCgi* parent, int fd) { m_parent = parent; m_fileDesc = fd; m_buffer = rak::cacheline_allocator::alloc_size((m_bufferSize = default_buffer_size) + 1); m_position = m_buffer; m_body = NULL; worker_thread->poll()->open(this); worker_thread->poll()->insert_read(this); worker_thread->poll()->insert_error(this); // scgiTimer = rak::timer::current(); } void SCgiTask::close() { if (!get_fd().is_valid()) return; worker_thread->poll()->remove_read(this); worker_thread->poll()->remove_write(this); worker_thread->poll()->remove_error(this); worker_thread->poll()->close(this); get_fd().close(); get_fd().clear(); ::free(m_buffer); m_buffer = NULL; // Test // char buffer[512]; // sprintf(buffer, "SCgi system call processed: %i", (int)(rak::timer::current() - scgiTimer).usec()); // control->core()->push_log(std::string(buffer)); } void SCgiTask::event_read() { int bytes = ::recv(m_fileDesc, m_position, m_bufferSize - (m_position - m_buffer), 0); if (bytes <= 0) { if (bytes == 0 || !rak::error_number::current().is_blocked_momentary()) close(); return; } // The buffer has space to nul-terminate to ease the parsing below. m_position += bytes; *m_position = '\0'; if (m_body == NULL) { // Don't bother caching the parsed values, as we're likely to // receive all the data we need the first time. char* current; int contentSize; int headerSize = strtol(m_buffer, ¤t, 0); if (current == m_position) return; // If the request doesn't start with an integer or if it didn't // end in ':', then close the connection. if (current == m_buffer || *current != ':' || headerSize < 17 || headerSize > max_header_size) goto event_read_failed; if (std::distance(++current, m_position) < headerSize + 1) return; if (std::memcmp(current, "CONTENT_LENGTH", 15) != 0) goto event_read_failed; char* contentPos; contentSize = strtol(current + 15, &contentPos, 0); if (*contentPos != '\0' || contentSize <= 0 || contentSize > max_content_size) goto event_read_failed; m_body = current + headerSize + 1; headerSize = std::distance(m_buffer, m_body); if ((unsigned int)(contentSize + headerSize) < m_bufferSize) { m_bufferSize = contentSize + headerSize; } else if ((unsigned int)contentSize <= default_buffer_size) { m_bufferSize = contentSize; std::memmove(m_buffer, m_body, std::distance(m_body, m_position)); m_position = m_buffer + std::distance(m_body, m_position); m_body = m_buffer; } else { realloc_buffer((m_bufferSize = contentSize) + 1, m_body, std::distance(m_body, m_position)); m_position = m_buffer + std::distance(m_body, m_position); m_body = m_buffer; } } if ((unsigned int)std::distance(m_buffer, m_position) != m_bufferSize) return; worker_thread->poll()->remove_read(this); worker_thread->poll()->insert_write(this); if (m_parent->log_fd() >= 0) { int __UNUSED result; // Clean up logging, this is just plain ugly... // write(m_logFd, "\n---\n", sizeof("\n---\n")); result = write(m_parent->log_fd(), m_buffer, m_bufferSize); result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n")); } lt_log_print_dump(torrent::LOG_RPC_DUMP, m_body, m_bufferSize - std::distance(m_buffer, m_body), "scgi", "RPC read.", 0); // Close if the call failed, else stay open to write back data. if (!m_parent->receive_call(this, m_body, m_bufferSize - std::distance(m_buffer, m_body))) close(); return; event_read_failed: // throw torrent::internal_error("SCgiTask::event_read() fault not handled."); close(); } void SCgiTask::event_write() { int bytes = ::send(m_fileDesc, m_position, m_bufferSize, 0); if (bytes == -1) { if (!rak::error_number::current().is_blocked_momentary()) close(); return; } m_position += bytes; m_bufferSize -= bytes; if (bytes == 0 || m_bufferSize == 0) return close(); } void SCgiTask::event_error() { close(); } bool SCgiTask::receive_write(const char* buffer, uint32_t length) { if (buffer == NULL || length > (100 << 20)) throw torrent::internal_error("SCgiTask::receive_write(...) received bad input."); // Need to cast due to a bug in MacOSX gcc-4.0.1. if (length + 256 > std::max(m_bufferSize, (unsigned int)default_buffer_size)) realloc_buffer(length + 256, NULL, 0); // Who ever bothers to check the return value? int headerSize = sprintf(m_buffer, "Status: 200 OK\r\nContent-Type: text/xml\r\nContent-Length: %i\r\n\r\n", length); m_position = m_buffer; m_bufferSize = length + headerSize; std::memcpy(m_buffer + headerSize, buffer, length); if (m_parent->log_fd() >= 0) { int __UNUSED result; // Clean up logging, this is just plain ugly... // write(m_logFd, "\n---\n", sizeof("\n---\n")); result = write(m_parent->log_fd(), m_buffer, m_bufferSize); result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n")); } lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer, m_bufferSize, "scgi", "RPC write.", 0); event_write(); return true; } } rtorrent-0.9.6/src/rpc/scgi_task.h000066400000000000000000000054711257211462100171100ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_SCGI_TASK_H #define RTORRENT_RPC_SCGI_TASK_H #include namespace utils { class SocketFd; } namespace rpc { class SCgi; class SCgiTask : public torrent::Event { public: static const unsigned int default_buffer_size = 2047; static const int max_header_size = 2000; static const int max_content_size = (2 << 20); SCgiTask() { m_fileDesc = -1; } bool is_open() const { return m_fileDesc != -1; } bool is_available() const { return m_fileDesc == -1; } void open(SCgi* parent, int fd); void close(); virtual void event_read(); virtual void event_write(); virtual void event_error(); bool receive_write(const char* buffer, uint32_t length); utils::SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } private: inline void realloc_buffer(uint32_t size, const char* buffer, uint32_t bufferSize); SCgi* m_parent; char* m_buffer; char* m_position; char* m_body; unsigned int m_bufferSize; }; } #endif rtorrent-0.9.6/src/rpc/xmlrpc.cc000066400000000000000000000431531257211462100166030ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #ifdef HAVE_XMLRPC_C #include #include #endif #include #include #include #include #include "xmlrpc.h" #include "parse_commands.h" namespace rpc { #ifdef HAVE_XMLRPC_C class xmlrpc_error : public torrent::base_error { public: xmlrpc_error(xmlrpc_env* env) : m_type(env->fault_code), m_msg(env->fault_string) {} xmlrpc_error(int type, const char* msg) : m_type(type), m_msg(msg) {} virtual ~xmlrpc_error() throw() {} virtual int type() const throw() { return m_type; } virtual const char* what() const throw() { return m_msg; } private: int m_type; const char* m_msg; }; torrent::Object xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType = 0, rpc::target_type* target = NULL); inline torrent::Object xmlrpc_list_entry_to_object(xmlrpc_env* env, xmlrpc_value* src, int index) { xmlrpc_value* tmp; xmlrpc_array_read_item(env, src, index, &tmp); if (env->fault_occurred) throw xmlrpc_error(env); torrent::Object obj = xmlrpc_to_object(env, tmp); xmlrpc_DECREF(tmp); return obj; } int64_t xmlrpc_list_entry_to_value(xmlrpc_env* env, xmlrpc_value* src, int index) { xmlrpc_value* tmp; xmlrpc_array_read_item(env, src, index, &tmp); if (env->fault_occurred) throw xmlrpc_error(env); switch (xmlrpc_value_type(tmp)) { case XMLRPC_TYPE_INT: int v; xmlrpc_read_int(env, tmp, &v); xmlrpc_DECREF(tmp); return v; #ifdef XMLRPC_HAVE_I8 case XMLRPC_TYPE_I8: xmlrpc_int64 v2; xmlrpc_read_i8(env, tmp, &v2); xmlrpc_DECREF(tmp); return v2; #endif case XMLRPC_TYPE_STRING: { const char* str; xmlrpc_read_string(env, tmp, &str); if (env->fault_occurred) throw xmlrpc_error(env); const char* end = str; int64_t v3 = ::strtoll(str, (char**)&end, 0); ::free((void*)str); if (*str == '\0' || *end != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); return v3; } default: xmlrpc_DECREF(tmp); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid type found."); } } // Consider making a helper function that creates a target_type from a // torrent::Object, then we can just use xmlrpc_to_object. rpc::target_type xmlrpc_to_target(xmlrpc_env* env, xmlrpc_value* value) { rpc::target_type target; switch (xmlrpc_value_type(value)) { case XMLRPC_TYPE_STRING: { const char* str; xmlrpc_read_string(env, value, &str); if (env->fault_occurred) throw xmlrpc_error(env); if (std::strlen(str) == 0) { // When specifying void, we require a zero-length string. ::free((void*)str); return rpc::make_target(); } else if (std::strlen(str) < 40) { ::free((void*)str); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Unsupported target type found."); } core::Download* download = xmlrpc.slot_find_download()(str); if (download == NULL) { ::free((void*)str); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Could not find info-hash."); } if (std::strlen(str) == 40) { ::free((void*)str); return rpc::make_target(download); } if (std::strlen(str) < 42 || str[40] != ':') { ::free((void*)str); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Unsupported target type found."); } // Files: ":f" // Trackers: ":t" int index; const char* end_ptr = str + 42; switch (str[41]) { case 'f': index = ::strtol(str + 42, (char**)&end_ptr, 0); if (*str == '\0' || *end_ptr != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); target = rpc::make_target(XmlRpc::call_file, xmlrpc.slot_find_file()(download, index)); break; case 't': index = ::strtol(str + 42, (char**)&end_ptr, 0); if (*str == '\0' || *end_ptr != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); target = rpc::make_target(XmlRpc::call_tracker, xmlrpc.slot_find_tracker()(download, index)); break; case 'p': { torrent::HashString hash; const char* hash_end = torrent::hash_string_from_hex_c_str(str + 42, hash); if (hash_end == end_ptr || *hash_end != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Not a hash string."); target = rpc::make_target(XmlRpc::call_peer, xmlrpc.slot_find_peer()(download, hash)); break; } default: ::free((void*)str); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Unsupported target type found."); } ::free((void*)str); // Check if the target pointer is NULL. if (target.second == NULL) throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); return target; } default: return rpc::make_target(); } } rpc::target_type xmlrpc_to_index_type(int index, int callType, core::Download* download) { void* result; switch (callType) { case XmlRpc::call_file: result = xmlrpc.slot_find_file()(download, index); break; case XmlRpc::call_tracker: result = xmlrpc.slot_find_tracker()(download, index); break; default: result = NULL; break; } if (result == NULL) throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); return rpc::make_target(callType, result); } torrent::Object xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target_type* target) { switch (xmlrpc_value_type(value)) { case XMLRPC_TYPE_INT: int v; xmlrpc_read_int(env, value, &v); return torrent::Object((int64_t)v); #ifdef XMLRPC_HAVE_I8 case XMLRPC_TYPE_I8: xmlrpc_int64 v2; xmlrpc_read_i8(env, value, &v2); return torrent::Object((int64_t)v2); #endif // case XMLRPC_TYPE_BOOL: // case XMLRPC_TYPE_DOUBLE: // case XMLRPC_TYPE_DATETIME: case XMLRPC_TYPE_STRING: if (callType != XmlRpc::call_generic) { // When the call type is not supposed to be void, we'll try to // convert it to a command target. It's not that important that // it is converted to the right type here, as an mismatch will // be caught when executing the command. *target = xmlrpc_to_target(env, value); return torrent::Object(); } else { const char* valueString; xmlrpc_read_string(env, value, &valueString); if (env->fault_occurred) throw xmlrpc_error(env); torrent::Object result = torrent::Object(std::string(valueString)); // Urgh, seriously? ::free((void*)valueString); return result; } case XMLRPC_TYPE_BASE64: { size_t valueSize; const char* valueString; xmlrpc_read_base64(env, value, &valueSize, (const unsigned char**)&valueString); if (env->fault_occurred) throw xmlrpc_error(env); torrent::Object result = torrent::Object(std::string(valueString, valueSize)); // Urgh, seriously? ::free((void*)valueString); return result; } case XMLRPC_TYPE_ARRAY: { unsigned int current = 0; unsigned int last = xmlrpc_array_size(env, value); if (env->fault_occurred) throw xmlrpc_error(env); if (callType != XmlRpc::call_generic && last != 0) { if (last < 1) throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Too few arguments."); xmlrpc_value* tmp; xmlrpc_array_read_item(env, value, current++, &tmp); if (env->fault_occurred) throw xmlrpc_error(env); *target = xmlrpc_to_target(env, tmp); xmlrpc_DECREF(tmp); if (env->fault_occurred) throw xmlrpc_error(env); if (target->first == XmlRpc::call_download && (callType == XmlRpc::call_file || callType == XmlRpc::call_tracker)) { // If we have a download target and the call type requires // another contained type, then we try to use the next // parameter as the index to support old-style calls. if (current == last) throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Too few arguments, missing index."); *target = xmlrpc_to_index_type(xmlrpc_list_entry_to_value(env, value, current++), callType, (core::Download*)target->second); } } if (current + 1 < last) { torrent::Object result = torrent::Object::create_list(); torrent::Object::list_type& listRef = result.as_list(); while (current != last) listRef.push_back(xmlrpc_list_entry_to_object(env, value, current++)); return result; } else if (current + 1 == last) { return xmlrpc_list_entry_to_object(env, value, current); } else { return torrent::Object(); } } // case XMLRPC_TYPE_STRUCT: // case XMLRPC_TYPE_C_PTR: // case XMLRPC_TYPE_NIL: // case XMLRPC_TYPE_DEAD: default: throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Unsupported type found."); } } xmlrpc_value* object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) { switch (object.type()) { case torrent::Object::TYPE_VALUE: #ifdef XMLRPC_HAVE_I8 if (xmlrpc.dialect() != XmlRpc::dialect_generic) return xmlrpc_i8_new(env, object.as_value()); #else return xmlrpc_int_new(env, object.as_value()); #endif case torrent::Object::TYPE_STRING: { #ifdef XMLRPC_HAVE_I8 // The versions that support I8 do implicit utf-8 validation. xmlrpc_value* result = xmlrpc_string_new(env, object.as_string().c_str()); #else // In older versions, xmlrpc-c doesn't validate the utf-8 encoding itself. xmlrpc_validate_utf8(env, object.as_string().c_str(), object.as_string().length()); xmlrpc_value* result = env->fault_occurred ? NULL : xmlrpc_string_new(env, object.as_string().c_str()); #endif if (env->fault_occurred) { xmlrpc_env_clean(env); xmlrpc_env_init(env); const std::string& str = object.as_string(); char buffer[str.size() + 1]; char* dst = buffer; for (std::string::const_iterator itr = str.begin(); itr != str.end(); ++itr) *dst++ = ((*itr < 0x20 && *itr != '\r' && *itr != '\n' && *itr != '\t') || (*itr & 0x80)) ? '?' : *itr; *dst = 0; result = xmlrpc_string_new(env, buffer); } return result; } case torrent::Object::TYPE_LIST: { xmlrpc_value* result = xmlrpc_array_new(env); for (torrent::Object::list_const_iterator itr = object.as_list().begin(), last = object.as_list().end(); itr != last; itr++) { xmlrpc_value* item = object_to_xmlrpc(env, *itr); xmlrpc_array_append_item(env, result, item); xmlrpc_DECREF(item); } return result; } case torrent::Object::TYPE_MAP: { xmlrpc_value* result = xmlrpc_struct_new(env); for (torrent::Object::map_const_iterator itr = object.as_map().begin(), last = object.as_map().end(); itr != last; itr++) { xmlrpc_value* item = object_to_xmlrpc(env, itr->second); xmlrpc_struct_set_value(env, result, itr->first.c_str(), item); xmlrpc_DECREF(item); } return result; } case torrent::Object::TYPE_DICT_KEY: { xmlrpc_value* result = xmlrpc_array_new(env); xmlrpc_value* key_item = object_to_xmlrpc(env, object.as_dict_key()); xmlrpc_array_append_item(env, result, key_item); xmlrpc_DECREF(key_item); if (object.as_dict_obj().is_list()) { for (torrent::Object::list_const_iterator itr = object.as_dict_obj().as_list().begin(), last = object.as_dict_obj().as_list().end(); itr != last; itr++) { xmlrpc_value* item = object_to_xmlrpc(env, *itr); xmlrpc_array_append_item(env, result, item); xmlrpc_DECREF(item); } } else { xmlrpc_value* arg_item = object_to_xmlrpc(env, object.as_dict_obj()); xmlrpc_array_append_item(env, result, arg_item); xmlrpc_DECREF(arg_item); } return result; } default: return xmlrpc_int_new(env, 0); } } xmlrpc_value* xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) { CommandMap::iterator itr = commands.find((const char*)voidServerInfo); if (itr == commands.end()) { xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, ("Command \"" + std::string((const char*)voidServerInfo) + "\" does not exist.").c_str()); return NULL; } try { torrent::Object object; rpc::target_type target = rpc::make_target(); if (itr->second.m_flags & CommandMap::flag_no_target) xmlrpc_to_object(env, args, XmlRpc::call_generic, &target).swap(object); else if (itr->second.m_flags & CommandMap::flag_file_target) xmlrpc_to_object(env, args, XmlRpc::call_file, &target).swap(object); else if (itr->second.m_flags & CommandMap::flag_tracker_target) xmlrpc_to_object(env, args, XmlRpc::call_tracker, &target).swap(object); else xmlrpc_to_object(env, args, XmlRpc::call_any, &target).swap(object); if (env->fault_occurred) return NULL; return object_to_xmlrpc(env, rpc::commands.call_command(itr, object, target)); } catch (xmlrpc_error& e) { xmlrpc_env_set_fault(env, e.type(), e.what()); return NULL; } catch (torrent::local_error& e) { xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, e.what()); return NULL; } } void XmlRpc::initialize() { #ifndef XMLRPC_HAVE_I8 m_dialect = dialect_generic; #endif m_env = new xmlrpc_env; xmlrpc_env_init((xmlrpc_env*)m_env); m_registry = xmlrpc_registry_new((xmlrpc_env*)m_env); } void XmlRpc::cleanup() { if (!is_valid()) return; xmlrpc_registry_free((xmlrpc_registry*)m_registry); xmlrpc_env_clean((xmlrpc_env*)m_env); delete (xmlrpc_env*)m_env; } bool XmlRpc::process(const char* inBuffer, uint32_t length, slot_write slotWrite) { xmlrpc_env localEnv; xmlrpc_env_init(&localEnv); xmlrpc_mem_block* memblock = xmlrpc_registry_process_call(&localEnv, (xmlrpc_registry*)m_registry, NULL, inBuffer, length); if (localEnv.fault_occurred && localEnv.fault_code == XMLRPC_INTERNAL_ERROR) throw torrent::internal_error("Internal error in XMLRPC."); bool result = slotWrite((const char*)xmlrpc_mem_block_contents(memblock), xmlrpc_mem_block_size(memblock)); xmlrpc_mem_block_free(memblock); xmlrpc_env_clean(&localEnv); return result; } void XmlRpc::insert_command(const char* name, const char* parm, const char* doc) { xmlrpc_env localEnv; xmlrpc_env_init(&localEnv); xmlrpc_registry_add_method_w_doc(&localEnv, (xmlrpc_registry*)m_registry, NULL, name, &xmlrpc_call_command, const_cast(name), parm, doc); if (localEnv.fault_occurred) throw torrent::internal_error("Fault occured while inserting xmlrpc call."); xmlrpc_env_clean(&localEnv); } void XmlRpc::set_dialect(int dialect) { if (!is_valid()) throw torrent::input_error("Cannot select XMLRPC dialect before it is initialized."); xmlrpc_env localEnv; xmlrpc_env_init(&localEnv); switch (dialect) { case dialect_generic: break; #ifdef XMLRPC_HAVE_I8 case dialect_i8: xmlrpc_registry_set_dialect(&localEnv, (xmlrpc_registry*)m_registry, xmlrpc_dialect_i8); break; case dialect_apache: xmlrpc_registry_set_dialect(&localEnv, (xmlrpc_registry*)m_registry, xmlrpc_dialect_apache); break; #endif default: xmlrpc_env_clean(&localEnv); throw torrent::input_error("Unsupported XMLRPC dialect selected."); } if (localEnv.fault_occurred) { xmlrpc_env_clean(&localEnv); throw torrent::input_error("Unsupported XMLRPC dialect selected."); } xmlrpc_env_clean(&localEnv); m_dialect = dialect; } int64_t XmlRpc::size_limit() { return xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID); } void XmlRpc::set_size_limit(uint64_t size) { if (size >= (64 << 20)) throw torrent::input_error("Invalid XMLRPC limit size."); xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, size); } #else void XmlRpc::initialize() { throw torrent::resource_error("XMLRPC not supported."); } void XmlRpc::cleanup() {} void XmlRpc::insert_command(__UNUSED const char* name, __UNUSED const char* parm, __UNUSED const char* doc) {} void XmlRpc::set_dialect(__UNUSED int dialect) {} bool XmlRpc::process(__UNUSED const char* inBuffer, __UNUSED uint32_t length, __UNUSED slot_write slotWrite) { return false; } int64_t XmlRpc::size_limit() { return 0; } void XmlRpc::set_size_limit(uint64_t size) {} #endif } rtorrent-0.9.6/src/rpc/xmlrpc.h000066400000000000000000000076151257211462100164500ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_RPC_XMLRPC_H #define RTORRENT_RPC_XMLRPC_H #include #include namespace core { class Download; } namespace torrent { class File; class Object; class Tracker; } namespace rpc { class XmlRpc { public: typedef std::tr1::function slot_download; typedef std::tr1::function slot_file; typedef std::tr1::function slot_tracker; typedef std::tr1::function slot_peer; typedef std::tr1::function slot_write; static const int dialect_generic = 0; static const int dialect_i8 = 1; static const int dialect_apache = 2; // These need to match CommandMap type values. static const int call_generic = 0; static const int call_any = 1; static const int call_download = 2; static const int call_peer = 3; static const int call_tracker = 4; static const int call_file = 5; static const int call_file_itr = 6; XmlRpc() : m_env(NULL), m_registry(NULL), m_dialect(dialect_i8) {} bool is_valid() const { return m_env != NULL; } void initialize(); void cleanup(); bool process(const char* inBuffer, uint32_t length, slot_write slotWrite); void insert_command(const char* name, const char* parm, const char* doc); int dialect() { return m_dialect; } void set_dialect(int dialect); slot_download& slot_find_download() { return m_slotFindDownload; } slot_file& slot_find_file() { return m_slotFindFile; } slot_tracker& slot_find_tracker() { return m_slotFindTracker; } slot_peer& slot_find_peer() { return m_slotFindPeer; } static int64_t size_limit(); static void set_size_limit(uint64_t size); private: void* m_env; void* m_registry; int m_dialect; slot_download m_slotFindDownload; slot_file m_slotFindFile; slot_tracker m_slotFindTracker; slot_peer m_slotFindPeer; }; } #endif rtorrent-0.9.6/src/signal_handler.cc000066400000000000000000000103351257211462100174600ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include "rak/error_number.h" #include "signal_handler.h" #ifdef __sun__ #include //extern "C" void (*signal (int sig, void (*disp)(int)))(int); #endif SignalHandler::slot_void SignalHandler::m_handlers[HIGHEST_SIGNAL]; void SignalHandler::set_default(unsigned int signum) { if (signum > HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::set_default(...) received invalid signal value."); signal(signum, SIG_DFL); m_handlers[signum] = slot_void(); } void SignalHandler::set_ignore(unsigned int signum) { if (signum > HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::set_ignore(...) received invalid signal value."); signal(signum, SIG_IGN); m_handlers[signum] = slot_void(); } void SignalHandler::set_handler(unsigned int signum, slot_void slot) { if (signum > HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value."); if (!slot) throw std::logic_error("SignalHandler::set_handler(...) received an empty slot."); signal(signum, &SignalHandler::caught); m_handlers[signum] = slot; } void SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) { if (signum > HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value."); struct sigaction sa; sa.sa_sigaction = slot; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); if (sigaction(signum, &sa, NULL) == -1) throw std::logic_error("Could not set sigaction: " + std::string(rak::error_number::current().c_str())); } void SignalHandler::caught(int signum) { if ((unsigned)signum > HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::caught(...) received invalid signal from the kernel, bork bork bork."); if (!m_handlers[signum]) throw std::logic_error("SignalHandler::caught(...) received a signal we don't have a handler for."); m_handlers[signum](); } const char* SignalHandler::as_string(unsigned int signum) { switch (signum) { case SIGHUP: return "Hangup detected"; case SIGINT: return "Interrupt from keyboard"; case SIGQUIT: return "Quit signal"; case SIGILL: return "Illegal instruction"; case SIGABRT: return "Abort signal"; case SIGFPE: return "Floating point exception"; case SIGKILL: return "Kill signal"; case SIGSEGV: return "Segmentation fault"; case SIGPIPE: return "Broken pipe"; case SIGALRM: return "Timer signal"; case SIGTERM: return "Termination signal"; case SIGBUS: return "Bus error"; default: return "Unlisted"; } } rtorrent-0.9.6/src/signal_handler.h000066400000000000000000000050151257211462100173210ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_SIGNAL_HANDLER_H #define RTORRENT_SIGNAL_HANDLER_H #include #include class SignalHandler { public: typedef std::tr1::function slot_void; // typedef void (*handler_slot)(int, siginfo_t *info, ucontext_t *uap); typedef void (*handler_slot)(int, siginfo_t*, void*); #ifdef NSIG static const unsigned int HIGHEST_SIGNAL = NSIG; #else // Let's be on the safe side. static const unsigned int HIGHEST_SIGNAL = 32; #endif static void set_default(unsigned int signum); static void set_ignore(unsigned int signum); static void set_handler(unsigned int signum, slot_void slot); static void set_sigaction_handler(unsigned int signum, handler_slot slot); static const char* as_string(unsigned int signum); private: static void caught(int signum); static slot_void m_handlers[HIGHEST_SIGNAL]; }; #endif rtorrent-0.9.6/src/thread_base.cc000066400000000000000000000113441257211462100167500ustar00rootroot00000000000000// libTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "thread_base.h" #include #include #include #include #include #include #include #include #include #include #include "globals.h" #include "control.h" #include "core/manager.h" // Temporarly injected into config.h. /* temp hack */ //#define lt_cacheline_aligned __attribute__((__aligned__(128))) class lt_cacheline_aligned thread_queue_hack { public: typedef ThreadBase::thread_base_func value_type; typedef ThreadBase::thread_base_func* iterator; static const unsigned int max_size = 32; thread_queue_hack() { std::memset(this, 0, sizeof(thread_queue_hack)); } void lock() { while (!__sync_bool_compare_and_swap(&m_lock, 0, 1)) usleep(0); } void unlock() { __sync_bool_compare_and_swap(&m_lock, 1, 0); } iterator begin() { return m_queue; } iterator max_capacity() { return m_queue + max_size; } iterator end_and_lock() { lock(); return std::find(begin(), max_capacity(), (value_type)NULL); } bool empty() const { return m_queue[0] == NULL; } void push_back(value_type v) { iterator itr = end_and_lock(); if (itr == max_capacity()) throw torrent::internal_error("Overflowed thread_queue."); __sync_bool_compare_and_swap(itr, NULL, v); unlock(); } value_type* copy_and_clear(value_type* dest) { iterator itr = begin(); lock(); while (*itr != NULL) *dest++ = *itr++; clear_and_unlock(); return dest; } void clear_and_unlock() { std::memset(this, 0, sizeof(thread_queue_hack)); __sync_synchronize(); } private: int m_lock; value_type m_queue[max_size + 1]; }; void throw_shutdown_exception() { throw torrent::shutdown_exception(); } ThreadBase::ThreadBase() { m_taskShutdown.slot() = std::tr1::bind(&throw_shutdown_exception); m_threadQueue = new thread_queue_hack; } ThreadBase::~ThreadBase() { delete m_threadQueue; } // Move to libtorrent... void ThreadBase::stop_thread(ThreadBase* thread) { if (!thread->m_taskShutdown.is_queued()) priority_queue_insert(&thread->m_taskScheduler, &thread->m_taskShutdown, cachedTime); } int64_t ThreadBase::next_timeout_usec() { if (m_taskScheduler.empty()) return rak::timer::from_seconds(600).usec(); else if (m_taskScheduler.top()->time() <= cachedTime) return 0; else return (m_taskScheduler.top()->time() - cachedTime).usec(); } void ThreadBase::call_queued_items() { thread_base_func result[thread_queue_hack::max_size]; thread_base_func* first = result; thread_base_func* last = m_threadQueue->copy_and_clear((thread_base_func*)result); while (first != last && *first) (*first++)(this); } void ThreadBase::call_events() { // Check for new queued items set by other threads. if (!m_threadQueue->empty()) call_queued_items(); rak::priority_queue_perform(&m_taskScheduler, cachedTime); } void ThreadBase::queue_item(thread_base_func newFunc) { m_threadQueue->push_back(newFunc); // Make it also restart inactive threads? if (m_state == STATE_ACTIVE) interrupt(); } rtorrent-0.9.6/src/thread_base.h000066400000000000000000000056561257211462100166230ustar00rootroot00000000000000// libTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_THREAD_BASE_H #define RTORRENT_UTILS_THREAD_BASE_H #include #include #include #include "rak/priority_queue_default.h" #include "core/poll_manager.h" // Move this class to libtorrent. class thread_queue_hack; class ThreadBase : public torrent::thread_base { public: typedef rak::priority_queue_default priority_queue; typedef void (*thread_base_func)(ThreadBase*); ThreadBase(); virtual ~ThreadBase(); priority_queue& task_scheduler() { return m_taskScheduler; } // Throw torrent::shutdown_exception to stop the thread. static void stop_thread(ThreadBase* thread); // ATM, only interaction with a thread's allowed by other threads is // through the queue_item call. void queue_item(thread_base_func newFunc); protected: int64_t next_timeout_usec(); void call_queued_items(); virtual void call_events(); // TODO: Add thread name. // The timer needs to be sync'ed when updated... rak::priority_queue_default m_taskScheduler; rak::priority_item m_taskShutdown; // Temporary hack to pass messages to a thread. This really needs to // be cleaned up and/or integrated into the priority queue itself. thread_queue_hack* m_threadQueue; }; #endif rtorrent-0.9.6/src/thread_worker.cc000066400000000000000000000074021257211462100173470ustar00rootroot00000000000000// rTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include "thread_worker.h" #include "globals.h" #include "control.h" #include #include #include #include #include #include "core/manager.h" #include "rpc/scgi.h" #include "rpc/xmlrpc.h" #include "rpc/parse_commands.h" ThreadWorker::ThreadWorker() { } ThreadWorker::~ThreadWorker() { if (m_safe.scgi) m_safe.scgi->deactivate(); } void ThreadWorker::init_thread() { m_poll = core::create_poll(); m_state = STATE_INITIALIZED; } bool ThreadWorker::set_scgi(rpc::SCgi* scgi) { if (!__sync_bool_compare_and_swap(&m_safe.scgi, NULL, scgi)) return false; change_xmlrpc_log(); // The xmlrpc process call requires a global lock. // m_safe.scgi->set_slot_process(rak::mem_fn(&rpc::xmlrpc, &rpc::XmlRpc::process)); // Synchronize in order to ensure the worker thread sees the updated // SCgi object. __sync_synchronize(); queue_item((thread_base_func)&start_scgi); return true; } void ThreadWorker::set_xmlrpc_log(const std::string& filename) { m_xmlrpcLog = filename; queue_item((thread_base_func)&msg_change_xmlrpc_log); } void ThreadWorker::start_scgi(ThreadBase* baseThread) { ThreadWorker* thread = (ThreadWorker*)baseThread; if (thread->m_safe.scgi == NULL) throw torrent::internal_error("Tried to start SCGI but object was not present."); thread->m_safe.scgi->activate(); } void ThreadWorker::msg_change_xmlrpc_log(ThreadBase* baseThread) { ThreadWorker* thread = (ThreadWorker*)baseThread; acquire_global_lock(); thread->change_xmlrpc_log(); release_global_lock(); } void ThreadWorker::change_xmlrpc_log() { if (scgi() == NULL) return; if (scgi()->log_fd() != -1) ::close(scgi()->log_fd()); if (m_xmlrpcLog.empty()) { control->core()->push_log("Closed XMLRPC log."); return; } scgi()->set_log_fd(open(rak::path_expand(m_xmlrpcLog).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644)); if (scgi()->log_fd() == -1) { control->core()->push_log_std("Could not open XMLRPC log file '" + m_xmlrpcLog + "'."); return; } control->core()->push_log_std("Logging XMLRPC events to '" + m_xmlrpcLog + "'."); } rtorrent-0.9.6/src/thread_worker.h000066400000000000000000000053101257211462100172050ustar00rootroot00000000000000// rTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_THREAD_WORKER_H #define RTORRENT_THREAD_WORKER_H #include "thread_base.h" #include namespace rpc { class SCgi; } // Check if cacheline aligned with inheritance ends up taking two // cachelines. class lt_cacheline_aligned ThreadWorker : public ThreadBase { public: ThreadWorker(); ~ThreadWorker(); const char* name() const { return "worker_rtorrent"; } virtual void init_thread(); rpc::SCgi* scgi() { return m_safe.scgi; } bool set_scgi(rpc::SCgi* scgi); void set_xmlrpc_log(const std::string& filename); static void start_scgi(ThreadBase* thread); static void msg_change_xmlrpc_log(ThreadBase* thread); private: void task_touch_log(); void change_xmlrpc_log(); struct lt_cacheline_aligned safe_type { safe_type() : scgi(NULL) {} rpc::SCgi* scgi; }; safe_type m_safe; // The following types shall only be modified while holding the // global lock. std::string m_xmlrpcLog; }; #endif rtorrent-0.9.6/src/ui/000077500000000000000000000000001257211462100146125ustar00rootroot00000000000000rtorrent-0.9.6/src/ui/Makefile.am000066400000000000000000000013241257211462100166460ustar00rootroot00000000000000noinst_LIBRARIES = libsub_ui.a libsub_ui_a_SOURCES = \ download.cc \ download.h \ download_list.cc \ download_list.h \ element_base.h \ element_base.cc \ element_chunks_seen.cc \ element_chunks_seen.h \ element_download_list.cc \ element_download_list.h \ element_file_list.cc \ element_file_list.h \ element_log_complete.cc \ element_log_complete.h \ element_menu.cc \ element_menu.h \ element_peer_list.cc \ element_peer_list.h \ element_string_list.cc \ element_string_list.h \ element_text.cc \ element_text.h \ element_tracker_list.cc \ element_tracker_list.h \ element_transfer_list.cc \ element_transfer_list.h \ root.cc \ root.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/ui/download.cc000066400000000000000000000425331257211462100167370ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "core/download.h" #include "core/manager.h" #include "input/manager.h" #include "display/window_title.h" #include "display/window_download_statusbar.h" #include "display/text_element_string.h" #include "control.h" #include "download.h" #include "root.h" #include "element_file_list.h" #include "element_menu.h" #include "element_text.h" #include "element_peer_list.h" #include "element_tracker_list.h" #include "element_chunks_seen.h" #include "element_transfer_list.h" namespace ui { Download::Download(core::Download* d) : m_download(d), m_state(DISPLAY_MAX_SIZE), m_focusDisplay(false) { m_windowDownloadStatus = new WDownloadStatus(d); m_windowDownloadStatus->set_bottom(true); m_uiArray[DISPLAY_MENU] = create_menu(); m_uiArray[DISPLAY_PEER_LIST] = new ElementPeerList(d); m_uiArray[DISPLAY_INFO] = create_info(); m_uiArray[DISPLAY_FILE_LIST] = new ElementFileList(d); m_uiArray[DISPLAY_TRACKER_LIST] = new ElementTrackerList(d); m_uiArray[DISPLAY_CHUNKS_SEEN] = new ElementChunksSeen(d); m_uiArray[DISPLAY_TRANSFER_LIST] = new ElementTransferList(d); m_uiArray[DISPLAY_MENU]->slot_exit(std::tr1::bind(&slot_type::operator(), &m_slot_exit)); m_uiArray[DISPLAY_PEER_LIST]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_PEER_LIST)); m_uiArray[DISPLAY_INFO]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_INFO)); m_uiArray[DISPLAY_FILE_LIST]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_FILE_LIST)); m_uiArray[DISPLAY_TRACKER_LIST]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_TRACKER_LIST)); m_uiArray[DISPLAY_CHUNKS_SEEN]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_CHUNKS_SEEN)); m_uiArray[DISPLAY_TRANSFER_LIST]->slot_exit(std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_TRANSFER_LIST)); bind_keys(); } Download::~Download() { if (is_active()) throw torrent::internal_error("ui::Download::~Download() called on an active object."); std::for_each(m_uiArray, m_uiArray + DISPLAY_MAX_SIZE, rak::call_delete()); delete m_windowDownloadStatus; } inline ElementBase* Download::create_menu() { ElementMenu* element = new ElementMenu; element->push_back("Peer list", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_PEER_LIST), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_PEER_LIST)); element->push_back("Info", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_INFO), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_INFO)); element->push_back("File list", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_FILE_LIST), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_FILE_LIST)); element->push_back("Tracker list", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_TRACKER_LIST), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_TRACKER_LIST)); element->push_back("Chunks seen", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_CHUNKS_SEEN), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_CHUNKS_SEEN)); element->push_back("Transfer list", std::tr1::bind(&Download::activate_display_focus, this, DISPLAY_TRANSFER_LIST), std::tr1::bind(&Download::activate_display_menu, this, DISPLAY_TRANSFER_LIST)); element->set_entry(0, false); m_bindings['p'] = std::tr1::bind(&ElementMenu::set_entry_trigger, element, 0); m_bindings['o'] = std::tr1::bind(&ElementMenu::set_entry_trigger, element, 1); m_bindings['i'] = std::tr1::bind(&ElementMenu::set_entry_trigger, element, 2); m_bindings['u'] = std::tr1::bind(&ElementMenu::set_entry_trigger, element, 3); return element; } inline ElementBase* Download::create_info() { using namespace display::helpers; ElementText* element = new ElementText(rpc::make_target(m_download)); element->set_column(1); element->set_interval(1); // Get these bindings with some kind of string map. element->push_column("Name:", te_command("d.name=")); element->push_column("Local id:", te_command("d.local_id_html=")); element->push_column("Info hash:", te_command("d.hash=")); element->push_column("Created:", te_command("cat=$convert.date=$d.creation_date=,\" \",$convert.time=$d.creation_date=")); element->push_back(""); element->push_column("Directory:", te_command("d.directory=")); element->push_column("Base Path:", te_command("d.base_path=")); element->push_column("Tied to file:", te_command("d.tied_to_file=")); element->push_column("File stats:", te_command("cat=$if=$d.is_multi_file=\\,multi\\,single,\" \",$d.size_files=,\" files\"")); element->push_back(""); element->push_column("Chunks:", te_command("cat=(d.completed_chunks),\" / \",(d.size_chunks),\" * \",(d.chunk_size),\" (\",(d.wanted_chunks),\")\"")); element->push_column("Priority:", te_command("d.priority=")); element->push_column("Peer exchange:", te_command("cat=$if=$d.peer_exchange=\\,enabled\\,disabled,\\ ," "$if=$d.is_pex_active=\\,active\\,$d.is_private=\\,private\\,inactive," "\\ (,$d.size_pex=,/,$d.max_size_pex=,)")); element->push_column("State changed:", te_command("convert.elapsed_time=$d.state_changed=")); element->push_back(""); element->push_column("Memory usage:", te_command("cat=$convert.mb=$pieces.memory.current=,\" MB\"")); element->push_column("Max memory usage:", te_command("cat=$convert.mb=$pieces.memory.max=,\" MB\"")); element->push_column("Free diskspace:", te_command("cat=$convert.mb=$d.free_diskspace=,\" MB\"")); element->push_column("Safe diskspace:", te_command("cat=$convert.mb=$pieces.sync.safe_free_diskspace=,\" MB\"")); element->push_back(""); element->push_column("Connection type:", te_command("cat=(d.connection_current),\" \",(if,(d.accepting_seeders),"",\"no_seeders\")")); element->push_column("Choke heuristic:", te_command("cat=(d.up.choke_heuristics),\", \",(d.down.choke_heuristics),\", \",(d.group)")); element->push_column("Safe sync:", te_command("if=$pieces.sync.always_safe=,yes,no")); element->push_column("Send buffer:", te_command("cat=$convert.kb=$network.send_buffer.size=,\" KB\"")); element->push_column("Receive buffer:", te_command("cat=$convert.kb=$network.receive_buffer.size=,\" KB\"")); // TODO: Define a custom command for this and use $argument.0 instead of looking up the name multiple times? element->push_column("Throttle:", te_command("branch=d.throttle_name=,\"" "cat=$d.throttle_name=,\\\" [Max \\\"," "$convert.throttle=$throttle.up.max=$d.throttle_name=,\\\"/\\\"," "$convert.throttle=$throttle.down.max=$d.throttle_name=,\\\" KB] [Rate \\\"," "$convert.kb=$throttle.up.rate=$d.throttle_name=,\\\"/\\\"," "$convert.kb=$throttle.down.rate=$d.throttle_name=,\\\" KB]\\\"\"," "cat=\"global\"")); element->push_back(""); element->push_column("Upload:", te_command("cat=$convert.kb=$d.up.rate=,\" KB / \",$convert.xb=$d.up.total=")); element->push_column("Download:", te_command("cat=$convert.kb=$d.down.rate=,\" KB / \",$convert.xb=$d.down.total=")); element->push_column("Skipped:", te_command("cat=$convert.kb=$d.skip.rate=,\" KB / \",$convert.xb=$d.skip.total=")); element->push_column("Preload:", te_command("cat=$pieces.preload.type=,\" / \",$pieces.stats_preloaded=,\" / \",$pieces.stats_preloaded=")); element->set_column_width(element->column_width() + 1); return element; } void Download::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::Download::activate() called on an already activated object."); control->input()->push_back(&m_bindings); m_frame = frame; m_frame->initialize_row(2); m_frame->frame(1)->initialize_window(m_windowDownloadStatus); m_windowDownloadStatus->set_active(true); activate_display_menu(DISPLAY_PEER_LIST); } void Download::disable() { if (!is_active()) throw torrent::internal_error("ui::Download::disable() called on an already disabled object."); control->input()->erase(&m_bindings); activate_display_focus(DISPLAY_MAX_SIZE); m_windowDownloadStatus->set_active(false); m_frame->clear(); m_frame = NULL; } void Download::activate_display(Display displayType, bool focusDisplay) { if (!is_active()) throw torrent::internal_error("ui::Download::activate_display(...) !is_active()."); if (displayType > DISPLAY_MAX_SIZE) throw torrent::internal_error("ui::Download::activate_display(...) out of bounds"); if (focusDisplay == m_focusDisplay && displayType == m_state) return; display::Frame* frame = m_frame->frame(0); // Cleanup previous state. switch (m_state) { case DISPLAY_PEER_LIST: case DISPLAY_INFO: case DISPLAY_FILE_LIST: case DISPLAY_TRACKER_LIST: case DISPLAY_CHUNKS_SEEN: case DISPLAY_TRANSFER_LIST: m_uiArray[DISPLAY_MENU]->disable(); m_uiArray[m_state]->disable(); frame->clear(); break; case DISPLAY_MENU: case DISPLAY_MAX_SIZE: break; } m_state = displayType; m_focusDisplay = focusDisplay; // Initialize new state. switch (displayType) { case DISPLAY_PEER_LIST: case DISPLAY_INFO: case DISPLAY_FILE_LIST: case DISPLAY_TRACKER_LIST: case DISPLAY_CHUNKS_SEEN: case DISPLAY_TRANSFER_LIST: frame->initialize_column(2); m_uiArray[DISPLAY_MENU]->activate(frame->frame(0), !focusDisplay); m_uiArray[displayType]->activate(frame->frame(1), focusDisplay); break; case DISPLAY_MENU: case DISPLAY_MAX_SIZE: break; } // Set title. switch (displayType) { case DISPLAY_MAX_SIZE: break; default: control->ui()->window_title()->set_title(m_download->info()->name()); break; } control->display()->adjust_layout(); } void Download::receive_max_uploads(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->set_uploads_max(std::max(m_download->download()->uploads_max() + t, 0)); } void Download::receive_min_uploads(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->set_uploads_min(std::max(m_download->download()->uploads_min() + t, 0)); } void Download::receive_max_downloads(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->set_downloads_max(std::max(m_download->download()->downloads_max() + t, 0)); } void Download::receive_min_downloads(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->set_downloads_min(std::max(m_download->download()->downloads_min() + t, 0)); } void Download::receive_min_peers(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->connection_list()->set_min_size(std::max(m_download->download()->connection_list()->min_size() + t, (int32_t)5)); } void Download::receive_max_peers(int t) { m_windowDownloadStatus->mark_dirty(); m_download->download()->connection_list()->set_max_size(std::max(m_download->download()->connection_list()->max_size() + t, (int32_t)5)); } void Download::receive_next_priority() { m_download->set_priority((m_download->priority() + 1) % 4); } void Download::receive_prev_priority() { m_download->set_priority((m_download->priority() - 1) % 4); } void Download::adjust_down_throttle(int throttle) { core::ThrottleMap::iterator itr = control->core()->throttles().find(m_download->bencode()->get_key("rtorrent").get_key_string("throttle_name")); if (itr == control->core()->throttles().end() || itr->second.second == NULL || itr->first == "NULL") control->ui()->adjust_down_throttle(throttle); else itr->second.second->set_max_rate(std::max((itr->second.second->is_throttled() ? itr->second.second->max_rate() : 0) + throttle * 1024, 0)); if (m_uiArray[DISPLAY_INFO]->is_active()) m_uiArray[DISPLAY_INFO]->mark_dirty(); } void Download::adjust_up_throttle(int throttle) { core::ThrottleMap::iterator itr = control->core()->throttles().find(m_download->bencode()->get_key("rtorrent").get_key_string("throttle_name")); if (itr == control->core()->throttles().end() || itr->second.first == NULL || itr->first == "NULL") control->ui()->adjust_up_throttle(throttle); else itr->second.first->set_max_rate(std::max((itr->second.first->is_throttled() ? itr->second.first->max_rate() : 0) + throttle * 1024, 0)); if (m_uiArray[DISPLAY_INFO]->is_active()) m_uiArray[DISPLAY_INFO]->mark_dirty(); } void Download::bind_keys() { m_bindings['1'] = std::tr1::bind(&Download::receive_min_uploads, this, -1); m_bindings['2'] = std::tr1::bind(&Download::receive_min_uploads, this, 1); m_bindings['3'] = std::tr1::bind(&Download::receive_max_uploads, this, -1); m_bindings['4'] = std::tr1::bind(&Download::receive_max_uploads, this, 1); m_bindings['!'] = std::tr1::bind(&Download::receive_min_downloads, this, -1); m_bindings['@'] = std::tr1::bind(&Download::receive_min_downloads, this, 1); m_bindings['#'] = std::tr1::bind(&Download::receive_max_downloads, this, -1); m_bindings['$'] = std::tr1::bind(&Download::receive_max_downloads, this, 1); m_bindings['5'] = std::tr1::bind(&Download::receive_min_peers, this, -5); m_bindings['6'] = std::tr1::bind(&Download::receive_min_peers, this, 5); m_bindings['7'] = std::tr1::bind(&Download::receive_max_peers, this, -5); m_bindings['8'] = std::tr1::bind(&Download::receive_max_peers, this, 5); m_bindings['+'] = std::tr1::bind(&Download::receive_next_priority, this); m_bindings['-'] = std::tr1::bind(&Download::receive_prev_priority, this); m_bindings['t'] = std::tr1::bind(&torrent::Download::manual_request, m_download->download(), false); m_bindings['T'] = std::tr1::bind(&torrent::Download::manual_request, m_download->download(), true); const char* keys = control->ui()->get_throttle_keys(); m_bindings[keys[ 0]] = std::tr1::bind(&Download::adjust_up_throttle, this, 1); m_bindings[keys[ 1]] = std::tr1::bind(&Download::adjust_up_throttle, this, -1); m_bindings[keys[ 2]] = std::tr1::bind(&Download::adjust_down_throttle, this, 1); m_bindings[keys[ 3]] = std::tr1::bind(&Download::adjust_down_throttle, this, -1); m_bindings[keys[ 4]] = std::tr1::bind(&Download::adjust_up_throttle, this, 5); m_bindings[keys[ 5]] = std::tr1::bind(&Download::adjust_up_throttle, this, -5); m_bindings[keys[ 6]] = std::tr1::bind(&Download::adjust_down_throttle, this, 5); m_bindings[keys[ 7]] = std::tr1::bind(&Download::adjust_down_throttle, this, -5); m_bindings[keys[ 8]] = std::tr1::bind(&Download::adjust_up_throttle, this, 50); m_bindings[keys[ 9]] = std::tr1::bind(&Download::adjust_up_throttle, this, -50); m_bindings[keys[10]] = std::tr1::bind(&Download::adjust_down_throttle, this, 50); m_bindings[keys[11]] = std::tr1::bind(&Download::adjust_down_throttle, this, -50); } } rtorrent-0.9.6/src/ui/download.h000066400000000000000000000071561257211462100166030ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_DOWNLOAD_H #define RTORRENT_UI_DOWNLOAD_H #include #include #include "display/manager.h" #include "utils/list_focus.h" #include "element_base.h" namespace display { class WindowDownloadStatusbar; } namespace core { class Download; } namespace ui { class Download : public ElementBase { public: typedef display::WindowDownloadStatusbar WDownloadStatus; typedef std::list PList; typedef enum { DISPLAY_MENU, DISPLAY_PEER_LIST, DISPLAY_INFO, DISPLAY_FILE_LIST, DISPLAY_TRACKER_LIST, DISPLAY_CHUNKS_SEEN, DISPLAY_TRANSFER_LIST, DISPLAY_MAX_SIZE } Display; Download(core::Download* d); ~Download(); void activate(display::Frame* frame, bool focus = true); void disable(); void activate_display(Display d, bool focusDisplay); void activate_display_focus(Display d) { activate_display(d, true); } void activate_display_menu(Display d) { activate_display(d, false); } void receive_next_priority(); void receive_prev_priority(); void adjust_up_throttle(int throttle); void adjust_down_throttle(int throttle); display::Window* window() { return NULL; } private: Download(const Download&); void operator = (const Download&); inline ElementBase* create_menu(); inline ElementBase* create_info(); void receive_min_uploads(int t); void receive_max_uploads(int t); void receive_min_downloads(int t); void receive_max_downloads(int t); void receive_min_peers(int t); void receive_max_peers(int t); void bind_keys(); core::Download* m_download; Display m_state; ElementBase* m_uiArray[DISPLAY_MAX_SIZE]; bool m_focusDisplay; WDownloadStatus* m_windowDownloadStatus; }; } #endif rtorrent-0.9.6/src/ui/download_list.cc000066400000000000000000000262011257211462100177640ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/download.h" #include "core/download_list.h" #include "core/manager.h" #include "core/view.h" #include "core/view_manager.h" #include "input/bindings.h" #include "input/manager.h" #include "input/path_input.h" #include "display/window_log.h" #include "display/window_title.h" #include "rpc/parse_commands.h" #include "control.h" #include "download.h" #include "download_list.h" #include "element_download_list.h" #include "element_log_complete.h" #include "element_string_list.h" #include "root.h" namespace ui { DownloadList::DownloadList() : m_state(DISPLAY_MAX_SIZE) { m_uiArray[DISPLAY_DOWNLOAD] = NULL; m_uiArray[DISPLAY_DOWNLOAD_LIST] = new ElementDownloadList(); m_uiArray[DISPLAY_LOG] = new ElementLogComplete(control->core()->log_complete()); m_uiArray[DISPLAY_STRING_LIST] = new ElementStringList(); m_windowLog = new WLog(control->core()->log_important()); setup_keys(); } DownloadList::~DownloadList() { if (is_active()) throw std::logic_error("ui::DownloadList::~DownloadList() called on an active object"); std::for_each(m_uiArray, m_uiArray + DISPLAY_MAX_SIZE, rak::call_delete()); delete m_windowLog; } void DownloadList::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::DownloadList::activate() called on an already activated object"); m_frame = frame; control->input()->push_back(&m_bindings); activate_display(DISPLAY_DOWNLOAD_LIST); } void DownloadList::disable() { if (!is_active()) throw std::logic_error("ui::DownloadList::disable() called on an already disabled object"); receive_exit_input(INPUT_NONE); activate_display(DISPLAY_MAX_SIZE); m_frame = NULL; control->input()->erase(&m_bindings); } core::View* DownloadList::current_view() { return dynamic_cast(m_uiArray[DISPLAY_DOWNLOAD_LIST])->view(); } void DownloadList::set_current_view(const std::string& name) { return dynamic_cast(m_uiArray[DISPLAY_DOWNLOAD_LIST])->receive_change_view(name); } // This should also do focus_next() or something. void DownloadList::unfocus_download(core::Download* d) { if (current_view()->focus() >= current_view()->end_visible() || *current_view()->focus() != d) return; if (m_state == DISPLAY_DOWNLOAD) activate_display(DISPLAY_DOWNLOAD_LIST); current_view()->next_focus(); } void DownloadList::activate_display(Display displayType) { if (!is_active()) throw torrent::internal_error("ui::DownloadList::activate_display(...) !is_active()."); if (displayType > DISPLAY_MAX_SIZE) throw torrent::internal_error("ui::DownloadList::activate_display(...) out of bounds"); if (displayType == m_state) return; // Cleanup previous state. switch (m_state) { case DISPLAY_DOWNLOAD: m_uiArray[m_state]->disable(); delete m_uiArray[m_state]; m_uiArray[m_state] = NULL; break; case DISPLAY_DOWNLOAD_LIST: m_uiArray[DISPLAY_DOWNLOAD_LIST]->disable(); m_windowLog->set_active(false); m_frame->frame(1)->clear(); m_frame->clear(); break; case DISPLAY_LOG: case DISPLAY_STRING_LIST: m_uiArray[m_state]->disable(); break; default: break; } m_state = displayType; // Initialize new state. switch (displayType) { case DISPLAY_DOWNLOAD: // If no download has the focus, just return to the download list. if (current_view()->focus() == current_view()->end_visible()) { m_state = DISPLAY_MAX_SIZE; activate_display(DISPLAY_DOWNLOAD_LIST); return; } else { Download* download = new Download(*current_view()->focus()); download->activate(m_frame); download->slot_exit(std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD_LIST)); m_uiArray[DISPLAY_DOWNLOAD] = download; break; } case DISPLAY_DOWNLOAD_LIST: m_frame->initialize_row(2); m_uiArray[DISPLAY_DOWNLOAD_LIST]->activate(m_frame->frame(0)); m_frame->frame(1)->initialize_window(m_windowLog); m_windowLog->set_active(true); m_windowLog->receive_update(); break; case DISPLAY_LOG: case DISPLAY_STRING_LIST: m_uiArray[displayType]->activate(m_frame); break; default: break; } // Set title. switch (displayType) { case DISPLAY_DOWNLOAD_LIST: control->ui()->window_title()->set_title("rTorrent " VERSION "/" + std::string(torrent::version()) + " - " + rpc::call_command_string("session.name")); break; case DISPLAY_LOG: control->ui()->window_title()->set_title("Log"); break; default: break; } control->display()->adjust_layout(); } void DownloadList::receive_view_input(Input type) { if (control->ui()->current_input() != NULL) return; input::PathInput* input = new input::PathInput; const char* title; switch (type) { case INPUT_LOAD_DEFAULT: title = "load.start"; break; case INPUT_LOAD_MODIFIED: title = "load.normal"; break; case INPUT_CHANGE_DIRECTORY: title = "change_directory"; input->str() = rpc::call_command_string("directory.default"); input->set_pos(input->str().length()); break; case INPUT_COMMAND: title = "command"; break; default: throw torrent::internal_error("DownloadList::receive_view_input(...) Invalid input type."); } ElementStringList* esl = dynamic_cast(m_uiArray[DISPLAY_STRING_LIST]); input->signal_show_next().push_back(std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_STRING_LIST)); input->signal_show_next().push_back(std::tr1::bind(&ElementStringList::next_screen, esl)); input->signal_show_range().push_back(std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_STRING_LIST)); input->signal_show_range().push_back(std::tr1::bind(&ElementStringList::set_range_dirent, esl, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); input->bindings()['\n'] = std::tr1::bind(&DownloadList::receive_exit_input, this, type); input->bindings()[KEY_ENTER] = std::tr1::bind(&DownloadList::receive_exit_input, this, type); input->bindings()['\x07'] = std::tr1::bind(&DownloadList::receive_exit_input, this, INPUT_NONE); control->ui()->enable_input(title, input); } void DownloadList::receive_exit_input(Input type) { input::TextInput* input = control->ui()->current_input(); // We should check that this object is the one holding the input. if (input == NULL) return; control->ui()->disable_input(); try { switch (type) { case INPUT_NONE: break; case INPUT_LOAD_DEFAULT: case INPUT_LOAD_MODIFIED: if (input->str().empty()) break; control->core()->try_create_download_expand(input->str(), type == INPUT_LOAD_DEFAULT ? core::Manager::create_start : 0); break; case INPUT_CHANGE_DIRECTORY: if (current_view()->focus() == current_view()->end_visible()) throw torrent::input_error("No download in focus to change root directory."); if ((*current_view()->focus())->is_open()) throw torrent::input_error("Cannot change root directory on an open download."); rpc::call_command("d.directory.set", rak::trim(input->str()), rpc::make_target(*current_view()->focus())); control->core()->push_log_std("New root directory \"" + rpc::call_command_string("d.directory", rpc::make_target(*current_view()->focus())) + "\" for torrent."); break; case INPUT_COMMAND: rpc::parse_command_single(current_view()->focus() != current_view()->end_visible() ? rpc::make_target(*current_view()->focus()) : rpc::make_target(), input->str()); break; default: throw torrent::internal_error("DownloadList::receive_exit_input(...) Invalid input type."); } } catch (torrent::input_error& e) { lt_log_print(torrent::LOG_WARN, "Input failed: %s", e.what()); } activate_display(DISPLAY_DOWNLOAD_LIST); delete input; } void DownloadList::setup_keys() { m_bindings['\x7f'] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_DEFAULT); m_bindings[KEY_BACKSPACE] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_DEFAULT); m_bindings['\n'] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_MODIFIED); m_bindings[KEY_ENTER] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_LOAD_MODIFIED); m_bindings['\x0F'] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_CHANGE_DIRECTORY); m_bindings['X' - '@'] = std::tr1::bind(&DownloadList::receive_view_input, this, INPUT_COMMAND); m_uiArray[DISPLAY_LOG]->bindings()[KEY_LEFT] = m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] = m_uiArray[DISPLAY_LOG]->bindings()[' '] = std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD_LIST); m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[KEY_RIGHT] = m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD); m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] = std::tr1::bind(&DownloadList::activate_display, this, DISPLAY_LOG); } } rtorrent-0.9.6/src/ui/download_list.h000066400000000000000000000067541257211462100176410ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_DOWNLOAD_LIST_H #define RTORRENT_UI_DOWNLOAD_LIST_H #include "element_base.h" #include "globals.h" #include "display/manager.h" class Control; namespace core { class Download; class View; } namespace input { class Bindings; } namespace display { class Frame; class WindowDownloadList; class WindowHttpQueue; class WindowInput; class WindowLog; class WindowLogComplete; } namespace ui { class Download; class DownloadList : public ElementBase { public: typedef display::WindowDownloadList WList; typedef display::WindowLog WLog; typedef display::WindowLogComplete WLogComplete; typedef std::tr1::function slot_string; typedef enum { DISPLAY_DOWNLOAD, DISPLAY_DOWNLOAD_LIST, DISPLAY_LOG, DISPLAY_STRING_LIST, DISPLAY_MAX_SIZE } Display; typedef enum { INPUT_NONE, INPUT_LOAD_DEFAULT, INPUT_LOAD_MODIFIED, INPUT_CHANGE_DIRECTORY, INPUT_COMMAND } Input; DownloadList(); ~DownloadList(); void activate(display::Frame* frame, bool focus = true); void disable(); void activate_display(Display d); core::View* current_view(); void set_current_view(const std::string& name); void slot_open_uri(slot_string s) { m_slot_open_uri = s; } void unfocus_download(core::Download* d); private: DownloadList(const DownloadList&); void operator = (const DownloadList&); void receive_view_input(Input type); void receive_exit_input(Input type); void setup_keys(); void setup_input(); Display m_state; ElementBase* m_uiArray[DISPLAY_MAX_SIZE]; WLog* m_windowLog; slot_string m_slot_open_uri; }; } #endif rtorrent-0.9.6/src/ui/element_base.cc000066400000000000000000000035511257211462100175500ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "display/window.h" #include "element_base.h" namespace ui { void ElementBase::mark_dirty() { if (is_active()) m_frame->window()->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_base.h000066400000000000000000000046771257211462100174240ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_BASE_H #define RTORRENT_UI_ELEMENT_BASE_H #include "input/bindings.h" namespace display { class Frame; class Window; } namespace ui { class ElementBase { public: typedef std::tr1::function slot_type; ElementBase() : m_frame(NULL), m_focus(false) {} virtual ~ElementBase() {} bool is_active() const { return m_frame != NULL; } input::Bindings& bindings() { return m_bindings; } virtual void activate(display::Frame* frame, bool focus = true) = 0; virtual void disable() = 0; void slot_exit(const slot_type& s) { m_slot_exit = s; } void mark_dirty(); protected: display::Frame* m_frame; bool m_focus; input::Bindings m_bindings; slot_type m_slot_exit; }; } #endif rtorrent-0.9.6/src/ui/element_chunks_seen.cc000066400000000000000000000117341257211462100211450ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "display/window_download_chunks_seen.h" #include "input/manager.h" #include "control.h" #include "element_chunks_seen.h" namespace ui { ElementChunksSeen::ElementChunksSeen(core::Download* d) : m_download(d), m_window(NULL), m_focus(0) { m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementChunksSeen::receive_next, this); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementChunksSeen::receive_prev, this); m_bindings[KEY_NPAGE] = std::tr1::bind(&ElementChunksSeen::receive_pagenext, this); m_bindings[KEY_PPAGE] = std::tr1::bind(&ElementChunksSeen::receive_pageprev, this); } void ElementChunksSeen::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementChunksSeen::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_window = new WChunksSeen(m_download, &m_focus); m_window->set_active(true); m_frame = frame; m_frame->initialize_window(m_window); } void ElementChunksSeen::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementChunksSeen::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } display::Window* ElementChunksSeen::window() { return m_window; } // void // ElementChunksSeen::receive_disable() { // if (m_window == NULL) // throw std::logic_error("ui::ElementChunksSeen::receive_disable(...) called on a disabled object"); // if (m_download->download()->tracker(m_focus).is_enabled()) // m_download->download()->tracker(m_focus).disable(); // else // m_download->download()->tracker(m_focus).enable(); // m_window->mark_dirty(); // } void ElementChunksSeen::receive_next() { if (m_window == NULL) throw torrent::internal_error("ui::ElementChunksSeen::receive_next(...) called on a disabled object"); if (++m_focus > m_window->max_focus()) m_focus = 0; m_window->mark_dirty(); } void ElementChunksSeen::receive_prev() { if (m_window == NULL) throw torrent::internal_error("ui::ElementChunksSeen::receive_prev(...) called on a disabled object"); if (m_focus > 0) --m_focus; else m_focus = m_window->max_focus(); m_window->mark_dirty(); } void ElementChunksSeen::receive_pagenext() { if (m_window == NULL) throw torrent::internal_error("ui::ElementChunksSeen::receive_pagenext(...) called on a disabled object"); unsigned int visible = m_window->height() - 1; unsigned int maxFocus = m_window->max_focus(); if (maxFocus == 0 || m_focus == maxFocus) m_focus = 0; else if (m_focus + visible / 2 < maxFocus) m_focus += visible / 2; else m_focus = maxFocus; m_window->mark_dirty(); } void ElementChunksSeen::receive_pageprev() { if (m_window == NULL) throw torrent::internal_error("ui::ElementChunksSeen::receive_pageprev(...) called on a disabled object"); unsigned int visible = m_window->height() - 1; unsigned int maxFocus = m_window->max_focus(); if (m_focus > visible / 2) m_focus -= visible / 2; else if (maxFocus > 0 && m_focus == 0) m_focus = maxFocus; else m_focus = 0; m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_chunks_seen.h000066400000000000000000000047071257211462100210110ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_CHUNKS_SEEN_H #define RTORRENT_UI_ELEMENT_CHUNKS_SEEN_H #include "core/download.h" #include "element_base.h" class Control; namespace display { class WindowDownloadChunksSeen; } namespace ui { class ElementChunksSeen : public ElementBase { public: typedef display::WindowDownloadChunksSeen WChunksSeen; ElementChunksSeen(core::Download* d); void activate(display::Frame* frame, bool focus = true); void disable(); display::Window* window(); private: // void receive_disable(); void receive_next(); void receive_prev(); void receive_pagenext(); void receive_pageprev(); core::Download* m_download; WChunksSeen* m_window; unsigned int m_focus; }; } #endif rtorrent-0.9.6/src/ui/element_download_list.cc000066400000000000000000000204111257211462100214720ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "core/download.h" #include "core/manager.h" #include "core/view.h" #include "core/view_manager.h" #include "display/frame.h" #include "display/manager.h" #include "input/manager.h" #include "rpc/parse_commands.h" #include "control.h" #include "element_download_list.h" namespace ui { ElementDownloadList::ElementDownloadList() : m_window(NULL), m_view(NULL) { receive_change_view("main"); if (m_view == NULL) throw torrent::internal_error("View \"main\" must be present to initialize the main display."); m_bindings['\x13'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "d.start="); m_bindings['\x04'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "branch=d.state=,d.stop=,d.erase="); m_bindings['\x0B'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "d.ignore_commands.set=1; d.stop=; d.close="); m_bindings['\x12'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "d.complete.set=0; d.check_hash="); m_bindings['\x05'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "f.multicall=,f.set_create_queued=0,f.set_resize_queued=0; print=\"Queued create/resize of files in torrent.\""); m_bindings['+'] = std::tr1::bind(&ElementDownloadList::receive_next_priority, this); m_bindings['-'] = std::tr1::bind(&ElementDownloadList::receive_prev_priority, this); m_bindings['T'-'@']= std::tr1::bind(&ElementDownloadList::receive_cycle_throttle, this); m_bindings['I'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "branch=d.ignore_commands=," "{d.ignore_commands.set=0, print=\"Torrent set to heed commands.\"}," "{d.ignore_commands.set=1, print=\"Torrent set to ignore commands.\"}"); m_bindings['B'-'@']= std::tr1::bind(&ElementDownloadList::receive_command, this, "branch=d.is_active=," "{print=\"Cannot enable initial seeding on an active download.\"}," "{d.connection_seed.set=initial_seed, print=\"Enabled initial seeding for the selected download.\"}"); m_bindings['U'] = std::tr1::bind(&ElementDownloadList::receive_command, this, "d.delete_tied=; print=\"Cleared tied to file association for the selected download.\""); // These should also be commands. m_bindings['1'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "main"); m_bindings['2'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "name"); m_bindings['3'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "started"); m_bindings['4'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "stopped"); m_bindings['5'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "complete"); m_bindings['6'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "incomplete"); m_bindings['7'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "hashing"); m_bindings['8'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "seeding"); m_bindings['9'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "leeching"); m_bindings['0'] = std::tr1::bind(&ElementDownloadList::receive_change_view, this, "active"); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementDownloadList::receive_prev, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementDownloadList::receive_next, this); } void ElementDownloadList::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementDownloadList::activate(...) is_active()."); control->input()->push_back(&m_bindings); m_window = new WDownloadList(); m_window->set_active(true); m_window->set_view(m_view); m_frame = frame; m_frame->initialize_window(m_window); } void ElementDownloadList::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementDownloadList::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } void ElementDownloadList::set_view(core::View* l) { m_view = l; m_view->sort(); if (m_window == NULL) return; m_window->set_view(l); m_window->mark_dirty(); } void ElementDownloadList::receive_command(const char* cmd) { try { if (m_view->focus() == m_view->end_visible()) rpc::parse_command_multiple(rpc::make_target(), cmd, cmd + strlen(cmd)); else rpc::parse_command_multiple(rpc::make_target(*m_view->focus()), cmd, cmd + strlen(cmd)); m_view->set_last_changed(); } catch (torrent::input_error& e) { lt_log_print(torrent::LOG_WARN, "Command failed: %s", e.what()); return; } } void ElementDownloadList::receive_next() { m_view->next_focus(); m_view->set_last_changed(); } void ElementDownloadList::receive_prev() { m_view->prev_focus(); m_view->set_last_changed(); } void ElementDownloadList::receive_next_priority() { if (m_view->focus() == m_view->end_visible()) return; (*m_view->focus())->set_priority((*m_view->focus())->priority() + 1); m_window->mark_dirty(); } void ElementDownloadList::receive_prev_priority() { if (m_view->focus() == m_view->end_visible()) return; (*m_view->focus())->set_priority((*m_view->focus())->priority() - 1); m_window->mark_dirty(); } void ElementDownloadList::receive_cycle_throttle() { if (m_view->focus() == m_view->end_visible()) return; core::Download* download = *m_view->focus(); if (download->is_active()) { lt_log_print(torrent::LOG_TORRENT_WARN, "Cannot change throttle on active download."); return; } core::ThrottleMap::const_iterator itr = control->core()->throttles().find(download->bencode()->get_key("rtorrent").get_key_string("throttle_name")); if (itr == control->core()->throttles().end()) itr = control->core()->throttles().begin(); else ++itr; download->set_throttle_name(itr == control->core()->throttles().end() ? std::string() : itr->first); m_window->mark_dirty(); } void ElementDownloadList::receive_change_view(const std::string& name) { core::ViewManager::iterator itr = control->view_manager()->find(name); if (itr == control->view_manager()->end()) { control->core()->push_log_std("Could not find view \"" + name + "\"."); return; } set_view(*itr); } } rtorrent-0.9.6/src/ui/element_download_list.h000066400000000000000000000053301257211462100213370ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_DOWNLOAD_LIST_H #define RTORRENT_UI_ELEMENT_DOWNLOAD_LIST_H #include "core/download_list.h" #include "display/window_download_list.h" #include "element_base.h" class Control; namespace core { class View; } namespace ui { class ElementDownloadList : public ElementBase { public: typedef display::WindowDownloadList WDownloadList; ElementDownloadList(); void activate(display::Frame* frame, bool focus = true); void disable(); core::View* view() { return m_view; } void set_view(core::View* l); void receive_command(const char* cmd); void receive_next(); void receive_prev(); void receive_stop_download(); void receive_close_download(); void receive_next_priority(); void receive_prev_priority(); void receive_cycle_throttle(); void receive_change_view(const std::string& name); private: WDownloadList* m_window; core::View* m_view; }; } #endif rtorrent-0.9.6/src/ui/element_file_list.cc000066400000000000000000000206551257211462100206140ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include "display/frame.h" #include "display/manager.h" #include "display/text_element_string.h" #include "display/window_file_list.h" #include "input/manager.h" #include "control.h" #include "element_file_list.h" #include "element_text.h" namespace ui { ElementFileList::ElementFileList(core::Download* d) : m_download(d), m_state(DISPLAY_MAX_SIZE), m_window(NULL), m_elementInfo(NULL), m_selected(iterator(d->download()->file_list()->begin())), m_collapsed(false) { m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::tr1::bind(&ElementFileList::receive_select, this); m_bindings[' '] = std::tr1::bind(&ElementFileList::receive_priority, this); m_bindings['*'] = std::tr1::bind(&ElementFileList::receive_change_all, this); m_bindings['/'] = std::tr1::bind(&ElementFileList::receive_collapse, this); m_bindings[KEY_NPAGE] = std::tr1::bind(&ElementFileList::receive_pagenext, this); m_bindings[KEY_PPAGE] = std::tr1::bind(&ElementFileList::receive_pageprev, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementFileList::receive_next, this); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementFileList::receive_prev, this); } inline ElementText* element_file_list_create_info() { using namespace display::helpers; ElementText* element = new ElementText(rpc::make_target()); element->set_column(1); element->set_interval(1); element->push_back("File info:"); element->push_back(""); element->push_column("Filename:", te_command("fi.filename_last=")); element->push_back(""); element->push_column("Size:", te_command("if=$fi.is_file=,$convert.xb=$f.size_bytes=,---")); element->push_column("Chunks:", te_command("cat=$f.completed_chunks=,\" / \",$f.size_chunks=")); element->push_column("Range:", te_command("cat=$f.range_first=,\" - \",$f.range_second=")); element->push_back(""); element->push_column("Queued:", te_command("cat=\"$if=$f.is_create_queued=,create\",\" \",\"$if=$f.is_resize_queued=,resize\"")); element->push_column("Prioritize:", te_command("cat=\"$if=$f.prioritize_first=,first\",\" \",\"$if=$f.prioritize_last=,last\"")); element->set_column_width(element->column_width() + 1); return element; } void ElementFileList::activate(display::Frame* frame, bool focus) { if (m_window != NULL) throw torrent::internal_error("ui::ElementFileList::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_window = new WFileList(this); m_window->set_active(true); m_window->set_focused(focus); m_elementInfo = element_file_list_create_info(); m_elementInfo->slot_exit(std::tr1::bind(&ElementFileList::activate_display, this, DISPLAY_LIST)); m_elementInfo->set_target(rpc::make_target(&m_selected)); m_frame = frame; activate_display(DISPLAY_LIST); } void ElementFileList::disable() { if (m_window == NULL) throw torrent::internal_error("ui::ElementFileList::disable(...) !is_active()."); control->input()->erase(&m_bindings); activate_display(DISPLAY_MAX_SIZE); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; delete m_elementInfo; m_elementInfo = NULL; } void ElementFileList::activate_display(Display display) { if (display == m_state) return; switch (m_state) { case DISPLAY_INFO: m_elementInfo->disable(); break; case DISPLAY_LIST: m_window->set_active(false); m_frame->clear(); break; case DISPLAY_MAX_SIZE: break; } m_state = display; switch (m_state) { case DISPLAY_INFO: m_elementInfo->activate(m_frame, true); break; case DISPLAY_LIST: m_window->set_active(true); m_frame->initialize_window(m_window); break; case DISPLAY_MAX_SIZE: break; } control->display()->adjust_layout(); } void ElementFileList::receive_next() { torrent::FileList* fl = m_download->download()->file_list(); if (is_collapsed()) m_selected.forward_current_depth(); else m_selected++; if (m_selected == iterator(fl->end())) m_selected = iterator(fl->begin()); update_itr(); } void ElementFileList::receive_prev() { torrent::FileList* fl = m_download->download()->file_list(); if (m_selected == iterator(fl->begin())) m_selected = iterator(fl->end()); if (is_collapsed()) m_selected.backward_current_depth(); else m_selected--; update_itr(); } void ElementFileList::receive_pagenext() { torrent::FileList* fl = m_download->download()->file_list(); if (m_selected == --iterator(fl->end())) { m_selected = iterator(fl->begin()); } else { m_selected = rak::advance_forward(m_selected, iterator(fl->end()), (m_window->height() - 1) / 2); if (m_selected == iterator(fl->end())) m_selected = --iterator(fl->end()); } update_itr(); } void ElementFileList::receive_pageprev() { if (m_window == NULL) return; torrent::FileList* fl = m_download->download()->file_list(); if (m_selected == iterator(fl->begin())) m_selected = --iterator(fl->end()); else m_selected = rak::advance_backward(m_selected, iterator(fl->begin()), (m_window->height() - 1) / 2); update_itr(); } void ElementFileList::receive_select() { if (m_window == NULL || m_state != DISPLAY_LIST) return; if (is_collapsed() && !m_selected.is_file()) { torrent::FileList* fl = m_download->download()->file_list(); m_selected++; if (m_selected == iterator(fl->end())) m_selected = iterator(fl->begin()); m_window->mark_dirty(); } else { activate_display(DISPLAY_INFO); } } void ElementFileList::receive_priority() { if (m_window == NULL) return; torrent::priority_t priority = torrent::priority_t((m_selected.file()->priority() + 2) % 3); iterator first = m_selected; iterator last = m_selected; last.forward_current_depth(); while (first != last) { if (first.is_file()) first.file()->set_priority(priority); first++; } m_download->download()->update_priorities(); update_itr(); } void ElementFileList::receive_change_all() { if (m_window == NULL) return; torrent::FileList* fl = m_download->download()->file_list(); torrent::priority_t priority = torrent::priority_t((m_selected.file()->priority() + 2) % 3); for (torrent::FileList::iterator itr = fl->begin(), last = fl->end(); itr != last; ++itr) (*itr)->set_priority(priority); m_download->download()->update_priorities(); update_itr(); } void ElementFileList::receive_collapse() { if (m_window == NULL) return; set_collapsed(!is_collapsed()); m_window->mark_dirty(); } void ElementFileList::update_itr() { m_window->mark_dirty(); m_elementInfo->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_file_list.h000066400000000000000000000063231257211462100204520ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_FILE_LIST_H #define RTORRENT_UI_ELEMENT_FILE_LIST_H #include #include #include "core/download.h" #include "element_base.h" namespace display { class WindowFileList; } namespace ui { class ElementText; class ElementFileList : public ElementBase { public: typedef display::WindowFileList WFileList; typedef torrent::FileListIterator iterator; typedef enum { DISPLAY_LIST, DISPLAY_INFO, DISPLAY_MAX_SIZE } Display; ElementFileList(core::Download* d); void activate(display::Frame* frame, bool focus = true); void disable(); void activate_display(Display display); bool is_collapsed() const { return m_collapsed; } void set_collapsed(bool s) { m_collapsed = s; } iterator selected() const { return m_selected; } core::Download* download() const { return m_download; } private: void receive_next(); void receive_prev(); void receive_pagenext(); void receive_pageprev(); void receive_select(); void receive_priority(); void receive_change_all(); void receive_collapse(); void update_itr(); core::Download* m_download; Display m_state; WFileList* m_window; ElementText* m_elementInfo; // Change to unsigned, please. iterator m_selected; bool m_collapsed; }; } #endif rtorrent-0.9.6/src/ui/element_log_complete.cc000066400000000000000000000061151257211462100213060ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "display/frame.h" #include "display/manager.h" #include "display/window_log_complete.h" #include "input/manager.h" #include "control.h" #include "element_log_complete.h" namespace ui { ElementLogComplete::ElementLogComplete(torrent::log_buffer* l) : m_window(NULL), m_log(l) { unsigned int signal_index = torrent::main_thread()->signal_bitfield()->add_signal(std::tr1::bind(&ElementLogComplete::received_update, this)); m_log->lock_and_set_update_slot(std::tr1::bind(&torrent::thread_base::send_event_signal, torrent::main_thread(), signal_index, false)); } void ElementLogComplete::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementLogComplete::activate(...) is_active()."); control->input()->push_back(&m_bindings); m_window = new WLogComplete(m_log); m_window->set_active(true); m_frame = frame; m_frame->initialize_window(m_window); } void ElementLogComplete::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementLogComplete::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } display::Window* ElementLogComplete::window() { return m_window; } void ElementLogComplete::received_update() { if (m_window != NULL) m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_log_complete.h000066400000000000000000000044121257211462100211460ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_LOG_COMPLETE_H #define RTORRENT_UI_ELEMENT_LOG_COMPLETE_H #include #include "element_base.h" class Control; namespace display { class WindowLogComplete; } namespace ui { class ElementLogComplete : public ElementBase { public: typedef display::WindowLogComplete WLogComplete; ElementLogComplete(torrent::log_buffer* l); void activate(display::Frame* frame, bool focus = true); void disable(); display::Window* window(); private: void received_update(); WLogComplete* m_window; torrent::log_buffer* m_log; }; } #endif rtorrent-0.9.6/src/ui/element_menu.cc000066400000000000000000000117021257211462100175770ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "display/window_text.h" #include "display/text_element_string.h" #include "input/manager.h" #include "control.h" #include "element_menu.h" namespace ui { inline void ElementMenu::focus_entry(size_type idx) { if (idx >= size()) return; if (m_focus) base_type::operator[](idx).m_element->set_attributes(display::Attributes::a_reverse); else base_type::operator[](idx).m_element->set_attributes(display::Attributes::a_bold); } inline void ElementMenu::unfocus_entry(size_type idx) { if (idx >= size()) return; base_type::operator[](idx).m_element->set_attributes(display::Attributes::a_normal); } ElementMenu::ElementMenu() : m_window(new WindowText(rpc::make_target(), 2)), m_entry(entry_invalid) { // Move bindings into a function that defines default bindings. m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::tr1::bind(&ElementMenu::entry_select, this); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementMenu::entry_prev, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementMenu::entry_next, this); } ElementMenu::~ElementMenu() { delete m_window; } void ElementMenu::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementMenu::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_focus = focus; focus_entry(m_entry); m_frame = frame; m_frame->initialize_window(m_window); m_window->set_active(true); } void ElementMenu::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementMenu::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; m_window->set_active(false); } void ElementMenu::push_back(const char* name, const slot_type& slotSelect, const slot_type& slotFocus) { iterator entry = base_type::insert(end(), value_type()); entry->m_element = new display::TextElementCString(name); entry->m_slotSelect = slotSelect; entry->m_slotFocus = slotFocus; m_window->push_back(NULL); m_window->push_back(entry->m_element); // For the moment, don't bother doing anything if the window is // already active. m_window->mark_dirty(); } void ElementMenu::entry_next() { if (empty() || (size() == 1 && m_entry == 0)) return; unfocus_entry(m_entry); if (++m_entry >= size()) m_entry = 0; focus_entry(m_entry); base_type::operator[](m_entry).m_slotFocus(); m_window->mark_dirty(); } void ElementMenu::entry_prev() { if (empty() || (size() == 1 && m_entry == 0)) return; unfocus_entry(m_entry); if (--m_entry >= size()) m_entry = size() - 1; focus_entry(m_entry); base_type::operator[](m_entry).m_slotFocus(); m_window->mark_dirty(); } void ElementMenu::entry_select() { if (m_entry >= size()) return; base_type::operator[](m_entry).m_slotSelect(); m_window->mark_dirty(); } void ElementMenu::set_entry(size_type idx, bool triggerSlot) { if (idx == m_entry) return; unfocus_entry(m_entry); m_entry = idx; focus_entry(m_entry); if (triggerSlot) base_type::operator[](m_entry).m_slotFocus(); m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_menu.h000066400000000000000000000070311257211462100174410ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_MENU_H #define RTORRENT_UI_ELEMENT_MENU_H #include "core/download.h" #include "element_base.h" namespace display { class WindowText; class TextElementStringBase; } namespace ui { struct ElementMenuEntry { display::TextElementStringBase* m_element; std::tr1::function m_slotFocus; std::tr1::function m_slotSelect; }; class ElementMenu : public ElementBase, public std::vector { public: typedef std::vector base_type; typedef display::WindowText WindowText; typedef uint32_t size_type; typedef base_type::value_type value_type; typedef base_type::reference reference; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; typedef base_type::reverse_iterator reverse_iterator; using base_type::empty; using base_type::size; static const size_type entry_invalid = ~size_type(); ElementMenu(); ~ElementMenu(); void activate(display::Frame* frame, bool focus = false); void disable(); // Consider returning a pointer that can be used to manipulate // entries, f.ex disabling them. // The c string is not copied nor freed, so it should be constant. void push_back(const char* name, const slot_type& slotSelect = slot_type(), const slot_type& slotFocus = slot_type()); void entry_next(); void entry_prev(); void entry_select(); void set_entry(size_type idx, bool triggerSlot); void set_entry_trigger(size_type idx) { set_entry(idx, true); } private: void focus_entry(size_type idx); void unfocus_entry(size_type idx); WindowText* m_window; size_type m_entry; }; } #endif rtorrent-0.9.6/src/ui/element_peer_list.cc000066400000000000000000000203031257211462100206160ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "display/frame.h" #include "display/manager.h" #include "display/text_element_string.h" #include "display/utils.h" #include "display/window_peer_list.h" #include "input/manager.h" #include "control.h" #include "element_peer_list.h" #include "element_text.h" namespace ui { ElementPeerList::ElementPeerList(core::Download* d) : m_download(d), m_state(DISPLAY_MAX_SIZE) { m_listItr = m_list.end(); std::for_each(m_download->download()->connection_list()->begin(), m_download->download()->connection_list()->end(), rak::bind1st(std::mem_fun(&PList::push_back), &m_list)); torrent::ConnectionList* connection_list = m_download->download()->connection_list(); m_peer_connected = connection_list->signal_connected().insert(connection_list->signal_connected().end(), tr1::bind(&ElementPeerList::receive_peer_connected, this, tr1::placeholders::_1)); m_peer_disconnected = connection_list->signal_disconnected().insert(connection_list->signal_disconnected().end(), tr1::bind(&ElementPeerList::receive_peer_disconnected, this, tr1::placeholders::_1)); m_windowList = new display::WindowPeerList(m_download, &m_list, &m_listItr); m_elementInfo = create_info(); m_elementInfo->slot_exit(std::tr1::bind(&ElementPeerList::activate_display, this, DISPLAY_LIST)); m_bindings['k'] = std::tr1::bind(&ElementPeerList::receive_disconnect_peer, this); m_bindings['*'] = std::tr1::bind(&ElementPeerList::receive_snub_peer, this); m_bindings['B'] = std::tr1::bind(&ElementPeerList::receive_ban_peer, this); m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::tr1::bind(&ElementPeerList::activate_display, this, DISPLAY_INFO); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementPeerList::receive_prev, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementPeerList::receive_next, this); } ElementPeerList::~ElementPeerList() { torrent::ConnectionList* connection_list = m_download->download()->connection_list(); connection_list->signal_connected().erase(m_peer_connected); connection_list->signal_disconnected().erase(m_peer_disconnected); delete m_windowList; delete m_elementInfo; } inline ElementText* ElementPeerList::create_info() { using namespace display::helpers; ElementText* element = new ElementText(rpc::make_target()); element->set_column(1); element->set_interval(1); element->push_back("Peer info:"); element->push_back(""); element->push_column("Address:", te_command("cat=$p.address=,:,$p.port=")); element->push_column("Id:", te_command("p.id_html=")); element->push_column("Client:", te_command("p.client_version=")); element->push_column("Options:", te_command("p.options_str=")); element->push_column("Connected:", te_command("if=$p.is_incoming=,incoming,outgoing")); element->push_column("Encrypted:", te_command("if=$p.is_encrypted=,yes,$p.is_obfuscated=,handshake,no")); element->push_back(""); element->push_column("Snubbed:", te_command("if=$p.is_snubbed=,yes,no")); element->push_column("Done:", te_command("p.completed_percent=")); element->push_column("Rate:", te_command("cat=$convert.kb=$p.up_rate=,\\ KB\\ ,$convert.kb=$p.down_rate=,\\ KB")); element->push_column("Total:", te_command("cat=$convert.kb=$p.up_total=,\\ KB\\ ,$convert.kb=$p.down_total=,\\ KB")); element->set_column_width(element->column_width() + 1); element->set_error_handler(new display::TextElementCString("No peer selected.")); return element; } void ElementPeerList::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementPeerList::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_frame = frame; m_focus = focus; activate_display(DISPLAY_LIST); } void ElementPeerList::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementPeerList::disable(...) !is_active()."); control->input()->erase(&m_bindings); activate_display(DISPLAY_MAX_SIZE); m_frame->clear(); m_frame = NULL; } void ElementPeerList::activate_display(Display display) { if (display == m_state) return; switch (m_state) { case DISPLAY_INFO: m_elementInfo->disable(); break; case DISPLAY_LIST: m_windowList->set_active(false); m_frame->clear(); break; case DISPLAY_MAX_SIZE: break; } m_state = display; switch (m_state) { case DISPLAY_INFO: m_elementInfo->activate(m_frame, true); break; case DISPLAY_LIST: m_windowList->set_active(true); m_frame->initialize_window(m_windowList); break; case DISPLAY_MAX_SIZE: break; } control->display()->adjust_layout(); } void ElementPeerList::receive_next() { if (m_listItr != m_list.end()) ++m_listItr; else m_listItr = m_list.begin(); update_itr(); } void ElementPeerList::receive_prev() { if (m_listItr != m_list.begin()) --m_listItr; else m_listItr = m_list.end(); update_itr(); } void ElementPeerList::receive_disconnect_peer() { if (m_listItr == m_list.end()) return; m_download->connection_list()->erase(*m_listItr, 0); } void ElementPeerList::receive_peer_connected(torrent::Peer* p) { m_list.push_back(p); } void ElementPeerList::receive_peer_disconnected(torrent::Peer* p) { PList::iterator itr = std::find(m_list.begin(), m_list.end(), p); if (itr == m_list.end()) throw torrent::internal_error("ElementPeerList::receive_peer_disconnected(...) itr == m_list.end()."); if (itr == m_listItr) m_listItr = m_list.erase(itr); else m_list.erase(itr); update_itr(); } void ElementPeerList::receive_snub_peer() { if (m_listItr == m_list.end()) return; (*m_listItr)->set_snubbed(!(*m_listItr)->is_snubbed()); update_itr(); } void ElementPeerList::receive_ban_peer() { if (m_listItr == m_list.end()) return; (*m_listItr)->set_banned(true); m_download->download()->connection_list()->erase(*m_listItr, torrent::ConnectionList::disconnect_quick); update_itr(); } void ElementPeerList::update_itr() { m_windowList->mark_dirty(); m_elementInfo->set_target(m_listItr != m_list.end() ? rpc::make_target(*m_listItr) : rpc::make_target()); } } rtorrent-0.9.6/src/ui/element_peer_list.h000066400000000000000000000060261257211462100204660ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_PEER_LIST_H #define RTORRENT_UI_ELEMENT_PEER_LIST_H #include #include "core/download.h" #include "element_base.h" namespace ui { class ElementText; class ElementPeerList : public ElementBase { public: typedef std::list PList; typedef torrent::ConnectionList::signal_peer_type::iterator signal_connection; typedef enum { DISPLAY_LIST, DISPLAY_INFO, DISPLAY_MAX_SIZE } Display; ElementPeerList(core::Download* d); ~ElementPeerList(); void activate(display::Frame* frame, bool focus = true); void disable(); void activate_display(Display display); private: inline ElementText* create_info(); void receive_next(); void receive_prev(); void receive_disconnect_peer(); void receive_peer_connected(torrent::Peer* p); void receive_peer_disconnected(torrent::Peer* p); void receive_snub_peer(); void receive_ban_peer(); void update_itr(); core::Download* m_download; Display m_state; display::Window* m_windowList; ElementText* m_elementInfo; PList m_list; PList::iterator m_listItr; signal_connection m_peer_connected; signal_connection m_peer_disconnected; }; } #endif rtorrent-0.9.6/src/ui/element_string_list.cc000066400000000000000000000055751257211462100212070ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "input/manager.h" #include "control.h" #include "element_string_list.h" namespace ui { ElementStringList::ElementStringList() : m_window(NULL) { } void ElementStringList::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementStringList::activate(...) is_active()."); lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: activate"); control->input()->push_back(&m_bindings); m_window = new WStringList(); m_window->set_active(true); m_frame = frame; m_frame->initialize_window(m_window); } void ElementStringList::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementStringList::disable(...) !is_active()."); lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: deactivate"); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } void ElementStringList::next_screen() { if (m_window == NULL) return; if (m_window->get_draw_end() != m_list.end()) m_window->set_range(m_window->get_draw_end(), m_list.end()); else m_window->set_range(m_list.begin(), m_list.end()); m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_string_list.h000066400000000000000000000066031257211462100210420ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_STRING_LIST_H #define RTORRENT_UI_ELEMENT_STRING_LIST_H #include #include #include #include #include #include "element_base.h" #include "display/window_string_list.h" class Control; namespace ui { class ElementStringList : public ElementBase { public: typedef display::WindowStringList WStringList; typedef std::list List; ElementStringList(); void activate(display::Frame* frame, bool focus = true); void disable(); display::Window* window() { return m_window; } template void set_range(InputIter first, InputIter last) { m_list.clear(); while (first != last) m_list.push_back(*(first++)); if (m_window != NULL) { lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: set range (visible)"); m_window->set_range(m_list.begin(), m_list.end()); m_window->mark_dirty(); } else { lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: set range (hidden)"); } } // A hack, clean this up. template void set_range_dirent(InputIter first, InputIter last) { m_list.clear(); while (first != last) m_list.push_back((first++)->d_name); if (m_window != NULL) { lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: set dirent range (visible)"); m_window->set_range(m_list.begin(), m_list.end()); m_window->mark_dirty(); } else { lt_log_print(torrent::LOG_UI_EVENTS, "element_string_list: set dirent range (hidden)"); } } void next_screen(); private: WStringList* m_window; List m_list; }; } #endif rtorrent-0.9.6/src/ui/element_text.cc000066400000000000000000000137501257211462100176240ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "display/window_text.h" #include "display/text_element_list.h" #include "input/manager.h" #include "control.h" #include "element_text.h" namespace ui { ElementText::ElementText(rpc::target_type target) : m_window(new WindowText(target)), m_column(0), m_columnWidth(0) { // Move bindings into a function that defines default bindings. m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); // m_bindings[KEY_UP] = std::tr1::bind(this, &ElementText::entry_prev); // m_bindings[KEY_DOWN] = std::tr1::bind(this, &ElementText::entry_next); // m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::tr1::bind(this, &ElementText::entry_select); } ElementText::~ElementText() { delete m_window; } void ElementText::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementText::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_focus = focus; m_frame = frame; m_frame->initialize_window(m_window); m_window->set_active(true); } void ElementText::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementText::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; m_window->set_active(false); } void ElementText::push_back(text_element_wrapper entry) { m_window->push_back(entry.m_element); // For the moment, don't bother doing anything if the window is // already active. m_window->mark_dirty(); } void ElementText::push_column(text_element_wrapper entry1, text_element_wrapper entry2) { m_columnWidth = std::max(entry1.m_element->max_length(), m_columnWidth); display::TextElementList* list = new display::TextElementList; list->set_column(m_column); list->set_column_width(&m_columnWidth); list->push_back(entry1.m_element); list->push_back(entry2.m_element); push_back(list); } void ElementText::push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3) { m_columnWidth = std::max(entry1.m_element->max_length(), m_columnWidth); display::TextElementList* list = new display::TextElementList; list->set_column(m_column); list->set_column_width(&m_columnWidth); list->push_back(entry1.m_element); list->push_back(entry2.m_element); list->push_back(entry3.m_element); push_back(list); } void ElementText::push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4) { m_columnWidth = std::max(entry1.m_element->max_length(), m_columnWidth); display::TextElementList* list = new display::TextElementList; list->set_column(m_column); list->set_column_width(&m_columnWidth); list->push_back(entry1.m_element); list->push_back(entry2.m_element); list->push_back(entry3.m_element); list->push_back(entry4.m_element); push_back(list); } void ElementText::push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4, text_element_wrapper entry5) { m_columnWidth = std::max(entry1.m_element->max_length(), m_columnWidth); display::TextElementList* list = new display::TextElementList; list->set_column(m_column); list->set_column_width(&m_columnWidth); list->push_back(entry1.m_element); list->push_back(entry2.m_element); list->push_back(entry3.m_element); list->push_back(entry4.m_element); list->push_back(entry5.m_element); push_back(list); } void ElementText::push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4, text_element_wrapper entry5, text_element_wrapper entry6) { m_columnWidth = std::max(entry1.m_element->max_length(), m_columnWidth); display::TextElementList* list = new display::TextElementList; list->set_column(m_column); list->set_column_width(&m_columnWidth); list->push_back(entry1.m_element); list->push_back(entry2.m_element); list->push_back(entry3.m_element); list->push_back(entry4.m_element); list->push_back(entry5.m_element); list->push_back(entry6.m_element); push_back(list); } } rtorrent-0.9.6/src/ui/element_text.h000066400000000000000000000110451257211462100174610ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_TEXT_H #define RTORRENT_UI_ELEMENT_TEXT_H #include "core/download.h" #include "display/text_element_string.h" #include "display/window_text.h" #include "element_base.h" namespace display { class TextElement; } namespace ui { struct text_element_wrapper; class ElementText : public ElementBase { public: typedef display::WindowText WindowText; typedef uint32_t size_type; typedef uint32_t extent_type; ElementText(rpc::target_type target); ~ElementText(); rpc::target_type target() const { return m_window->target(); } void set_target(rpc::target_type target) { m_window->set_target(target); m_window->mark_dirty(); } uint32_t interval() const { return m_window->interval(); } void set_interval(uint32_t i) { m_window->set_interval(i); m_window->mark_dirty(); } void activate(display::Frame* frame, bool focus = false); void disable(); void mark_dirty() { m_window->mark_dirty(); } // Consider returning a pointer that can be used to manipulate // entries, f.ex disabling them. void push_back(text_element_wrapper entry); void push_column(text_element_wrapper entry1, text_element_wrapper entry2); void push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3); void push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4); void push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4, text_element_wrapper entry5); void push_column(text_element_wrapper entry1, text_element_wrapper entry2, text_element_wrapper entry3, text_element_wrapper entry4, text_element_wrapper entry5, text_element_wrapper entry6); void set_column(unsigned int column) { m_column = column; } void set_error_handler(display::TextElement* t) { m_window->set_error_handler(t); } extent_type column_width() const { return m_columnWidth; } void set_column_width(extent_type width) { m_columnWidth = width; } private: WindowText* m_window; unsigned int m_column; extent_type m_columnWidth; }; struct text_element_wrapper { text_element_wrapper(const char* cstr) : m_element(new display::TextElementCString(cstr)) {} text_element_wrapper(display::TextElement* element) : m_element(element) {} display::TextElement* m_element; }; } #endif rtorrent-0.9.6/src/ui/element_tracker_list.cc000066400000000000000000000113041257211462100213170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "display/frame.h" #include "display/window_tracker_list.h" #include "input/manager.h" #include "control.h" #include "element_tracker_list.h" namespace ui { ElementTrackerList::ElementTrackerList(core::Download* d) : m_download(d), m_window(NULL), m_focus(0) { m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[' '] = std::tr1::bind(&ElementTrackerList::receive_cycle_group, this); m_bindings['*'] = std::tr1::bind(&ElementTrackerList::receive_disable, this); m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::tr1::bind(&ElementTrackerList::receive_next, this); m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::tr1::bind(&ElementTrackerList::receive_prev, this); } void ElementTrackerList::activate(display::Frame* frame, bool focus) { if (m_window != NULL) throw torrent::internal_error("ui::ElementTrackerList::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_window = new WTrackerList(m_download, &m_focus); m_window->set_active(true); m_window->set_focused(focus); m_frame = frame; m_frame->initialize_window(m_window); } void ElementTrackerList::disable() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTrackerList::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } display::Window* ElementTrackerList::window() { return m_window; } void ElementTrackerList::receive_disable() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTrackerList::receive_disable(...) called on a disabled object"); torrent::Tracker* t = m_download->download()->tracker_list()->at(m_focus); if (t->is_enabled()) t->disable(); else t->enable(); m_window->mark_dirty(); } void ElementTrackerList::receive_next() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTrackerList::receive_next(...) called on a disabled object"); if (++m_focus >= m_download->download()->tracker_list()->size()) m_focus = 0; m_window->mark_dirty(); } void ElementTrackerList::receive_prev() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTrackerList::receive_prev(...) called on a disabled object"); if (m_download->download()->tracker_list()->size() == 0) return; if (m_focus != 0) --m_focus; else m_focus = m_download->download()->tracker_list()->size() - 1; m_window->mark_dirty(); } void ElementTrackerList::receive_cycle_group() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTrackerList::receive_group_cycle(...) called on a disabled object"); torrent::TrackerList* tl = m_download->tracker_list(); if (m_focus >= tl->size()) throw torrent::internal_error("ui::ElementTrackerList::receive_group_cycle(...) called with an invalid focus"); tl->cycle_group(tl->at(m_focus)->group()); m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_tracker_list.h000066400000000000000000000046711257211462100211720ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_TRACKER_LIST_H #define RTORRENT_UI_ELEMENT_TRACKER_LIST_H #include "core/download.h" #include "element_base.h" class Control; namespace display { class WindowTrackerList; } namespace ui { class ElementTrackerList : public ElementBase { public: typedef display::WindowTrackerList WTrackerList; ElementTrackerList(core::Download* d); void activate(display::Frame* frame, bool focus = true); void disable(); display::Window* window(); private: void receive_next(); void receive_prev(); void receive_disable(); void receive_cycle_group(); core::Download* m_download; WTrackerList* m_window; // Change to unsigned, please. unsigned int m_focus; }; } #endif rtorrent-0.9.6/src/ui/element_transfer_list.cc000066400000000000000000000120461257211462100215140ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include "display/frame.h" #include "display/window_download_transfer_list.h" #include "input/manager.h" #include "control.h" #include "element_transfer_list.h" namespace ui { ElementTransferList::ElementTransferList(core::Download* d) : m_download(d), m_window(NULL), m_focus(0) { m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::tr1::bind(&slot_type::operator(), &m_slot_exit); m_bindings[KEY_DOWN] = std::tr1::bind(&ElementTransferList::receive_next, this); m_bindings[KEY_UP] = std::tr1::bind(&ElementTransferList::receive_prev, this); m_bindings[KEY_NPAGE] = std::tr1::bind(&ElementTransferList::receive_pagenext, this); m_bindings[KEY_PPAGE] = std::tr1::bind(&ElementTransferList::receive_pageprev, this); } void ElementTransferList::activate(display::Frame* frame, bool focus) { if (is_active()) throw torrent::internal_error("ui::ElementTransferList::activate(...) is_active()."); if (focus) control->input()->push_back(&m_bindings); m_window = new WTransferList(m_download, &m_focus); m_window->set_active(true); m_frame = frame; m_frame->initialize_window(m_window); } void ElementTransferList::disable() { if (!is_active()) throw torrent::internal_error("ui::ElementTransferList::disable(...) !is_active()."); control->input()->erase(&m_bindings); m_frame->clear(); m_frame = NULL; delete m_window; m_window = NULL; } display::Window* ElementTransferList::window() { return m_window; } // void // ElementTransferList::receive_disable() { // if (m_window == NULL) // throw std::logic_error("ui::ElementTransferList::receive_disable(...) called on a disabled object"); // if (m_download->download()->tracker(m_focus).is_enabled()) // m_download->download()->tracker(m_focus).disable(); // else // m_download->download()->tracker(m_focus).enable(); // m_window->mark_dirty(); // } void ElementTransferList::receive_next() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTransferList::receive_next(...) called on a disabled object"); if (++m_focus > m_window->max_focus()) m_focus = 0; // m_window->mark_dirty(); } void ElementTransferList::receive_prev() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTransferList::receive_prev(...) called on a disabled object"); if (m_focus > 0) --m_focus; else m_focus = m_window->max_focus(); // m_window->mark_dirty(); } void ElementTransferList::receive_pagenext() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTransferList::receive_pagenext(...) called on a disabled object"); unsigned int visible = m_window->height() - 1; unsigned int scrollable = std::max(m_window->rows() - visible, 0); if (scrollable == 0 || m_focus == scrollable) m_focus = 0; else if (m_focus + visible / 2 < scrollable) m_focus += visible / 2; else m_focus = scrollable; // m_window->mark_dirty(); } void ElementTransferList::receive_pageprev() { if (m_window == NULL) throw torrent::internal_error("ui::ElementTransferList::receive_pageprev(...) called on a disabled object"); unsigned int visible = m_window->height() - 1; unsigned int scrollable = std::max(m_window->rows() - visible, 0); if (m_focus > visible / 2) m_focus -= visible / 2; else if (scrollable > 0 && m_focus == 0) m_focus = scrollable; else m_focus = 0; // m_window->mark_dirty(); } } rtorrent-0.9.6/src/ui/element_transfer_list.h000066400000000000000000000047251257211462100213630ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ELEMENT_TRANSFER_LIST_H #define RTORRENT_UI_ELEMENT_TRANSFER_LIST_H #include "core/download.h" #include "element_base.h" class Control; namespace display { class WindowDownloadTransferList; } namespace ui { class ElementTransferList : public ElementBase { public: typedef display::WindowDownloadTransferList WTransferList; ElementTransferList(core::Download* d); void activate(display::Frame* frame, bool focus = true); void disable(); display::Window* window(); private: // void receive_disable(); void receive_next(); void receive_prev(); void receive_pagenext(); void receive_pageprev(); core::Download* m_download; WTransferList* m_window; unsigned int m_focus; }; } #endif rtorrent-0.9.6/src/ui/root.cc000066400000000000000000000210011257211462100160760ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include "core/manager.h" #include "display/frame.h" #include "display/window_http_queue.h" #include "display/window_title.h" #include "display/window_input.h" #include "display/window_statusbar.h" #include "input/manager.h" #include "input/text_input.h" #include "rpc/parse_commands.h" #include "control.h" #include "download_list.h" #include "root.h" namespace ui { Root::Root() : m_control(NULL), m_downloadList(NULL), m_windowTitle(NULL), m_windowHttpQueue(NULL), m_windowInput(NULL), m_windowStatusbar(NULL) { } void Root::init(Control* c) { if (m_control != NULL) throw std::logic_error("Root::init() called twice on the same object"); m_control = c; m_windowTitle = new WTitle(); m_windowHttpQueue = new WHttpQueue(control->core()->http_queue()); m_windowInput = new WInput(); m_windowStatusbar = new WStatusbar(); m_downloadList = new DownloadList(); display::Frame* rootFrame = m_control->display()->root_frame(); rootFrame->initialize_row(5); rootFrame->frame(0)->initialize_window(m_windowTitle); rootFrame->frame(2)->initialize_window(m_windowHttpQueue); rootFrame->frame(3)->initialize_window(m_windowInput); rootFrame->frame(4)->initialize_window(m_windowStatusbar); m_windowTitle->set_active(true); m_windowStatusbar->set_active(true); m_windowStatusbar->set_bottom(true); setup_keys(); m_downloadList->activate(rootFrame->frame(1)); } void Root::cleanup() { if (m_control == NULL) throw std::logic_error("Root::cleanup() called twice on the same object"); if (m_downloadList->is_active()) m_downloadList->disable(); m_control->display()->root_frame()->clear(); delete m_downloadList; delete m_windowTitle; delete m_windowHttpQueue; delete m_windowInput; delete m_windowStatusbar; m_control->input()->erase(&m_bindings); m_control = NULL; } const char* Root::get_throttle_keys() { const std::string& keyLayout = rpc::call_command_string("keys.layout"); if (strcasecmp(keyLayout.c_str(), "azerty") == 0) return "qwQWsxSXdcDC"; else if (strcasecmp(keyLayout.c_str(), "qwertz") == 0) return "ayAYsxSXdcDC"; else if (strcasecmp(keyLayout.c_str(), "dvorak") == 0) return "a;A:oqOQejEJ"; else return "azAZsxSXdcDC"; } void Root::setup_keys() { m_control->input()->push_back(&m_bindings); const char* keys = get_throttle_keys(); m_bindings[keys[ 0]] = std::tr1::bind(&Root::adjust_up_throttle, this, 1); m_bindings[keys[ 1]] = std::tr1::bind(&Root::adjust_up_throttle, this, -1); m_bindings[keys[ 2]] = std::tr1::bind(&Root::adjust_down_throttle, this, 1); m_bindings[keys[ 3]] = std::tr1::bind(&Root::adjust_down_throttle, this, -1); m_bindings[keys[ 4]] = std::tr1::bind(&Root::adjust_up_throttle, this, 5); m_bindings[keys[ 5]] = std::tr1::bind(&Root::adjust_up_throttle, this, -5); m_bindings[keys[ 6]] = std::tr1::bind(&Root::adjust_down_throttle, this, 5); m_bindings[keys[ 7]] = std::tr1::bind(&Root::adjust_down_throttle, this, -5); m_bindings[keys[ 8]] = std::tr1::bind(&Root::adjust_up_throttle, this, 50); m_bindings[keys[ 9]] = std::tr1::bind(&Root::adjust_up_throttle, this, -50); m_bindings[keys[10]] = std::tr1::bind(&Root::adjust_down_throttle, this, 50); m_bindings[keys[11]] = std::tr1::bind(&Root::adjust_down_throttle, this, -50); m_bindings['\x0C'] = std::tr1::bind(&display::Manager::force_redraw, m_control->display()); // ^L m_bindings['\x11'] = std::tr1::bind(&Control::receive_normal_shutdown, m_control); // ^Q } void Root::set_down_throttle(unsigned int throttle) { if (m_windowStatusbar != NULL) m_windowStatusbar->mark_dirty(); torrent::down_throttle_global()->set_max_rate(throttle * 1024); unsigned int div = std::max(rpc::call_command_value("throttle.max_downloads.div"), 0); unsigned int global = std::max(rpc::call_command_value("throttle.max_downloads.global"), 0); if (throttle == 0 || div == 0) { torrent::resource_manager()->set_max_download_unchoked(global); return; } throttle /= div; unsigned int maxUnchoked; if (throttle <= 10) maxUnchoked = 1 + throttle / 1; else maxUnchoked = 10 + throttle / 5; if (global != 0) torrent::resource_manager()->set_max_download_unchoked(std::min(maxUnchoked, global)); else torrent::resource_manager()->set_max_download_unchoked(maxUnchoked); } void Root::set_up_throttle(unsigned int throttle) { if (m_windowStatusbar != NULL) m_windowStatusbar->mark_dirty(); torrent::up_throttle_global()->set_max_rate(throttle * 1024); unsigned int div = std::max(rpc::call_command_value("throttle.max_uploads.div"), 0); unsigned int global = std::max(rpc::call_command_value("throttle.max_uploads.global"), 0); if (throttle == 0 || div == 0) { torrent::resource_manager()->set_max_upload_unchoked(global); return; } throttle /= div; unsigned int maxUnchoked; if (throttle <= 10) maxUnchoked = 1 + throttle / 1; else maxUnchoked = 10 + throttle / 5; if (global != 0) torrent::resource_manager()->set_max_upload_unchoked(std::min(maxUnchoked, global)); else torrent::resource_manager()->set_max_upload_unchoked(maxUnchoked); } void Root::adjust_down_throttle(int throttle) { set_down_throttle(std::max(torrent::down_throttle_global()->max_rate() / 1024 + throttle, 0)); } void Root::adjust_up_throttle(int throttle) { set_up_throttle(std::max(torrent::up_throttle_global()->max_rate() / 1024 + throttle, 0)); } void Root::enable_input(const std::string& title, input::TextInput* input) { if (m_windowInput->input() != NULL) throw torrent::internal_error("Root::enable_input(...) m_windowInput->input() != NULL."); input->slot_dirty(std::tr1::bind(&WInput::mark_dirty, m_windowInput)); m_windowStatusbar->set_active(false); m_windowInput->set_active(true); m_windowInput->set_input(input); m_windowInput->set_title(title); m_windowInput->set_focus(true); input->bindings()['\x0C'] = std::tr1::bind(&display::Manager::force_redraw, m_control->display()); // ^L input->bindings()['\x11'] = std::tr1::bind(&Control::receive_normal_shutdown, m_control); // ^Q control->input()->set_text_input(input); control->display()->adjust_layout(); } void Root::disable_input() { if (m_windowInput->input() == NULL) throw torrent::internal_error("Root::disable_input() m_windowInput->input() == NULL."); m_windowInput->input()->slot_dirty(ElementBase::slot_type()); m_windowStatusbar->set_active(true); m_windowInput->set_active(false); m_windowInput->set_focus(false); m_windowInput->set_input(NULL); control->input()->set_text_input(NULL); control->display()->adjust_layout(); } input::TextInput* Root::current_input() { return m_windowInput->input(); } } rtorrent-0.9.6/src/ui/root.h000066400000000000000000000071071257211462100157530ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UI_ROOT_H #define RTORRENT_UI_ROOT_H #include #include "input/bindings.h" class Control; namespace display { class Frame; class WindowTitle; class WindowHttpQueue; class WindowInput; class WindowStatusbar; } namespace input { class TextInput; } namespace ui { class DownloadList; class Root { public: typedef display::WindowTitle WTitle; typedef display::WindowHttpQueue WHttpQueue; typedef display::WindowInput WInput; typedef display::WindowStatusbar WStatusbar; Root(); void init(Control* c); void cleanup(); WTitle* window_title() { return m_windowTitle; } WStatusbar* window_statusbar() { return m_windowStatusbar; } WInput* window_input() { return m_windowInput; } DownloadList* download_list() { return m_downloadList; } void set_down_throttle(unsigned int throttle); void set_up_throttle(unsigned int throttle); // Rename to raw or something, make base function. void set_down_throttle_i64(int64_t throttle) { set_down_throttle(throttle >> 10); } void set_up_throttle_i64(int64_t throttle) { set_up_throttle(throttle >> 10); } void adjust_down_throttle(int throttle); void adjust_up_throttle(int throttle); const char* get_throttle_keys(); void enable_input(const std::string& title, input::TextInput* input); void disable_input(); input::TextInput* current_input(); private: void setup_keys(); Control* m_control; DownloadList* m_downloadList; WTitle* m_windowTitle; WHttpQueue* m_windowHttpQueue; WInput* m_windowInput; WStatusbar* m_windowStatusbar; input::Bindings m_bindings; }; } #endif rtorrent-0.9.6/src/utils/000077500000000000000000000000001257211462100153355ustar00rootroot00000000000000rtorrent-0.9.6/src/utils/Makefile.am000066400000000000000000000004201257211462100173650ustar00rootroot00000000000000noinst_LIBRARIES = libsub_utils.a libsub_utils_a_SOURCES = \ directory.cc \ directory.h \ file_status_cache.cc \ file_status_cache.h \ list_focus.h \ lockfile.cc \ lockfile.h \ socket_fd.cc \ socket_fd.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir) rtorrent-0.9.6/src/utils/directory.cc000066400000000000000000000057361257211462100176630ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include "directory.h" namespace utils { // Keep this? bool Directory::is_valid() const { if (m_path.empty()) return false; DIR* d = opendir(rak::path_expand(m_path).c_str()); closedir(d); return d; } bool Directory::update(int flags) { if (m_path.empty()) throw torrent::input_error("Directory::update() tried to open an empty path."); DIR* d = opendir(rak::path_expand(m_path).c_str()); if (d == NULL) return false; struct dirent* entry; #ifdef __sun__ struct stat s; #endif while ((entry = readdir(d)) != NULL) { if ((flags & update_hide_dot) && entry->d_name[0] == '.') continue; iterator itr = base_type::insert(end(), value_type()); #ifdef __sun__ stat(entry->d_name, &s); itr->d_fileno = entry->d_ino; itr->d_reclen = 0; itr->d_type = s.st_mode; #else itr->d_fileno = entry->d_fileno; itr->d_reclen = entry->d_reclen; itr->d_type = entry->d_type; #endif #ifdef DIRENT_NAMLEN_EXISTS_FOOBAR itr->d_name = std::string(entry->d_name, entry->d_name + entry->d_namlen); #else itr->d_name = std::string(entry->d_name); #endif } closedir(d); if (flags & update_sort) std::sort(begin(), end()); return true; } } rtorrent-0.9.6/src/utils/directory.h000066400000000000000000000073231257211462100175170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_DIRECTORY_H #define RTORRENT_UTILS_DIRECTORY_H #include #include #include namespace utils { struct directory_entry { // Fix. bool is_file() const { return true; } // The name and types should match POSIX. uint32_t d_fileno; uint32_t d_reclen; //Not used. Messes with Solaris. uint8_t d_type; std::string d_name; }; class Directory : private std::vector { public: typedef std::vector base_type; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::value_type; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::size; using base_type::erase; static const uint32_t buffer_size = 64 * 1024; static const int update_sort = 0x1; static const int update_hide_dot = 0x2; Directory() {} Directory(const std::string& path) : m_path(path) {} bool is_valid() const; const std::string& path() { return m_path; } void set_path(const std::string& path) { m_path = path; } bool update(int flags); private: std::string m_path; }; inline bool operator == (const directory_entry& left, const directory_entry& right) { return left.d_name == right.d_name; } inline bool operator != (const directory_entry& left, const directory_entry& right) { return left.d_name != right.d_name; } inline bool operator < (const directory_entry& left, const directory_entry& right) { return left.d_name < right.d_name; } inline bool operator > (const directory_entry& left, const directory_entry& right) { return left.d_name > right.d_name; } inline bool operator <= (const directory_entry& left, const directory_entry& right) { return left.d_name <= right.d_name; } inline bool operator >= (const directory_entry& left, const directory_entry& right) { return left.d_name >= right.d_name; } } #endif rtorrent-0.9.6/src/utils/file_status_cache.cc000066400000000000000000000055331257211462100213170ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include "file_status_cache.h" namespace utils { bool FileStatusCache::insert(const std::string& path, int flags) { rak::file_stat fs; // Should we expand somewhere else? Problem is it adds a lot of junk // to the start of the paths added to the cache, causing more work // during search, etc. if (!fs.update(rak::path_expand(path))) return false; std::pair result = base_type::insert(value_type(path, file_status())); // Return false if the file hasn't been modified since last time. We // use 'equal to' instead of 'greater than' since the file might // have been replaced by another file, and thus should be re-tried. if (!result.second && result.first->second.m_mtime == (uint32_t)fs.modified_time()) return false; result.first->second.m_flags = 0; result.first->second.m_mtime = fs.modified_time(); return true; } void FileStatusCache::prune() { iterator itr = begin(); while (itr != end()) { rak::file_stat fs; iterator tmp = itr++; if (!fs.update(rak::path_expand(tmp->first)) || tmp->second.m_mtime != (uint32_t)fs.modified_time()) base_type::erase(tmp); } } } rtorrent-0.9.6/src/utils/file_status_cache.h000066400000000000000000000052621257211462100211600ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_FILE_STATUS_CACHE_H #define RTORRENT_UTILS_FILE_STATUS_CACHE_H #include #include namespace utils { struct file_status { int m_flags; uint32_t m_mtime; }; class FileStatusCache : public std::map { public: typedef std::map base_type; using base_type::iterator; using base_type::const_iterator; using base_type::reverse_iterator; using base_type::const_reverse_iterator; using base_type::value_type; using base_type::begin; using base_type::end; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::size; using base_type::erase; // static int flag_ // Insert and return true if the entry does not exist or the new // file's mtime is more recent. bool insert(const std::string& path, int flags); // Add a function for pruning a sorted list of paths. // Function for pruning entries that no longer points to a file, or // has a different mtime. void prune(); }; } #endif rtorrent-0.9.6/src/utils/list_focus.h000066400000000000000000000112511257211462100176600ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_LIST_FOCUS_H #define RTORRENT_UTILS_LIST_FOCUS_H #include namespace utils { // Can't make this class inherit privately due to gcc PR 14258. template class ListFocus { public: typedef Base base_type; typedef std::tr1::function slot_void; typedef std::list signal_void; typedef typename base_type::iterator iterator; typedef typename base_type::const_iterator const_iterator; typedef typename base_type::reverse_iterator reverse_iterator; typedef typename base_type::const_reverse_iterator const_reverse_iterator; typedef typename base_type::value_type value_type; ListFocus(base_type* b = NULL) : m_base(b) { if (b) m_focus = b->end(); } // Convinience functions, would have added more through using, but // can't. iterator begin() { return m_base->begin(); } iterator end() { return m_base->end(); } reverse_iterator rbegin() { return m_base->rbegin(); } reverse_iterator rend() { return m_base->rend(); } // Don't do erase on this object without making sure focus is right. base_type& base() { return *m_base; } iterator get_focus() { return m_focus; } void set_focus(iterator itr); // These are looping increment/decrements. iterator inc_focus(); iterator dec_focus(); iterator erase(iterator itr); void remove(const value_type& v); // Be careful with copying signals. signal_void& signal_changed() { return m_signal_changed; } private: void emit_changed(); base_type* m_base; iterator m_focus; signal_void m_signal_changed; }; template void ListFocus::set_focus(iterator itr) { m_focus = itr; emit_changed(); } template typename ListFocus::iterator ListFocus::inc_focus() { if (m_focus != end()) ++m_focus; else m_focus = begin(); emit_changed(); return m_focus; } template typename ListFocus::iterator ListFocus::dec_focus() { if (m_focus != begin()) --m_focus; else m_focus = end(); emit_changed(); return m_focus; } template typename ListFocus::iterator ListFocus::erase(iterator itr) { if (itr == m_focus) return m_focus = m_base->erase(itr); else return m_base->erase(itr); emit_changed(); } template void ListFocus::remove(const value_type& v) { iterator first = begin(); iterator last = end(); while (first != last) if (*first == v) first = erase(first); else ++first; } template void ListFocus::emit_changed() { for (signal_void::iterator itr = m_signal_changed.begin(), last = m_signal_changed.end(); itr != last; itr++) (*itr)(); } } #endif rtorrent-0.9.6/src/utils/lockfile.cc000066400000000000000000000077231257211462100174450ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "lockfile.h" namespace utils { struct lockfile_valid_char { bool operator () (char c) { return !std::isgraph(c); } }; struct lockfile_valid_hostname { bool operator () (char c) { return !std::isgraph(c) || c == ':'; } }; bool Lockfile::is_stale() { process_type process = locked_by(); char buf[256]; if (process.second <= 0 || ::gethostname(buf, 255) != 0 || buf != process.first) return false; return ::kill(process.second, 0) != 0 && errno != EPERM; } bool Lockfile::try_lock() { if (m_path.empty()) { m_locked = true; return true; } if (is_stale()) ::unlink(m_path.c_str()); // Just do a simple locking for now that isn't safe for network // devices. int fd = ::open(m_path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0444); if (fd == -1) return false; char buf[256]; int pos = ::gethostname(buf, 255); if (pos == 0) { ::snprintf(buf + std::strlen(buf), 255, ":+%i\n", ::getpid()); int __UNUSED result = ::write(fd, buf, std::strlen(buf)); } ::close(fd); m_locked = true; return true; } bool Lockfile::unlock() { m_locked = false; if (m_path.empty()) return true; else return ::unlink(m_path.c_str()) != -1; } Lockfile::process_type Lockfile::locked_by() const { int fd = ::open(m_path.c_str(), O_RDONLY); if (fd < 0) return process_type(std::string(), 0); char first[256]; char* last = first + std::max(read(fd, first, 255), 0); *last = '\0'; ::close(fd); char* endHostname = std::find_if(first, last, lockfile_valid_hostname()); char* beginPid = endHostname; char* endPid; long long int pid; if (beginPid + 2 >= last || *(beginPid++) != ':' || *(beginPid++) != '+' || (pid = strtoll(beginPid, &endPid, 10)) == 0 || endPid == NULL) return process_type(std::string(), 0); return process_type(std::string(first, endHostname), pid); } std::string Lockfile::locked_by_as_string() const { process_type p = locked_by(); if (p.first.empty()) return ""; std::stringstream str; str << p.first << ":+" << p.second; return str.str(); } } rtorrent-0.9.6/src/utils/lockfile.h000066400000000000000000000054311257211462100173010ustar00rootroot00000000000000// rTorrent - BitTorrent client // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY // A simple, and not guaranteed atomic, lockfile implementation. It // saves the hostname and pid in the lock file, which may be accessed // by Lockfile::locked_by(). If the path is an empty string then no // lockfile will be created when Lockfile::try_lock() is called, still // it will set the locked state of the Lockfile instance. #ifndef RTORRENT_UTILS_LOCKFILE_H #define RTORRENT_UTILS_LOCKFILE_H #include #include namespace utils { class Lockfile { public: typedef std::pair process_type; Lockfile() : m_locked(false) {} bool is_locked() const { return m_locked; } bool is_stale(); // If the path is empty no lock file will be created, although // is_locked() will return true. bool try_lock(); bool unlock(); const std::string& path() const { return m_path; } void set_path(const std::string& path) { m_path = path; } std::string locked_by_as_string() const; process_type locked_by() const; private: std::string m_path; bool m_locked; }; } #endif rtorrent-0.9.6/src/utils/socket_fd.cc000066400000000000000000000122421257211462100176060ustar00rootroot00000000000000// libTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "socket_fd.h" namespace utils { inline void SocketFd::check_valid() const { if (!is_valid()) throw torrent::internal_error("SocketFd function called on an invalid fd."); } bool SocketFd::set_nonblock() { check_valid(); return fcntl(m_fd, F_SETFL, O_NONBLOCK) == 0; } bool SocketFd::set_priority(priority_type p) { check_valid(); int opt = p; return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0; } bool SocketFd::set_reuse_address(bool state) { check_valid(); int opt = state; return setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == 0; } bool SocketFd::set_dont_route(bool state) { check_valid(); int opt = state; return setsockopt(m_fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)) == 0; } // bool // SocketFd::set_bind_to_device(const char* device) { // check_valid(); // struct ifreq ifr; // strlcpy(ifr.ifr_name, device, IFNAMSIZ); // return setsockopt(m_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == 0; // } bool SocketFd::set_send_buffer_size(uint32_t s) { check_valid(); int opt = s; return setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) == 0; } bool SocketFd::set_receive_buffer_size(uint32_t s) { check_valid(); int opt = s; return setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == 0; } int SocketFd::get_error() const { check_valid(); int err; socklen_t length = sizeof(err); if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &err, &length) == -1) throw torrent::internal_error("SocketFd::get_error() could not get error"); return err; } bool SocketFd::open_stream() { return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1; } bool SocketFd::open_datagram() { return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1; } bool SocketFd::open_local() { return (m_fd = socket(rak::socket_address::pf_local, SOCK_STREAM, 0)) != -1; } void SocketFd::close() { if (::close(m_fd) && errno == EBADF) throw torrent::internal_error("SocketFd::close() called on an invalid file descriptor"); } bool SocketFd::bind(const rak::socket_address& sa) { check_valid(); return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { check_valid(); return !::bind(m_fd, sa.c_sockaddr(), length); } bool SocketFd::connect(const rak::socket_address& sa) { check_valid(); return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS; } bool SocketFd::listen(int size) { check_valid(); return !::listen(m_fd, size); } SocketFd SocketFd::accept(rak::socket_address* sa) { check_valid(); socklen_t len = sizeof(rak::socket_address); return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len)); } // unsigned int // SocketFd::get_read_queue_size() const { // unsigned int v; // if (!is_valid() || ioctl(m_fd, SIOCINQ, &v) < 0) // throw internal_error("SocketFd::get_read_queue_size() could not be performed"); // return v; // } // unsigned int // SocketFd::get_write_queue_size() const { // unsigned int v; // if (!is_valid() || ioctl(m_fd, SIOCOUTQ, &v) < 0) // throw internal_error("SocketFd::get_write_queue_size() could not be performed"); // return v; // } } rtorrent-0.9.6/src/utils/socket_fd.h000066400000000000000000000063721257211462100174570ustar00rootroot00000000000000// libTorrent - BitTorrent library // Copyright (C) 2005-2011, Jari Sundell // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations // including the two. // // You must obey the GNU General Public License in all respects for // all of the code used other than OpenSSL. If you modify file(s) // with this exception, you may extend this exception to your version // of the file(s), but you are not obligated to do so. If you do not // wish to do so, delete this exception statement from your version. // If you delete this exception statement from all source files in the // program, then also delete it here. // // Contact: Jari Sundell // // Skomakerveien 33 // 3185 Skoppum, NORWAY #ifndef RTORRENT_UTILS_SOCKET_FD_H #define RTORRENT_UTILS_SOCKET_FD_H #include namespace rak { class socket_address; } namespace utils { class SocketFd { public: typedef uint8_t priority_type; SocketFd() : m_fd(-1) {} explicit SocketFd(int fd) : m_fd(fd) {} bool is_valid() const { return m_fd >= 0; } int get_fd() const { return m_fd; } void set_fd(int fd) { m_fd = fd; } bool set_nonblock(); bool set_reuse_address(bool state); bool set_dont_route(bool state); bool set_bind_to_device(const char* device); bool set_priority(priority_type p); bool set_send_buffer_size(uint32_t s); bool set_receive_buffer_size(uint32_t s); int get_error() const; bool open_stream(); bool open_datagram(); bool open_local(); void close(); void clear() { m_fd = -1; } bool bind(const rak::socket_address& sa); bool bind(const rak::socket_address& sa, unsigned int length); bool connect(const rak::socket_address& sa); bool listen(int size); SocketFd accept(rak::socket_address* sa); // unsigned int get_read_queue_size() const; // unsigned int get_write_queue_size() const; private: inline void check_valid() const; int m_fd; }; } #endif rtorrent-0.9.6/test/000077500000000000000000000000001257211462100143655ustar00rootroot00000000000000rtorrent-0.9.6/test/Makefile.am000066400000000000000000000013741257211462100164260ustar00rootroot00000000000000TESTS = rtorrentTest AUTOMAKE_OPTIONS = subdir-objects check_PROGRAMS = $(TESTS) rtorrentTest_LDADD = \ ../src/libsub_root.a \ ../src/ui/libsub_ui.a \ ../src/core/libsub_core.a \ ../src/display/libsub_display.a \ ../src/input/libsub_input.a \ ../src/rpc/libsub_rpc.a \ ../src/utils/libsub_utils.a rtorrentTest_SOURCES = \ rpc/command_test.cc \ rpc/command_test.h \ rpc/command_map_test.cc \ rpc/command_map_test.h \ rpc/command_slot_test.cc \ rpc/command_slot_test.h \ rpc/object_storage_test.cc \ rpc/object_storage_test.h \ src/command_dynamic_test.cc \ src/command_dynamic_test.h \ main.cc rtorrentTest_CXXFLAGS = $(CPPUNIT_CFLAGS) rtorrentTest_LDFLAGS = $(CPPUNIT_LIBS) -ldl AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/src rtorrent-0.9.6/test/main.cc000066400000000000000000000013741257211462100156250ustar00rootroot00000000000000#include #include #include int main(int argc, char* argv[]) { // Get the top level suite from the registry CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); // Change the default outputter to a compiler error format outputter runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); // Run the tests. bool wasSucessful = runner.run(); // Return error code 1 if the one of test failed. return wasSucessful ? 0 : 1; } rtorrent-0.9.6/test/rpc/000077500000000000000000000000001257211462100151515ustar00rootroot00000000000000rtorrent-0.9.6/test/rpc/command_map_test.cc000066400000000000000000000023551257211462100207770ustar00rootroot00000000000000#include "config.h" #include "command_helpers.h" #include "rpc/command_map.h" #include "command_map_test.h" CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest); #undef CMD2_A_FUNCTION #define CMD2_A_FUNCTION(key, function, slot, parm, doc) \ m_map.insert_slot::type>(key, slot, &rpc::function, \ rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); torrent::Object cmd_test_map_a(rpc::target_type t, const torrent::Object& obj) { return obj; } torrent::Object cmd_test_map_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } torrent::Object cmd_test_any_string(__UNUSED rpc::target_type target, const std::string& rawArgs) { return (int64_t)3; } void CommandMapTest::test_basics() { CMD2_ANY("test_a", &cmd_test_map_a); CMD2_ANY("test_b", tr1::bind(&cmd_test_map_b, tr1::placeholders::_1, tr1::placeholders::_2, (uint64_t)2)); CMD2_ANY_STRING("any_string", &cmd_test_any_string); CPPUNIT_ASSERT(m_map.call_command("test_a", (int64_t)1).as_value() == 1); CPPUNIT_ASSERT(m_map.call_command("test_b", (int64_t)1).as_value() == 2); CPPUNIT_ASSERT(m_map.call_command("any_string", "").as_value() == 3); } rtorrent-0.9.6/test/rpc/command_map_test.h000066400000000000000000000007331257211462100206370ustar00rootroot00000000000000#include #include "rpc/command_map.h" class CommandMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandMapTest); CPPUNIT_TEST(test_basics); CPPUNIT_TEST_SUITE_END(); public: static const int cmd_size = 256; void setUp() { m_commandItr = m_commands; } void tearDown() {} void test_basics(); private: rpc::CommandMap m_map; rpc::command_base m_commands[cmd_size]; rpc::command_base* m_commandItr; }; rtorrent-0.9.6/test/rpc/command_slot_test.cc000066400000000000000000000052041257211462100211770ustar00rootroot00000000000000#include "config.h" #include #include #include "rpc/command_map.h" #include "command_slot_test.h" CPPUNIT_TEST_SUITE_REGISTRATION(CommandSlotTest); torrent::Object cmd_test_a(rpc::target_type t, const torrent::Object& obj) { return obj; } torrent::Object cmd_test_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } torrent::Object cmd_test_list(rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); } void cmd_test_convert_void(rpc::target_type t, const torrent::Object& obj) {} int32_t cmd_test_convert_int32_t(rpc::target_type t, const torrent::Object& obj) { return 9; } int64_t cmd_test_convert_int64_t(rpc::target_type t, const torrent::Object& obj) { return 10; } std::string cmd_test_convert_string(rpc::target_type t, const torrent::Object& obj) { return "test_1"; } const std::string& cmd_test_convert_const_string(rpc::target_type t, const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; } void CommandSlotTest::test_basics() { // rpc::command_base test_any; // test_any.set_function(&cmd_test_a); // CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 1); // test_any.set_function(tr1::bind(&cmd_test_b, tr1::placeholders::_1, tr1::placeholders::_2, (uint64_t)2)); // CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 2); // test_any.set_function(&cmd_test_list); // CPPUNIT_ASSERT(rpc::command_base_call_any_list(&test_any, rpc::make_target(), (int64_t)3).as_value() == 3); } void CommandSlotTest::test_type_validity() { // CPPUNIT_ASSERT((rpc::command_base_is_type::value)); // CPPUNIT_ASSERT((rpc::command_base_is_type::value)); } void CommandSlotTest::test_convert_return() { // rpc::command_base test_any; // test_any.set_function(&cmd_test_convert_string); // CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_string() == "test_1"); // test_any.set_function(&cmd_test_convert_const_string); // CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_string() == "test_2"); // test_any.set_function(object_convert_void(&cmd_test_convert_void)); // CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).is_empty()); } rtorrent-0.9.6/test/rpc/command_slot_test.h000066400000000000000000000006541257211462100210450ustar00rootroot00000000000000#include #include "rpc/command.h" class CommandSlotTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandSlotTest); CPPUNIT_TEST(test_basics); CPPUNIT_TEST(test_type_validity); CPPUNIT_TEST(test_convert_return); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} void tearDown() {} void test_basics(); void test_type_validity(); void test_convert_return(); }; rtorrent-0.9.6/test/rpc/command_test.cc000066400000000000000000000051411257211462100201360ustar00rootroot00000000000000#include "config.h" #include "command_test.h" CPPUNIT_TEST_SUITE_REGISTRATION(CommandTest); bool command_stack_all_empty() { return std::find_if(rpc::command_base::stack_begin(), rpc::command_base::stack_end(), std::mem_fun_ref(&torrent::Object::is_not_empty)) == rpc::command_base::stack_end(); } void CommandTest::test_stack() { torrent::Object::list_type args; rpc::command_base::stack_type stack; torrent::Object* last_stack; // Test empty stack. CPPUNIT_ASSERT(command_stack_all_empty()); last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(command_stack_all_empty()); rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); // Test stack with one. args.push_back(int64_t(1)); last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(!command_stack_all_empty()); CPPUNIT_ASSERT(rpc::command_base::stack_begin()->as_value() == 1); rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); // Test stack with two args.clear(); args.push_back(int64_t(2)); args.push_back(int64_t(3)); last_stack = rpc::command_base::push_stack(args, &stack); CPPUNIT_ASSERT(!command_stack_all_empty()); CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 2); CPPUNIT_ASSERT(rpc::command_base::current_stack[1].as_value() == 3); rpc::command_base::pop_stack(&stack, last_stack); CPPUNIT_ASSERT(command_stack_all_empty()); } void CommandTest::test_stack_double() { torrent::Object::list_type args; rpc::command_base::stack_type stack_first; rpc::command_base::stack_type stack_second; torrent::Object* last_stack_first; torrent::Object* last_stack_second; // Test double-stacked. args.push_back(int64_t(1)); last_stack_first = rpc::command_base::push_stack(args, &stack_first); CPPUNIT_ASSERT(!command_stack_all_empty()); CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 1); args.clear(); args.push_back(int64_t(2)); args.push_back(int64_t(3)); last_stack_second = rpc::command_base::push_stack(args, &stack_second); CPPUNIT_ASSERT(!command_stack_all_empty()); CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 2); CPPUNIT_ASSERT(rpc::command_base::current_stack[1].as_value() == 3); rpc::command_base::pop_stack(&stack_second, last_stack_second); CPPUNIT_ASSERT(!command_stack_all_empty()); CPPUNIT_ASSERT(rpc::command_base::current_stack[0].as_value() == 1); rpc::command_base::pop_stack(&stack_first, last_stack_first); CPPUNIT_ASSERT(command_stack_all_empty()); } rtorrent-0.9.6/test/rpc/command_test.h000066400000000000000000000005501257211462100177770ustar00rootroot00000000000000#include #include "rpc/command.h" class CommandTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandTest); CPPUNIT_TEST(test_stack); CPPUNIT_TEST(test_stack_double); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() {} void test_stack(); void test_stack_double(); private: }; rtorrent-0.9.6/test/rpc/object_storage_test.cc000066400000000000000000000062271257211462100215200ustar00rootroot00000000000000#include "config.h" #include "object_storage_test.h" CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStorageTest); #define ASSERT_CATCH_INPUT_ERROR(some_code) \ try { some_code; CPPUNIT_ASSERT("torrent::input_error not caught" && false); } catch (torrent::input_error& e) { } void ObjectStorageTest::test_basics() { rpc::object_storage::iterator itr; CPPUNIT_ASSERT(m_storage.empty()); itr = m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type); CPPUNIT_ASSERT(itr != m_storage.end()); CPPUNIT_ASSERT(&*itr != NULL); CPPUNIT_ASSERT(itr->first.size() == 6 && std::strcmp(itr->first.data(), "test_1") == 0); CPPUNIT_ASSERT(itr->second.object.is_string() && itr->second.object.as_string() == "a"); ASSERT_CATCH_INPUT_ERROR( { m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type); } ); // Test erase. m_storage.erase(rpc::object_storage::key_type::from_c_str("test_1")); CPPUNIT_ASSERT(m_storage.empty()); // Test with no type flag. ASSERT_CATCH_INPUT_ERROR( { m_storage.insert("test_2", torrent::Object("b"), 0); } ); ASSERT_CATCH_INPUT_ERROR( { m_storage.insert("test_3", torrent::Object("c"), ~rpc::object_storage::mask_type); } ); m_storage.clear(); } void ObjectStorageTest::test_conversions() { CPPUNIT_ASSERT(m_storage.insert("test_1", torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end()); CPPUNIT_ASSERT(m_storage.insert_str(std::string("test_2"), torrent::Object("a"), rpc::object_storage::flag_string_type) != m_storage.end()); char raw_3[8] = "test_3\x1"; torrent::raw_string raw_string_3(raw_3, 6); CPPUNIT_ASSERT(m_storage.insert(raw_string_3, torrent::Object("a"), rpc::object_storage::flag_string_type)->first == std::string("test_3")); m_storage.clear(); } void ObjectStorageTest::test_validate_keys() { torrent::raw_string raw_string_4("test_4\0foo", 10); ASSERT_CATCH_INPUT_ERROR( { m_storage.insert(raw_string_4, torrent::Object("a"), rpc::object_storage::flag_string_type); } ); } // And test many other bad/good string combos. // Test for various conversions of fixed_key_type. void ObjectStorageTest::test_access() { m_storage.insert("string_1", torrent::Object("gen_a"), rpc::object_storage::flag_string_type); m_storage.insert("value_1", int64_t(1), rpc::object_storage::flag_value_type); CPPUNIT_ASSERT(m_storage.get_c_str("string_1").as_string() == "gen_a"); CPPUNIT_ASSERT(m_storage.set_c_str_string("string_1", "test").as_string() == "test"); // Test value from raw and normal, list, etc. CPPUNIT_ASSERT(m_storage.get_c_str("value_1").as_value() == 1); CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", int64_t(2)).as_value() == 2); // CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", "123").as_value() == 123); // CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_string::from_c_str("321")).as_value() == 321); // CPPUNIT_ASSERT(m_storage.set_c_str_value("value_1", torrent::raw_bencode::from_c_str("i567e")).as_value() == 567); // ASSERT_CATCH_INPUT_ERROR( { m_storage.set_c_str_value("value_1", "e123"); } ); // Test string from raw and normal, list, etc. } rtorrent-0.9.6/test/rpc/object_storage_test.h000066400000000000000000000010221257211462100213460ustar00rootroot00000000000000#include #include "rpc/object_storage.h" class ObjectStorageTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ObjectStorageTest); CPPUNIT_TEST(test_basics); CPPUNIT_TEST(test_conversions); CPPUNIT_TEST(test_validate_keys); CPPUNIT_TEST(test_access); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() {} void test_basics(); void test_conversions(); void test_validate_keys(); void test_access(); private: rpc::object_storage m_storage; }; rtorrent-0.9.6/test/src/000077500000000000000000000000001257211462100151545ustar00rootroot00000000000000rtorrent-0.9.6/test/src/command_dynamic_test.cc000066400000000000000000000045611257211462100216520ustar00rootroot00000000000000#include "config.h" #include #include "command_dynamic_test.h" #include "rpc/parse_commands.h" #include "control.h" #include "globals.h" CPPUNIT_TEST_SUITE_REGISTRATION(CommandDynamicTest); #define ASSERT_CATCH_INPUT_ERROR(some_code) \ try { some_code; CPPUNIT_ASSERT("torrent::input_error not caught" && false); } catch (torrent::input_error& e) { } void initialize_command_dynamic(); void initialize_command_ui(); void CommandDynamicTest::setUp() { if (rpc::commands.empty()) { setlocale(LC_ALL, ""); cachedTime = rak::timer::current(); control = new Control; initialize_command_dynamic(); initialize_command_ui(); } } void CommandDynamicTest::test_basics() { rpc::commands.call_command("method.insert.value", rpc::create_object_list("test_basics.1", int64_t(1))); CPPUNIT_ASSERT(rpc::commands.call_command("test_basics.1", torrent::Object()).as_value() == 1); } void CommandDynamicTest::test_get_set() { rpc::commands.call_command("method.insert.simple", rpc::create_object_list("test_get_set.1", "cat=1")); CPPUNIT_ASSERT(rpc::commands.call_command("test_get_set.1", torrent::Object()).as_string() == "1"); CPPUNIT_ASSERT(rpc::commands.call_command("method.get", "test_get_set.1").as_string() == "cat=1"); rpc::commands.call_command("method.set", rpc::create_object_list("test_get_set.1", "cat=2")); CPPUNIT_ASSERT(rpc::commands.call_command("method.get", "test_get_set.1").as_string() == "cat=2"); } void CommandDynamicTest::test_old_style() { rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.1", "value", int64_t(1))); CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.1", torrent::Object()).as_value() == 1); rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.2", "bool", int64_t(5))); CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.2", torrent::Object()).as_value() == 1); rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.3", "string", "test.2")); CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.3", torrent::Object()).as_string() == "test.2"); rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.4", "simple", "cat=test.3")); CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.4", torrent::Object()).as_string() == "test.3"); } rtorrent-0.9.6/test/src/command_dynamic_test.h000066400000000000000000000006131257211462100215060ustar00rootroot00000000000000#include class CommandDynamicTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandDynamicTest); CPPUNIT_TEST(test_basics); CPPUNIT_TEST(test_get_set); CPPUNIT_TEST(test_old_style); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown() {} void test_basics(); void test_get_set(); void test_old_style(); private: };