mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-10 15:07:45 -05:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36d772e5fe | ||
|
|
91ab53a471 | ||
|
|
9656d5274c | ||
|
|
01fd805ee6 | ||
|
|
846b3b81ff | ||
|
|
5c921c2bff | ||
|
|
d3317a48c0 | ||
|
|
ac8b7610cf | ||
|
|
a06edd4c4e | ||
|
|
b9d6c11e63 | ||
|
|
ce9519c9cb | ||
|
|
dbda657e6e | ||
|
|
7d2b895bfb | ||
|
|
ad719a2c07 | ||
|
|
ae31139ffe | ||
|
|
bea0806a47 | ||
|
|
7394595abb | ||
|
|
d2ce6f826a | ||
|
|
2544ff5902 | ||
|
|
113306ac23 | ||
|
|
e2cedb5594 | ||
|
|
63cf2ec616 | ||
|
|
c99cc22138 | ||
|
|
b76f7bd3ba | ||
|
|
d37e9ea1c3 | ||
|
|
1d008961ab | ||
|
|
8a7224d4b5 | ||
|
|
bd95a7fc01 | ||
|
|
6a9cdc9e18 | ||
|
|
3a9fbf88bd | ||
|
|
d9ca826095 | ||
|
|
1d36fbba53 | ||
|
|
7d230aeebc | ||
|
|
4e573c46cb | ||
|
|
0c649c3959 | ||
|
|
a14a99b681 | ||
|
|
aefd87e3e5 | ||
|
|
109d56b55e | ||
|
|
4eed0b38f8 | ||
|
|
424ae68621 | ||
|
|
101b2e7bdf | ||
|
|
049dba4b06 | ||
|
|
3024d32257 | ||
|
|
784ed7f21b | ||
|
|
2de44bfd99 | ||
|
|
65e391a4a7 | ||
|
|
16057247c2 | ||
|
|
04506c1e1e | ||
|
|
7038e2a18e | ||
|
|
3429444c0c | ||
|
|
3c46953d47 | ||
|
|
6c7a1b5697 | ||
|
|
cc35644e24 | ||
|
|
ccf2b3bc5b | ||
|
|
698a46eb7b | ||
|
|
9e5de62841 | ||
|
|
70ac9029c6 | ||
|
|
b66b989de0 | ||
|
|
9c82b2ea34 | ||
|
|
d033088113 | ||
|
|
240ccdc65e | ||
|
|
975d632007 | ||
|
|
53371344ae | ||
|
|
e9356ebe79 | ||
|
|
bc0c8fc84a | ||
|
|
6252f2c8c1 | ||
|
|
708f819182 | ||
|
|
bad4c7ed34 | ||
|
|
7e6f8f19eb | ||
|
|
a6fd969ead | ||
|
|
7b5443d680 | ||
|
|
8de723d2aa | ||
|
|
82b252ce2e | ||
|
|
a2dfb26b36 |
262
ChangeLog
262
ChangeLog
@@ -1,22 +1,260 @@
|
||||
nzbget-15.0:
|
||||
- improved application for Windows:
|
||||
- added tray icon (near clock);
|
||||
- left click on icon pauses/resumes download;
|
||||
- right click opens menu with important functions;
|
||||
- console window can be shown/hidden via preferences (is hidden by
|
||||
default);
|
||||
- new preference to automatically start the program after login;
|
||||
- new preference to show browser on start;
|
||||
- new preference to hide tray icon;
|
||||
- menu commands to show important folders in windows explorer
|
||||
(destination, etc.);
|
||||
- on first start the config file is now placed into subdirectory
|
||||
"NZBGet" inside standard AppData-directory;
|
||||
- default destination and other directories are now placed in the
|
||||
AppData\NZBGet-directory instead of programs directory; this allows
|
||||
to install the program into "program files"-directory since the
|
||||
program does not write into the programs directory anymore;
|
||||
- the program exe has an icon now;
|
||||
- if the exe is started from windows explorer the program starts in
|
||||
application mode; if the exe is called from command prompt the program
|
||||
works in console mode;
|
||||
- added built-in update feature to windows package; accessible via
|
||||
web-interface -> settings -> system -> check for updates;
|
||||
- created installer for windows:
|
||||
- the program is installed into "program files" by default;
|
||||
- the working directory with all subdirectories is now placed into
|
||||
"AppData" directory;
|
||||
- the batch files nzbget-start.bat and nzbget-recovery-mode.bat are not
|
||||
needed and not installed anymore;
|
||||
- created installer for Linux:
|
||||
- included are precompiled binaries for the most common CPU architectures:
|
||||
x86, ARM, MIPS and PowerPC;
|
||||
- installer automatically detects CPU architecture of the system and
|
||||
installs an appropriate executable;
|
||||
- configuration file is automatically preconfigured for immediate use;
|
||||
- installation on supported platforms has become as simple as:
|
||||
download, run installer, start installed nzbget;
|
||||
- installer supports automatic updates via web-interface -> settings
|
||||
-> system - check for updates;
|
||||
- added support for password list file:
|
||||
- new option "UnpackPassFile" to set the location of the file;
|
||||
- during unpack the passwords are tried from the file until unpack
|
||||
succeeds or all passwords were tried;
|
||||
- implemented different strategies for rar4 and rar5-archives taking
|
||||
into account the features of formats;
|
||||
- for rar5-archives a wrong password is reported by unrar unambiguously
|
||||
and the program can immediately try other passwords from the password
|
||||
list;
|
||||
- for rar4-archives and for 7z-archives it is not possible to
|
||||
differentiate between damaged archive and wrong password; for those
|
||||
archives if the first unpack attempt (without password) fails the
|
||||
program executes par-check (preferably quick par-check if enabled via
|
||||
option "ParQuick) before trying the passwords from the list;
|
||||
- another optimization is that the password list is tried only when the
|
||||
first unpack attempt (without password) reports a password error or
|
||||
decryption errors; this saves unnecessary unpack attempts for damaged
|
||||
unencrypted archives;
|
||||
- options "UnrarCmd" and "SevenZipCmd" can include extra switches to pass to
|
||||
unrar/7-zip:
|
||||
- this allows for easy passing of additional parameters without creating
|
||||
of proxy shell scripts;
|
||||
- improved news server connections handling:
|
||||
- if a download of an article fails due to connection error the news
|
||||
server becomes temporary disabled (blocked) for several seconds
|
||||
(defined by option "RetryInterval");
|
||||
- the download is then retried on another news server (of the same
|
||||
level) if available;
|
||||
- if no other news servers (of the same level) exist the program will
|
||||
retry the same news server after its block interval expires;
|
||||
- this increases failure tolerance when multiple news servers are used;
|
||||
- added on-demand queue sorting:
|
||||
- one click on column title in web interface sorts the selected or all
|
||||
items;
|
||||
- if the items were already sorted in that order they are sorted
|
||||
backwards; in other words the second click sorts in descending order;
|
||||
- when sorting selected items they are also grouped together in a case
|
||||
there were holes between selected items;
|
||||
- RPC-method "editqueue" has new command "GroupSort", parameter "Text"
|
||||
must be one of: "name", "priority", "category", "size", "left"; add
|
||||
character "+" or "-" to explicitly define ascending or descending
|
||||
order (for example "name-"); if none of these characters
|
||||
is used the auto-mode is active: the items are sorted in ascending
|
||||
order first, if nothing changed - they are sorted again in descending
|
||||
order;
|
||||
- added restricted user and add-user:
|
||||
- restricted user has access to most program functions but cannot see
|
||||
security related options (including usernames and passwords) and
|
||||
cannot save configuration;
|
||||
- restricted user can be used with other programs and web-sites;
|
||||
- add-user can only add new downloads via RPC-API and can be used with
|
||||
other programs or web-sites;
|
||||
- added per-nzb logging:
|
||||
- each nzb now has its own individual log;
|
||||
- messages printed during download or post-processing are saved;
|
||||
- the messages can be retrieved later at any time;
|
||||
- new button "Log" in the history details dialog;
|
||||
- button "Log" in the download details dialog is now active during
|
||||
download too (not only during post-processing);
|
||||
- the log contains all nzb-related messages except detail-messages and
|
||||
errors printed during retrieving of articles (they would produce way
|
||||
too many messages and are not that useful anyway);
|
||||
- new option "NzbLog" to deactivate per-nzb logging if necessary;
|
||||
- per-nzb logs are saved in the queue-directory (option "QueueDir");
|
||||
- new RPC-method "loadlog" returns the previously saved messages for a
|
||||
given nzb-file;
|
||||
- new field "MessageCount" is returned by RPC-methods "listgroups" and
|
||||
"history" and indicates if there are any messages saved for the item;
|
||||
- parameter "NumberOfLogEntries" of RPC-method "listgroups" and the
|
||||
field "Log" returned by the method are now deprecated, use method
|
||||
"loadlog" instead;
|
||||
- field "PostInfoText" returned by RPC-method "listgroups" is now
|
||||
automatically filled with the latest message printed by a pp-script
|
||||
eliminating the need to access deprecated field "Log"';
|
||||
- actions for history items can now be performed for multiple (selected) records:
|
||||
- post-process again, download again, mark as good, mark as bad;
|
||||
- extended RPC-API method "editqueue": for history-records of type
|
||||
"URL" the action "HistoryRedownload" can now be used as synonym to
|
||||
"HistoryReturn" (makes it easier to redownload multiple items of
|
||||
different types (URL and NZB) with one API call).
|
||||
- options "ParIgnoreExt" and "ExtCleanupDisk" can now contain wildcard
|
||||
characters * and ?;
|
||||
- added new option "ServerX.Retention" to define server retention time (days);
|
||||
files older than configured server retention time are not even tried on this
|
||||
server;
|
||||
- added support for negative numeric values in rss filter (useful for fields
|
||||
"dupescore" and "priority");
|
||||
- added subcommand "HA" to remote command "--list/-L" to list the whole
|
||||
history including hidden records;
|
||||
- added optional parameters to remote command "--append/-A" allowing to pass
|
||||
duplicate key, duplicate mode and duplicate score; removed parameters "F"
|
||||
and "U" of command "--append/-A", which were used to set mode (file or URL),
|
||||
which is now detected automatically; the parameters are still supported for
|
||||
compatibility;
|
||||
- name and category of history items can now be changed in web-interface;
|
||||
RPC-API method "editqueue" extended with new actions "HistorySetName" and
|
||||
"HistorySetCategory";
|
||||
- improved timeout handling during establishing of connections;
|
||||
- updated pp-script "EMail.py":
|
||||
- using the new nzb-log feature;
|
||||
- new option "SendMail" allows to choose if the e-mail should be send
|
||||
always or on failure only;
|
||||
- updated pp-script "Logger.py" to use the new nzb-log feature;
|
||||
- improved cleanup (option ExtCleanupDisk):
|
||||
- if download was successful with health 100% the cleanup is now
|
||||
performed even if par-check and unpack were not made; previously a
|
||||
successful par-check or unpack were required for cleanup;
|
||||
- now the files are deleted in subdirectories too (recursively);
|
||||
- added a small button near feed name in the feed menu on downloads-page; a
|
||||
click on the button fetches the feed, whereas a click on the feed title
|
||||
shows feed's content (as before);
|
||||
- improved detection of malformed nzb-files: nzbs which are valid
|
||||
xml-documents but without nzb content are now rejected with an appropriate
|
||||
error message;
|
||||
- new action "Mark as success" on history page and in history details dialog:
|
||||
- items marked as success are considered successfully downloaded and
|
||||
processed, which is important for duplicate check;
|
||||
- use this command if the download was repaired outside of NZBGet;
|
||||
- new action "HistoryMarkSuccess" in RPC-method "editqueue";
|
||||
- new subcommand "S" of command "-E H" (command line interface);
|
||||
- new status "SUCCESS/MARK" can be returned by RPC-method "history";
|
||||
- improved support for update-scripts:
|
||||
- all command line parameters used to launch nzbget are passed to the
|
||||
script in env vars NZBUP_CMDLINEX, where X is a parameter number
|
||||
starting with 0;
|
||||
- if the path to update-script defined in package-info.json does not
|
||||
start with slash the path is considered being relative to application
|
||||
directory;
|
||||
- new env var NZBUP_RUNMODE (DAEMON, SERVER) is passed to the script;
|
||||
- fixed: env var NZBUP_PROCESSID had wrong value (ID of the parent
|
||||
process instead of the nzbget process);
|
||||
- added button "Test Connection" to make a news server connection test from
|
||||
web-interface;
|
||||
- renamed option "CreateBrokenLog" to "BrokenLog"; the old option name is
|
||||
recognized and automatically converted when the configuration is saved in
|
||||
web-interface;
|
||||
- improved the quality of speed throttling when a speed limit is active;
|
||||
- added hidden webui setting "rowSelect" to select records by clicking on any
|
||||
part of the row, not just on the check mark; to activate it change the
|
||||
setting "rowSelect" in webui/index.js;
|
||||
- when moving files to final destination the hidden files (with names starting
|
||||
with dot) are considered unimportant and no errors are printed if they
|
||||
cannot be moved; such files (.AppleDouble, .DS_Store, etc.) are usually
|
||||
used by services to hold metadata and can be safely ignored;
|
||||
- option sets (such as news-servers, categories, etc.) can now be reordered
|
||||
using news buttons "move up" and "move down";
|
||||
- updated info in about dialogs (Windows and Mac OS X);
|
||||
- updated description of few options;
|
||||
- changed defaults for few logging options;
|
||||
- improved timeout handling when connecting to news servers which have
|
||||
multiple addresses;
|
||||
- improved error handling when communicating with secure servers (do not
|
||||
trying to send quit-command if connection could not be established or was
|
||||
interrupted; this avoids unnecessary timeout);
|
||||
- improved connection handling when fetching nzb-files and rss feeds; do not
|
||||
print warning "Content-Length is not submitted by server..." anymore;
|
||||
- download speed in context menu of menubar icon is now shown in MB/s instead
|
||||
of KB/s (for speeds from 1 MB/s) (Mac OS X only);
|
||||
- configuration file nzbget.conf is now also searched in the app-directory on
|
||||
all platforms (for easier installation);
|
||||
- removed shell script "nzbgetd" which were used to control nzbget as a
|
||||
service; modern systems manage services in a diffreent way and do not
|
||||
require that old script anymore;
|
||||
- disabled changing of compiler options during configuring in debug mode
|
||||
(--enable-debug); it conflicted with cross-compiling and did not allow to
|
||||
pass extra options via CXXFLAGS; required debug options must be passed via
|
||||
CXXFLAGS now (for example for gcc: CXXFLAGS=-g ./configure --enable-debug);
|
||||
- disabled unnecessary assert-statements in par2-module when building in
|
||||
release mode;
|
||||
- fixed: parsing of RPC-parameters passed via URL were sometimes incorrect;
|
||||
- fixed: lowercase hex digits were not correctly parsed in URLs passed to
|
||||
RPC-API method "append";
|
||||
- fixed: in JSON-RPC the request-id was not transfered back in the response as
|
||||
required by JSON-RPC specification;
|
||||
- fixed: par-check in full verification mode (not in quick mode) could not
|
||||
detect damaged files if they were completely empty (0 bytes), which is
|
||||
possible when option "DirectWrite" was not active and all articles of the
|
||||
file were missing;
|
||||
- fixed possible crash when using remote command "-B dump" to print debug
|
||||
info;
|
||||
- fixed: remote command "-L HA" (which prints the history including hidden
|
||||
records) could crash;
|
||||
- suppress printing of memory leaks reports when the program terminates
|
||||
because of wrong command line switches (Windows debug mode only);
|
||||
- fixed: command "nzbget -L H" may crash if the history contained URL-items
|
||||
with certain status;
|
||||
- fixed: action "Split" may not work for bad nzb-files with missing segments;
|
||||
new Field "Progress" returned by RPC-method "listfiles" shows the download
|
||||
progress of the file taking missing articles into account;
|
||||
- if the lock-file cannot be created or the lock could not be acquired an
|
||||
error message is printed to the log-file;
|
||||
- fixed: update log shown during automatic update via web-interface may show
|
||||
duplicate messages or messages may clear out;
|
||||
- fixed: web-interface may fail to load on Firefox mobile;
|
||||
- fixed: command "make install" installed README from par2-subdirectory
|
||||
instead of main README.
|
||||
|
||||
nzbget-14.2:
|
||||
- fixed: the program could crash during download when article cache was
|
||||
active (more likely on very high download speeds);
|
||||
- fixed: the program could crash during download when article cache was active
|
||||
(more likely on very high download speeds);
|
||||
- fixed: unlike to all other scripts the update-script should not be
|
||||
automatically terminated when the program quits;
|
||||
- fixed: XML-RPC method "history" returned invalid xml when used with
|
||||
parameter "hidden=true" (JSON-RPC was fine).
|
||||
|
||||
nzbget-14.1:
|
||||
- fixed: program could crash during unpack (Posix) or unpack failure
|
||||
was reported (Windows);
|
||||
- fixed: program could crash during unpack (Posix) or unpack failure was
|
||||
reported (Windows);
|
||||
- fixed: quick par-check could hang on certain nzb-files containing multiple
|
||||
par-sets (occured only in 64 bit mode);
|
||||
- fixed: menubar icon was not visible on OSX in dark mode;
|
||||
- system sleep on idle state is now prevented during download and
|
||||
post-processing (Mac OSX only);
|
||||
- fixed: unrar may sometimes fail with message "no files to extract"
|
||||
(certain Linux systems);
|
||||
- fixed: menubar icon was not visible on Mac OS X in dark mode; system sleep
|
||||
on idle state is now prevented during download and post-processing
|
||||
(Mac OS X only);
|
||||
- fixed: unrar may sometimes fail with message "no files to extract" (certain
|
||||
Linux systems);
|
||||
- fixed false memory leak warning when compiled in debug mode (Windows only);
|
||||
- fixed: Mac OS X app didn't work on OS X 10.7 Lion.
|
||||
|
||||
nzbget-14.0:
|
||||
- added article cache:
|
||||
@@ -223,7 +461,7 @@ nzbget-14.0:
|
||||
- fixed: splitted .cbr-files were not properly joined;
|
||||
- fixed: inner files (files listed in nzb) bigger than 2GB could not be
|
||||
downloaded;
|
||||
- fixed: cleanup may leave some files undeleted (Mac OSX only);
|
||||
- fixed: cleanup may leave some files undeleted (Mac OS X only);
|
||||
- fixed: compiler error if configured using parameter "--disable-gzip";
|
||||
- fixed: one log-message was printed only to global log but not to nzb-item
|
||||
pp-log;
|
||||
@@ -677,7 +915,7 @@ nzbget-12.0:
|
||||
be viewed and changed in download-edit-dialog and
|
||||
history-edit-dialog via new button "Dupe";
|
||||
- for full documentation see http://nzbget.net/RSS#Duplicates;
|
||||
- created NZBGet.app - NZBGet is now a user friendly Mac OSX application
|
||||
- created NZBGet.app - NZBGet is now a user friendly Mac OS X application
|
||||
with easy installation and seamless integration into OS UI:
|
||||
works in background, is controlled from a web-browser, few
|
||||
important functions are accessible via menubar icon;
|
||||
@@ -811,7 +1049,7 @@ nzbget-12.0:
|
||||
DestDir is mounted to a network drive which is not available on program start;
|
||||
- added special handling for files ".AppleDouble" and ".DS_Store" during
|
||||
unpack to avoid problems on NAS having support for AFP protocol (used
|
||||
on Mac OSX);
|
||||
on Mac OS X);
|
||||
- history records with failed script status are now shown as "PP-FAILURE"
|
||||
in history list (instead of just "FAILURE");
|
||||
- option "DiskSpace" now checks space on "InterDir" in addition to
|
||||
|
||||
43
Makefile.am
43
Makefile.am
@@ -183,17 +183,31 @@ AM_CPPFLAGS = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs \
|
||||
nzbgetd \
|
||||
$(windows_FILES) \
|
||||
$(osx_FILES)
|
||||
$(osx_FILES) \
|
||||
$(linux_FILES)
|
||||
|
||||
windows_FILES = \
|
||||
daemon/windows/NTService.cpp \
|
||||
daemon/windows/NTService.h \
|
||||
daemon/windows/win32.h \
|
||||
daemon/windows/WinConsole.cpp \
|
||||
daemon/windows/WinConsole.h \
|
||||
nzbget.sln \
|
||||
nzbget.vcproj \
|
||||
nzbget-shell.bat
|
||||
windows/nzbget-command-shell.bat \
|
||||
windows/install-update.bat \
|
||||
windows/README-WINDOWS.txt \
|
||||
windows/package-info.json \
|
||||
windows/resources/mainicon.ico \
|
||||
windows/resources/nzbget.rc \
|
||||
windows/resources/resource.h \
|
||||
windows/resources/trayicon_idle.ico \
|
||||
windows/resources/trayicon_paused.ico \
|
||||
windows/resources/trayicon_working.ico \
|
||||
windows/setup/nzbget-setup.nsi \
|
||||
windows/setup/install.bmp \
|
||||
windows/setup/uninstall.bmp
|
||||
|
||||
osx_FILES = \
|
||||
osx/App_Prefix.pch \
|
||||
@@ -226,12 +240,21 @@ osx_FILES = \
|
||||
osx/Resources/Localizable.strings \
|
||||
osx/Resources/Welcome.rtf
|
||||
|
||||
linux_FILES = \
|
||||
linux/installer.sh \
|
||||
linux/install-update.sh \
|
||||
linux/package-info.json \
|
||||
linux/build-info.txt \
|
||||
linux/build-nzbget \
|
||||
linux/build-unpack
|
||||
|
||||
doc_FILES = \
|
||||
lib/par2/AUTHORS \
|
||||
lib/par2/README \
|
||||
AUTHORS \
|
||||
README \
|
||||
ChangeLog \
|
||||
COPYING \
|
||||
lib/par2/AUTHORS \
|
||||
lib/par2/README
|
||||
COPYING
|
||||
|
||||
exampleconf_FILES = \
|
||||
nzbget.conf
|
||||
@@ -273,7 +296,6 @@ scripts_FILES = \
|
||||
scripts/Logger.py
|
||||
|
||||
# Install
|
||||
sbin_SCRIPTS = nzbgetd
|
||||
dist_doc_DATA = $(doc_FILES)
|
||||
exampleconfdir = $(datadir)/nzbget
|
||||
dist_exampleconf_DATA = $(exampleconf_FILES)
|
||||
@@ -291,13 +313,6 @@ nobase_dist_scripts_SCRIPTS = $(scripts_FILES)
|
||||
# 3) delete original.temp
|
||||
# These steps ensure that the output file has the same permissions as the original file.
|
||||
|
||||
# Configure installed script
|
||||
install-exec-hook:
|
||||
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
|
||||
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
|
||||
# Prepare example configuration file
|
||||
install-data-hook:
|
||||
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
|
||||
97
Makefile.in
97
Makefile.in
@@ -122,8 +122,8 @@ mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(scriptsdir)" \
|
||||
"$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" \
|
||||
"$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"
|
||||
"$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampleconfdir)" \
|
||||
"$(DESTDIR)$(webuidir)"
|
||||
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
|
||||
PROGRAMS = $(bin_PROGRAMS)
|
||||
am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
|
||||
@@ -249,8 +249,7 @@ am__vpath_adj = case $$p in \
|
||||
esac;
|
||||
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||
nobase_dist_scriptsSCRIPT_INSTALL = $(install_sh_SCRIPT)
|
||||
sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
|
||||
SCRIPTS = $(nobase_dist_scripts_SCRIPTS) $(sbin_SCRIPTS)
|
||||
SCRIPTS = $(nobase_dist_scripts_SCRIPTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
@@ -453,17 +452,31 @@ AM_CPPFLAGS = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs \
|
||||
nzbgetd \
|
||||
$(windows_FILES) \
|
||||
$(osx_FILES)
|
||||
$(osx_FILES) \
|
||||
$(linux_FILES)
|
||||
|
||||
windows_FILES = \
|
||||
daemon/windows/NTService.cpp \
|
||||
daemon/windows/NTService.h \
|
||||
daemon/windows/win32.h \
|
||||
daemon/windows/WinConsole.cpp \
|
||||
daemon/windows/WinConsole.h \
|
||||
nzbget.sln \
|
||||
nzbget.vcproj \
|
||||
nzbget-shell.bat
|
||||
windows/nzbget-command-shell.bat \
|
||||
windows/install-update.bat \
|
||||
windows/README-WINDOWS.txt \
|
||||
windows/package-info.json \
|
||||
windows/resources/mainicon.ico \
|
||||
windows/resources/nzbget.rc \
|
||||
windows/resources/resource.h \
|
||||
windows/resources/trayicon_idle.ico \
|
||||
windows/resources/trayicon_paused.ico \
|
||||
windows/resources/trayicon_working.ico \
|
||||
windows/setup/nzbget-setup.nsi \
|
||||
windows/setup/install.bmp \
|
||||
windows/setup/uninstall.bmp
|
||||
|
||||
osx_FILES = \
|
||||
osx/App_Prefix.pch \
|
||||
@@ -496,12 +509,21 @@ osx_FILES = \
|
||||
osx/Resources/Localizable.strings \
|
||||
osx/Resources/Welcome.rtf
|
||||
|
||||
linux_FILES = \
|
||||
linux/installer.sh \
|
||||
linux/install-update.sh \
|
||||
linux/package-info.json \
|
||||
linux/build-info.txt \
|
||||
linux/build-nzbget \
|
||||
linux/build-unpack
|
||||
|
||||
doc_FILES = \
|
||||
lib/par2/AUTHORS \
|
||||
lib/par2/README \
|
||||
AUTHORS \
|
||||
README \
|
||||
ChangeLog \
|
||||
COPYING \
|
||||
lib/par2/AUTHORS \
|
||||
lib/par2/README
|
||||
COPYING
|
||||
|
||||
exampleconf_FILES = \
|
||||
nzbget.conf
|
||||
@@ -544,7 +566,6 @@ scripts_FILES = \
|
||||
|
||||
|
||||
# Install
|
||||
sbin_SCRIPTS = nzbgetd
|
||||
dist_doc_DATA = $(doc_FILES)
|
||||
exampleconfdir = $(datadir)/nzbget
|
||||
dist_exampleconf_DATA = $(exampleconf_FILES)
|
||||
@@ -664,25 +685,6 @@ uninstall-nobase_dist_scriptsSCRIPTS:
|
||||
echo " rm -f '$(DESTDIR)$(scriptsdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(scriptsdir)/$$f"; \
|
||||
done
|
||||
install-sbinSCRIPTS: $(sbin_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
|
||||
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f $$d$$p; then \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
echo " $(sbinSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
|
||||
$(sbinSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(sbindir)/$$f"; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-sbinSCRIPTS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(sbindir)/$$f"; \
|
||||
done
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
@@ -1846,7 +1848,7 @@ distclean-tags:
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(mkdir_p) $(distdir)/daemon/windows $(distdir)/lib/par2 $(distdir)/osx $(distdir)/osx/NZBGet.xcodeproj $(distdir)/osx/Resources $(distdir)/osx/Resources/Images $(distdir)/osx/Resources/licenses $(distdir)/scripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
|
||||
$(mkdir_p) $(distdir)/daemon/windows $(distdir)/lib/par2 $(distdir)/linux $(distdir)/osx $(distdir)/osx/NZBGet.xcodeproj $(distdir)/osx/Resources $(distdir)/osx/Resources/Images $(distdir)/osx/Resources/licenses $(distdir)/scripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib $(distdir)/windows $(distdir)/windows/resources $(distdir)/windows/setup
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
@@ -1977,7 +1979,7 @@ check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) config.h
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(scriptsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"; do \
|
||||
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(scriptsdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"; do \
|
||||
test -z "$$dir" || $(mkdir_p) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
@@ -2031,9 +2033,7 @@ install-data-am: install-dist_docDATA install-dist_exampleconfDATA \
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-data-hook
|
||||
|
||||
install-exec-am: install-binPROGRAMS install-sbinSCRIPTS
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
|
||||
install-exec-am: install-binPROGRAMS
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
@@ -2063,7 +2063,7 @@ ps-am:
|
||||
uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
|
||||
uninstall-dist_exampleconfDATA uninstall-info-am \
|
||||
uninstall-nobase_dist_scriptsSCRIPTS \
|
||||
uninstall-nobase_dist_webuiDATA uninstall-sbinSCRIPTS
|
||||
uninstall-nobase_dist_webuiDATA
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
|
||||
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
|
||||
@@ -2074,16 +2074,16 @@ uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
|
||||
install-binPROGRAMS install-data install-data-am \
|
||||
install-data-hook install-dist_docDATA \
|
||||
install-dist_exampleconfDATA install-exec install-exec-am \
|
||||
install-exec-hook install-info install-info-am install-man \
|
||||
install-info install-info-am install-man \
|
||||
install-nobase_dist_scriptsSCRIPTS \
|
||||
install-nobase_dist_webuiDATA install-sbinSCRIPTS \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-binPROGRAMS \
|
||||
uninstall-dist_docDATA uninstall-dist_exampleconfDATA \
|
||||
uninstall-info-am uninstall-nobase_dist_scriptsSCRIPTS \
|
||||
uninstall-nobase_dist_webuiDATA uninstall-sbinSCRIPTS
|
||||
install-nobase_dist_webuiDATA install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-binPROGRAMS uninstall-dist_docDATA \
|
||||
uninstall-dist_exampleconfDATA uninstall-info-am \
|
||||
uninstall-nobase_dist_scriptsSCRIPTS \
|
||||
uninstall-nobase_dist_webuiDATA
|
||||
|
||||
|
||||
# Note about "sed":
|
||||
@@ -2095,13 +2095,6 @@ uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
|
||||
# 3) delete original.temp
|
||||
# These steps ensure that the output file has the same permissions as the original file.
|
||||
|
||||
# Configure installed script
|
||||
install-exec-hook:
|
||||
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
|
||||
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
|
||||
# Prepare example configuration file
|
||||
install-data-hook:
|
||||
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
|
||||
36
README
36
README
@@ -44,25 +44,16 @@ depends on command-line parameters passed to the program.
|
||||
2. Supported OS
|
||||
=====================================
|
||||
|
||||
NZBGet is written in C++ and was initialy developed on Linux.
|
||||
It was ported to Windows later and tested for compatibility with
|
||||
several POSIX-OS'es.
|
||||
|
||||
It should run at least on:
|
||||
- Linux Debian 5.0 on x86;
|
||||
- Linux with uClibc on MIPSEL and ARM;
|
||||
- OpenBSD 5.0 on x86;
|
||||
- Mac OS X 10.7 Lion on x64;
|
||||
- Windows XP SP3 on x86 and Windows 7 on x64.
|
||||
NZBGet is written in C++ and works on Windows, OS X, Linux and
|
||||
most POSIX-conform OS'es.
|
||||
|
||||
Clients and servers running on different OS'es may communicate with
|
||||
each other. For example, you can use NZBGet as client on Windows to
|
||||
control your NZBGet-server running on Linux.
|
||||
|
||||
The download-section of NZBGet web-site provides binary files
|
||||
for Windows. The binary packages for many routers and NAS devices are
|
||||
also available in OPTWARE repository (http://www.nslu2-linux.org),
|
||||
but for most POSIX-systems you need to compile the program yourself.
|
||||
for Windows, OS X and Linux. For most POSIX-systems you need to compile
|
||||
the program yourself.
|
||||
|
||||
If you have downloaded binaries you can just jump to section
|
||||
"Configuration".
|
||||
@@ -71,8 +62,8 @@ If you have downloaded binaries you can just jump to section
|
||||
3. Prerequisites on POSIX
|
||||
=====================================
|
||||
|
||||
NZBGet is developed on a linux-system, but it should run on other
|
||||
POSIX platforms (see the list of tested platforms above).
|
||||
NZBGet is developed on a linux-system, but it runs on other
|
||||
POSIX platforms.
|
||||
|
||||
NZBGet absolutely needs the following libraries:
|
||||
|
||||
@@ -94,7 +85,7 @@ And the following libraries are optional:
|
||||
- for gzip support in web-server and web-client (enabled by default):
|
||||
- zlib (http://www.zlib.net)
|
||||
|
||||
All these libraries are included in modern Linux distributions and
|
||||
All these libraries are included in modern POSIX distributions and
|
||||
should be available as installable packages. Please note that you also
|
||||
need the developer packages for these libraries too, they package names
|
||||
have often suffix "dev" or "devel". On other systems you may need to
|
||||
@@ -180,8 +171,8 @@ For curses-outputmode you need ncurses or curses on your system.
|
||||
If you do not have one of them you can download and compile ncurses yourself.
|
||||
Following configure-parameters may be useful:
|
||||
|
||||
--with-libcurses-includes
|
||||
--with-libcurses-libraries
|
||||
--with-libcurses-includes=/path/to/curses/includes
|
||||
--with-libcurses-libraries=/path/to/curses/libraries
|
||||
|
||||
If you are not able to use curses or ncurses or do not want them you can
|
||||
make the program without support for curses using option "--disable-curses":
|
||||
@@ -200,11 +191,11 @@ the option --with-tlslib=(OpenSSL, GnuTLS). For example to build with GnuTLS:
|
||||
|
||||
Following configure-parameters may be useful:
|
||||
|
||||
--with-libtls-includes
|
||||
--with-libtls-libraries
|
||||
--with-libtls-includess=/path/to/gnutls/includes
|
||||
--with-libtls-libraries=/path/to/gnutls/libraries
|
||||
|
||||
--with-openssl-includes
|
||||
--with-openssl-libraries
|
||||
--with-openssl-includess=/path/to/openssl/includes
|
||||
--with-openssl-libraries=/path/to/openssl/libraries
|
||||
|
||||
If none of these libraries is available you can make the program without
|
||||
TLS/SSL support using option "--disable-tls":
|
||||
@@ -253,6 +244,7 @@ The program looks for configuration file in following standard
|
||||
locations (in this order):
|
||||
|
||||
On POSIX systems:
|
||||
<EXE-DIR>/nzbget.conf
|
||||
~/.nzbget
|
||||
/etc/nzbget.conf
|
||||
/usr/etc/nzbget.conf
|
||||
|
||||
@@ -155,6 +155,9 @@
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to 1 to exclude debug-code */
|
||||
#undef NDEBUG
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
|
||||
45
configure
vendored
45
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 14.2.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 15.0.
|
||||
#
|
||||
# Report bugs to <hugbug@users.sourceforge.net>.
|
||||
#
|
||||
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='nzbget'
|
||||
PACKAGE_TARNAME='nzbget'
|
||||
PACKAGE_VERSION='14.2'
|
||||
PACKAGE_STRING='nzbget 14.2'
|
||||
PACKAGE_VERSION='15.0'
|
||||
PACKAGE_STRING='nzbget 15.0'
|
||||
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
|
||||
|
||||
ac_unique_file="daemon/main/nzbget.cpp"
|
||||
@@ -1233,7 +1233,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures nzbget 14.2 to adapt to many kinds of systems.
|
||||
\`configure' configures nzbget 15.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1304,7 +1304,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of nzbget 14.2:";;
|
||||
short | recursive ) echo "Configuration of nzbget 15.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1435,7 +1435,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
nzbget configure 14.2
|
||||
nzbget configure 15.0
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1449,7 +1449,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by nzbget $as_me 14.2, which was
|
||||
It was created by nzbget $as_me 15.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2245,7 +2245,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=nzbget
|
||||
VERSION=14.2
|
||||
VERSION=15.0
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -8243,13 +8243,11 @@ _ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <sys/types.h> /* for off_t */
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int (*fp) (FILE *, off_t, int) = fseeko;
|
||||
return fseeko (stdin, 0, 0) && fp (stdin, 0, 0);
|
||||
return fseeko (stdin, 0, 0) && (fseeko) (stdin, 0, 0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@@ -8289,13 +8287,11 @@ cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
#include <sys/types.h> /* for off_t */
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int (*fp) (FILE *, off_t, int) = fseeko;
|
||||
return fseeko (stdin, 0, 0) && fp (stdin, 0, 0);
|
||||
return fseeko (stdin, 0, 0) && (fseeko) (stdin, 0, 0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@@ -10070,13 +10066,6 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
if test "$CC" = "gcc"; then
|
||||
CXXFLAGS="-g -Wall"
|
||||
else
|
||||
CXXFLAGS=""
|
||||
fi
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for macro returning current function name" >&5
|
||||
echo $ECHO_N "checking for macro returning current function name... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
@@ -10327,6 +10316,12 @@ fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
|
||||
else
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define NDEBUG 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -10756,7 +10751,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by nzbget $as_me 14.2, which was
|
||||
This file was extended by nzbget $as_me 15.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -10809,7 +10804,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
nzbget config.status 14.2
|
||||
nzbget config.status 15.0
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
18
configure.ac
18
configure.ac
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# This file is part of nzbget
|
||||
#
|
||||
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -23,9 +23,9 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 14.2, hugbug@users.sourceforge.net)
|
||||
AC_INIT(nzbget, 15.0, hugbug@users.sourceforge.net)
|
||||
AC_CANONICAL_SYSTEM
|
||||
AM_INIT_AUTOMAKE(nzbget, 14.2)
|
||||
AM_INIT_AUTOMAKE(nzbget, 15.0)
|
||||
AC_CONFIG_SRCDIR([daemon/main/nzbget.cpp])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
@@ -524,16 +524,6 @@ dnl
|
||||
AC_DEFINE([DEBUG],1,Define to 1 to include debug-code)
|
||||
|
||||
|
||||
dnl
|
||||
dnl Set debug flags for gcc (if gcc is used)
|
||||
dnl
|
||||
if test "$CC" = "gcc"; then
|
||||
CXXFLAGS="-g -Wall"
|
||||
else
|
||||
CXXFLAGS=""
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl check for __FUNCTION__ or __func__ macro
|
||||
dnl
|
||||
@@ -597,6 +587,8 @@ AC_MSG_CHECKING(for rdynamic linker flag)
|
||||
dnl
|
||||
dnl End of debugging code
|
||||
dnl
|
||||
else
|
||||
AC_DEFINE([NDEBUG],1,Define to 1 to exclude debug-code)
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,8 +49,12 @@
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Connection.h"
|
||||
#include "Log.h"
|
||||
@@ -62,7 +66,6 @@ Mutex* Connection::m_pMutexGetHostByName = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void Connection::Init()
|
||||
{
|
||||
debug("Initializing global connection data");
|
||||
@@ -128,6 +131,7 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
|
||||
m_bSuppressErrors = true;
|
||||
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
|
||||
m_iTotalBytesRead = 0;
|
||||
m_bBroken = false;
|
||||
#ifndef DISABLE_TLS
|
||||
m_pTLSSocket = NULL;
|
||||
m_bTLSError = false;
|
||||
@@ -254,14 +258,18 @@ bool Connection::Bind()
|
||||
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
|
||||
if (res != 0)
|
||||
{
|
||||
error("Could not resolve hostname %s", m_szHost);
|
||||
ReportError("Could not resolve hostname %s", m_szHost, false, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bBroken = false;
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
#ifdef WIN32
|
||||
SetHandleInformation((HANDLE)m_iSocket, HANDLE_FLAG_INHERIT, 0);
|
||||
#endif
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
int opt = 1;
|
||||
@@ -345,6 +353,10 @@ int Connection::WriteLine(const char* pBuffer)
|
||||
}
|
||||
|
||||
int iRes = send(m_iSocket, pBuffer, strlen(pBuffer), 0);
|
||||
if (iRes <= 0)
|
||||
{
|
||||
m_bBroken = true;
|
||||
}
|
||||
|
||||
return iRes;
|
||||
}
|
||||
@@ -364,6 +376,7 @@ bool Connection::Send(const char* pBuffer, int iSize)
|
||||
int iRes = send(m_iSocket, pBuffer + iBytesSent, iSize-iBytesSent, 0);
|
||||
if (iRes <= 0)
|
||||
{
|
||||
m_bBroken = true;
|
||||
return false;
|
||||
}
|
||||
iBytesSent += iRes;
|
||||
@@ -392,6 +405,7 @@ char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
if (iBufAvail < 0)
|
||||
{
|
||||
ReportError("Could not receive data on socket", NULL, true, 0);
|
||||
m_bBroken = true;
|
||||
break;
|
||||
}
|
||||
else if (iBufAvail == 0)
|
||||
@@ -530,6 +544,7 @@ bool Connection::DoConnect()
|
||||
debug("Do connecting");
|
||||
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
m_bBroken = false;
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo addr_hints, *addr_list, *addr;
|
||||
@@ -548,32 +563,49 @@ bool Connection::DoConnect()
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<SockAddr> triedAddr;
|
||||
bool bConnected = false;
|
||||
|
||||
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
bool bLastAddr = !addr->ai_next;
|
||||
// don't try the same combinations of ai_family, ai_socktype, ai_protocol multiple times
|
||||
SockAddr sa = { addr->ai_family, addr->ai_socktype, addr->ai_protocol };
|
||||
if (std::find(triedAddr.begin(), triedAddr.end(), sa) != triedAddr.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
triedAddr.push_back(sa);
|
||||
|
||||
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
#ifdef WIN32
|
||||
SetHandleInformation((HANDLE)m_iSocket, HANDLE_FLAG_INHERIT, 0);
|
||||
#endif
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
res = connect(m_iSocket , addr->ai_addr, addr->ai_addrlen);
|
||||
if (res != -1)
|
||||
{
|
||||
// Connection established
|
||||
break;
|
||||
}
|
||||
// Connection failed
|
||||
if (bLastAddr)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
}
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
// try another addr/family/protocol
|
||||
continue;
|
||||
}
|
||||
else if (bLastAddr)
|
||||
|
||||
if (ConnectWithTimeout(addr->ai_addr, addr->ai_addrlen))
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_szHost, true, 0);
|
||||
// Connection established
|
||||
bConnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET && addr_list)
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_szHost, true, 0);
|
||||
}
|
||||
|
||||
if (!bConnected && m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
freeaddrinfo(addr_list);
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
@@ -600,8 +632,7 @@ bool Connection::DoConnect()
|
||||
return false;
|
||||
}
|
||||
|
||||
int res = connect(m_iSocket , (struct sockaddr *) & sSocketAddress, sizeof(sSocketAddress));
|
||||
if (res == -1)
|
||||
if (!ConnectWithTimeout(&sSocketAddress, sizeof(sSocketAddress)))
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
closesocket(m_iSocket);
|
||||
@@ -610,18 +641,9 @@ bool Connection::DoConnect()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
int MSecVal = m_iTimeout * 1000;
|
||||
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&MSecVal, sizeof(MSecVal));
|
||||
#else
|
||||
struct timeval TimeVal;
|
||||
TimeVal.tv_sec = m_iTimeout;
|
||||
TimeVal.tv_usec = 0;
|
||||
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&TimeVal, sizeof(TimeVal));
|
||||
#endif
|
||||
if (err != 0)
|
||||
if (!InitSocketOpts())
|
||||
{
|
||||
ReportError("Socket initialization failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
@@ -634,6 +656,146 @@ bool Connection::DoConnect()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::InitSocketOpts()
|
||||
{
|
||||
char* optbuf = NULL;
|
||||
int optsize = 0;
|
||||
#ifdef WIN32
|
||||
int MSecVal = m_iTimeout * 1000;
|
||||
optbuf = (char*)&MSecVal;
|
||||
optsize = sizeof(MSecVal);
|
||||
#else
|
||||
struct timeval TimeVal;
|
||||
TimeVal.tv_sec = m_iTimeout;
|
||||
TimeVal.tv_usec = 0;
|
||||
optbuf = (char*)&TimeVal;
|
||||
optsize = sizeof(TimeVal);
|
||||
#endif
|
||||
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, optbuf, optsize);
|
||||
if (err != 0)
|
||||
{
|
||||
ReportError("Socket initialization failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
err = setsockopt(m_iSocket, SOL_SOCKET, SO_SNDTIMEO, optbuf, optsize);
|
||||
if (err != 0)
|
||||
{
|
||||
ReportError("Socket initialization failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::ConnectWithTimeout(void* address, int address_len)
|
||||
{
|
||||
int flags = 0, error = 0, ret = 0;
|
||||
fd_set rset, wset;
|
||||
socklen_t len = sizeof(error);
|
||||
|
||||
struct timeval ts;
|
||||
ts.tv_sec = m_iTimeout;
|
||||
ts.tv_usec = 0;
|
||||
|
||||
//clear out descriptor sets for select
|
||||
//add socket to the descriptor sets
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(m_iSocket, &rset);
|
||||
wset = rset; //structure assignment ok
|
||||
|
||||
//set socket nonblocking flag
|
||||
#ifdef WIN32
|
||||
u_long mode = 1;
|
||||
if (ioctlsocket(m_iSocket, FIONBIO, &mode) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
flags = fcntl(m_iSocket, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcntl(m_iSocket, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//initiate non-blocking connect
|
||||
ret = connect(m_iSocket, (struct sockaddr*)address, address_len);
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (errno != EINPROGRESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//connect succeeded right away?
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = select(m_iSocket + 1, &rset, &wset, NULL, m_iTimeout ? &ts : NULL);
|
||||
//we are waiting for connect to complete now
|
||||
if (ret < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
//we had a timeout
|
||||
#ifdef WIN32
|
||||
WSASetLastError(WSAETIMEDOUT);
|
||||
#else
|
||||
errno = ETIMEDOUT;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(FD_ISSET(m_iSocket, &rset) || FD_ISSET(m_iSocket, &wset)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//we had a positivite return so a descriptor is ready
|
||||
|
||||
if (getsockopt(m_iSocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if we had a socket error
|
||||
if (error)
|
||||
{
|
||||
errno = error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//put socket back in blocking mode
|
||||
#ifdef WIN32
|
||||
mode = 0;
|
||||
if (ioctlsocket(m_iSocket, FIONBIO, &mode) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (fcntl(m_iSocket, F_SETFL, flags) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connection::DoDisconnect()
|
||||
{
|
||||
debug("Do disconnecting");
|
||||
@@ -686,12 +848,15 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
char szErrPrefix[1024];
|
||||
snprintf(szErrPrefix, 1024, szMsgPrefix, szMsgArg);
|
||||
szErrPrefix[1024-1] = '\0';
|
||||
|
||||
|
||||
char szMessage[1024];
|
||||
|
||||
if (PrintErrCode)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int ErrCode = WSAGetLastError();
|
||||
char szErrMsg[1024];
|
||||
szErrMsg[0] = '\0';
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrCode, 0, szErrMsg, 1024, NULL);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
#else
|
||||
@@ -713,7 +878,9 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
|
||||
snprintf(szMessage, sizeof(szMessage), "%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
|
||||
szMessage[sizeof(szMessage) - 1] = '\0';
|
||||
PrintError(szMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -724,18 +891,23 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
error(szErrPrefix);
|
||||
PrintError(szErrPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::PrintError(const char* szErrMsg)
|
||||
{
|
||||
error("%s", szErrMsg);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
bool Connection::StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile)
|
||||
{
|
||||
debug("Starting TLS");
|
||||
|
||||
delete m_pTLSSocket;
|
||||
m_pTLSSocket = new TLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher);
|
||||
m_pTLSSocket = new ConTLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher, this);
|
||||
m_pTLSSocket->SetSuppressErrors(m_bSuppressErrors);
|
||||
|
||||
return m_pTLSSocket->Start();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -61,8 +61,31 @@ protected:
|
||||
bool m_bSuppressErrors;
|
||||
char m_szRemoteAddr[20];
|
||||
int m_iTotalBytesRead;
|
||||
bool m_bBroken;
|
||||
|
||||
struct SockAddr
|
||||
{
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
bool operator==(const SockAddr& rhs) const
|
||||
{ return memcmp(this, &rhs, sizeof(SockAddr)) == 0; }
|
||||
};
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
TLSSocket* m_pTLSSocket;
|
||||
class ConTLSSocket: public TLSSocket
|
||||
{
|
||||
private:
|
||||
Connection* m_pOwner;
|
||||
protected:
|
||||
virtual void PrintError(const char* szErrMsg) { m_pOwner->PrintError(szErrMsg); }
|
||||
public:
|
||||
ConTLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile,
|
||||
const char* szKeyFile, const char* szCipher, Connection* pOwner):
|
||||
TLSSocket(iSocket, bIsClient, szCertFile, szKeyFile, szCipher), m_pOwner(pOwner) {}
|
||||
};
|
||||
|
||||
ConTLSSocket* m_pTLSSocket;
|
||||
bool m_bTLSError;
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -73,8 +96,11 @@ protected:
|
||||
|
||||
Connection(SOCKET iSocket, bool bTLS);
|
||||
void ReportError(const char* szMsgPrefix, const char* szMsgArg, bool PrintErrCode, int herrno);
|
||||
virtual void PrintError(const char* szErrMsg);
|
||||
bool DoConnect();
|
||||
bool DoDisconnect();
|
||||
bool InitSocketOpts();
|
||||
bool ConnectWithTimeout(void* address, int address_len);
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
unsigned int ResolveHostAddr(const char* szHost);
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -283,6 +284,8 @@ TLSSocket::~TLSSocket()
|
||||
|
||||
void TLSSocket::ReportError(const char* szErrMsg)
|
||||
{
|
||||
char szMessage[1024];
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
const char* errstr = gnutls_strerror(m_iRetCode);
|
||||
if (m_bSuppressErrors)
|
||||
@@ -291,7 +294,9 @@ void TLSSocket::ReportError(const char* szErrMsg)
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s: %s", szErrMsg, errstr);
|
||||
snprintf(szMessage, sizeof(szMessage), "%s: %s", szErrMsg, errstr);
|
||||
szMessage[sizeof(szMessage) - 1] = '\0';
|
||||
PrintError(szMessage);
|
||||
}
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
|
||||
@@ -311,16 +316,23 @@ void TLSSocket::ReportError(const char* szErrMsg)
|
||||
}
|
||||
else if (errcode != 0)
|
||||
{
|
||||
error("%s: %s", szErrMsg, errstr);
|
||||
snprintf(szMessage, sizeof(szMessage), "%s: %s", szErrMsg, errstr);
|
||||
szMessage[sizeof(szMessage) - 1] = '\0';
|
||||
PrintError(szMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s", szErrMsg);
|
||||
PrintError(szErrMsg);
|
||||
}
|
||||
} while (errcode);
|
||||
#endif /* HAVE_OPENSSL */
|
||||
}
|
||||
|
||||
void TLSSocket::PrintError(const char* szErrMsg)
|
||||
{
|
||||
error("%s", szErrMsg);
|
||||
}
|
||||
|
||||
bool TLSSocket::Start()
|
||||
{
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -46,9 +46,12 @@ private:
|
||||
|
||||
void ReportError(const char* szErrMsg);
|
||||
|
||||
protected:
|
||||
virtual void PrintError(const char* szErrMsg);
|
||||
|
||||
public:
|
||||
TLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile, const char* szKeyFile, const char* szCipher);
|
||||
~TLSSocket();
|
||||
virtual ~TLSSocket();
|
||||
static void Init();
|
||||
static void Final();
|
||||
bool Start();
|
||||
|
||||
@@ -366,10 +366,6 @@ WebDownloader::EStatus WebDownloader::DownloadHeaders()
|
||||
// detect body of response
|
||||
if (*line == '\r' || *line == '\n')
|
||||
{
|
||||
if (m_iContentLen == -1 && !m_bGZip)
|
||||
{
|
||||
warn("URL %s: Content-Length is not submitted by server, cannot verify whether the file is complete", m_szInfoName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -420,10 +416,10 @@ WebDownloader::EStatus WebDownloader::DownloadBody()
|
||||
szBuffer = szLineBuf;
|
||||
}
|
||||
|
||||
// Have we encountered a timeout?
|
||||
// Connection closed or timeout?
|
||||
if (iLen <= 0)
|
||||
{
|
||||
if (m_iContentLen == -1 && iWrittenLen > 0)
|
||||
if (iLen == 0 && m_iContentLen == -1 && iWrittenLen > 0)
|
||||
{
|
||||
bEnd = true;
|
||||
break;
|
||||
|
||||
@@ -521,7 +521,7 @@ bool FeedFilter::Term::ParseNumericParam(const char* szParam)
|
||||
m_bFloat = strchr(szParam, '.');
|
||||
|
||||
const char* p;
|
||||
for (p = szParam; *p && ((*p >= '0' && *p <='9') || *p == '.') ; p++) ;
|
||||
for (p = szParam; *p && ((*p >= '0' && *p <='9') || *p == '.' || *p == '-') ; p++) ;
|
||||
if (*p)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -119,11 +119,7 @@ void Frontend::FreeData()
|
||||
{
|
||||
if (IsRemoteMode())
|
||||
{
|
||||
for (Log::Messages::iterator it = m_RemoteMessages.begin(); it != m_RemoteMessages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_RemoteMessages.clear();
|
||||
m_RemoteMessages.Clear();
|
||||
|
||||
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
|
||||
pDownloadQueue->GetQueue()->Clear();
|
||||
@@ -131,7 +127,7 @@ void Frontend::FreeData()
|
||||
}
|
||||
}
|
||||
|
||||
Log::Messages* Frontend::LockMessages()
|
||||
MessageList* Frontend::LockMessages()
|
||||
{
|
||||
if (IsRemoteMode())
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,7 +36,7 @@
|
||||
class Frontend : public Thread
|
||||
{
|
||||
private:
|
||||
Log::Messages m_RemoteMessages;
|
||||
MessageList m_RemoteMessages;
|
||||
|
||||
bool RequestMessages();
|
||||
bool RequestFileList();
|
||||
@@ -62,7 +62,7 @@ protected:
|
||||
|
||||
bool PrepareData();
|
||||
void FreeData();
|
||||
Log::Messages* LockMessages();
|
||||
MessageList* LockMessages();
|
||||
void UnlockMessages();
|
||||
DownloadQueue* LockQueue();
|
||||
void UnlockQueue();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -79,7 +79,7 @@ void LoggableFrontend::Update()
|
||||
|
||||
BeforePrint();
|
||||
|
||||
Log::Messages* pMessages = LockMessages();
|
||||
MessageList* pMessages = LockMessages();
|
||||
if (!pMessages->empty())
|
||||
{
|
||||
Message* pFirstMessage = pMessages->front();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -504,7 +504,7 @@ void NCursesFrontend::PrintMessages()
|
||||
int iLine = iLineNr + m_iMessagesWinClientHeight - 1;
|
||||
int iLinesToPrint = m_iMessagesWinClientHeight;
|
||||
|
||||
Log::Messages* pMessages = LockMessages();
|
||||
MessageList* pMessages = LockMessages();
|
||||
|
||||
// print messages from bottom
|
||||
for (int i = (int)pMessages->size() - 1; i >= 0 && iLinesToPrint > 0; i--)
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern Maintenance* g_pMaintenance;
|
||||
extern void ExitProc();
|
||||
extern int g_iArgumentCount;
|
||||
extern char* (*g_szArguments)[];
|
||||
|
||||
Maintenance::Maintenance()
|
||||
{
|
||||
@@ -69,7 +72,7 @@ Maintenance::~Maintenance()
|
||||
}
|
||||
}
|
||||
|
||||
ClearMessages();
|
||||
m_Messages.Clear();
|
||||
|
||||
free(m_szUpdateScript);
|
||||
}
|
||||
@@ -81,16 +84,7 @@ void Maintenance::ResetUpdateController()
|
||||
m_mutexController.Unlock();
|
||||
}
|
||||
|
||||
void Maintenance::ClearMessages()
|
||||
{
|
||||
for (Log::Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
}
|
||||
|
||||
Log::Messages* Maintenance::LockMessages()
|
||||
MessageList* Maintenance::LockMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
@@ -101,7 +95,7 @@ void Maintenance::UnlockMessages()
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void Maintenance::AppendMessage(Message::EKind eKind, time_t tTime, const char * szText)
|
||||
void Maintenance::AddMessage(Message::EKind eKind, time_t tTime, const char * szText)
|
||||
{
|
||||
if (tTime == 0)
|
||||
{
|
||||
@@ -137,7 +131,20 @@ bool Maintenance::StartUpdate(EBranch eBranch)
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearMessages();
|
||||
// make absolute path
|
||||
if (m_szUpdateScript[0] != PATH_SEPARATOR
|
||||
#ifdef WIN32
|
||||
&& !(strlen(m_szUpdateScript) > 2 && m_szUpdateScript[1] == ':')
|
||||
#endif
|
||||
)
|
||||
{
|
||||
char szFilename[MAX_PATH + 100];
|
||||
snprintf(szFilename, sizeof(szFilename), "%s%c%s", g_pOptions->GetAppDir(), PATH_SEPARATOR, m_szUpdateScript);
|
||||
free(m_szUpdateScript);
|
||||
m_szUpdateScript = strdup(szFilename);
|
||||
}
|
||||
|
||||
m_Messages.Clear();
|
||||
|
||||
m_UpdateScriptController = new UpdateScriptController();
|
||||
m_UpdateScriptController->SetScript(m_szUpdateScript);
|
||||
@@ -243,11 +250,21 @@ void UpdateScriptController::Run()
|
||||
const char* szBranchName[] = { "STABLE", "TESTING", "DEVEL" };
|
||||
SetEnvVar("NZBUP_BRANCH", szBranchName[m_eBranch]);
|
||||
|
||||
SetEnvVar("NZBUP_RUNMODE", g_pOptions->GetDaemonMode() ? "DAEMON" : "SERVER");
|
||||
|
||||
for (int i = 0; i < g_iArgumentCount; i++)
|
||||
{
|
||||
char szEnvName[40];
|
||||
snprintf(szEnvName, 40, "NZBUP_CMDLINE%i", i);
|
||||
szInfoName[40-1] = '\0';
|
||||
SetEnvVar(szEnvName, (*g_szArguments)[i]);
|
||||
}
|
||||
|
||||
char szProcessID[20];
|
||||
#ifdef WIN32
|
||||
int pid = (int)GetCurrentProcessId();
|
||||
#else
|
||||
int pid = (int)getppid();
|
||||
int pid = (int)getpid();
|
||||
#endif
|
||||
snprintf(szProcessID, 20, "%i", pid);
|
||||
szProcessID[20-1] = '\0';
|
||||
@@ -269,8 +286,24 @@ void UpdateScriptController::AddMessage(Message::EKind eKind, const char* szText
|
||||
{
|
||||
szText = szText + m_iPrefixLen;
|
||||
|
||||
g_pMaintenance->AppendMessage(eKind, time(NULL), szText);
|
||||
ScriptController::AddMessage(eKind, szText);
|
||||
if (!strncmp(szText, "[NZB] ", 6))
|
||||
{
|
||||
debug("Command %s detected", szText + 6);
|
||||
if (!strcmp(szText + 6, "QUIT"))
|
||||
{
|
||||
Detach();
|
||||
ExitProc();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Invalid command \"%s\" received", szText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pMaintenance->AddMessage(eKind, time(NULL), szText);
|
||||
ScriptController::AddMessage(eKind, szText);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInfoScriptController::ExecuteScript(const char* szScript, char** pUpdateInfo)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,7 +35,7 @@ class UpdateScriptController;
|
||||
class Maintenance
|
||||
{
|
||||
private:
|
||||
Log::Messages m_Messages;
|
||||
MessageList m_Messages;
|
||||
Mutex m_mutexLog;
|
||||
Mutex m_mutexController;
|
||||
int m_iIDMessageGen;
|
||||
@@ -54,9 +54,8 @@ public:
|
||||
|
||||
Maintenance();
|
||||
~Maintenance();
|
||||
void ClearMessages();
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
Log::Messages* LockMessages();
|
||||
void AddMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
MessageList* LockMessages();
|
||||
void UnlockMessages();
|
||||
bool StartUpdate(EBranch eBranch);
|
||||
void ResetUpdateController();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,11 +35,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <set>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#include <Shlobj.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
@@ -60,6 +62,10 @@ extern ServerPool* g_pServerPool;
|
||||
extern Scheduler* g_pScheduler;
|
||||
extern FeedCoordinator* g_pFeedCoordinator;
|
||||
|
||||
#ifdef WIN32
|
||||
extern void SetupFirstStart();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static struct option long_options[] =
|
||||
{
|
||||
@@ -77,7 +83,7 @@ static struct option long_options[] =
|
||||
{"pause", no_argument, 0, 'P'},
|
||||
{"unpause", no_argument, 0, 'U'},
|
||||
{"rate", required_argument, 0, 'R'},
|
||||
{"debug", no_argument, 0, 'B'},
|
||||
{"system", no_argument, 0, 'B'},
|
||||
{"log", required_argument, 0, 'G'},
|
||||
{"top", no_argument, 0, 'T'},
|
||||
{"edit", required_argument, 0, 'E'},
|
||||
@@ -120,6 +126,10 @@ static const char* OPTION_CONTROLIP = "ControlIp";
|
||||
static const char* OPTION_CONTROLPORT = "ControlPort";
|
||||
static const char* OPTION_CONTROLUSERNAME = "ControlUsername";
|
||||
static const char* OPTION_CONTROLPASSWORD = "ControlPassword";
|
||||
static const char* OPTION_RESTRICTEDUSERNAME = "RestrictedUsername";
|
||||
static const char* OPTION_RESTRICTEDPASSWORD = "RestrictedPassword";
|
||||
static const char* OPTION_ADDUSERNAME = "AddUsername";
|
||||
static const char* OPTION_ADDPASSWORD = "AddPassword";
|
||||
static const char* OPTION_SECURECONTROL = "SecureControl";
|
||||
static const char* OPTION_SECUREPORT = "SecurePort";
|
||||
static const char* OPTION_SECURECERT = "SecureCert";
|
||||
@@ -129,7 +139,8 @@ static const char* OPTION_ARTICLETIMEOUT = "ArticleTimeout";
|
||||
static const char* OPTION_URLTIMEOUT = "UrlTimeout";
|
||||
static const char* OPTION_SAVEQUEUE = "SaveQueue";
|
||||
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
|
||||
static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog";
|
||||
static const char* OPTION_BROKENLOG = "BrokenLog";
|
||||
static const char* OPTION_NZBLOG = "NzbLog";
|
||||
static const char* OPTION_DECODE = "Decode";
|
||||
static const char* OPTION_RETRIES = "Retries";
|
||||
static const char* OPTION_RETRYINTERVAL = "RetryInterval";
|
||||
@@ -176,6 +187,7 @@ static const char* OPTION_UNPACK = "Unpack";
|
||||
static const char* OPTION_UNPACKCLEANUPDISK = "UnpackCleanupDisk";
|
||||
static const char* OPTION_UNRARCMD = "UnrarCmd";
|
||||
static const char* OPTION_SEVENZIPCMD = "SevenZipCmd";
|
||||
static const char* OPTION_UNPACKPASSFILE = "UnpackPassFile";
|
||||
static const char* OPTION_UNPACKPAUSEQUEUE = "UnpackPauseQueue";
|
||||
static const char* OPTION_SCRIPTORDER = "ScriptOrder";
|
||||
static const char* OPTION_POSTSCRIPT = "PostScript";
|
||||
@@ -272,6 +284,29 @@ void Options::OptEntry::SetValue(const char* szValue)
|
||||
}
|
||||
}
|
||||
|
||||
bool Options::OptEntry::Restricted()
|
||||
{
|
||||
char szLoName[256];
|
||||
strncpy(szLoName, m_szName, sizeof(szLoName));
|
||||
szLoName[256-1] = '\0';
|
||||
for (char* p = szLoName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
bool bRestricted = !strcasecmp(m_szName, OPTION_CONTROLIP) ||
|
||||
!strcasecmp(m_szName, OPTION_CONTROLPORT) ||
|
||||
!strcasecmp(m_szName, OPTION_SECURECONTROL) ||
|
||||
!strcasecmp(m_szName, OPTION_SECUREPORT) ||
|
||||
!strcasecmp(m_szName, OPTION_SECURECERT) ||
|
||||
!strcasecmp(m_szName, OPTION_SECUREKEY) ||
|
||||
!strcasecmp(m_szName, OPTION_AUTHORIZEDIP) ||
|
||||
!strcasecmp(m_szName, OPTION_DAEMONUSERNAME) ||
|
||||
!strcasecmp(m_szName, OPTION_UMASK) ||
|
||||
strchr(m_szName, ':') || // All extension script options
|
||||
strstr(szLoName, "username") || // ServerX.Username, ControlUsername, etc.
|
||||
strstr(szLoName, "password"); // ServerX.Password, ControlPassword, etc.
|
||||
|
||||
return bRestricted;
|
||||
}
|
||||
|
||||
Options::OptEntries::~OptEntries()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
@@ -448,7 +483,7 @@ Options::Script* Options::Scripts::Find(const char* szName)
|
||||
}
|
||||
|
||||
|
||||
Options::Options(int argc, char* argv[])
|
||||
Options::Options()
|
||||
{
|
||||
m_bConfigErrors = false;
|
||||
m_iConfigLine = 0;
|
||||
@@ -456,6 +491,7 @@ Options::Options(int argc, char* argv[])
|
||||
// initialize options with default values
|
||||
m_bConfigInitialized = false;
|
||||
m_szConfigFilename = NULL;
|
||||
m_szAppDir = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_szInterDir = NULL;
|
||||
m_szTempDir = NULL;
|
||||
@@ -474,7 +510,8 @@ Options::Options(int argc, char* argv[])
|
||||
m_bPausePostProcess = false;
|
||||
m_bPauseScan = false;
|
||||
m_bTempPauseDownload = false;
|
||||
m_bCreateBrokenLog = false;
|
||||
m_bBrokenLog = false;
|
||||
m_bNzbLog = false;
|
||||
m_iDownloadRate = 0;
|
||||
m_iEditQueueAction = 0;
|
||||
m_pEditQueueIDList = NULL;
|
||||
@@ -495,6 +532,9 @@ Options::Options(int argc, char* argv[])
|
||||
m_bRemoteClientMode = false;
|
||||
m_bPrintOptions = false;
|
||||
m_bAddTop = false;
|
||||
m_szAddDupeKey = NULL;
|
||||
m_iAddDupeScore = 0;
|
||||
m_iAddDupeMode = 0;
|
||||
m_bAppendCategoryDir = false;
|
||||
m_bContinuePartial = false;
|
||||
m_bSaveQueue = false;
|
||||
@@ -505,6 +545,10 @@ Options::Options(int argc, char* argv[])
|
||||
m_szControlIP = NULL;
|
||||
m_szControlUsername = NULL;
|
||||
m_szControlPassword = NULL;
|
||||
m_szRestrictedUsername = NULL;
|
||||
m_szRestrictedPassword = NULL;
|
||||
m_szAddUsername = NULL;
|
||||
m_szAddPassword = NULL;
|
||||
m_bSecureControl = false;
|
||||
m_iSecurePort = 0;
|
||||
m_szSecureCert = NULL;
|
||||
@@ -547,6 +591,8 @@ Options::Options(int argc, char* argv[])
|
||||
m_bParCleanupQueue = false;
|
||||
m_iDiskSpace = 0;
|
||||
m_bTestBacktrace = false;
|
||||
m_bWebGet = false;
|
||||
m_szWebGetFilename = NULL;
|
||||
m_bTLS = false;
|
||||
m_bDumpCore = false;
|
||||
m_bParPauseQueue = false;
|
||||
@@ -562,6 +608,7 @@ Options::Options(int argc, char* argv[])
|
||||
m_bUnpackCleanupDisk = false;
|
||||
m_szUnrarCmd = NULL;
|
||||
m_szSevenZipCmd = NULL;
|
||||
m_szUnpackPassFile = NULL;
|
||||
m_bUnpackPauseQueue = false;
|
||||
m_szExtCleanupDisk = NULL;
|
||||
m_szParIgnoreExt = NULL;
|
||||
@@ -572,22 +619,73 @@ Options::Options(int argc, char* argv[])
|
||||
m_iPropagationDelay = 0;
|
||||
m_iArticleCache = 0;
|
||||
m_iEventInterval = 0;
|
||||
}
|
||||
|
||||
Options::~Options()
|
||||
{
|
||||
free(m_szConfigFilename);
|
||||
free(m_szAppDir);
|
||||
free(m_szDestDir);
|
||||
free(m_szInterDir);
|
||||
free(m_szTempDir);
|
||||
free(m_szQueueDir);
|
||||
free(m_szNzbDir);
|
||||
free(m_szWebDir);
|
||||
free(m_szConfigTemplate);
|
||||
free(m_szScriptDir);
|
||||
free(m_szArgFilename);
|
||||
free(m_szAddCategory);
|
||||
free(m_szEditQueueText);
|
||||
free(m_szLastArg);
|
||||
free(m_szControlIP);
|
||||
free(m_szControlUsername);
|
||||
free(m_szControlPassword);
|
||||
free(m_szRestrictedUsername);
|
||||
free(m_szRestrictedPassword);
|
||||
free(m_szAddUsername);
|
||||
free(m_szAddPassword);
|
||||
free(m_szSecureCert);
|
||||
free(m_szSecureKey);
|
||||
free(m_szAuthorizedIP);
|
||||
free(m_szLogFile);
|
||||
free(m_szLockFile);
|
||||
free(m_szDaemonUsername);
|
||||
free(m_szScriptOrder);
|
||||
free(m_szPostScript);
|
||||
free(m_szScanScript);
|
||||
free(m_szQueueScript);
|
||||
free(m_pEditQueueIDList);
|
||||
free(m_szAddNZBFilename);
|
||||
free(m_szAddDupeKey);
|
||||
free(m_szUnrarCmd);
|
||||
free(m_szSevenZipCmd);
|
||||
free(m_szUnpackPassFile);
|
||||
free(m_szExtCleanupDisk);
|
||||
free(m_szParIgnoreExt);
|
||||
free(m_szWebGetFilename);
|
||||
|
||||
for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_EditQueueNameList.clear();
|
||||
}
|
||||
|
||||
void Options::Init(int argc, char* argv[])
|
||||
{
|
||||
// Option "ConfigFile" will be initialized later, but we want
|
||||
// to see it at the top of option list, so we add it first
|
||||
SetOption(OPTION_CONFIGFILE, "");
|
||||
|
||||
char szFilename[MAX_PATH + 1];
|
||||
#ifdef WIN32
|
||||
GetModuleFileName(NULL, szFilename, sizeof(szFilename));
|
||||
#else
|
||||
Util::ExpandFileName(argv[0], szFilename, sizeof(szFilename));
|
||||
#endif
|
||||
Util::GetExeFileName(argv[0], szFilename, sizeof(szFilename));
|
||||
Util::NormalizePathSeparators(szFilename);
|
||||
SetOption(OPTION_APPBIN, szFilename);
|
||||
|
||||
char* end = strrchr(szFilename, PATH_SEPARATOR);
|
||||
if (end) *end = '\0';
|
||||
SetOption(OPTION_APPDIR, szFilename);
|
||||
m_szAppDir = strdup(szFilename);
|
||||
|
||||
SetOption(OPTION_VERSION, Util::VersionRevision());
|
||||
|
||||
@@ -652,48 +750,6 @@ Options::Options(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
Options::~Options()
|
||||
{
|
||||
free(m_szConfigFilename);
|
||||
free(m_szDestDir);
|
||||
free(m_szInterDir);
|
||||
free(m_szTempDir);
|
||||
free(m_szQueueDir);
|
||||
free(m_szNzbDir);
|
||||
free(m_szWebDir);
|
||||
free(m_szConfigTemplate);
|
||||
free(m_szScriptDir);
|
||||
free(m_szArgFilename);
|
||||
free(m_szAddCategory);
|
||||
free(m_szEditQueueText);
|
||||
free(m_szLastArg);
|
||||
free(m_szControlIP);
|
||||
free(m_szControlUsername);
|
||||
free(m_szControlPassword);
|
||||
free(m_szSecureCert);
|
||||
free(m_szSecureKey);
|
||||
free(m_szAuthorizedIP);
|
||||
free(m_szLogFile);
|
||||
free(m_szLockFile);
|
||||
free(m_szDaemonUsername);
|
||||
free(m_szScriptOrder);
|
||||
free(m_szPostScript);
|
||||
free(m_szScanScript);
|
||||
free(m_szQueueScript);
|
||||
free(m_pEditQueueIDList);
|
||||
free(m_szAddNZBFilename);
|
||||
free(m_szUnrarCmd);
|
||||
free(m_szSevenZipCmd);
|
||||
free(m_szExtCleanupDisk);
|
||||
free(m_szParIgnoreExt);
|
||||
|
||||
for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_EditQueueNameList.clear();
|
||||
}
|
||||
|
||||
void Options::Dump()
|
||||
{
|
||||
for (OptEntries::iterator it = m_OptEntries.begin(); it != m_OptEntries.end(); it++)
|
||||
@@ -750,8 +806,12 @@ void Options::InitDefault()
|
||||
{
|
||||
#ifdef WIN32
|
||||
SetOption(OPTION_MAINDIR, "${AppDir}");
|
||||
SetOption(OPTION_WEBDIR, "${AppDir}\\webui");
|
||||
SetOption(OPTION_CONFIGTEMPLATE, "${AppDir}\\nzbget.conf.template");
|
||||
#else
|
||||
SetOption(OPTION_MAINDIR, "~/downloads");
|
||||
SetOption(OPTION_WEBDIR, "");
|
||||
SetOption(OPTION_CONFIGTEMPLATE, "");
|
||||
#endif
|
||||
SetOption(OPTION_TEMPDIR, "${MainDir}/tmp");
|
||||
SetOption(OPTION_DESTDIR, "${MainDir}/dst");
|
||||
@@ -760,8 +820,6 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_NZBDIR, "${MainDir}/nzb");
|
||||
SetOption(OPTION_LOCKFILE, "${MainDir}/nzbget.lock");
|
||||
SetOption(OPTION_LOGFILE, "${DestDir}/nzbget.log");
|
||||
SetOption(OPTION_WEBDIR, "");
|
||||
SetOption(OPTION_CONFIGTEMPLATE, "");
|
||||
SetOption(OPTION_SCRIPTDIR, "${MainDir}/scripts");
|
||||
SetOption(OPTION_WRITELOG, "append");
|
||||
SetOption(OPTION_ROTATELOG, "3");
|
||||
@@ -772,6 +830,10 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_CONTROLIP, "0.0.0.0");
|
||||
SetOption(OPTION_CONTROLUSERNAME, "nzbget");
|
||||
SetOption(OPTION_CONTROLPASSWORD, "tegbzn6789");
|
||||
SetOption(OPTION_RESTRICTEDUSERNAME, "");
|
||||
SetOption(OPTION_RESTRICTEDPASSWORD, "");
|
||||
SetOption(OPTION_ADDUSERNAME, "");
|
||||
SetOption(OPTION_ADDPASSWORD, "");
|
||||
SetOption(OPTION_CONTROLPORT, "6789");
|
||||
SetOption(OPTION_SECURECONTROL, "no");
|
||||
SetOption(OPTION_SECUREPORT, "6791");
|
||||
@@ -782,7 +844,8 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_URLTIMEOUT, "60");
|
||||
SetOption(OPTION_SAVEQUEUE, "yes");
|
||||
SetOption(OPTION_RELOADQUEUE, "yes");
|
||||
SetOption(OPTION_CREATEBROKENLOG, "yes");
|
||||
SetOption(OPTION_BROKENLOG, "yes");
|
||||
SetOption(OPTION_NZBLOG, "yes");
|
||||
SetOption(OPTION_DECODE, "yes");
|
||||
SetOption(OPTION_RETRIES, "3");
|
||||
SetOption(OPTION_RETRYINTERVAL, "10");
|
||||
@@ -837,6 +900,7 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_UNRARCMD, "unrar");
|
||||
SetOption(OPTION_SEVENZIPCMD, "7z");
|
||||
#endif
|
||||
SetOption(OPTION_UNPACKPASSFILE, "");
|
||||
SetOption(OPTION_UNPACKPAUSEQUEUE, "no");
|
||||
SetOption(OPTION_EXTCLEANUPDISK, "");
|
||||
SetOption(OPTION_PARIGNOREEXT, "");
|
||||
@@ -859,33 +923,53 @@ void Options::InitOptFile()
|
||||
{
|
||||
// search for config file in default locations
|
||||
#ifdef WIN32
|
||||
char szFilename[MAX_PATH + 1];
|
||||
GetModuleFileName(NULL, szFilename, MAX_PATH + 1);
|
||||
szFilename[MAX_PATH] = '\0';
|
||||
Util::NormalizePathSeparators(szFilename);
|
||||
char* end = strrchr(szFilename, PATH_SEPARATOR);
|
||||
if (end) end[1] = '\0';
|
||||
strcat(szFilename, "nzbget.conf");
|
||||
char szFilename[MAX_PATH + 20];
|
||||
snprintf(szFilename, sizeof(szFilename), "%s\\nzbget.conf", m_szAppDir);
|
||||
|
||||
if (!Util::FileExists(szFilename))
|
||||
{
|
||||
char szAppDataPath[MAX_PATH];
|
||||
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szAppDataPath);
|
||||
snprintf(szFilename, sizeof(szFilename), "%s\\NZBGet\\nzbget.conf", szAppDataPath);
|
||||
szFilename[sizeof(szFilename)-1] = '\0';
|
||||
|
||||
if (!Util::FileExists(szFilename))
|
||||
{
|
||||
SetupFirstStart();
|
||||
}
|
||||
}
|
||||
|
||||
if (Util::FileExists(szFilename))
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
}
|
||||
#else
|
||||
int p = 0;
|
||||
while (const char* szFilename = PossibleConfigLocations[p++])
|
||||
{
|
||||
// substitute HOME-variable
|
||||
char szExpandedFilename[1024];
|
||||
if (Util::ExpandHomePath(szFilename, szExpandedFilename, sizeof(szExpandedFilename)))
|
||||
{
|
||||
szFilename = szExpandedFilename;
|
||||
}
|
||||
// look in the exe-directory first
|
||||
char szFilename[1024];
|
||||
snprintf(szFilename, sizeof(szFilename), "%s/nzbget.conf", m_szAppDir);
|
||||
szFilename[1024-1] = '\0';
|
||||
|
||||
if (Util::FileExists(szFilename))
|
||||
if (Util::FileExists(szFilename))
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
int p = 0;
|
||||
while (const char* szFilename = PossibleConfigLocations[p++])
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
break;
|
||||
// substitute HOME-variable
|
||||
char szExpandedFilename[1024];
|
||||
if (Util::ExpandHomePath(szFilename, szExpandedFilename, sizeof(szExpandedFilename)))
|
||||
{
|
||||
szFilename = szExpandedFilename;
|
||||
}
|
||||
|
||||
if (Util::FileExists(szFilename))
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1000,6 +1084,10 @@ void Options::InitOptions()
|
||||
m_szControlIP = strdup(GetOption(OPTION_CONTROLIP));
|
||||
m_szControlUsername = strdup(GetOption(OPTION_CONTROLUSERNAME));
|
||||
m_szControlPassword = strdup(GetOption(OPTION_CONTROLPASSWORD));
|
||||
m_szRestrictedUsername = strdup(GetOption(OPTION_RESTRICTEDUSERNAME));
|
||||
m_szRestrictedPassword = strdup(GetOption(OPTION_RESTRICTEDPASSWORD));
|
||||
m_szAddUsername = strdup(GetOption(OPTION_ADDUSERNAME));
|
||||
m_szAddPassword = strdup(GetOption(OPTION_ADDPASSWORD));
|
||||
m_szSecureCert = strdup(GetOption(OPTION_SECURECERT));
|
||||
m_szSecureKey = strdup(GetOption(OPTION_SECUREKEY));
|
||||
m_szAuthorizedIP = strdup(GetOption(OPTION_AUTHORIZEDIP));
|
||||
@@ -1008,6 +1096,7 @@ void Options::InitOptions()
|
||||
m_szLogFile = strdup(GetOption(OPTION_LOGFILE));
|
||||
m_szUnrarCmd = strdup(GetOption(OPTION_UNRARCMD));
|
||||
m_szSevenZipCmd = strdup(GetOption(OPTION_SEVENZIPCMD));
|
||||
m_szUnpackPassFile = strdup(GetOption(OPTION_UNPACKPASSFILE));
|
||||
m_szExtCleanupDisk = strdup(GetOption(OPTION_EXTCLEANUPDISK));
|
||||
m_szParIgnoreExt = strdup(GetOption(OPTION_PARIGNOREEXT));
|
||||
|
||||
@@ -1045,7 +1134,8 @@ void Options::InitOptions()
|
||||
|
||||
CheckDir(&m_szNzbDir, OPTION_NZBDIR, szMainDir, m_iNzbDirInterval == 0, true);
|
||||
|
||||
m_bCreateBrokenLog = (bool)ParseEnumValue(OPTION_CREATEBROKENLOG, BoolCount, BoolNames, BoolValues);
|
||||
m_bBrokenLog = (bool)ParseEnumValue(OPTION_BROKENLOG, BoolCount, BoolNames, BoolValues);
|
||||
m_bNzbLog = (bool)ParseEnumValue(OPTION_NZBLOG, BoolCount, BoolNames, BoolValues);
|
||||
m_bAppendCategoryDir = (bool)ParseEnumValue(OPTION_APPENDCATEGORYDIR, BoolCount, BoolNames, BoolValues);
|
||||
m_bContinuePartial = (bool)ParseEnumValue(OPTION_CONTINUEPARTIAL, BoolCount, BoolNames, BoolValues);
|
||||
m_bSaveQueue = (bool)ParseEnumValue(OPTION_SAVEQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
@@ -1250,19 +1340,15 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
m_bDaemonMode = true;
|
||||
break;
|
||||
case 'A':
|
||||
m_eClientOperation = opClientRequestDownload; // default
|
||||
m_eClientOperation = opClientRequestDownload;
|
||||
|
||||
while (true)
|
||||
{
|
||||
optind++;
|
||||
optarg = optind > argc ? NULL : argv[optind-1];
|
||||
if (optarg && !strcasecmp(optarg, "F"))
|
||||
if (optarg && (!strcasecmp(optarg, "F") || !strcasecmp(optarg, "U")))
|
||||
{
|
||||
m_eClientOperation = opClientRequestDownload;
|
||||
}
|
||||
else if (optarg && !strcasecmp(optarg, "U"))
|
||||
{
|
||||
m_eClientOperation = opClientRequestDownloadUrl;
|
||||
// option ignored (but kept for compatibility)
|
||||
}
|
||||
else if (optarg && !strcasecmp(optarg, "T"))
|
||||
{
|
||||
@@ -1301,6 +1387,51 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
free(m_szAddNZBFilename);
|
||||
m_szAddNZBFilename = strdup(argv[optind-1]);
|
||||
}
|
||||
else if (optarg && !strcasecmp(optarg, "DK"))
|
||||
{
|
||||
optind++;
|
||||
if (optind > argc)
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'A'\n");
|
||||
}
|
||||
free(m_szAddDupeKey);
|
||||
m_szAddDupeKey = strdup(argv[optind-1]);
|
||||
}
|
||||
else if (optarg && !strcasecmp(optarg, "DS"))
|
||||
{
|
||||
optind++;
|
||||
if (optind > argc)
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'A'\n");
|
||||
}
|
||||
m_iAddDupeScore = atoi(argv[optind-1]);
|
||||
}
|
||||
else if (optarg && !strcasecmp(optarg, "DM"))
|
||||
{
|
||||
optind++;
|
||||
if (optind > argc)
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'A'\n");
|
||||
}
|
||||
|
||||
const char* szDupeMode = argv[optind-1];
|
||||
if (!strcasecmp(szDupeMode, "score"))
|
||||
{
|
||||
m_iAddDupeMode = dmScore;
|
||||
}
|
||||
else if (!strcasecmp(szDupeMode, "all"))
|
||||
{
|
||||
m_iAddDupeMode = dmAll;
|
||||
}
|
||||
else if (!strcasecmp(szDupeMode, "force"))
|
||||
{
|
||||
m_iAddDupeMode = dmForce;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'A'\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
optind--;
|
||||
@@ -1336,6 +1467,10 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
{
|
||||
m_eClientOperation = opClientRequestHistory;
|
||||
}
|
||||
else if (!strcasecmp(optarg, "HA"))
|
||||
{
|
||||
m_eClientOperation = opClientRequestHistoryAll;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'L'\n");
|
||||
@@ -1392,6 +1527,17 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
{
|
||||
m_bTestBacktrace = true;
|
||||
}
|
||||
else if (!strcasecmp(optarg, "webget"))
|
||||
{
|
||||
m_bWebGet = true;
|
||||
optind++;
|
||||
if (optind > argc)
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'E'\n");
|
||||
}
|
||||
optarg = argv[optind-1];
|
||||
m_szWebGetFilename = strdup(optarg);
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'B'\n");
|
||||
@@ -1495,6 +1641,10 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
{
|
||||
m_iEditQueueAction = DownloadQueue::eaHistoryMarkGood;
|
||||
}
|
||||
else if (!strcasecmp(optarg, "S"))
|
||||
{
|
||||
m_iEditQueueAction = DownloadQueue::eaHistoryMarkSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'E'\n");
|
||||
@@ -1720,16 +1870,17 @@ void Options::PrintUsage(char* com)
|
||||
" -V, --serverversion Print server's version and exit\n"
|
||||
" -Q, --quit Shutdown server\n"
|
||||
" -O, --reload Reload config and restart all services\n"
|
||||
" -A, --append [F|U] [<options>] <nzb-file/url> Send file/url to server's\n"
|
||||
" -A, --append [<options>] <nzb-file/url> Send file/url to server's\n"
|
||||
" download queue\n"
|
||||
" F Send file (default)\n"
|
||||
" U Send url\n"
|
||||
" <options> are (multiple options must be separated with space):\n"
|
||||
" T Add file to the top (beginning) of queue\n"
|
||||
" P Pause added files\n"
|
||||
" C <name> Assign category to nzb-file\n"
|
||||
" N <name> Use this name as nzb-filename (only for URLs)\n"
|
||||
" N <name> Use this name as nzb-filename\n"
|
||||
" I <priority> Set priority (signed integer)\n"
|
||||
" DK <dupekey> Set duplicate key (string)\n"
|
||||
" DS <dupescore> Set duplicate score (signed integer)\n"
|
||||
" DM (score|all|force) Set duplicate mode\n"
|
||||
" -C, --connect Attach client to server\n"
|
||||
" -L, --list [F|FR|G|GR|O|H|S] [RegEx] Request list of items from server\n"
|
||||
" F List individual files and server status (default)\n"
|
||||
@@ -1738,6 +1889,7 @@ void Options::PrintUsage(char* com)
|
||||
" GR Like \"G\" but apply regular expression filter\n"
|
||||
" O List post-processor-queue\n"
|
||||
" H List history\n"
|
||||
" HA List history, all records (incl. hidden)\n"
|
||||
" S Print only server status\n"
|
||||
" <RegEx> Regular expression (only with options \"FR\", \"GR\")\n"
|
||||
" using POSIX Extended Regular Expression Syntax\n"
|
||||
@@ -1795,6 +1947,7 @@ void Options::PrintUsage(char* com)
|
||||
" O <name>=<value> Set post-process parameter\n"
|
||||
" B Mark as bad\n"
|
||||
" G Mark as good\n"
|
||||
" S Mark as success\n"
|
||||
" <IDs> Comma-separated list of file- or group- ids or\n"
|
||||
" ranges of file-ids, e. g.: 1-5,3,10-22\n"
|
||||
" <Names> List of names (with options \"FN\" and \"GN\"),\n"
|
||||
@@ -1821,7 +1974,7 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Nzb-file not specified\n");
|
||||
abort("FATAL ERROR: Nzb-file or Url not specified\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1847,7 +2000,7 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
#ifdef WIN32
|
||||
m_szArgFilename = strdup(szFileName);
|
||||
#else
|
||||
if (szFileName[0] == '/')
|
||||
if (szFileName[0] == '/' || !strncasecmp(szFileName, "http://", 6) || !strncasecmp(szFileName, "https://", 7))
|
||||
{
|
||||
m_szArgFilename = strdup(szFileName);
|
||||
}
|
||||
@@ -1865,7 +2018,6 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
if (m_bServerMode || m_bRemoteClientMode ||
|
||||
!(m_eClientOperation == opClientNoOperation ||
|
||||
m_eClientOperation == opClientRequestDownload ||
|
||||
m_eClientOperation == opClientRequestDownloadUrl ||
|
||||
m_eClientOperation == opClientRequestWriteLog))
|
||||
{
|
||||
abort("FATAL ERROR: Too many arguments\n");
|
||||
@@ -2045,8 +2197,11 @@ void Options::InitServers()
|
||||
sprintf(optname, "Server%i.Connections", n);
|
||||
const char* nconnections = GetOption(optname);
|
||||
|
||||
sprintf(optname, "Server%i.Retention", n);
|
||||
const char* nretention = GetOption(optname);
|
||||
|
||||
bool definition = nactive || nname || nlevel || ngroup || nhost || nport ||
|
||||
nusername || npassword || nconnections || njoingroup || ntls || ncipher;
|
||||
nusername || npassword || nconnections || njoingroup || ntls || ncipher || nretention;
|
||||
bool completed = nhost && nport && nconnections;
|
||||
|
||||
if (!definition)
|
||||
@@ -2057,10 +2212,14 @@ void Options::InitServers()
|
||||
if (completed)
|
||||
{
|
||||
NewsServer* pNewsServer = new NewsServer(n, bActive, nname,
|
||||
nhost, atoi(nport), nusername, npassword,
|
||||
bJoinGroup, bTLS, ncipher, atoi((char*)nconnections),
|
||||
nlevel ? atoi((char*)nlevel) : 0,
|
||||
ngroup ? atoi((char*)ngroup) : 0);
|
||||
nhost,
|
||||
nport ? atoi(nport) : 119,
|
||||
nusername, npassword,
|
||||
bJoinGroup, bTLS, ncipher,
|
||||
nconnections ? atoi(nconnections) : 1,
|
||||
nretention ? atoi(nretention) : 0,
|
||||
nlevel ? atoi(nlevel) : 0,
|
||||
ngroup ? atoi(ngroup) : 0);
|
||||
g_pServerPool->AddServer(pNewsServer);
|
||||
}
|
||||
else
|
||||
@@ -2072,6 +2231,7 @@ void Options::InitServers()
|
||||
}
|
||||
|
||||
g_pServerPool->SetTimeout(GetArticleTimeout());
|
||||
g_pServerPool->SetRetryInterval(GetRetryInterval());
|
||||
}
|
||||
|
||||
void Options::InitCategories()
|
||||
@@ -2577,7 +2737,8 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
|
||||
!strcasecmp(p, ".port") || !strcasecmp(p, ".username") ||
|
||||
!strcasecmp(p, ".password") || !strcasecmp(p, ".joingroup") ||
|
||||
!strcasecmp(p, ".encryption") || !strcasecmp(p, ".connections") ||
|
||||
!strcasecmp(p, ".cipher") || !strcasecmp(p, ".group")))
|
||||
!strcasecmp(p, ".cipher") || !strcasecmp(p, ".group") ||
|
||||
!strcasecmp(p, ".retention")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2730,6 +2891,11 @@ void Options::ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue,
|
||||
strncpy(szOption, "ArticleTimeout", iOptionBufLen);
|
||||
}
|
||||
|
||||
if (!strcasecmp(szOption, "CreateBrokenLog"))
|
||||
{
|
||||
strncpy(szOption, "BrokenLog", iOptionBufLen);
|
||||
}
|
||||
|
||||
szOption[iOptionBufLen-1] = '\0';
|
||||
szOption[iValueBufLen-1] = '\0';
|
||||
}
|
||||
@@ -2807,6 +2973,11 @@ void Options::CheckOptions()
|
||||
m_iArticleCache = 1900;
|
||||
m_iParBuffer = 400;
|
||||
}
|
||||
|
||||
if (!Util::EmptyStr(m_szUnpackPassFile) && !Util::FileExists(m_szUnpackPassFile))
|
||||
{
|
||||
ConfigError("Invalid value for option \"UnpackPassFile\": %s. File not found", m_szUnpackPassFile);
|
||||
}
|
||||
}
|
||||
|
||||
void Options::ParseFileIDList(int argc, char* argv[], int optind)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
opClientRequestScanPause,
|
||||
opClientRequestScanUnpause,
|
||||
opClientRequestHistory,
|
||||
opClientRequestDownloadUrl
|
||||
opClientRequestHistoryAll
|
||||
};
|
||||
enum EWriteLog
|
||||
{
|
||||
@@ -132,6 +132,7 @@ public:
|
||||
const char* GetValue() { return m_szValue; }
|
||||
const char* GetDefValue() { return m_szDefValue; }
|
||||
int GetLineNo() { return m_iLineNo; }
|
||||
bool Restricted();
|
||||
};
|
||||
|
||||
typedef std::vector<OptEntry*> OptEntriesBase;
|
||||
@@ -248,6 +249,7 @@ private:
|
||||
// Options
|
||||
bool m_bConfigErrors;
|
||||
int m_iConfigLine;
|
||||
char* m_szAppDir;
|
||||
char* m_szConfigFilename;
|
||||
char* m_szDestDir;
|
||||
char* m_szInterDir;
|
||||
@@ -263,7 +265,8 @@ private:
|
||||
EMessageTarget m_eDebugTarget;
|
||||
EMessageTarget m_eDetailTarget;
|
||||
bool m_bDecode;
|
||||
bool m_bCreateBrokenLog;
|
||||
bool m_bBrokenLog;
|
||||
bool m_bNzbLog;
|
||||
int m_iArticleTimeout;
|
||||
int m_iUrlTimeout;
|
||||
int m_iTerminateTimeout;
|
||||
@@ -276,6 +279,10 @@ private:
|
||||
char* m_szControlIP;
|
||||
char* m_szControlUsername;
|
||||
char* m_szControlPassword;
|
||||
char* m_szRestrictedUsername;
|
||||
char* m_szRestrictedPassword;
|
||||
char* m_szAddUsername;
|
||||
char* m_szAddPassword;
|
||||
int m_iControlPort;
|
||||
bool m_bSecureControl;
|
||||
int m_iSecurePort;
|
||||
@@ -329,6 +336,7 @@ private:
|
||||
bool m_bUnpackCleanupDisk;
|
||||
char* m_szUnrarCmd;
|
||||
char* m_szSevenZipCmd;
|
||||
char* m_szUnpackPassFile;
|
||||
bool m_bUnpackPauseQueue;
|
||||
char* m_szExtCleanupDisk;
|
||||
char* m_szParIgnoreExt;
|
||||
@@ -358,10 +366,15 @@ private:
|
||||
char* m_szLastArg;
|
||||
bool m_bPrintOptions;
|
||||
bool m_bAddTop;
|
||||
char* m_szAddDupeKey;
|
||||
int m_iAddDupeScore;
|
||||
int m_iAddDupeMode;
|
||||
int m_iSetRate;
|
||||
int m_iLogLines;
|
||||
int m_iWriteLogKind;
|
||||
bool m_bTestBacktrace;
|
||||
bool m_bWebGet;
|
||||
char* m_szWebGetFilename;
|
||||
|
||||
// Current state
|
||||
bool m_bPauseDownload;
|
||||
@@ -413,8 +426,9 @@ private:
|
||||
void LoadScripts(Scripts* pScripts);
|
||||
|
||||
public:
|
||||
Options(int argc, char* argv[]);
|
||||
Options();
|
||||
~Options();
|
||||
void Init(int argc, char* argv[]);
|
||||
|
||||
bool LoadConfig(OptEntries* pOptEntries);
|
||||
bool SaveConfig(OptEntries* pOptEntries);
|
||||
@@ -426,6 +440,7 @@ public:
|
||||
OptEntries* LockOptEntries();
|
||||
void UnlockOptEntries();
|
||||
const char* GetConfigFilename() { return m_szConfigFilename; }
|
||||
const char* GetAppDir() { return m_szAppDir; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
const char* GetInterDir() { return m_szInterDir; }
|
||||
const char* GetTempDir() { return m_szTempDir; }
|
||||
@@ -434,7 +449,8 @@ public:
|
||||
const char* GetWebDir() { return m_szWebDir; }
|
||||
const char* GetConfigTemplate() { return m_szConfigTemplate; }
|
||||
const char* GetScriptDir() { return m_szScriptDir; }
|
||||
bool GetCreateBrokenLog() const { return m_bCreateBrokenLog; }
|
||||
bool GetBrokenLog() const { return m_bBrokenLog; }
|
||||
bool GetNzbLog() const { return m_bNzbLog; }
|
||||
EMessageTarget GetInfoTarget() const { return m_eInfoTarget; }
|
||||
EMessageTarget GetWarningTarget() const { return m_eWarningTarget; }
|
||||
EMessageTarget GetErrorTarget() const { return m_eErrorTarget; }
|
||||
@@ -453,6 +469,10 @@ public:
|
||||
const char* GetControlIP();
|
||||
const char* GetControlUsername() { return m_szControlUsername; }
|
||||
const char* GetControlPassword() { return m_szControlPassword; }
|
||||
const char* GetRestrictedUsername() { return m_szRestrictedUsername; }
|
||||
const char* GetRestrictedPassword() { return m_szRestrictedPassword; }
|
||||
const char* GetAddUsername() { return m_szAddUsername; }
|
||||
const char* GetAddPassword() { return m_szAddPassword; }
|
||||
int GetControlPort() { return m_iControlPort; }
|
||||
bool GetSecureControl() { return m_bSecureControl; }
|
||||
int GetSecurePort() { return m_iSecurePort; }
|
||||
@@ -505,6 +525,7 @@ public:
|
||||
bool GetUnpackCleanupDisk() { return m_bUnpackCleanupDisk; }
|
||||
const char* GetUnrarCmd() { return m_szUnrarCmd; }
|
||||
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
|
||||
const char* GetUnpackPassFile() { return m_szUnpackPassFile; }
|
||||
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
|
||||
const char* GetExtCleanupDisk() { return m_szExtCleanupDisk; }
|
||||
const char* GetParIgnoreExt() { return m_szParIgnoreExt; }
|
||||
@@ -515,6 +536,7 @@ public:
|
||||
int GetArticleCache() { return m_iArticleCache; }
|
||||
int GetEventInterval() { return m_iEventInterval; }
|
||||
|
||||
Categories* GetCategories() { return &m_Categories; }
|
||||
Category* FindCategory(const char* szName, bool bSearchAliases) { return m_Categories.FindCategory(szName, bSearchAliases); }
|
||||
|
||||
// Parsed command-line parameters
|
||||
@@ -536,10 +558,15 @@ public:
|
||||
int GetAddPriority() { return m_iAddPriority; }
|
||||
char* GetAddNZBFilename() { return m_szAddNZBFilename; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
const char* GetAddDupeKey() { return m_szAddDupeKey; }
|
||||
int GetAddDupeScore() { return m_iAddDupeScore; }
|
||||
int GetAddDupeMode() { return m_iAddDupeMode; }
|
||||
int GetSetRate() { return m_iSetRate; }
|
||||
int GetLogLines() { return m_iLogLines; }
|
||||
int GetWriteLogKind() { return m_iWriteLogKind; }
|
||||
bool GetTestBacktrace() { return m_bTestBacktrace; }
|
||||
bool GetWebGet() { return m_bWebGet; }
|
||||
const char* GetWebGetFilename() { return m_szWebGetFilename; }
|
||||
|
||||
// Current state
|
||||
void SetPauseDownload(bool bPauseDownload) { m_bPauseDownload = bPauseDownload; }
|
||||
|
||||
0
daemon/main/StackTrace.cpp
Executable file → Normal file
0
daemon/main/StackTrace.cpp
Executable file → Normal file
0
daemon/main/StackTrace.h
Executable file → Normal file
0
daemon/main/StackTrace.h
Executable file → Normal file
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -82,6 +82,8 @@
|
||||
#include "StackTrace.h"
|
||||
#ifdef WIN32
|
||||
#include "NTService.h"
|
||||
#include "WinConsole.h"
|
||||
#include "WebDownloader.h"
|
||||
#endif
|
||||
|
||||
// Prototypes
|
||||
@@ -90,6 +92,7 @@ void Run(bool bReload);
|
||||
void Reload();
|
||||
void Cleanup();
|
||||
void ProcessClientRequest();
|
||||
void ProcessWebGet();
|
||||
#ifndef WIN32
|
||||
void Daemonize();
|
||||
#endif
|
||||
@@ -120,6 +123,9 @@ int g_iArgumentCount;
|
||||
char* (*g_szEnvironmentVariables)[] = NULL;
|
||||
char* (*g_szArguments)[] = NULL;
|
||||
bool g_bReloading = true;
|
||||
#ifdef WIN32
|
||||
WinConsole* g_pWinConsole = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
@@ -200,6 +206,11 @@ void Run(bool bReload)
|
||||
Thread::Init();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
g_pWinConsole = new WinConsole();
|
||||
g_pWinConsole->InitAppMode();
|
||||
#endif
|
||||
|
||||
g_pServerPool = new ServerPool();
|
||||
g_pScheduler = new Scheduler();
|
||||
g_pQueueCoordinator = new QueueCoordinator();
|
||||
@@ -215,7 +226,8 @@ void Run(bool bReload)
|
||||
g_pQueueScriptCoordinator = new QueueScriptCoordinator();
|
||||
|
||||
debug("Reading options");
|
||||
g_pOptions = new Options(g_iArgumentCount, *g_szArguments);
|
||||
g_pOptions = new Options();
|
||||
g_pOptions->Init(g_iArgumentCount, *g_szArguments);
|
||||
|
||||
#ifndef WIN32
|
||||
if (g_pOptions->GetUMask() < 01000)
|
||||
@@ -270,6 +282,12 @@ void Run(bool bReload)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_pOptions->GetWebGet())
|
||||
{
|
||||
ProcessWebGet();
|
||||
return;
|
||||
}
|
||||
|
||||
// client request
|
||||
if (g_pOptions->GetClientOperation() != Options::opClientNoOperation)
|
||||
{
|
||||
@@ -339,6 +357,9 @@ void Run(bool bReload)
|
||||
g_pDiskState = new DiskState();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
g_pWinConsole->Start();
|
||||
#endif
|
||||
g_pQueueCoordinator->Start();
|
||||
g_pUrlCoordinator->Start();
|
||||
g_pPrePostProcessor->Start();
|
||||
@@ -353,6 +374,9 @@ void Run(bool bReload)
|
||||
g_pUrlCoordinator->IsRunning() ||
|
||||
g_pPrePostProcessor->IsRunning() ||
|
||||
g_pFeedCoordinator->IsRunning() ||
|
||||
#ifdef WIN32
|
||||
g_pWinConsole->IsRunning() ||
|
||||
#endif
|
||||
g_pArticleCache->IsRunning())
|
||||
{
|
||||
if (!g_pOptions->GetServerMode() &&
|
||||
@@ -504,7 +528,9 @@ void ProcessClientRequest()
|
||||
break;
|
||||
|
||||
case Options::opClientRequestDownload:
|
||||
Client->RequestServerDownload(g_pOptions->GetArgFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
|
||||
Client->RequestServerDownload(g_pOptions->GetAddNZBFilename(), g_pOptions->GetArgFilename(),
|
||||
g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority(),
|
||||
g_pOptions->GetAddDupeKey(), g_pOptions->GetAddDupeMode(), g_pOptions->GetAddDupeScore());
|
||||
break;
|
||||
|
||||
case Options::opClientRequestVersion:
|
||||
@@ -543,12 +569,9 @@ void ProcessClientRequest()
|
||||
Client->RequestServerPauseUnpause(false, eRemotePauseUnpauseActionScan);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestHistory:
|
||||
Client->RequestHistory();
|
||||
break;
|
||||
|
||||
case Options::opClientRequestDownloadUrl:
|
||||
Client->RequestServerDownloadUrl(g_pOptions->GetLastArg(), g_pOptions->GetAddNZBFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
|
||||
case Options::opClientRequestHistory:
|
||||
case Options::opClientRequestHistoryAll:
|
||||
Client->RequestHistory(g_pOptions->GetClientOperation() == Options::opClientRequestHistoryAll);
|
||||
break;
|
||||
|
||||
case Options::opClientNoOperation:
|
||||
@@ -558,6 +581,27 @@ void ProcessClientRequest()
|
||||
delete Client;
|
||||
}
|
||||
|
||||
void ProcessWebGet()
|
||||
{
|
||||
WebDownloader downloader;
|
||||
downloader.SetURL(g_pOptions->GetLastArg());
|
||||
downloader.SetForce(true);
|
||||
downloader.SetRetry(false);
|
||||
downloader.SetOutputFilename(g_pOptions->GetWebGetFilename());
|
||||
downloader.SetInfoName("WebGet");
|
||||
|
||||
int iRedirects = 0;
|
||||
WebDownloader::EStatus eStatus = WebDownloader::adRedirect;
|
||||
while (eStatus == WebDownloader::adRedirect && iRedirects < 5)
|
||||
{
|
||||
iRedirects++;
|
||||
eStatus = downloader.Download();
|
||||
}
|
||||
bool bOK = eStatus == WebDownloader::adFinished;
|
||||
|
||||
exit(bOK ? 0 : 1);
|
||||
}
|
||||
|
||||
void ExitProc()
|
||||
{
|
||||
if (!g_bReloading)
|
||||
@@ -582,6 +626,9 @@ void ExitProc()
|
||||
g_pPrePostProcessor->Stop();
|
||||
g_pFeedCoordinator->Stop();
|
||||
g_pArticleCache->Stop();
|
||||
#ifdef WIN32
|
||||
g_pWinConsole->Stop();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,6 +745,11 @@ void Cleanup()
|
||||
Thread::Final();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
delete g_pWinConsole;
|
||||
g_pWinConsole = NULL;
|
||||
#endif
|
||||
|
||||
debug("Global objects cleaned up");
|
||||
|
||||
delete g_pLog;
|
||||
@@ -707,42 +759,76 @@ void Cleanup()
|
||||
#ifndef WIN32
|
||||
void Daemonize()
|
||||
{
|
||||
int i, lfp;
|
||||
char str[10];
|
||||
if (getppid() == 1) return; /* already a daemon */
|
||||
i = fork();
|
||||
if (i < 0) exit(1); /* fork error */
|
||||
if (i > 0) exit(0); /* parent exits */
|
||||
int f = fork();
|
||||
if (f < 0) exit(1); /* fork error */
|
||||
if (f > 0) exit(0); /* parent exits */
|
||||
|
||||
/* child (daemon) continues */
|
||||
setsid(); /* obtain a new process group */
|
||||
for (i = getdtablesize();i >= 0;--i) close(i); /* close all descriptors */
|
||||
i = open("/dev/null", O_RDWR); dup(i); dup(i); /* handle standart I/O */
|
||||
chdir(g_pOptions->GetDestDir()); /* change running directory */
|
||||
lfp = open(g_pOptions->GetLockFile(), O_RDWR | O_CREAT, 0640);
|
||||
if (lfp < 0) exit(1); /* can not open */
|
||||
if (lockf(lfp, F_TLOCK, 0) < 0) exit(0); /* can not lock */
|
||||
|
||||
// obtain a new process group
|
||||
setsid();
|
||||
|
||||
// close all descriptors
|
||||
for (int i = getdtablesize(); i >= 0; --i)
|
||||
{
|
||||
close(i);
|
||||
}
|
||||
|
||||
// handle standart I/O
|
||||
int d = open("/dev/null", O_RDWR);
|
||||
dup(d);
|
||||
dup(d);
|
||||
|
||||
// change running directory
|
||||
chdir(g_pOptions->GetDestDir());
|
||||
|
||||
// set up lock-file
|
||||
int lfp = -1;
|
||||
if (!Util::EmptyStr(g_pOptions->GetLockFile()))
|
||||
{
|
||||
lfp = open(g_pOptions->GetLockFile(), O_RDWR | O_CREAT, 0640);
|
||||
if (lfp < 0)
|
||||
{
|
||||
error("Starting daemon failed: could not create lock-file %s", g_pOptions->GetLockFile());
|
||||
exit(1);
|
||||
}
|
||||
if (lockf(lfp, F_TLOCK, 0) < 0)
|
||||
{
|
||||
error("Starting daemon failed: could not acquire lock on lock-file %s", g_pOptions->GetLockFile());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop user if there is one, and we were run as root */
|
||||
if ( getuid() == 0 || geteuid() == 0 )
|
||||
if (getuid() == 0 || geteuid() == 0)
|
||||
{
|
||||
struct passwd *pw = getpwnam(g_pOptions->GetDaemonUsername());
|
||||
if (pw)
|
||||
{
|
||||
fchown(lfp, pw->pw_uid, pw->pw_gid); /* change owner of lock file */
|
||||
setgroups( 0, (const gid_t*) 0 ); /* Set aux groups to null. */
|
||||
setgid(pw->pw_gid); /* Set primary group. */
|
||||
/* Try setting aux groups correctly - not critical if this fails. */
|
||||
initgroups( g_pOptions->GetDaemonUsername(),pw->pw_gid);
|
||||
/* Finally, set uid. */
|
||||
// Change owner of lock file
|
||||
fchown(lfp, pw->pw_uid, pw->pw_gid);
|
||||
// Set aux groups to null.
|
||||
setgroups(0, (const gid_t*)0);
|
||||
// Set primary group.
|
||||
setgid(pw->pw_gid);
|
||||
// Try setting aux groups correctly - not critical if this fails.
|
||||
initgroups(g_pOptions->GetDaemonUsername(), pw->pw_gid);
|
||||
// Finally, set uid.
|
||||
setuid(pw->pw_uid);
|
||||
}
|
||||
}
|
||||
|
||||
/* first instance continues */
|
||||
sprintf(str, "%d\n", getpid());
|
||||
write(lfp, str, strlen(str)); /* record pid to lockfile */
|
||||
signal(SIGCHLD, SIG_IGN); /* ignore child */
|
||||
signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
|
||||
// record pid to lockfile
|
||||
if (lfp > -1)
|
||||
{
|
||||
char str[10];
|
||||
sprintf(str, "%d\n", getpid());
|
||||
write(lfp, str, strlen(str));
|
||||
}
|
||||
|
||||
// ignore unwanted signals
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
#define FOPEN_AB "abN"
|
||||
#define FOPEN_ABP "ab+N"
|
||||
|
||||
#ifdef DEBUG
|
||||
// redefine "exit" to avoid printing memory leaks report when terminated because of wrong command line switches
|
||||
#define exit(code) ExitProcess(code)
|
||||
#endif
|
||||
|
||||
#pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||
|
||||
|
||||
@@ -158,13 +158,31 @@ void ArticleDownloader::Run()
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
|
||||
m_szConnectionName[sizeof(m_szConnectionName) - 1] = '\0';
|
||||
|
||||
// check server retention
|
||||
bool bRetentionFailure = m_pConnection->GetNewsServer()->GetRetention() > 0 &&
|
||||
(time(NULL) - m_pFileInfo->GetTime()) / 86400 > m_pConnection->GetNewsServer()->GetRetention();
|
||||
if (bRetentionFailure)
|
||||
{
|
||||
detail("Article %s @ %s failed: out of server retention (file age: %i, configured retention: %i)",
|
||||
m_szInfoName, m_szConnectionName,
|
||||
(time(NULL) - m_pFileInfo->GetTime()) / 86400,
|
||||
m_pConnection->GetNewsServer()->GetRetention());
|
||||
Status = adFailed;
|
||||
FreeConnection(true);
|
||||
}
|
||||
|
||||
if (m_pConnection && !IsStopped())
|
||||
{
|
||||
detail("Downloading %s @ %s", m_szInfoName, m_szConnectionName);
|
||||
}
|
||||
|
||||
// test connection
|
||||
bool bConnected = m_pConnection && m_pConnection->Connect();
|
||||
if (bConnected && !IsStopped())
|
||||
{
|
||||
NewsServer* pNewsServer = m_pConnection->GetNewsServer();
|
||||
detail("Downloading %s @ %s", m_szInfoName, m_szConnectionName);
|
||||
|
||||
// Download article
|
||||
Status = Download();
|
||||
|
||||
if (Status == adFinished || Status == adFailed || Status == adNotFound || Status == adCrcError)
|
||||
@@ -173,66 +191,45 @@ void ArticleDownloader::Run()
|
||||
}
|
||||
}
|
||||
|
||||
if (bConnected)
|
||||
{
|
||||
if (Status == adConnectError)
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
bConnected = false;
|
||||
Status = adFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// freeing connection allows other threads to start.
|
||||
// we doing this only if the problem was with article or group.
|
||||
// if the problem occurs by connecting or authorization we do not
|
||||
// free the connection, to prevent starting of thousands of threads
|
||||
// (cause each of them will also free it's connection after the
|
||||
// same connect-error).
|
||||
FreeConnection(Status == adFinished || Status == adNotFound);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pConnection)
|
||||
{
|
||||
AddServerData();
|
||||
}
|
||||
|
||||
if (Status == adFinished || Status == adFatalError)
|
||||
if (!bConnected && m_pConnection)
|
||||
{
|
||||
break;
|
||||
detail("Article %s @ %s failed: could not establish connection", m_szInfoName, m_szConnectionName);
|
||||
}
|
||||
|
||||
pWantServer = NULL;
|
||||
if (Status == adConnectError)
|
||||
{
|
||||
bConnected = false;
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (bConnected && Status == adFailed)
|
||||
{
|
||||
iRemainedRetries--;
|
||||
}
|
||||
|
||||
if (!bConnected || (Status == adFailed && iRemainedRetries > 0))
|
||||
if (!bConnected && m_pConnection && !IsStopped())
|
||||
{
|
||||
g_pServerPool->BlockServer(pLastServer);
|
||||
}
|
||||
|
||||
pWantServer = NULL;
|
||||
if (bConnected && Status == adFailed && iRemainedRetries > 0 && !bRetentionFailure)
|
||||
{
|
||||
pWantServer = pLastServer;
|
||||
}
|
||||
|
||||
if (pWantServer &&
|
||||
!(IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
|
||||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration()))
|
||||
else
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
SetStatus(adWaiting);
|
||||
int msec = 0;
|
||||
while (!(IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
|
||||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration()) &&
|
||||
msec < g_pOptions->GetRetryInterval() * 1000)
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
}
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
FreeConnection(Status == adFinished || Status == adNotFound);
|
||||
}
|
||||
|
||||
if (Status == adFinished || Status == adFatalError)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
|
||||
@@ -243,7 +240,7 @@ void ArticleDownloader::Run()
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pWantServer)
|
||||
if (!pWantServer && (bConnected || bRetentionFailure))
|
||||
{
|
||||
failedServers.push_back(pLastServer);
|
||||
|
||||
@@ -397,7 +394,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
|
||||
// Throttle the bandwidth
|
||||
while (!IsStopped() && (g_pOptions->GetDownloadRate() > 0.0f) &&
|
||||
(g_pStatMeter->CalcCurrentDownloadSpeed() > g_pOptions->GetDownloadRate()))
|
||||
(g_pStatMeter->CalcCurrentDownloadSpeed() > g_pOptions->GetDownloadRate() ||
|
||||
g_pStatMeter->CalcMomentaryDownloadSpeed() > g_pOptions->GetDownloadRate()))
|
||||
{
|
||||
SetLastUpdateTimeNow();
|
||||
usleep(10 * 1000);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2014-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -190,7 +190,9 @@ bool ArticleWriter::Start(Decoder::EFormat eFormat, const char* szFilename, long
|
||||
m_pOutFile = fopen(szFilename, bDirectWrite ? FOPEN_RBP : FOPEN_WB);
|
||||
if (!m_pOutFile)
|
||||
{
|
||||
error("Could not %s file %s: %s", bDirectWrite ? "open" : "create", szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not %s file %s: %s", bDirectWrite ? "open" : "create", szFilename,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
return false;
|
||||
}
|
||||
SetWriteBuffer(m_pOutFile, m_pArticleInfo->GetSize());
|
||||
@@ -250,7 +252,9 @@ void ArticleWriter::Finish(bool bSuccess)
|
||||
{
|
||||
if (!Util::MoveFile(m_szTempFilename, m_szResultFilename))
|
||||
{
|
||||
error("Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +283,9 @@ void ArticleWriter::Finish(bool bSuccess)
|
||||
// rawmode
|
||||
if (!Util::MoveFile(m_szTempFilename, m_szResultFilename))
|
||||
{
|
||||
error("Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,13 +313,15 @@ bool ArticleWriter::CreateOutputFile(long long iSize)
|
||||
|
||||
if (!Util::ForceDirectories(szDestDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", szDestDir, szErrBuf);
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create directory %s: %s", szDestDir, szErrBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Util::CreateSparseFile(m_szOutputFilename, iSize))
|
||||
{
|
||||
error("Could not create file %s", m_szOutputFilename);
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create file %s", m_szOutputFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -399,7 +407,8 @@ void ArticleWriter::CompleteFileParts()
|
||||
// Ensure the DstDir is created
|
||||
if (!Util::ForceDirectories(szNZBDestDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", szNZBDestDir, szErrBuf);
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create directory %s: %s", szNZBDestDir, szErrBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -417,7 +426,8 @@ void ArticleWriter::CompleteFileParts()
|
||||
outfile = fopen(tmpdestfile, FOPEN_WBP);
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s: %s", tmpdestfile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create file %s: %s", tmpdestfile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -426,7 +436,8 @@ void ArticleWriter::CompleteFileParts()
|
||||
outfile = fopen(m_szOutputFilename, FOPEN_RBP);
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not open file %s: %s", m_szOutputFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not open file %s: %s", m_szOutputFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
return;
|
||||
}
|
||||
strncpy(tmpdestfile, m_szOutputFilename, 1024);
|
||||
@@ -437,7 +448,8 @@ void ArticleWriter::CompleteFileParts()
|
||||
remove(tmpdestfile);
|
||||
if (!Util::CreateDirectory(ofn))
|
||||
{
|
||||
error("Could not create directory %s: %s", ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create directory %s: %s", ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -504,7 +516,8 @@ void ArticleWriter::CompleteFileParts()
|
||||
{
|
||||
m_pFileInfo->SetFailedArticles(m_pFileInfo->GetFailedArticles() + 1);
|
||||
m_pFileInfo->SetSuccessArticles(m_pFileInfo->GetSuccessArticles() - 1);
|
||||
error("Could not find file %s for %s%c%s [%i/%i]",
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not find file %s for %s%c%s [%i/%i]",
|
||||
pa->GetResultFilename(), szNZBName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename(),
|
||||
pa->GetPartNumber(), (int)m_pFileInfo->GetArticles()->size());
|
||||
}
|
||||
@@ -516,7 +529,9 @@ void ArticleWriter::CompleteFileParts()
|
||||
dstFileName[1024-1] = '\0';
|
||||
if (!Util::MoveFile(pa->GetResultFilename(), dstFileName))
|
||||
{
|
||||
error("Could not move file %s to %s: %s", pa->GetResultFilename(), dstFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not move file %s to %s: %s", pa->GetResultFilename(), dstFileName,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +555,9 @@ void ArticleWriter::CompleteFileParts()
|
||||
fclose(outfile);
|
||||
if (!bDirectWrite && !Util::MoveFile(tmpdestfile, ofn))
|
||||
{
|
||||
error("Could not move file %s to %s: %s", tmpdestfile, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not move file %s to %s: %s", tmpdestfile, ofn,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +565,9 @@ void ArticleWriter::CompleteFileParts()
|
||||
{
|
||||
if (!Util::MoveFile(m_szOutputFilename, ofn))
|
||||
{
|
||||
error("Could not move file %s to %s: %s", m_szOutputFilename, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not move file %s to %s: %s", m_szOutputFilename, ofn,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
|
||||
// if destination directory was changed delete the old directory (if empty)
|
||||
@@ -581,14 +600,16 @@ void ArticleWriter::CompleteFileParts()
|
||||
|
||||
if (m_pFileInfo->GetMissedArticles() == 0 && m_pFileInfo->GetFailedArticles() == 0)
|
||||
{
|
||||
info("Successfully downloaded %s", szInfoFilename);
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, "Successfully downloaded %s", szInfoFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("%i of %i article downloads failed for \"%s\"", m_pFileInfo->GetMissedArticles() + m_pFileInfo->GetFailedArticles(),
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkWarning,
|
||||
"%i of %i article downloads failed for \"%s\"",
|
||||
m_pFileInfo->GetMissedArticles() + m_pFileInfo->GetFailedArticles(),
|
||||
m_pFileInfo->GetTotalArticles(), szInfoFilename);
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
if (g_pOptions->GetBrokenLog())
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", szNZBDestDir, (int)PATH_SEPARATOR);
|
||||
@@ -668,7 +689,9 @@ void ArticleWriter::FlushCache()
|
||||
outfile = fopen(m_pFileInfo->GetOutputFilename(), FOPEN_RBP);
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not open file %s: %s", m_pFileInfo->GetOutputFilename(), Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not open file %s: %s", m_pFileInfo->GetOutputFilename(),
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
break;
|
||||
}
|
||||
bNeedBufFile = true;
|
||||
@@ -682,7 +705,9 @@ void ArticleWriter::FlushCache()
|
||||
outfile = fopen(szDestFile, FOPEN_WB);
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s: %s", "create", szDestFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not create file %s: %s", "create", szDestFile,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
break;
|
||||
}
|
||||
bNeedBufFile = true;
|
||||
@@ -713,7 +738,9 @@ void ArticleWriter::FlushCache()
|
||||
|
||||
if (!Util::MoveFile(szDestFile, pa->GetResultFilename()))
|
||||
{
|
||||
error("Could not rename file %s to %s: %s", szDestFile, pa->GetResultFilename(), Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Could not rename file %s to %s: %s", szDestFile, pa->GetResultFilename(),
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -743,7 +770,7 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(pNZBInfo->GetDestDir(), szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf);
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -770,13 +797,14 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD
|
||||
if (!Util::MoveFile(szOldFileName, szNewFileName))
|
||||
{
|
||||
char szErrBuf[256];
|
||||
error("Could not move file %s to %s: %s", szOldFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Could not move file %s to %s: %s",
|
||||
szOldFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move brokenlog.txt
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
if (g_pOptions->GetBrokenLog())
|
||||
{
|
||||
char szOldBrokenLogName[1024];
|
||||
snprintf(szOldBrokenLogName, 1024, "%s%c_brokenlog.txt", szOldDestDir, (int)PATH_SEPARATOR);
|
||||
@@ -813,13 +841,13 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not open file %s", szOldBrokenLogName);
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Could not open file %s", szOldBrokenLogName);
|
||||
}
|
||||
fclose(outfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not open file %s", szBrokenLogName);
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Could not open file %s", szBrokenLogName);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -828,7 +856,8 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD
|
||||
if (!Util::MoveFile(szOldBrokenLogName, szBrokenLogName))
|
||||
{
|
||||
char szErrBuf[256];
|
||||
error("Could not move file %s to %s: %s", szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Could not move file %s to %s: %s",
|
||||
szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -99,8 +99,8 @@ bool NNTPConnection::Authenticate()
|
||||
{
|
||||
if (strlen(m_pNewsServer->GetUser()) == 0 || strlen(m_pNewsServer->GetPassword()) == 0)
|
||||
{
|
||||
error("%c%s (%s) requested authorization but username/password are not set in settings",
|
||||
toupper(m_pNewsServer->GetName()[0]), m_pNewsServer->GetName() + 1, m_pNewsServer->GetHost());
|
||||
ReportError("Could not connect to %s: server requested authorization but username/password are not set in settings",
|
||||
m_pNewsServer->GetHost(), false, 0);
|
||||
m_bAuthError = true;
|
||||
return false;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
if (!answer)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
ReportErrorAnswer("Authorization for %s (%s) failed: Connection closed by remote host", NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
|
||||
if (GetStatus() != csCancelled)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Authorization for %s (%s) failed: %s", answer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
if (!answer)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
ReportErrorAnswer("Authorization failed for %s (%s): Connection closed by remote host", NULL);
|
||||
return false;
|
||||
}
|
||||
else if (!strncmp(answer, "2", 1))
|
||||
@@ -185,7 +185,7 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
|
||||
if (GetStatus() != csCancelled)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Authorization for %s (%s) failed: %s", answer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -237,14 +237,14 @@ bool NNTPConnection::Connect()
|
||||
|
||||
if (!answer)
|
||||
{
|
||||
ReportErrorAnswer("Connection to server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
ReportErrorAnswer("Connection to %s (%s) failed: Connection closed by remote host", NULL);
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(answer, "2", 1))
|
||||
{
|
||||
ReportErrorAnswer("Connection to server%i (%s) failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Connection to %s (%s) failed: %s", answer);
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
@@ -264,7 +264,10 @@ bool NNTPConnection::Disconnect()
|
||||
{
|
||||
if (m_eStatus == csConnected)
|
||||
{
|
||||
Request("quit\r\n");
|
||||
if (!m_bBroken)
|
||||
{
|
||||
Request("quit\r\n");
|
||||
}
|
||||
free(m_szActiveGroup);
|
||||
m_szActiveGroup = NULL;
|
||||
}
|
||||
@@ -274,7 +277,7 @@ bool NNTPConnection::Disconnect()
|
||||
void NNTPConnection::ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer)
|
||||
{
|
||||
char szErrStr[1024];
|
||||
snprintf(szErrStr, 1024, szMsgPrefix, m_pNewsServer->GetID(), m_pNewsServer->GetHost(), szAnswer);
|
||||
snprintf(szErrStr, 1024, szMsgPrefix, m_pNewsServer->GetName(), m_pNewsServer->GetHost(), szAnswer);
|
||||
szErrStr[1024-1] = '\0';
|
||||
|
||||
ReportError(szErrStr, NULL, false, 0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
const char* Request(const char* req);
|
||||
const char* JoinGroup(const char* grp);
|
||||
bool GetAuthError() { return m_bAuthError; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
NewsServer::NewsServer(int iID, bool bActive, const char* szName, const char* szHost, int iPort,
|
||||
const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS,
|
||||
const char* szCipher, int iMaxConnections, int iLevel, int iGroup)
|
||||
const char* szCipher, int iMaxConnections, int iRetention, int iLevel, int iGroup)
|
||||
{
|
||||
m_iID = iID;
|
||||
m_iStateID = 0;
|
||||
@@ -57,6 +57,8 @@ NewsServer::NewsServer(int iID, bool bActive, const char* szName, const char* sz
|
||||
m_szUser = strdup(szUser ? szUser : "");
|
||||
m_szPassword = strdup(szPass ? szPass : "");
|
||||
m_szCipher = strdup(szCipher ? szCipher : "");
|
||||
m_iRetention = iRetention;
|
||||
m_tBlockTime = 0;
|
||||
|
||||
if (szName && strlen(szName) > 0)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,6 +28,7 @@
|
||||
#define NEWSSERVER_H
|
||||
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
class NewsServer
|
||||
{
|
||||
@@ -47,11 +48,14 @@ private:
|
||||
bool m_bJoinGroup;
|
||||
bool m_bTLS;
|
||||
char* m_szCipher;
|
||||
int m_iRetention;
|
||||
time_t m_tBlockTime;
|
||||
|
||||
public:
|
||||
NewsServer(int iID, bool bActive, const char* szName, const char* szHost, int iPort,
|
||||
const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup);
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iRetention,
|
||||
int iLevel, int iGroup);
|
||||
~NewsServer();
|
||||
int GetID() { return m_iID; }
|
||||
int GetStateID() { return m_iStateID; }
|
||||
@@ -71,6 +75,9 @@ public:
|
||||
int GetJoinGroup() { return m_bJoinGroup; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
const char* GetCipher() { return m_szCipher; }
|
||||
int GetRetention() { return m_iRetention; }
|
||||
time_t GetBlockTime() { return m_tBlockTime; }
|
||||
void SetBlockTime(time_t tBlockTime) { m_tBlockTime = tBlockTime; }
|
||||
};
|
||||
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -58,6 +58,7 @@ ServerPool::ServerPool()
|
||||
m_iMaxNormLevel = 0;
|
||||
m_iTimeout = 60;
|
||||
m_iGeneration = 0;
|
||||
m_iRetryInterval = 0;
|
||||
|
||||
g_pLog->RegisterDebuggable(this);
|
||||
}
|
||||
@@ -157,6 +158,7 @@ void ServerPool::InitConnections()
|
||||
for (Servers::iterator it = m_SortedServers.begin(); it != m_SortedServers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
pNewsServer->SetBlockTime(0);
|
||||
int iNormLevel = pNewsServer->GetNormLevel();
|
||||
if (pNewsServer->GetNormLevel() > -1)
|
||||
{
|
||||
@@ -199,11 +201,15 @@ void ServerPool::InitConnections()
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers)
|
||||
{
|
||||
PooledConnection* pConnection = NULL;
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
time_t tCurTime = time(NULL);
|
||||
|
||||
if (iLevel < (int)m_Levels.size() && m_Levels[iLevel] > 0)
|
||||
{
|
||||
Connections candidates;
|
||||
candidates.reserve(m_Connections.size());
|
||||
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pCandidateConnection = *it;
|
||||
@@ -211,7 +217,11 @@ NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, S
|
||||
if (!pCandidateConnection->GetInUse() && pCandidateServer->GetActive() &&
|
||||
pCandidateServer->GetNormLevel() == iLevel &&
|
||||
(!pWantServer || pCandidateServer == pWantServer ||
|
||||
(pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())))
|
||||
(pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())) &&
|
||||
(pCandidateConnection->GetStatus() == Connection::csConnected ||
|
||||
!pCandidateServer->GetBlockTime() ||
|
||||
pCandidateServer->GetBlockTime() + m_iRetryInterval <= tCurTime ||
|
||||
pCandidateServer->GetBlockTime() > tCurTime))
|
||||
{
|
||||
// free connection found, check if it's not from the server which should be ignored
|
||||
bool bUseConnection = true;
|
||||
@@ -230,15 +240,25 @@ NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, S
|
||||
}
|
||||
}
|
||||
|
||||
pCandidateServer->SetBlockTime(0);
|
||||
|
||||
if (bUseConnection)
|
||||
{
|
||||
pConnection = pCandidateConnection;
|
||||
pConnection->SetInUse(true);
|
||||
break;
|
||||
candidates.push_back(pCandidateConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!candidates.empty())
|
||||
{
|
||||
// Peeking a random free connection. This is better than taking the first
|
||||
// available connection because provides better distribution across news servers,
|
||||
// especially when one of servers becomes unavailable or doesn't have requested articles.
|
||||
int iRandomIndex = rand() % candidates.size();
|
||||
pConnection = candidates[iRandomIndex];
|
||||
pConnection->SetInUse(true);
|
||||
}
|
||||
|
||||
if (pConnection)
|
||||
{
|
||||
m_Levels[iLevel]--;
|
||||
@@ -273,12 +293,27 @@ void ServerPool::FreeConnection(NNTPConnection* pConnection, bool bUsed)
|
||||
m_mutexConnections.Unlock();
|
||||
}
|
||||
|
||||
void ServerPool::BlockServer(NewsServer* pNewsServer)
|
||||
{
|
||||
m_mutexConnections.Lock();
|
||||
time_t tCurTime = time(NULL);
|
||||
bool bNewBlock = pNewsServer->GetBlockTime() != tCurTime;
|
||||
pNewsServer->SetBlockTime(tCurTime);
|
||||
m_mutexConnections.Unlock();
|
||||
|
||||
if (bNewBlock && m_iRetryInterval > 0)
|
||||
{
|
||||
warn("Blocking %s (%s) for %i sec", pNewsServer->GetName(), pNewsServer->GetHost(), m_iRetryInterval);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerPool::CloseUnusedConnections()
|
||||
{
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
time_t curtime = ::time(NULL);
|
||||
|
||||
// close and free all connections of servers which were disabled since the last check
|
||||
int i = 0;
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); )
|
||||
{
|
||||
@@ -300,16 +335,6 @@ void ServerPool::CloseUnusedConnections()
|
||||
bDeleted = true;
|
||||
}
|
||||
|
||||
if (!bDeleted && !pConnection->GetInUse() && pConnection->GetStatus() == Connection::csConnected)
|
||||
{
|
||||
int tdiff = (int)(curtime - pConnection->GetFreeTime());
|
||||
if (tdiff > CONNECTION_HOLD_SECODNS)
|
||||
{
|
||||
debug("Closing (and keeping) unused connection to server%i", pConnection->GetNewsServer()->GetID());
|
||||
pConnection->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDeleted)
|
||||
{
|
||||
it++;
|
||||
@@ -317,6 +342,50 @@ void ServerPool::CloseUnusedConnections()
|
||||
}
|
||||
}
|
||||
|
||||
// close all opened connections on levels not having any in-use connections
|
||||
for (int iLevel = 0; iLevel <= m_iMaxNormLevel; iLevel++)
|
||||
{
|
||||
// check if we have in-use connections on the level
|
||||
bool bHasInUseConnections = false;
|
||||
int iInactiveTime = 0;
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection = *it;
|
||||
if (pConnection->GetNewsServer()->GetNormLevel() == iLevel)
|
||||
{
|
||||
if (pConnection->GetInUse())
|
||||
{
|
||||
bHasInUseConnections = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tdiff = (int)(curtime - pConnection->GetFreeTime());
|
||||
if (tdiff > iInactiveTime)
|
||||
{
|
||||
iInactiveTime = tdiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no in-use connections on the level and the hold time out has
|
||||
// expired - close all connections of the level.
|
||||
if (!bHasInUseConnections && iInactiveTime > CONNECTION_HOLD_SECODNS)
|
||||
{
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection = *it;
|
||||
if (pConnection->GetNewsServer()->GetNormLevel() == iLevel &&
|
||||
pConnection->GetStatus() == Connection::csConnected)
|
||||
{
|
||||
debug("Closing (and keeping) unused connection to server%i", pConnection->GetNewsServer()->GetID());
|
||||
pConnection->Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
}
|
||||
|
||||
@@ -336,12 +405,16 @@ void ServerPool::LogDebugInfo()
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
time_t tCurTime = time(NULL);
|
||||
|
||||
info(" Servers: %i", m_Servers.size());
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
info(" %i) %s (%s): Level=%i, NormLevel=%i", pNewsServer->GetID(), pNewsServer->GetName(),
|
||||
pNewsServer->GetHost(), pNewsServer->GetLevel(), pNewsServer->GetNormLevel());
|
||||
info(" %i) %s (%s): Level=%i, NormLevel=%i, BlockSec=%i", pNewsServer->GetID(), pNewsServer->GetName(),
|
||||
pNewsServer->GetHost(), pNewsServer->GetLevel(), pNewsServer->GetNormLevel(),
|
||||
pNewsServer->GetBlockTime() && pNewsServer->GetBlockTime() + m_iRetryInterval > tCurTime ?
|
||||
pNewsServer->GetBlockTime() + m_iRetryInterval - tCurTime : 0);
|
||||
}
|
||||
|
||||
info(" Levels: %i", m_Levels.size());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -61,18 +61,20 @@ private:
|
||||
int m_iMaxNormLevel;
|
||||
Mutex m_mutexConnections;
|
||||
int m_iTimeout;
|
||||
int m_iRetryInterval;
|
||||
int m_iGeneration;
|
||||
|
||||
void NormalizeLevels();
|
||||
static bool CompareServers(NewsServer* pServer1, NewsServer* pServer2);
|
||||
|
||||
protected:
|
||||
virtual void LogDebugInfo();
|
||||
virtual void LogDebugInfo();
|
||||
|
||||
public:
|
||||
ServerPool();
|
||||
~ServerPool();
|
||||
void SetTimeout(int iTimeout) { m_iTimeout = iTimeout; }
|
||||
void SetRetryInterval(int iRetryInterval) { m_iRetryInterval = iRetryInterval; }
|
||||
void AddServer(NewsServer* pNewsServer);
|
||||
void InitConnections();
|
||||
int GetMaxNormLevel() { return m_iMaxNormLevel; }
|
||||
@@ -82,6 +84,7 @@ public:
|
||||
void CloseUnusedConnections();
|
||||
void Changed();
|
||||
int GetGeneration() { return m_iGeneration; }
|
||||
void BlockServer(NewsServer* pNewsServer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2014-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "Options.h"
|
||||
#include "ServerPool.h"
|
||||
#include "DiskState.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern ServerPool* g_pServerPool;
|
||||
extern Options* g_pOptions;
|
||||
@@ -171,43 +172,42 @@ void ServerVolume::LogDebugInfo()
|
||||
{
|
||||
info(" ---------- ServerVolume");
|
||||
|
||||
char szSec[4000];
|
||||
StringBuilder msg;
|
||||
|
||||
szSec[0] = '\0';
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
char szNum[20];
|
||||
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerSeconds[i]);
|
||||
strncat(szSec, szNum, 4000);
|
||||
char szNum[30];
|
||||
snprintf(szNum, 30, "[%i]=%lli ", i, m_BytesPerSeconds[i]);
|
||||
msg.Append(szNum);
|
||||
}
|
||||
info("Secs: %s", szSec);
|
||||
info("Secs: %s", msg.GetBuffer());
|
||||
|
||||
szSec[0] = '\0';
|
||||
msg.Clear();
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
char szNum[20];
|
||||
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerMinutes[i]);
|
||||
strncat(szSec, szNum, 4000);
|
||||
char szNum[30];
|
||||
snprintf(szNum, 30, "[%i]=%lli ", i, m_BytesPerMinutes[i]);
|
||||
msg.Append(szNum);
|
||||
}
|
||||
info("Mins: %s", szSec);
|
||||
info("Mins: %s", msg.GetBuffer());
|
||||
|
||||
szSec[0] = '\0';
|
||||
msg.Clear();
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
char szNum[20];
|
||||
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerHours[i]);
|
||||
strncat(szSec, szNum, 4000);
|
||||
char szNum[30];
|
||||
snprintf(szNum, 30, "[%i]=%lli ", i, m_BytesPerHours[i]);
|
||||
msg.Append(szNum);
|
||||
}
|
||||
info("Hours: %s", szSec);
|
||||
info("Hours: %s", msg.GetBuffer());
|
||||
|
||||
szSec[0] = '\0';
|
||||
msg.Clear();
|
||||
for (int i = 0; i < (int)m_BytesPerDays.size(); i++)
|
||||
{
|
||||
char szNum[20];
|
||||
snprintf(szNum, 20, "[%i]=%lli ", m_iFirstDay + i, m_BytesPerDays[i]);
|
||||
strncat(szSec, szNum, 4000);
|
||||
char szNum[30];
|
||||
snprintf(szNum, 30, "[%i]=%lli ", m_iFirstDay + i, m_BytesPerDays[i]);
|
||||
msg.Append(szNum);
|
||||
}
|
||||
info("Days: %s", szSec);
|
||||
info("Days: %s", msg.GetBuffer());
|
||||
}
|
||||
|
||||
StatMeter::StatMeter()
|
||||
@@ -356,9 +356,7 @@ void StatMeter::CalcTotalStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllB
|
||||
m_mutexStat.Unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: see note to "AddSpeedReading"
|
||||
*/
|
||||
// Average speed in last 30 seconds
|
||||
int StatMeter::CalcCurrentDownloadSpeed()
|
||||
{
|
||||
if (m_bStandBy)
|
||||
@@ -375,6 +373,14 @@ int StatMeter::CalcCurrentDownloadSpeed()
|
||||
return (int)(m_iSpeedTotalBytes / iTimeDiff);
|
||||
}
|
||||
|
||||
// Amount of data downloaded in current second
|
||||
int StatMeter::CalcMomentaryDownloadSpeed()
|
||||
{
|
||||
time_t tCurTime = time(NULL);
|
||||
int iSpeed = tCurTime == m_tCurSecTime ? m_iCurSecBytes : 0;
|
||||
return iSpeed;
|
||||
}
|
||||
|
||||
void StatMeter::AddSpeedReading(int iBytes)
|
||||
{
|
||||
time_t tCurTime = time(NULL);
|
||||
@@ -389,6 +395,13 @@ void StatMeter::AddSpeedReading(int iBytes)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (tCurTime != m_tCurSecTime)
|
||||
{
|
||||
m_tCurSecTime = tCurTime;
|
||||
m_iCurSecBytes = 0;
|
||||
}
|
||||
m_iCurSecBytes += iBytes;
|
||||
|
||||
while (iNowSlot > m_iSpeedTime[m_iSpeedBytesIndex])
|
||||
{
|
||||
//record bytes in next slot
|
||||
@@ -452,6 +465,8 @@ void StatMeter::ResetSpeedStat()
|
||||
m_iSpeedBytesIndex = 0;
|
||||
m_iSpeedTotalBytes = 0;
|
||||
m_tSpeedCorrection = tCurTime;
|
||||
m_tCurSecTime = 0;
|
||||
m_iCurSecBytes = 0;
|
||||
}
|
||||
|
||||
void StatMeter::LogDebugInfo()
|
||||
|
||||
@@ -93,6 +93,8 @@ private:
|
||||
int m_iSpeedStartTime;
|
||||
time_t m_tSpeedCorrection;
|
||||
int m_iSpeedBytesIndex;
|
||||
int m_iCurSecBytes;
|
||||
time_t m_tCurSecTime;
|
||||
#ifdef HAVE_SPINLOCK
|
||||
SpinLock m_spinlockSpeed;
|
||||
#else
|
||||
@@ -125,6 +127,7 @@ public:
|
||||
~StatMeter();
|
||||
void Init();
|
||||
int CalcCurrentDownloadSpeed();
|
||||
int CalcMomentaryDownloadSpeed();
|
||||
void AddSpeedReading(int iBytes);
|
||||
void AddServerData(int iBytes, int iServerID);
|
||||
void CalcTotalStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -192,7 +192,9 @@ bool Repairer::ScanDataFile(DiskFile *diskfile, Par2RepairerSourceFile* &sourcef
|
||||
{
|
||||
sig_done(name, iAvailableBlocks, sourcefile->BlockCount());
|
||||
sig_progress(1000.0);
|
||||
matchtype = eFileStatus == ParChecker::fsSuccess ? eFullMatch : ParChecker::fsPartial ? ePartialMatch : eNoMatch;
|
||||
matchtype = eFileStatus == ParChecker::fsSuccess ? eFullMatch :
|
||||
eFileStatus == ParChecker::fsPartial ? ePartialMatch : eNoMatch;
|
||||
m_pOwner->SetParFull(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -414,6 +416,7 @@ ParChecker::ParChecker()
|
||||
m_eStage = ptLoadingPars;
|
||||
m_bParQuick = false;
|
||||
m_bForceRepair = false;
|
||||
m_bParFull = false;
|
||||
}
|
||||
|
||||
ParChecker::~ParChecker()
|
||||
@@ -494,6 +497,7 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
|
||||
|
||||
EStatus eAllStatus = psRepairNotNeeded;
|
||||
m_bCancelled = false;
|
||||
m_bParFull = true;
|
||||
|
||||
for (ParCoordinator::ParFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
|
||||
{
|
||||
@@ -527,7 +531,7 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
|
||||
eAllStatus = eStatus;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
if (g_pOptions->GetBrokenLog())
|
||||
{
|
||||
WriteBrokenLog(eStatus);
|
||||
}
|
||||
@@ -572,6 +576,11 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
|
||||
if (!m_bParQuick)
|
||||
{
|
||||
CheckEmptyFiles();
|
||||
}
|
||||
|
||||
bool bAddedSplittedFragments = false;
|
||||
if (m_bHasDamagedFiles && !IsStopped() && res == eRepairNotPossible)
|
||||
{
|
||||
@@ -957,7 +966,7 @@ bool ParChecker::AddSplittedFragments()
|
||||
{
|
||||
m_iExtraFiles += extrafiles.size();
|
||||
m_bVerifyingExtraFiles = true;
|
||||
info("Found %i splitted fragments for %s", (int)extrafiles.size(), m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Found %i splitted fragments for %s", (int)extrafiles.size(), m_szInfoName);
|
||||
bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
|
||||
((Repairer*)m_pRepairer)->UpdateVerificationResults();
|
||||
m_bVerifyingExtraFiles = false;
|
||||
@@ -1027,7 +1036,7 @@ bool ParChecker::AddMissingFiles()
|
||||
bool bAdded = iWasMissing > (int)((Repairer*)m_pRepairer)->missingfilecount;
|
||||
if (bAdded)
|
||||
{
|
||||
info("Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str()));
|
||||
PrintMessage(Message::mkInfo, "Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str()));
|
||||
RegisterParredFile(Util::BaseFileName(pExtraFile->FileName().c_str()));
|
||||
}
|
||||
|
||||
@@ -1185,6 +1194,39 @@ void ParChecker::signal_done(std::string str, int available, int total)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Only if ParQuick isn't enabled:
|
||||
* For empty damaged files the callback-function "signal_done" isn't called and the flag "m_bHasDamagedFiles"
|
||||
* therefore isn't set. In this function we expicitly check such files.
|
||||
*/
|
||||
void ParChecker::CheckEmptyFiles()
|
||||
{
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
|
||||
if (sourcefile && sourcefile->GetDescriptionPacket())
|
||||
{
|
||||
const char* szFilename = sourcefile->GetDescriptionPacket()->FileName().c_str();
|
||||
if (!IsProcessedFile(szFilename))
|
||||
{
|
||||
bool bIgnore = Util::MatchFileExt(szFilename, g_pOptions->GetParIgnoreExt(), ",;") ||
|
||||
Util::MatchFileExt(szFilename, g_pOptions->GetExtCleanupDisk(), ",;");
|
||||
m_bHasDamagedFiles |= !bIgnore;
|
||||
|
||||
int total = sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0;
|
||||
PrintMessage(Message::mkWarning, "File %s has %i bad block(s) of total %i block(s)%s",
|
||||
szFilename, total, total, bIgnore ? ", ignoring" : "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bHasDamagedFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParChecker::Cancel()
|
||||
{
|
||||
((Repairer*)m_pRepairer)->cancelled = true;
|
||||
@@ -1294,7 +1336,7 @@ void ParChecker::DeleteLeftovers()
|
||||
* download with CRC stored in PAR2-file;
|
||||
* - for partially downloaded files the CRCs of articles are compared with block-CRCs stored
|
||||
* in PAR2-file;
|
||||
* - for completely failed files (not a single successful artice) no verification is needed at all.
|
||||
* - for completely failed files (not a single successful article) no verification is needed at all.
|
||||
*
|
||||
* Limitation of the function:
|
||||
* This function requires every block in the file to have an unique CRC (across all blocks
|
||||
@@ -1463,7 +1505,8 @@ bool ParChecker::VerifyPartialDataFile(void* pDiskfile, void* pSourcefile, Segme
|
||||
FILE* infile = fopen(szFilename, FOPEN_RB);
|
||||
if (!infile)
|
||||
{
|
||||
error("Could not open file %s: %s", szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
PrintMessage(Message::mkError, "Could not open file %s: %s",
|
||||
szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
}
|
||||
|
||||
// For each sequential range of presumably valid blocks:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -119,6 +119,7 @@ private:
|
||||
bool m_bHasDamagedFiles;
|
||||
bool m_bParQuick;
|
||||
bool m_bForceRepair;
|
||||
bool m_bParFull;
|
||||
|
||||
void Cleanup();
|
||||
EStatus RunParCheckAll();
|
||||
@@ -144,6 +145,7 @@ private:
|
||||
bool SmartCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, SegmentList* pSegments,
|
||||
unsigned long* pDownloadCrc);
|
||||
bool DumbCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, unsigned long* pDownloadCrc);
|
||||
void CheckEmptyFiles();
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -176,6 +178,8 @@ public:
|
||||
bool GetParQuick() { return m_bParQuick; }
|
||||
void SetForceRepair(bool bForceRepair) { m_bForceRepair = bForceRepair; }
|
||||
bool GetForceRepair() { return m_bForceRepair; }
|
||||
void SetParFull(bool bParFull) { m_bParFull = bParFull; }
|
||||
bool GetParFull() { return m_bParFull; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void AddParFile(const char* szParFilename);
|
||||
void QueueChanged();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -72,7 +72,7 @@ void ParCoordinator::PostParChecker::PrintMessage(Message::EKind eKind, const ch
|
||||
va_end(args);
|
||||
szText[1024-1] = '\0';
|
||||
|
||||
m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::RegisterParredFile(const char* szFilename)
|
||||
@@ -160,7 +160,7 @@ void ParCoordinator::PostParRenamer::PrintMessage(Message::EKind eKind, const ch
|
||||
va_end(args);
|
||||
szText[1024-1] = '\0';
|
||||
|
||||
m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::RegisterParredFile(const char* szFilename)
|
||||
@@ -441,6 +441,7 @@ void ParCoordinator::ParCheckCompleted()
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSuccess);
|
||||
pPostInfo->SetParRepaired(m_ParChecker.GetStatus() == ParChecker::psRepaired);
|
||||
}
|
||||
else if (m_ParChecker.GetStatus() == ParChecker::psRepairPossible &&
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)
|
||||
@@ -457,7 +458,7 @@ void ParCoordinator::ParCheckCompleted()
|
||||
int iParSec = (int)(time(NULL) - m_ParChecker.GetParTime()) - iWaitTime;
|
||||
pPostInfo->GetNZBInfo()->SetParSec(pPostInfo->GetNZBInfo()->GetParSec() + iParSec);
|
||||
|
||||
pPostInfo->GetNZBInfo()->SetParFull(!m_ParChecker.GetParQuick());
|
||||
pPostInfo->GetNZBInfo()->SetParFull(m_ParChecker.GetParFull());
|
||||
|
||||
pPostInfo->SetWorking(false);
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
@@ -578,7 +579,7 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
|
||||
if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
|
||||
{
|
||||
// should not happen
|
||||
error("Internal error: could not parse filename %s", szBaseParFilename);
|
||||
pNZBInfo->PrintMessage(Message::mkError, "Internal error: could not parse filename %s", szBaseParFilename);
|
||||
return;
|
||||
}
|
||||
int maxlen = iMainBaseLen < 1024 ? iMainBaseLen : 1024 - 1;
|
||||
@@ -758,7 +759,7 @@ void ParCoordinator::ParRenameCompleted()
|
||||
|
||||
if (m_ParRenamer.HasMissedFiles() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
|
||||
{
|
||||
PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName());
|
||||
m_ParRenamer.PrintMessage(Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName());
|
||||
pPostInfo->SetRequestParCheck(true);
|
||||
}
|
||||
|
||||
@@ -790,39 +791,4 @@ void ParCoordinator::UpdateParRenameProgress()
|
||||
CheckPauseState(pPostInfo);
|
||||
}
|
||||
|
||||
void ParCoordinator::PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...)
|
||||
{
|
||||
char szText[1024];
|
||||
va_list args;
|
||||
va_start(args, szFormat);
|
||||
vsnprintf(szText, 1024, szFormat, args);
|
||||
va_end(args);
|
||||
szText[1024-1] = '\0';
|
||||
|
||||
pPostInfo->AppendMessage(eKind, szText);
|
||||
|
||||
switch (eKind)
|
||||
{
|
||||
case Message::mkDetail:
|
||||
detail("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkInfo:
|
||||
info("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkWarning:
|
||||
warn("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkError:
|
||||
error("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkDebug:
|
||||
debug("%s", szText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -114,7 +114,6 @@ protected:
|
||||
void ParRenameCompleted();
|
||||
void CheckPauseState(PostInfo* pPostInfo);
|
||||
bool RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound);
|
||||
void PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -262,7 +262,7 @@ void ParRenamer::LoadParFile(const char* szParFilename)
|
||||
Par2RepairerSourceFile* sourceFile = (*it).second;
|
||||
if (!sourceFile || !sourceFile->GetDescriptionPacket())
|
||||
{
|
||||
warn("Damaged par2-file detected: %s", szParFilename);
|
||||
PrintMessage(Message::mkWarning, "Damaged par2-file detected: %s", szParFilename);
|
||||
continue;
|
||||
}
|
||||
m_FileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(),
|
||||
@@ -315,11 +315,11 @@ void ParRenamer::CheckMissing()
|
||||
if (Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetParIgnoreExt(), ",;") ||
|
||||
Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetExtCleanupDisk(), ",;"))
|
||||
{
|
||||
info("File %s is missing, ignoring", pFileHash->GetFilename());
|
||||
PrintMessage(Message::mkInfo, "File %s is missing, ignoring", pFileHash->GetFilename());
|
||||
}
|
||||
else
|
||||
{
|
||||
info("File %s is missing", pFileHash->GetFilename());
|
||||
PrintMessage(Message::mkInfo, "File %s is missing", pFileHash->GetFilename());
|
||||
m_bHasMissedFiles = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -104,6 +104,14 @@ void PostScriptController::ExecuteScript(Options::Script* pScript)
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing post-process-script %s for %s", pScript->GetName(), m_pPostInfo->GetNZBInfo()->GetName());
|
||||
|
||||
char szProgressLabel[1024];
|
||||
snprintf(szProgressLabel, 1024, "Executing post-process-script %s", pScript->GetName());
|
||||
szProgressLabel[1024-1] = '\0';
|
||||
|
||||
DownloadQueue::Lock();
|
||||
m_pPostInfo->SetProgressLabel(szProgressLabel);
|
||||
DownloadQueue::Unlock();
|
||||
|
||||
SetScript(pScript->GetLocation());
|
||||
SetArgs(NULL, false);
|
||||
|
||||
@@ -277,7 +285,8 @@ void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
|
||||
m_pPostInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
|
||||
}
|
||||
free(szParam);
|
||||
}
|
||||
@@ -290,17 +299,16 @@ void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
|
||||
m_pPostInfo->GetNZBInfo()->PrintMessage(Message::mkError,
|
||||
"Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
|
||||
}
|
||||
}
|
||||
else if (!strncmp(szMsgText, "[HISTORY] ", 10))
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szMsgText);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, szText);
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
|
||||
DownloadQueue::Lock();
|
||||
m_pPostInfo->SetProgressLabel(szText);
|
||||
DownloadQueue::Unlock();
|
||||
}
|
||||
|
||||
if (g_pOptions->GetPausePostProcess() && !m_pPostInfo->GetNZBInfo()->GetForcePriority())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -198,7 +198,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
|
||||
{
|
||||
// the deleting of nzbs is usually handled via eaFileDeleted-event, but when deleting nzb without
|
||||
// any files left the eaFileDeleted-event is not fired and we need to process eaNzbDeleted-event instead
|
||||
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
|
||||
pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo,
|
||||
"Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
|
||||
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
|
||||
}
|
||||
else if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
|
||||
@@ -222,7 +223,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
|
||||
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))) &&
|
||||
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth)
|
||||
{
|
||||
info("Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName());
|
||||
pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo,
|
||||
"Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName());
|
||||
g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeNzbDownloaded);
|
||||
NZBDownloaded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
|
||||
}
|
||||
@@ -232,7 +234,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
|
||||
!pQueueAspect->pNZBInfo->GetParCleanup() &&
|
||||
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))
|
||||
{
|
||||
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
|
||||
pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo,
|
||||
"Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
|
||||
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +272,7 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
{
|
||||
if (!pNZBInfo->GetPostInfo() && g_pOptions->GetDecode())
|
||||
{
|
||||
info("Queueing %s for post-processing", pNZBInfo->GetName());
|
||||
pNZBInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", pNZBInfo->GetName());
|
||||
|
||||
pNZBInfo->EnterPostProcess();
|
||||
m_iJobCount++;
|
||||
@@ -449,13 +452,15 @@ void PrePostProcessor::CheckPostQueue()
|
||||
|
||||
if (!pPostInfo->GetNZBInfo()->GetFileList()->empty())
|
||||
{
|
||||
info("Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pDownloadQueue->EditEntry(pPostInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupResume, 0, NULL);
|
||||
pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
@@ -564,7 +569,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSkipped);
|
||||
pPostInfo->SetWorking(false);
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
@@ -576,7 +582,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000 &&
|
||||
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
|
||||
{
|
||||
warn("Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(),
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkWarning,
|
||||
"Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(),
|
||||
pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) / 10.0);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
|
||||
return;
|
||||
@@ -585,7 +592,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
pPostInfo->GetNZBInfo()->GetFailedSize() - pPostInfo->GetNZBInfo()->GetParFailedSize() > 0 &&
|
||||
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
|
||||
{
|
||||
info("Collection %s with health %.1f%% needs par-check",
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"Collection %s with health %.1f%% needs par-check",
|
||||
pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->CalcHealth() / 10.0);
|
||||
pPostInfo->SetRequestParCheck(true);
|
||||
return;
|
||||
@@ -603,13 +611,18 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
|
||||
bool bCleanup = !bUnpack &&
|
||||
pPostInfo->GetNZBInfo()->GetCleanupStatus() == NZBInfo::csNone &&
|
||||
!Util::EmptyStr(g_pOptions->GetExtCleanupDisk()) &&
|
||||
((pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess &&
|
||||
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure &&
|
||||
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usSpace &&
|
||||
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword) ||
|
||||
(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess &&
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)) &&
|
||||
!Util::EmptyStr(g_pOptions->GetExtCleanupDisk());
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure) ||
|
||||
((pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone ||
|
||||
pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSkipped) &&
|
||||
(pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped) &&
|
||||
pPostInfo->GetNZBInfo()->CalcHealth() == 1000));
|
||||
|
||||
bool bMoveInter = !bUnpack &&
|
||||
pPostInfo->GetNZBInfo()->GetMoveStatus() == NZBInfo::msNone &&
|
||||
@@ -626,7 +639,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
|
||||
if (bUnpack && bParFailed)
|
||||
{
|
||||
warn("Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(),
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkWarning,
|
||||
"Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(),
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure");
|
||||
pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
|
||||
bUnpack = false;
|
||||
@@ -703,7 +717,7 @@ void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPo
|
||||
pNZBInfo->CalcCriticalHealth(false) < 1000);
|
||||
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue && !pNZBInfo->GetFileList()->empty())
|
||||
{
|
||||
info("Cleaning up download queue for %s", pNZBInfo->GetName());
|
||||
pNZBInfo->PrintMessage(Message::mkInfo, "Cleaning up download queue for %s", pNZBInfo->GetName());
|
||||
pNZBInfo->SetParCleanup(true);
|
||||
pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
|
||||
}
|
||||
@@ -809,7 +823,8 @@ bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pI
|
||||
{
|
||||
if (pPostInfo->GetWorking())
|
||||
{
|
||||
info("Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->SetDeleted(true);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (PostInfo::ptLoadingPars <= pPostInfo->GetStage() && pPostInfo->GetStage() <= PostInfo::ptRenaming)
|
||||
@@ -834,7 +849,8 @@ bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pI
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
|
||||
"Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
JobCompleted(pDownloadQueue, pPostInfo);
|
||||
bOK = true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -72,6 +72,28 @@ bool UnpackController::FileList::Exists(const char* szFilename)
|
||||
return false;
|
||||
}
|
||||
|
||||
UnpackController::ParamList::~ParamList()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
}
|
||||
|
||||
bool UnpackController::ParamList::Exists(const char* szParam)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
char* szParam1 = *it;
|
||||
if (!strcmp(szParam1, szParam))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnpackController::StartJob(PostInfo* pPostInfo)
|
||||
{
|
||||
UnpackController* pUnpackController = new UnpackController();
|
||||
@@ -100,6 +122,13 @@ void UnpackController::Run()
|
||||
m_szPassword[0] = '\0';
|
||||
m_szFinalDir[0] = '\0';
|
||||
m_bFinalDirCreated = false;
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
m_bUnpackSpaceError = false;
|
||||
m_bUnpackDecryptError = false;
|
||||
m_bUnpackPasswordError = false;
|
||||
m_bAutoTerminated = false;
|
||||
m_bPassListTried = false;
|
||||
|
||||
NZBParameter* pParameter = m_pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
|
||||
bool bUnpack = !(pParameter && !strcasecmp(pParameter->GetValue(), "no"));
|
||||
@@ -134,32 +163,32 @@ void UnpackController::Run()
|
||||
|
||||
bool bHasFiles = m_bHasRarFiles || m_bHasNonStdRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles || m_bHasSplittedFiles;
|
||||
|
||||
if (bUnpack && bHasFiles)
|
||||
if (m_pPostInfo->GetUnpackTried() && !m_pPostInfo->GetParRepaired() &&
|
||||
(!Util::EmptyStr(m_szPassword) || Util::EmptyStr(g_pOptions->GetUnpackPassFile()) || m_pPostInfo->GetPassListTried()))
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s failed: second unpack attempt skipped due to par-check not repaired anything", m_szInfoNameUp);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus((NZBInfo::EUnpackStatus)m_pPostInfo->GetLastUnpackStatus());
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else if (bUnpack && bHasFiles)
|
||||
{
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
m_bUnpackSpaceError = false;
|
||||
m_bUnpackPasswordError4 = false;
|
||||
m_bUnpackPasswordError5 = false;
|
||||
m_bAutoTerminated = false;
|
||||
|
||||
PrintMessage(Message::mkInfo, "Unpacking %s", m_szName);
|
||||
|
||||
CreateUnpackDir();
|
||||
|
||||
if (m_bHasRarFiles || m_bHasNonStdRarFiles)
|
||||
{
|
||||
ExecuteUnrar();
|
||||
UnpackArchives(upUnrar, false);
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipFiles && m_bUnpackOK)
|
||||
{
|
||||
ExecuteSevenZip(false);
|
||||
UnpackArchives(upSevenZip, false);
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipMultiFiles && m_bUnpackOK)
|
||||
{
|
||||
ExecuteSevenZip(true);
|
||||
UnpackArchives(upSevenZip, true);
|
||||
}
|
||||
|
||||
if (m_bHasSplittedFiles && m_bUnpackOK)
|
||||
@@ -195,36 +224,126 @@ void UnpackController::Run()
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteUnrar()
|
||||
void UnpackController::UnpackArchives(EUnpacker eUnpacker, bool bMultiVolumes)
|
||||
{
|
||||
if (!m_pPostInfo->GetUnpackTried() || m_pPostInfo->GetParRepaired())
|
||||
{
|
||||
ExecuteUnpack(eUnpacker, m_szPassword, bMultiVolumes);
|
||||
if (!m_bUnpackOK && m_bHasParFiles && !m_bUnpackPasswordError &&
|
||||
m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
|
||||
{
|
||||
// for rar4- or 7z-archives try par-check first, before trying password file
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bUnpackOK = false;
|
||||
m_bUnpackDecryptError = m_pPostInfo->GetLastUnpackStatus() == (int)NZBInfo::usPassword;
|
||||
}
|
||||
|
||||
if (!m_bUnpackOK && !m_bUnpackStartError && !m_bUnpackSpaceError &&
|
||||
(m_bUnpackDecryptError || m_bUnpackPasswordError) &&
|
||||
(!GetTerminated() || m_bAutoTerminated) &&
|
||||
Util::EmptyStr(m_szPassword) && !Util::EmptyStr(g_pOptions->GetUnpackPassFile()))
|
||||
{
|
||||
FILE* infile = fopen(g_pOptions->GetUnpackPassFile(), FOPEN_RB);
|
||||
if (!infile)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open file %s", g_pOptions->GetUnpackPassFile());
|
||||
return;
|
||||
}
|
||||
|
||||
char szPassword[512];
|
||||
while (!m_bUnpackOK && !m_bUnpackStartError && !m_bUnpackSpaceError &&
|
||||
(m_bUnpackDecryptError || m_bUnpackPasswordError) &&
|
||||
fgets(szPassword, sizeof(szPassword) - 1, infile))
|
||||
{
|
||||
// trim trailing <CR> and <LF>
|
||||
char* szEnd = szPassword + strlen(szPassword) - 1;
|
||||
while (szEnd >= szPassword && (*szEnd == '\n' || *szEnd == '\r')) *szEnd-- = '\0';
|
||||
|
||||
if (!Util::EmptyStr(szPassword))
|
||||
{
|
||||
if (IsStopped() && m_bAutoTerminated)
|
||||
{
|
||||
ScriptController::Resume();
|
||||
Thread::Resume();
|
||||
}
|
||||
m_bUnpackDecryptError = false;
|
||||
m_bUnpackPasswordError = false;
|
||||
m_bAutoTerminated = false;
|
||||
PrintMessage(Message::mkInfo, "Trying password %s for %s", szPassword, m_szName);
|
||||
ExecuteUnpack(eUnpacker, szPassword, bMultiVolumes);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
m_bPassListTried = !IsStopped() || m_bAutoTerminated;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteUnpack(EUnpacker eUnpacker, const char* szPassword, bool bMultiVolumes)
|
||||
{
|
||||
switch (eUnpacker)
|
||||
{
|
||||
case upUnrar:
|
||||
ExecuteUnrar(szPassword);
|
||||
break;
|
||||
|
||||
case upSevenZip:
|
||||
ExecuteSevenZip(szPassword, bMultiVolumes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteUnrar(const char* szPassword)
|
||||
{
|
||||
// Format:
|
||||
// unrar x -y -p- -o+ *.rar ./_unpack
|
||||
// unrar x -y -p- -o+ *.rar ./_unpack/
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[8];
|
||||
szArgs[0] = g_pOptions->GetUnrarCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
ParamList params;
|
||||
if (!PrepareCmdParams(g_pOptions->GetUnrarCmd(), ¶ms, "unrar"))
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
szPasswordParam[1024-1] = '\0';
|
||||
szArgs[3] = szPasswordParam;
|
||||
return;
|
||||
}
|
||||
szArgs[4] = "-o+";
|
||||
szArgs[5] = m_bHasNonStdRarFiles ? "*.*" : "*.rar";
|
||||
|
||||
if (!params.Exists("x") && !params.Exists("e"))
|
||||
{
|
||||
params.push_back(strdup("x"));
|
||||
}
|
||||
|
||||
params.push_back(strdup("-y"));
|
||||
|
||||
if (!Util::EmptyStr(szPassword))
|
||||
{
|
||||
char szPasswordParam[1024];
|
||||
snprintf(szPasswordParam, 1024, "-p%s", szPassword);
|
||||
szPasswordParam[1024-1] = '\0';
|
||||
params.push_back(strdup(szPasswordParam));
|
||||
}
|
||||
else
|
||||
{
|
||||
params.push_back(strdup("-p-"));
|
||||
}
|
||||
|
||||
if (!params.Exists("-o+") && !params.Exists("-o-"))
|
||||
{
|
||||
params.push_back(strdup("-o+"));
|
||||
}
|
||||
|
||||
params.push_back(strdup(m_bHasNonStdRarFiles ? "*.*" : "*.rar"));
|
||||
|
||||
char szUnpackDirParam[1024];
|
||||
snprintf(szUnpackDirParam, 1024, "%s%c", m_szUnpackDir, PATH_SEPARATOR);
|
||||
szUnpackDirParam[1024-1] = '\0';
|
||||
szArgs[6] = szUnpackDirParam;
|
||||
params.push_back(strdup(szUnpackDirParam));
|
||||
|
||||
szArgs[7] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetUnrarCmd());
|
||||
params.push_back(NULL);
|
||||
SetArgs((const char**)¶ms.front(), false);
|
||||
SetScript(params.at(0));
|
||||
SetLogPrefix("Unrar");
|
||||
ResetEnv();
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upUnrar;
|
||||
@@ -237,7 +356,7 @@ void UnpackController::ExecuteUnrar()
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
m_bUnpackSpaceError = iExitCode == 5;
|
||||
m_bUnpackPasswordError5 |= iExitCode == 11; // only for rar5-archives
|
||||
m_bUnpackPasswordError |= iExitCode == 11; // only for rar5-archives
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
@@ -245,37 +364,49 @@ void UnpackController::ExecuteUnrar()
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
|
||||
void UnpackController::ExecuteSevenZip(const char* szPassword, bool bMultiVolumes)
|
||||
{
|
||||
// Format:
|
||||
// 7z x -y -p- -o./_unpack *.7z
|
||||
// OR
|
||||
// 7z x -y -p- -o./_unpack *.7z.001
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[7];
|
||||
szArgs[0] = g_pOptions->GetSevenZipCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
ParamList params;
|
||||
if (!PrepareCmdParams(g_pOptions->GetSevenZipCmd(), ¶ms, "7-Zip"))
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.Exists("x") && !params.Exists("e"))
|
||||
{
|
||||
params.push_back(strdup("x"));
|
||||
}
|
||||
|
||||
params.push_back(strdup("-y"));
|
||||
|
||||
if (!Util::EmptyStr(szPassword))
|
||||
{
|
||||
char szPasswordParam[1024];
|
||||
snprintf(szPasswordParam, 1024, "-p%s", szPassword);
|
||||
szPasswordParam[1024-1] = '\0';
|
||||
szArgs[3] = szPasswordParam;
|
||||
params.push_back(strdup(szPasswordParam));
|
||||
}
|
||||
else
|
||||
{
|
||||
params.push_back(strdup("-p-"));
|
||||
}
|
||||
|
||||
char szUnpackDirParam[1024];
|
||||
snprintf(szUnpackDirParam, 1024, "-o%s", m_szUnpackDir);
|
||||
szUnpackDirParam[1024-1] = '\0';
|
||||
szArgs[4] = szUnpackDirParam;
|
||||
params.push_back(strdup(szUnpackDirParam));
|
||||
|
||||
szArgs[5] = bMultiVolumes ? "*.7z.001" : "*.7z";
|
||||
szArgs[6] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
params.push_back(strdup(bMultiVolumes ? "*.7z.001" : "*.7z"));
|
||||
|
||||
SetScript(g_pOptions->GetSevenZipCmd());
|
||||
params.push_back(NULL);
|
||||
SetArgs((const char**)¶ms.front(), false);
|
||||
SetScript(params.at(0));
|
||||
ResetEnv();
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upSevenZip;
|
||||
@@ -296,6 +427,32 @@ void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
|
||||
}
|
||||
}
|
||||
|
||||
bool UnpackController::PrepareCmdParams(const char* szCommand, ParamList* pParams, const char* szInfoName)
|
||||
{
|
||||
if (Util::FileExists(szCommand))
|
||||
{
|
||||
pParams->push_back(strdup(szCommand));
|
||||
return true;
|
||||
}
|
||||
|
||||
char** pCmdArgs = NULL;
|
||||
if (!Util::SplitCommandLine(szCommand, &pCmdArgs))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start %s, failed to parse command line: %s", szInfoName, szCommand);
|
||||
m_bUnpackOK = false;
|
||||
m_bUnpackStartError = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (char** szArgPtr = pCmdArgs; *szArgPtr; szArgPtr++)
|
||||
{
|
||||
pParams->push_back(*szArgPtr);
|
||||
}
|
||||
free(pCmdArgs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnpackController::JoinSplittedFiles()
|
||||
{
|
||||
SetLogPrefix("Join");
|
||||
@@ -405,7 +562,7 @@ bool UnpackController::JoinFile(const char* szFragBaseName)
|
||||
FILE* pOutFile = fopen(szDestFilename, FOPEN_WBP);
|
||||
if (!pOutFile)
|
||||
{
|
||||
error("Could not create file %s: %s", szDestFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
PrintMessage(Message::mkError, "Could not create file %s: %s", szDestFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
return false;
|
||||
}
|
||||
if (g_pOptions->GetWriteBuffer() > 0)
|
||||
@@ -457,7 +614,7 @@ bool UnpackController::JoinFile(const char* szFragBaseName)
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not open file %s", szFragFilename);
|
||||
PrintMessage(Message::mkError, "Could not open file %s", szFragFilename);
|
||||
bOK = false;
|
||||
break;
|
||||
}
|
||||
@@ -491,11 +648,13 @@ void UnpackController::Completed()
|
||||
if (!m_bUnpackOK &&
|
||||
(m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped ||
|
||||
!m_pPostInfo->GetNZBInfo()->GetParFull()) &&
|
||||
!m_bUnpackStartError && !m_bUnpackSpaceError &&
|
||||
(!m_bUnpackPasswordError5 || m_bUnpackPasswordError4) &&
|
||||
!m_bUnpackStartError && !m_bUnpackSpaceError && !m_bUnpackPasswordError &&
|
||||
(!GetTerminated() || m_bAutoTerminated) && m_bHasParFiles)
|
||||
{
|
||||
RequestParCheck(true);
|
||||
RequestParCheck(!Util::EmptyStr(m_szPassword) ||
|
||||
Util::EmptyStr(g_pOptions->GetUnpackPassFile()) || m_bPassListTried ||
|
||||
!(m_bUnpackDecryptError || m_bUnpackPasswordError) ||
|
||||
m_pPostInfo->GetNZBInfo()->GetParStatus() > NZBInfo::psSkipped);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -503,8 +662,7 @@ void UnpackController::Completed()
|
||||
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(
|
||||
m_bUnpackSpaceError ? NZBInfo::usSpace :
|
||||
m_bUnpackPasswordError5 || (m_bUnpackPasswordError4 &&
|
||||
m_pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess) ? NZBInfo::usPassword :
|
||||
m_bUnpackPasswordError || m_bUnpackDecryptError ? NZBInfo::usPassword :
|
||||
NZBInfo::usFailure);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
@@ -514,10 +672,15 @@ void UnpackController::Completed()
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void UnpackController::RequestParCheck(bool bForceRepair)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s requested par-check/repair", m_szInfoNameUp);
|
||||
PrintMessage(Message::mkInfo, "%s requested %s", m_szInfoNameUp, bForceRepair ? "par-check with forced repair" : "par-check/repair");
|
||||
m_pPostInfo->SetRequestParCheck(true);
|
||||
m_pPostInfo->SetForceRepair(bForceRepair);
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetUnpackTried(true);
|
||||
m_pPostInfo->SetPassListTried(m_bPassListTried);
|
||||
m_pPostInfo->SetLastUnpackStatus((int)(m_bUnpackSpaceError ? NZBInfo::usSpace :
|
||||
m_bUnpackPasswordError || m_bUnpackDecryptError ? NZBInfo::usPassword :
|
||||
NZBInfo::usFailure));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -541,7 +704,7 @@ void UnpackController::CreateUnpackDir()
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(m_szUnpackDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", m_szUnpackDir, szErrBuf);
|
||||
PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szUnpackDir, szErrBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,8 +802,7 @@ bool UnpackController::Cleanup()
|
||||
DirBrowser dir(m_szUnpackDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") &&
|
||||
strcmp(filename, ".AppleDouble") && strcmp(filename, ".DS_Store"))
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szUnpackDir, PATH_SEPARATOR, filename);
|
||||
@@ -653,10 +815,13 @@ bool UnpackController::Cleanup()
|
||||
// silently overwrite existing files
|
||||
remove(szDstFile);
|
||||
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
bool bHiddenFile = filename[0] == '.';
|
||||
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile) && !bHiddenFile)
|
||||
{
|
||||
char szErrBuf[256];
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
bOK = false;
|
||||
}
|
||||
|
||||
@@ -787,6 +952,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
char szMsgText[1024];
|
||||
strncpy(szMsgText, szText, 1024);
|
||||
szMsgText[1024-1] = '\0';
|
||||
int iLen = strlen(szText);
|
||||
|
||||
// Modify unrar messages for better readability:
|
||||
// remove the destination path part from message "Extracting file.xxx"
|
||||
@@ -797,8 +963,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
szMsgText[1024-1] = '\0';
|
||||
}
|
||||
|
||||
ScriptController::AddMessage(eKind, szMsgText);
|
||||
m_pPostInfo->AppendMessage(eKind, szMsgText);
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szMsgText);
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szMsgText, "Unrar: UNRAR ", 6) &&
|
||||
strstr(szMsgText, " Copyright ") && strstr(szMsgText, " Alexander Roshal"))
|
||||
@@ -824,16 +989,21 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
(!strncmp(szText, "Unrar: Checksum error in the encrypted file", 42) ||
|
||||
!strncmp(szText, "Unrar: CRC failed in the encrypted file", 39)))
|
||||
{
|
||||
m_bUnpackPasswordError4 = true;
|
||||
m_bUnpackDecryptError = true;
|
||||
}
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: The specified password is incorrect.'", 43))
|
||||
{
|
||||
m_bUnpackPasswordError5 = true;
|
||||
m_bUnpackPasswordError = true;
|
||||
}
|
||||
|
||||
int iLen = strlen(szText);
|
||||
if (m_eUnpacker == upUnrar && !IsStopped() && (m_bUnpackPasswordError4 || m_bUnpackPasswordError5 ||
|
||||
if (m_eUnpacker == upSevenZip &&
|
||||
(iLen > 18 && !strncmp(szText + iLen - 45, "Data Error in encrypted file. Wrong password?", 45)))
|
||||
{
|
||||
m_bUnpackDecryptError = true;
|
||||
}
|
||||
|
||||
if (!IsStopped() && (m_bUnpackDecryptError || m_bUnpackPasswordError ||
|
||||
strstr(szText, " : packed data CRC failed in volume") ||
|
||||
strstr(szText, " : packed data checksum error in volume") ||
|
||||
(iLen > 13 && !strncmp(szText + iLen - 13, " - CRC failed", 13)) ||
|
||||
@@ -843,8 +1013,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
char szMsgText[1024];
|
||||
snprintf(szMsgText, 1024, "Cancelling %s due to errors", m_szInfoName);
|
||||
szMsgText[1024-1] = '\0';
|
||||
ScriptController::AddMessage(Message::mkWarning, szMsgText);
|
||||
m_pPostInfo->AppendMessage(Message::mkWarning, szMsgText);
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(Message::mkWarning, szMsgText);
|
||||
m_bAutoTerminated = true;
|
||||
Stop();
|
||||
}
|
||||
@@ -904,7 +1073,7 @@ void MoveController::Run()
|
||||
|
||||
DownloadQueue::Unlock();
|
||||
|
||||
info("Moving completed files for %s", szNZBName);
|
||||
PrintMessage(Message::mkInfo, "Moving completed files for %s", szNZBName);
|
||||
|
||||
bool bOK = MoveFiles();
|
||||
|
||||
@@ -912,7 +1081,7 @@ void MoveController::Run()
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
info("%s successful", szInfoName);
|
||||
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
|
||||
// save new dest dir
|
||||
DownloadQueue::Lock();
|
||||
m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir);
|
||||
@@ -921,7 +1090,7 @@ void MoveController::Run()
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s failed", szInfoName);
|
||||
PrintMessage(Message::mkError, "%s failed", szInfoName);
|
||||
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msFailure);
|
||||
}
|
||||
|
||||
@@ -934,7 +1103,7 @@ bool MoveController::MoveFiles()
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(m_szDestDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", m_szDestDir, szErrBuf);
|
||||
PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szDestDir, szErrBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -942,8 +1111,7 @@ bool MoveController::MoveFiles()
|
||||
DirBrowser dir(m_szInterDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") &&
|
||||
strcmp(filename, ".AppleDouble") && strcmp(filename, ".DS_Store"))
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szInterDir, PATH_SEPARATOR, filename);
|
||||
@@ -952,10 +1120,18 @@ bool MoveController::MoveFiles()
|
||||
char szDstFile[1024];
|
||||
Util::MakeUniqueFilename(szDstFile, 1024, m_szDestDir, filename);
|
||||
|
||||
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
bool bHiddenFile = filename[0] == '.';
|
||||
|
||||
if (!bHiddenFile)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
|
||||
}
|
||||
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile) && !bHiddenFile)
|
||||
{
|
||||
char szErrBuf[256];
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile,
|
||||
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
@@ -963,12 +1139,16 @@ bool MoveController::MoveFiles()
|
||||
|
||||
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete intermediate directory %s: %s", m_szInterDir, szErrBuf);
|
||||
PrintMessage(Message::mkWarning, "Could not delete intermediate directory %s: %s", m_szInterDir, szErrBuf);
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void MoveController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
|
||||
}
|
||||
|
||||
void CleanupController::StartJob(PostInfo* pPostInfo)
|
||||
{
|
||||
@@ -1012,7 +1192,7 @@ void CleanupController::Run()
|
||||
|
||||
DownloadQueue::Unlock();
|
||||
|
||||
info("Cleaning up %s", szNZBName);
|
||||
PrintMessage(Message::mkInfo, "Cleaning up %s", szNZBName);
|
||||
|
||||
bool bDeleted = false;
|
||||
bool bOK = Cleanup(m_szDestDir, &bDeleted);
|
||||
@@ -1028,17 +1208,17 @@ void CleanupController::Run()
|
||||
|
||||
if (bOK && bDeleted)
|
||||
{
|
||||
info("%s successful", szInfoName);
|
||||
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
|
||||
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
|
||||
}
|
||||
else if (bOK)
|
||||
{
|
||||
info("Nothing to cleanup for %s", szNZBName);
|
||||
PrintMessage(Message::mkInfo, "Nothing to cleanup for %s", szNZBName);
|
||||
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s failed", szInfoName);
|
||||
PrintMessage(Message::mkError, "%s failed", szInfoName);
|
||||
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csFailure);
|
||||
}
|
||||
|
||||
@@ -1054,15 +1234,22 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
|
||||
DirBrowser dir(szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
bool bIsDir = Util::DirectoryExists(szFullFilename);
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && bIsDir)
|
||||
{
|
||||
bOK &= Cleanup(szFullFilename, bDeleted);
|
||||
}
|
||||
|
||||
// check file extension
|
||||
bool bDeleteIt = Util::MatchFileExt(filename, g_pOptions->GetExtCleanupDisk(), ",;");
|
||||
bool bDeleteIt = Util::MatchFileExt(filename, g_pOptions->GetExtCleanupDisk(), ",;") && !bIsDir;
|
||||
|
||||
if (bDeleteIt)
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
@@ -1077,3 +1264,8 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void CleanupController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,6 +27,7 @@
|
||||
#define UNPACK_H
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
@@ -50,6 +51,14 @@ private:
|
||||
bool Exists(const char* szFilename);
|
||||
};
|
||||
|
||||
typedef std::vector<char*> ParamListBase;
|
||||
class ParamList : public ParamListBase
|
||||
{
|
||||
public:
|
||||
~ParamList();
|
||||
bool Exists(const char* szParam);
|
||||
};
|
||||
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
char m_szName[1024];
|
||||
@@ -71,19 +80,22 @@ private:
|
||||
bool m_bUnpackOK;
|
||||
bool m_bUnpackStartError;
|
||||
bool m_bUnpackSpaceError;
|
||||
bool m_bUnpackPasswordError4;
|
||||
bool m_bUnpackPasswordError5;
|
||||
bool m_bUnpackDecryptError;
|
||||
bool m_bUnpackPasswordError;
|
||||
bool m_bCleanedUpDisk;
|
||||
bool m_bAutoTerminated;
|
||||
EUnpacker m_eUnpacker;
|
||||
bool m_bFinalDirCreated;
|
||||
FileList m_JoinedFiles;
|
||||
bool m_bPassListTried;
|
||||
|
||||
protected:
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
void ExecuteUnrar();
|
||||
void ExecuteSevenZip(bool bMultiVolumes);
|
||||
void ExecuteUnpack(EUnpacker eUnpacker, const char* szPassword, bool bMultiVolumes);
|
||||
void ExecuteUnrar(const char* szPassword);
|
||||
void ExecuteSevenZip(const char* szPassword, bool bMultiVolumes);
|
||||
void UnpackArchives(EUnpacker eUnpacker, bool bMultiVolumes);
|
||||
void JoinSplittedFiles();
|
||||
bool JoinFile(const char* szFragBaseName);
|
||||
void Completed();
|
||||
@@ -95,6 +107,7 @@ protected:
|
||||
void RequestParCheck(bool bForceRepair);
|
||||
#endif
|
||||
bool FileHasRarSignature(const char* szFilename);
|
||||
bool PrepareCmdParams(const char* szCommand, ParamList* pParams, const char* szInfoName);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
@@ -111,6 +124,9 @@ private:
|
||||
|
||||
bool MoveFiles();
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
static void StartJob(PostInfo* pPostInfo);
|
||||
@@ -125,6 +141,9 @@ private:
|
||||
|
||||
bool Cleanup(const char* szDestDir, bool *bDeleted);
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
static void StartJob(PostInfo* pPostInfo);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -136,7 +139,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 51);
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 53);
|
||||
|
||||
// save nzb-infos
|
||||
SaveNZBQueue(pDownloadQueue, outfile);
|
||||
@@ -179,7 +182,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServe
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (iFormatVersion < 3 || iFormatVersion > 51)
|
||||
if (iFormatVersion < 3 || iFormatVersion > 53)
|
||||
{
|
||||
error("Could not load diskstate due to file version mismatch");
|
||||
fclose(infile);
|
||||
@@ -361,7 +364,7 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
|
||||
(int)pNZBInfo->GetMarkStatus(), (int)pNZBInfo->GetUrlStatus());
|
||||
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetUnpackCleanedUpDisk(), (int)pNZBInfo->GetHealthPaused(),
|
||||
(int)pNZBInfo->GetAddUrlPaused());
|
||||
fprintf(outfile, "%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount());
|
||||
fprintf(outfile, "%i,%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(), pNZBInfo->GetMessageCount());
|
||||
fprintf(outfile, "%i,%i\n", (int)pNZBInfo->GetMinTime(), (int)pNZBInfo->GetMaxTime());
|
||||
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetParFull(),
|
||||
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceParFull() : 0,
|
||||
@@ -389,9 +392,6 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
|
||||
fprintf(outfile, "%lu,%lu,%i,%i,%i,%i,%i\n", High1, Low1, pNZBInfo->GetDownloadSec(), pNZBInfo->GetPostTotalSec(),
|
||||
pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec());
|
||||
|
||||
char DestDirSlash[1024];
|
||||
snprintf(DestDirSlash, 1023, "%s%c", pNZBInfo->GetDestDir(), PATH_SEPARATOR);
|
||||
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetCompletedFiles()->size());
|
||||
for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
|
||||
{
|
||||
@@ -416,15 +416,6 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
|
||||
|
||||
SaveServerStats(pNZBInfo->GetServerStats(), outfile);
|
||||
|
||||
NZBInfo::Messages* pMessages = pNZBInfo->LockMessages();
|
||||
fprintf(outfile, "%i\n", (int)pMessages->size());
|
||||
for (NZBInfo::Messages::iterator it = pMessages->begin(); it != pMessages->end(); it++)
|
||||
{
|
||||
Message* pMessage = *it;
|
||||
fprintf(outfile, "%i,%i,%s\n", pMessage->GetKind(), (int)pMessage->GetTime(), pMessage->GetText());
|
||||
}
|
||||
pNZBInfo->UnlockMessages();
|
||||
|
||||
// save file-infos
|
||||
int iSize = 0;
|
||||
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
|
||||
@@ -638,10 +629,19 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
|
||||
|
||||
if (iFormatVersion >= 28)
|
||||
{
|
||||
int iFileCount, iParkedFileCount;
|
||||
if (fscanf(infile, "%i,%i\n", &iFileCount, &iParkedFileCount) != 2) goto error;
|
||||
int iFileCount, iParkedFileCount, iMessageCount = 0;
|
||||
if (iFormatVersion >= 52)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i\n", &iFileCount, &iParkedFileCount, &iMessageCount) != 3) goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fscanf(infile, "%i,%i\n", &iFileCount, &iParkedFileCount) != 2) goto error;
|
||||
}
|
||||
|
||||
pNZBInfo->SetFileCount(iFileCount);
|
||||
pNZBInfo->SetParkedFileCount(iParkedFileCount);
|
||||
pNZBInfo->SetMessageCount(iMessageCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -852,23 +852,13 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
|
||||
pNZBInfo->GetCurrentServerStats()->ListOp(pNZBInfo->GetServerStats(), ServerStatList::soSet);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 11)
|
||||
if (iFormatVersion >= 11 && iFormatVersion < 52)
|
||||
{
|
||||
int iLogCount;
|
||||
if (fscanf(infile, "%i\n", &iLogCount) != 1) goto error;
|
||||
for (int i = 0; i < iLogCount; i++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
|
||||
int iKind, iTime;
|
||||
sscanf(buf, "%i,%i", &iKind, &iTime);
|
||||
char* szText = strchr(buf + 2, ',');
|
||||
if (szText)
|
||||
{
|
||||
szText++;
|
||||
}
|
||||
pNZBInfo->AppendMessage((Message::EKind)iKind, (time_t)iTime, szText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1372,12 +1362,13 @@ void DiskState::DiscardFiles(NZBInfo* pNZBInfo)
|
||||
DiscardFile(pFileInfo, true, true, true);
|
||||
}
|
||||
|
||||
char szFilename[1024];
|
||||
|
||||
for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
|
||||
{
|
||||
CompletedFile* pCompletedFile = *it;
|
||||
if (pCompletedFile->GetStatus() != CompletedFile::cfSuccess && pCompletedFile->GetID() > 0)
|
||||
{
|
||||
char szFilename[1024];
|
||||
snprintf(szFilename, 1024, "%s%i", g_pOptions->GetQueueDir(), pCompletedFile->GetID());
|
||||
szFilename[1024-1] = '\0';
|
||||
remove(szFilename);
|
||||
@@ -1391,6 +1382,10 @@ void DiskState::DiscardFiles(NZBInfo* pNZBInfo)
|
||||
remove(szFilename);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(szFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), pNZBInfo->GetID());
|
||||
szFilename[1024-1] = '\0';
|
||||
remove(szFilename);
|
||||
}
|
||||
|
||||
bool DiskState::LoadPostQueue12(DownloadQueue* pDownloadQueue, NZBList* pNZBList, FILE* infile, int iFormatVersion)
|
||||
@@ -1973,7 +1968,7 @@ bool DiskState::DownloadQueueExists()
|
||||
return Util::FileExists(fileName);
|
||||
}
|
||||
|
||||
bool DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState)
|
||||
void DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState)
|
||||
{
|
||||
char fileName[1024];
|
||||
|
||||
@@ -2000,8 +1995,6 @@ bool DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeleteP
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskState::CleanupTempDir(DownloadQueue* pDownloadQueue)
|
||||
@@ -2884,3 +2877,123 @@ void DiskState::DeleteCacheFlag()
|
||||
|
||||
remove(szFlagFilename);
|
||||
}
|
||||
|
||||
void DiskState::AppendNZBMessage(int iNZBID, Message::EKind eKind, const char* szText)
|
||||
{
|
||||
char szLogFilename[1024];
|
||||
snprintf(szLogFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), iNZBID);
|
||||
szLogFilename[1024-1] = '\0';
|
||||
|
||||
FILE* outfile = fopen(szLogFilename, FOPEN_ABP);
|
||||
if (!outfile)
|
||||
{
|
||||
error("Error saving log: Could not create file %s", szLogFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"};
|
||||
|
||||
char tmp2[1024];
|
||||
strncpy(tmp2, szText, 1024);
|
||||
tmp2[1024-1] = '\0';
|
||||
|
||||
// replace bad chars
|
||||
for (char* p = tmp2; *p; p++)
|
||||
{
|
||||
char ch = *p;
|
||||
if (ch == '\n' || ch == '\r' || ch == '\t')
|
||||
{
|
||||
*p = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
time_t tm = time(NULL);
|
||||
time_t rawtime = tm + g_pOptions->GetTimeCorrection();
|
||||
|
||||
char szTime[50];
|
||||
#ifdef HAVE_CTIME_R_3
|
||||
ctime_r(&rawtime, szTime, 50);
|
||||
#else
|
||||
ctime_r(&rawtime, szTime);
|
||||
#endif
|
||||
szTime[50-1] = '\0';
|
||||
szTime[strlen(szTime) - 1] = '\0'; // trim LF
|
||||
|
||||
fprintf(outfile, "%s\t%u\t%s\t%s%s", szTime, (int)tm, szMessageType[eKind], tmp2, LINE_ENDING);
|
||||
|
||||
fclose(outfile);
|
||||
}
|
||||
|
||||
void DiskState::LoadNZBMessages(int iNZBID, MessageList* pMessages)
|
||||
{
|
||||
// Important:
|
||||
// - Other threads may be writing into the log-file at any time;
|
||||
// - The log-file may also be deleted from another thread;
|
||||
|
||||
char szLogFilename[1024];
|
||||
snprintf(szLogFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), iNZBID);
|
||||
szLogFilename[1024-1] = '\0';
|
||||
|
||||
if (!Util::FileExists(szLogFilename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* infile = fopen(szLogFilename, FOPEN_RB);
|
||||
if (!infile)
|
||||
{
|
||||
error("Error reading log: could not open file %s", szLogFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
int iID = 0;
|
||||
char szLine[1024];
|
||||
while (fgets(szLine, sizeof(szLine), infile))
|
||||
{
|
||||
Util::TrimRight(szLine);
|
||||
|
||||
// time (skip formatted time first)
|
||||
char* p = strchr(szLine, '\t');
|
||||
if (!p) goto exit;
|
||||
int iTime = atoi(p + 1);
|
||||
|
||||
// kind
|
||||
p = strchr(p + 1, '\t');
|
||||
if (!p) goto exit;
|
||||
char* szKind = p + 1;
|
||||
|
||||
Message::EKind eKind = Message::mkError;
|
||||
if (!strncmp(szKind, "INFO", 4))
|
||||
{
|
||||
eKind = Message::mkInfo;
|
||||
}
|
||||
else if (!strncmp(szKind, "WARNING", 7))
|
||||
{
|
||||
eKind = Message::mkWarning;
|
||||
}
|
||||
else if (!strncmp(szKind, "ERROR", 5))
|
||||
{
|
||||
eKind = Message::mkError;
|
||||
}
|
||||
else if (!strncmp(szKind, "DETAIL", 6))
|
||||
{
|
||||
eKind = Message::mkDetail;
|
||||
}
|
||||
else if (!strncmp(szKind, "DEBUG", 5))
|
||||
{
|
||||
eKind = Message::mkDebug;
|
||||
}
|
||||
|
||||
// text
|
||||
p = strchr(p + 1, '\t');
|
||||
if (!p) goto exit;
|
||||
char* szText = p + 1;
|
||||
|
||||
Message* pMessage = new Message(++iID, eKind, (time_t)iTime, szText);
|
||||
pMessages->push_back(pMessage);
|
||||
}
|
||||
|
||||
exit:
|
||||
fclose(infile);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "FeedInfo.h"
|
||||
#include "NewsServer.h"
|
||||
#include "StatMeter.h"
|
||||
#include "Log.h"
|
||||
|
||||
class DiskState
|
||||
{
|
||||
@@ -83,7 +84,7 @@ public:
|
||||
bool LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bCompleted);
|
||||
bool LoadArticles(FileInfo* pFileInfo);
|
||||
void DiscardDownloadQueue();
|
||||
bool DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState);
|
||||
void DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState);
|
||||
void DiscardFiles(NZBInfo* pNZBInfo);
|
||||
bool SaveFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
|
||||
bool LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
|
||||
@@ -92,6 +93,8 @@ public:
|
||||
void CleanupTempDir(DownloadQueue* pDownloadQueue);
|
||||
void WriteCacheFlag();
|
||||
void DeleteCacheFlag();
|
||||
void AppendNZBMessage(int iNZBID, Message::EKind eKind, const char* szText);
|
||||
void LoadNZBMessages(int iNZBID, MessageList* pMessages);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
@@ -42,11 +43,13 @@
|
||||
#include "nzbget.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "ArticleWriter.h"
|
||||
#include "DiskState.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern ArticleCache* g_pArticleCache;
|
||||
extern DiskState* g_pDiskState;
|
||||
|
||||
int FileInfo::m_iIDGen = 0;
|
||||
int FileInfo::m_iIDMax = 0;
|
||||
@@ -342,6 +345,8 @@ NZBInfo::NZBInfo() : m_FileList(true)
|
||||
m_bReprocess = false;
|
||||
m_tQueueScriptTime = 0;
|
||||
m_bParFull = false;
|
||||
m_iMessageCount = 0;
|
||||
m_iCachedMessageCount = 0;
|
||||
}
|
||||
|
||||
NZBInfo::~NZBInfo()
|
||||
@@ -360,12 +365,6 @@ NZBInfo::~NZBInfo()
|
||||
|
||||
ClearCompletedFiles();
|
||||
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
|
||||
m_FileList.Clear();
|
||||
}
|
||||
|
||||
@@ -658,27 +657,81 @@ void NZBInfo::UpdateMinMaxTime()
|
||||
}
|
||||
}
|
||||
|
||||
NZBInfo::Messages* NZBInfo::LockMessages()
|
||||
MessageList* NZBInfo::LockCachedMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
}
|
||||
|
||||
void NZBInfo::UnlockMessages()
|
||||
void NZBInfo::UnlockCachedMessages()
|
||||
{
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void NZBInfo::AppendMessage(Message::EKind eKind, time_t tTime, const char * szText)
|
||||
void NZBInfo::AddMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
if (tTime == 0)
|
||||
switch (eKind)
|
||||
{
|
||||
tTime = time(NULL);
|
||||
case Message::mkDetail:
|
||||
detail("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkInfo:
|
||||
info("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkWarning:
|
||||
warn("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkError:
|
||||
error("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkDebug:
|
||||
debug("%s", szText);
|
||||
break;
|
||||
}
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode() && g_pOptions->GetNzbLog())
|
||||
{
|
||||
g_pDiskState->AppendNZBMessage(m_iID, eKind, szText);
|
||||
m_iMessageCount++;
|
||||
}
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
{
|
||||
Message* pMessage = m_Messages.front();
|
||||
delete pMessage;
|
||||
m_Messages.pop_front();
|
||||
}
|
||||
|
||||
m_iCachedMessageCount = m_Messages.size();
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void NZBInfo::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
|
||||
{
|
||||
char tmp2[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
vsnprintf(tmp2, 1024, szFormat, ap);
|
||||
tmp2[1024-1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
AddMessage(eKind, tmp2);
|
||||
}
|
||||
|
||||
void NZBInfo::ClearMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
m_Messages.Clear();
|
||||
m_iCachedMessageCount = 0;
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
@@ -735,6 +788,7 @@ void NZBInfo::LeavePostProcess()
|
||||
{
|
||||
delete m_pPostInfo;
|
||||
m_pPostInfo = NULL;
|
||||
ClearMessages();
|
||||
}
|
||||
|
||||
void NZBInfo::SetActiveDownloads(int iActiveDownloads)
|
||||
@@ -759,14 +813,16 @@ void NZBInfo::SetActiveDownloads(int iActiveDownloads)
|
||||
bool NZBInfo::IsDupeSuccess()
|
||||
{
|
||||
bool bFailure =
|
||||
m_eDeleteStatus != NZBInfo::dsNone ||
|
||||
m_eMarkStatus != NZBInfo::ksSuccess &&
|
||||
m_eMarkStatus != NZBInfo::ksGood &&
|
||||
(m_eDeleteStatus != NZBInfo::dsNone ||
|
||||
m_eMarkStatus == NZBInfo::ksBad ||
|
||||
m_eParStatus == NZBInfo::psFailure ||
|
||||
m_eUnpackStatus == NZBInfo::usFailure ||
|
||||
m_eUnpackStatus == NZBInfo::usPassword ||
|
||||
(m_eParStatus == NZBInfo::psSkipped &&
|
||||
m_eUnpackStatus == NZBInfo::usSkipped &&
|
||||
CalcHealth() < CalcCriticalHealth(true));
|
||||
CalcHealth() < CalcCriticalHealth(true)));
|
||||
return !bFailure;
|
||||
}
|
||||
|
||||
@@ -788,6 +844,10 @@ const char* NZBInfo::MakeTextStatus(bool bIgnoreScriptStatus)
|
||||
{
|
||||
szStatus = "SUCCESS/GOOD";
|
||||
}
|
||||
else if (m_eMarkStatus == NZBInfo::ksSuccess)
|
||||
{
|
||||
szStatus = "SUCCESS/MARK";
|
||||
}
|
||||
else if (m_eDeleteStatus == NZBInfo::dsHealth)
|
||||
{
|
||||
szStatus = "FAILURE/HEALTH";
|
||||
@@ -1196,6 +1256,10 @@ PostInfo::PostInfo()
|
||||
m_bRequestParCheck = false;
|
||||
m_bForceParFull = false;
|
||||
m_bForceRepair = false;
|
||||
m_bParRepaired = false;
|
||||
m_bUnpackTried = false;
|
||||
m_bPassListTried = false;
|
||||
m_eLastUnpackStatus = 0;
|
||||
m_szProgressLabel = strdup("");
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
@@ -1203,7 +1267,6 @@ PostInfo::PostInfo()
|
||||
m_tStageTime = 0;
|
||||
m_eStage = ptQueued;
|
||||
m_pPostThread = NULL;
|
||||
m_iIDMessageGen = 0;
|
||||
}
|
||||
|
||||
PostInfo::~ PostInfo()
|
||||
@@ -1212,11 +1275,6 @@ PostInfo::~ PostInfo()
|
||||
|
||||
free(m_szProgressLabel);
|
||||
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
|
||||
for (ParredFiles::iterator it = m_ParredFiles.begin(); it != m_ParredFiles.end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
@@ -1229,32 +1287,6 @@ void PostInfo::SetProgressLabel(const char* szProgressLabel)
|
||||
m_szProgressLabel = strdup(szProgressLabel);
|
||||
}
|
||||
|
||||
PostInfo::Messages* PostInfo::LockMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
}
|
||||
|
||||
void PostInfo::UnlockMessages()
|
||||
{
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
{
|
||||
Message* pMessage = m_Messages.front();
|
||||
delete pMessage;
|
||||
m_Messages.pop_front();
|
||||
}
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
|
||||
DupInfo::DupInfo()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -398,7 +398,8 @@ public:
|
||||
{
|
||||
ksNone,
|
||||
ksBad,
|
||||
ksGood
|
||||
ksGood,
|
||||
ksSuccess
|
||||
};
|
||||
|
||||
enum EUrlStatus
|
||||
@@ -418,8 +419,6 @@ public:
|
||||
nkUrl
|
||||
};
|
||||
|
||||
typedef std::deque<Message*> Messages;
|
||||
|
||||
static const int FORCE_PRIORITY = 900;
|
||||
|
||||
friend class DupInfo;
|
||||
@@ -489,7 +488,7 @@ private:
|
||||
ServerStatList m_ServerStats;
|
||||
ServerStatList m_CurrentServerStats;
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
MessageList m_Messages;
|
||||
int m_iIDMessageGen;
|
||||
PostInfo* m_pPostInfo;
|
||||
long long m_lDownloadedSize;
|
||||
@@ -502,10 +501,14 @@ private:
|
||||
bool m_bReprocess;
|
||||
time_t m_tQueueScriptTime;
|
||||
bool m_bParFull;
|
||||
int m_iMessageCount;
|
||||
int m_iCachedMessageCount;
|
||||
|
||||
static int m_iIDGen;
|
||||
static int m_iIDMax;
|
||||
|
||||
void ClearMessages();
|
||||
|
||||
public:
|
||||
NZBInfo();
|
||||
~NZBInfo();
|
||||
@@ -666,9 +669,13 @@ public:
|
||||
bool IsDupeSuccess();
|
||||
const char* MakeTextStatus(bool bIgnoreScriptStatus);
|
||||
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
void AddMessage(Message::EKind eKind, const char* szText);
|
||||
void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
|
||||
int GetMessageCount() { return m_iMessageCount; }
|
||||
void SetMessageCount(int iMessageCount) { m_iMessageCount = iMessageCount; }
|
||||
int GetCachedMessageCount() { return m_iCachedMessageCount; }
|
||||
MessageList* LockCachedMessages();
|
||||
void UnlockCachedMessages();
|
||||
};
|
||||
|
||||
typedef std::deque<NZBInfo*> NZBQueueBase;
|
||||
@@ -703,7 +710,6 @@ public:
|
||||
ptFinished
|
||||
};
|
||||
|
||||
typedef std::deque<Message*> Messages;
|
||||
typedef std::vector<char*> ParredFiles;
|
||||
|
||||
private:
|
||||
@@ -713,6 +719,10 @@ private:
|
||||
bool m_bRequestParCheck;
|
||||
bool m_bForceParFull;
|
||||
bool m_bForceRepair;
|
||||
bool m_bParRepaired;
|
||||
bool m_bUnpackTried;
|
||||
bool m_bPassListTried;
|
||||
int m_eLastUnpackStatus;
|
||||
EStage m_eStage;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
@@ -721,9 +731,6 @@ private:
|
||||
time_t m_tStageTime;
|
||||
Thread* m_pPostThread;
|
||||
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
int m_iIDMessageGen;
|
||||
ParredFiles m_ParredFiles;
|
||||
|
||||
public:
|
||||
@@ -753,11 +760,16 @@ public:
|
||||
void SetForceParFull(bool bForceParFull) { m_bForceParFull = bForceParFull; }
|
||||
bool GetForceRepair() { return m_bForceRepair; }
|
||||
void SetForceRepair(bool bForceRepair) { m_bForceRepair = bForceRepair; }
|
||||
bool GetParRepaired() { return m_bParRepaired; }
|
||||
void SetParRepaired(bool bParRepaired) { m_bParRepaired = bParRepaired; }
|
||||
bool GetUnpackTried() { return m_bUnpackTried; }
|
||||
void SetUnpackTried(bool bUnpackTried) { m_bUnpackTried = bUnpackTried; }
|
||||
bool GetPassListTried() { return m_bPassListTried; }
|
||||
void SetPassListTried(bool bPassListTried) { m_bPassListTried = bPassListTried; }
|
||||
int GetLastUnpackStatus() { return m_eLastUnpackStatus; }
|
||||
void SetLastUnpackStatus(int eUnpackStatus) { m_eLastUnpackStatus = eUnpackStatus; }
|
||||
Thread* GetPostThread() { return m_pPostThread; }
|
||||
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
ParredFiles* GetParredFiles() { return &m_ParredFiles; }
|
||||
};
|
||||
|
||||
@@ -897,6 +909,7 @@ public:
|
||||
eaGroupSetDupeKey, // set duplicate key
|
||||
eaGroupSetDupeScore, // set duplicate score
|
||||
eaGroupSetDupeMode, // set duplicate mode
|
||||
eaGroupSort, // sort groups
|
||||
eaPostDelete, // cancel post-processing
|
||||
eaHistoryDelete, // hide history-item
|
||||
eaHistoryFinalDelete, // delete history-item
|
||||
@@ -909,7 +922,10 @@ public:
|
||||
eaHistorySetDupeMode, // set duplicate mode
|
||||
eaHistorySetDupeBackup, // set duplicate backup flag
|
||||
eaHistoryMarkBad, // mark history-item as bad (and download other duplicate)
|
||||
eaHistoryMarkGood // mark history-item as good (and push it into dup-history)
|
||||
eaHistoryMarkGood, // mark history-item as good (and push it into dup-history)
|
||||
eaHistoryMarkSuccess, // mark history-item as success (and do nothing more)
|
||||
eaHistorySetCategory, // set or change category for history-item
|
||||
eaHistorySetName // set history-item name (rename)
|
||||
};
|
||||
|
||||
enum EMatchMode
|
||||
|
||||
@@ -236,7 +236,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
|
||||
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pHistoryInfo->GetNZBInfo()->GetName());
|
||||
info("Collection %s is a duplicate to %s", pNZBInfo->GetName(), pHistoryInfo->GetNZBInfo()->GetName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
|
||||
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pQueuedNZBInfo->GetName());
|
||||
info("Collection %s is a duplicate to %s", pNZBInfo->GetName(), pQueuedNZBInfo->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -334,8 +334,7 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
(pHistoryInfo->GetNZBInfo()->IsDupeSuccess() ||
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood) &&
|
||||
pHistoryInfo->GetNZBInfo()->IsDupeSuccess() &&
|
||||
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey))
|
||||
{
|
||||
if (!bHistoryDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > iHistoryScore)
|
||||
@@ -412,20 +411,25 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
}
|
||||
}
|
||||
|
||||
void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, bool bGood)
|
||||
void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, NZBInfo::EMarkStatus eMarkStatus)
|
||||
{
|
||||
char szNZBName[1024];
|
||||
pHistoryInfo->GetName(szNZBName, 1024);
|
||||
|
||||
info("Marking %s as %s", szNZBName, (bGood ? "good" : "bad"));
|
||||
const char* szMarkStatusName[] = { "NONE", "bad", "good", "success" };
|
||||
|
||||
info("Marking %s as %s", szNZBName, szMarkStatusName[eMarkStatus]);
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
|
||||
{
|
||||
pHistoryInfo->GetNZBInfo()->SetMarkStatus(bGood ? NZBInfo::ksGood : NZBInfo::ksBad);
|
||||
pHistoryInfo->GetNZBInfo()->SetMarkStatus(eMarkStatus);
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDup)
|
||||
{
|
||||
pHistoryInfo->GetDupInfo()->SetStatus(bGood ? DupInfo::dsGood : DupInfo::dsBad);
|
||||
pHistoryInfo->GetDupInfo()->SetStatus(
|
||||
eMarkStatus == NZBInfo::ksGood ? DupInfo::dsGood :
|
||||
eMarkStatus == NZBInfo::ksSuccess ? DupInfo::dsSuccess :
|
||||
DupInfo::dsBad);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -442,13 +446,13 @@ void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pH
|
||||
return;
|
||||
}
|
||||
|
||||
if (bGood)
|
||||
if (eMarkStatus == NZBInfo::ksGood)
|
||||
{
|
||||
// mark as good
|
||||
// moving all duplicates from history to dup-history
|
||||
HistoryCleanup(pDownloadQueue, pHistoryInfo);
|
||||
}
|
||||
else
|
||||
else if (eMarkStatus == NZBInfo::ksBad)
|
||||
{
|
||||
// mark as bad
|
||||
const char* szDupeKey = pHistoryInfo->GetKind() == HistoryInfo::hkNzb ? pHistoryInfo->GetNZBInfo()->GetDupeKey() :
|
||||
|
||||
@@ -49,7 +49,7 @@ private:
|
||||
public:
|
||||
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, bool bGood);
|
||||
void HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, NZBInfo::EMarkStatus eMarkStatus);
|
||||
EDupeStatus GetDupeStatus(DownloadQueue* pDownloadQueue, const char* szName, const char* szDupeKey);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -228,7 +228,7 @@ void HistoryCoordinator::AddToHistory(DownloadQueue* pDownloadQueue, NZBInfo* pN
|
||||
pNZBInfo->GetFileList()->Clear();
|
||||
}
|
||||
|
||||
info("Collection %s added to history", pNZBInfo->GetName());
|
||||
pNZBInfo->PrintMessage(Message::mkInfo, "Collection %s added to history", pNZBInfo->GetName());
|
||||
}
|
||||
|
||||
void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex)
|
||||
@@ -250,6 +250,7 @@ void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo*
|
||||
pDupInfo->SetStatus(
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood ? DupInfo::dsGood :
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksBad ? DupInfo::dsBad :
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksSuccess ? DupInfo::dsSuccess :
|
||||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe ? DupInfo::dsDupe :
|
||||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsManual ? DupInfo::dsDeleted :
|
||||
pHistoryInfo->GetNZBInfo()->IsDupeSuccess() ? DupInfo::dsSuccess :
|
||||
@@ -277,6 +278,8 @@ bool HistoryCoordinator::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList
|
||||
HistoryInfo* pHistoryInfo = *itHistory;
|
||||
if (pHistoryInfo->GetID() == iID)
|
||||
{
|
||||
bOK = true;
|
||||
|
||||
switch (eAction)
|
||||
{
|
||||
case DownloadQueue::eaHistoryDelete:
|
||||
@@ -294,7 +297,15 @@ bool HistoryCoordinator::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetParameter:
|
||||
HistorySetParameter(pHistoryInfo, szText);
|
||||
bOK = HistorySetParameter(pHistoryInfo, szText);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetCategory:
|
||||
bOK = HistorySetCategory(pHistoryInfo, szText);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetName:
|
||||
bOK = HistorySetName(pHistoryInfo, szText);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetDupeKey:
|
||||
@@ -305,8 +316,15 @@ bool HistoryCoordinator::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistoryMarkBad:
|
||||
g_pDupeCoordinator->HistoryMark(pDownloadQueue, pHistoryInfo, NZBInfo::ksBad);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistoryMarkGood:
|
||||
g_pDupeCoordinator->HistoryMark(pDownloadQueue, pHistoryInfo, eAction == DownloadQueue::eaHistoryMarkGood);
|
||||
g_pDupeCoordinator->HistoryMark(pDownloadQueue, pHistoryInfo, NZBInfo::ksGood);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistoryMarkSuccess:
|
||||
g_pDupeCoordinator->HistoryMark(pDownloadQueue, pHistoryInfo, NZBInfo::ksSuccess);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -314,7 +332,6 @@ bool HistoryCoordinator::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList
|
||||
break;
|
||||
}
|
||||
|
||||
bOK = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -440,7 +457,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
pHistoryInfo->DiscardNZBInfo();
|
||||
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsNone);
|
||||
@@ -449,7 +466,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
|
||||
|
||||
pDownloadQueue->GetHistory()->erase(itHistory);
|
||||
// the object "pHistoryInfo" is released few lines later, after the call to "NZBDownloaded"
|
||||
info("%s returned from history back to download queue", szNiceName);
|
||||
pNZBInfo->PrintMessage(Message::mkInfo, "%s returned from history back to download queue", szNiceName);
|
||||
|
||||
if (bReprocess)
|
||||
{
|
||||
@@ -464,12 +481,26 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
|
||||
void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory,
|
||||
HistoryInfo* pHistoryInfo, bool bRestorePauseState)
|
||||
{
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
|
||||
{
|
||||
HistoryReturn(pDownloadQueue, itHistory, pHistoryInfo, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() != HistoryInfo::hkNzb)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
error("Could not return %s from history back to queue: history item has wrong type", szNiceName);
|
||||
return;
|
||||
}
|
||||
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
bool bPaused = bRestorePauseState && pNZBInfo->GetDeletePaused();
|
||||
|
||||
if (!Util::FileExists(pNZBInfo->GetQueuedFilename()))
|
||||
{
|
||||
error("Could not return collection %s from history back to queue: could not find source nzb-file %s",
|
||||
error("Could not return %s from history back to queue: could not find source nzb-file %s",
|
||||
pNZBInfo->GetName(), pNZBInfo->GetQueuedFilename());
|
||||
return;
|
||||
}
|
||||
@@ -477,12 +508,12 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
|
||||
NZBFile* pNZBFile = NZBFile::Create(pNZBInfo->GetQueuedFilename(), "");
|
||||
if (pNZBFile == NULL)
|
||||
{
|
||||
error("Could not return collection %s from history back to queue: could not parse nzb-file",
|
||||
error("Could not return %s from history back to queue: could not parse nzb-file",
|
||||
pNZBInfo->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
info("Returning collection %s from history back to queue", pNZBInfo->GetName());
|
||||
info("Returning %s from history back to queue", pNZBInfo->GetName());
|
||||
|
||||
for (FileList::iterator it = pNZBFile->GetNZBInfo()->GetFileList()->begin(); it != pNZBFile->GetNZBInfo()->GetFileList()->end(); it++)
|
||||
{
|
||||
@@ -538,7 +569,7 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
|
||||
g_pPrePostProcessor->NZBAdded(pDownloadQueue, pNZBInfo);
|
||||
}
|
||||
|
||||
void HistoryCoordinator::HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText)
|
||||
bool HistoryCoordinator::HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
@@ -547,7 +578,7 @@ void HistoryCoordinator::HistorySetParameter(HistoryInfo* pHistoryInfo, const ch
|
||||
if (!(pHistoryInfo->GetKind() == HistoryInfo::hkNzb || pHistoryInfo->GetKind() == HistoryInfo::hkUrl))
|
||||
{
|
||||
error("Could not set post-process-parameter for %s: history item has wrong type", szNiceName);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* szStr = strdup(szText);
|
||||
@@ -565,6 +596,49 @@ void HistoryCoordinator::HistorySetParameter(HistoryInfo* pHistoryInfo, const ch
|
||||
}
|
||||
|
||||
free(szStr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HistoryCoordinator::HistorySetCategory(HistoryInfo* pHistoryInfo, const char* szText)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
debug("Setting category '%s' for '%s'", szText, szNiceName);
|
||||
|
||||
if (!(pHistoryInfo->GetKind() == HistoryInfo::hkNzb || pHistoryInfo->GetKind() == HistoryInfo::hkUrl))
|
||||
{
|
||||
error("Could not set category for %s: history item has wrong type", szNiceName);
|
||||
return false;
|
||||
}
|
||||
|
||||
pHistoryInfo->GetNZBInfo()->SetCategory(szText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HistoryCoordinator::HistorySetName(HistoryInfo* pHistoryInfo, const char* szText)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
debug("Setting name '%s' for '%s'", szText, szNiceName);
|
||||
|
||||
if (Util::EmptyStr(szText))
|
||||
{
|
||||
error("Could not rename %s. The new name cannot be empty", szNiceName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb || pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
|
||||
{
|
||||
pHistoryInfo->GetNZBInfo()->SetName(szText);
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDup)
|
||||
{
|
||||
pHistoryInfo->GetDupInfo()->SetName(szText);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HistoryCoordinator::HistorySetDupeParam(HistoryInfo* pHistoryInfo, DownloadQueue::EEditAction eAction, const char* szText)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -34,8 +34,10 @@ private:
|
||||
void HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bFinal);
|
||||
void HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bReprocess);
|
||||
void HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bRestorePauseState);
|
||||
void HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText);
|
||||
bool HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText);
|
||||
void HistorySetDupeParam(HistoryInfo* pHistoryInfo, DownloadQueue::EEditAction eAction, const char* szText);
|
||||
bool HistorySetCategory(HistoryInfo* pHistoryInfo, const char* szText);
|
||||
bool HistorySetName(HistoryInfo* pHistoryInfo, const char* szText);
|
||||
void HistoryTransformToDup(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
|
||||
void SaveQueue(DownloadQueue* pDownloadQueue);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -526,21 +526,27 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
{
|
||||
_bstr_t r(doc->GetparseError()->reason);
|
||||
const char* szErrMsg = r;
|
||||
error("Error parsing nzb-file: %s", szErrMsg);
|
||||
error("Error parsing nzb-file %s: %s", Util::BaseFileName(szFileName), szErrMsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NZBFile* pFile = new NZBFile(szFileName, szCategory);
|
||||
if (pFile->ParseNZB(doc))
|
||||
{
|
||||
pFile->ProcessFiles();
|
||||
}
|
||||
else
|
||||
|
||||
if (!pFile->ParseNZB(doc))
|
||||
{
|
||||
delete pFile;
|
||||
pFile = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pFile->GetNZBInfo()->GetFileList()->empty())
|
||||
{
|
||||
error("Error parsing nzb-file %s: file has no content", Util::BaseFileName(szFileName));
|
||||
delete pFile;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFile->ProcessFiles();
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
@@ -654,17 +660,22 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
|
||||
int ret = xmlSAXUserParseFile(&SAX_handler, pFile, szFileName);
|
||||
|
||||
if (ret == 0)
|
||||
if (ret != 0)
|
||||
{
|
||||
pFile->ProcessFiles();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Failed to parse nzb-file");
|
||||
error("Error parsing nzb-file %s", Util::BaseFileName(szFileName));
|
||||
delete pFile;
|
||||
pFile = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (pFile->GetNZBInfo()->GetFileList()->empty())
|
||||
{
|
||||
error("Error parsing nzb-file %s: file has no content", Util::BaseFileName(szFileName));
|
||||
delete pFile;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFile->ProcessFiles();
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -398,7 +398,7 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, NZBInfo* pUrlInfo, b
|
||||
|
||||
if (eDeleteStatus == NZBInfo::dsNone)
|
||||
{
|
||||
info("Collection %s added to queue", pNZBInfo->GetName());
|
||||
pNZBInfo->PrintMessage(Message::mkInfo, "Collection %s added to queue", pNZBInfo->GetName());
|
||||
}
|
||||
|
||||
if (eDeleteStatus != NZBInfo::dsManual)
|
||||
@@ -887,8 +887,10 @@ void QueueCoordinator::CheckHealth(DownloadQueue* pDownloadQueue, FileInfo* pFil
|
||||
}
|
||||
else if (g_pOptions->GetHealthCheck() == Options::hcDelete)
|
||||
{
|
||||
warn("Cancelling download and deleting %s due to health %.1f%% below critical %.1f%%", pFileInfo->GetNZBInfo()->GetName(),
|
||||
pFileInfo->GetNZBInfo()->CalcHealth() / 10.0, pFileInfo->GetNZBInfo()->CalcCriticalHealth(true) / 10.0);
|
||||
pFileInfo->GetNZBInfo()->PrintMessage(Message::mkWarning,
|
||||
"Cancelling download and deleting %s due to health %.1f%% below critical %.1f%%",
|
||||
pFileInfo->GetNZBInfo()->GetName(), pFileInfo->GetNZBInfo()->CalcHealth() / 10.0,
|
||||
pFileInfo->GetNZBInfo()->CalcCriticalHealth(true) / 10.0);
|
||||
pFileInfo->GetNZBInfo()->SetDeleteStatus(NZBInfo::dsHealth);
|
||||
pDownloadQueue->EditEntry(pFileInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
|
||||
}
|
||||
@@ -1141,6 +1143,7 @@ bool QueueCoordinator::MergeQueueEntries(DownloadQueue* pDownloadQueue, NZBInfo*
|
||||
free(szQueuedFilename);
|
||||
|
||||
pDownloadQueue->GetQueue()->Remove(pSrcNZBInfo);
|
||||
g_pDiskState->DiscardFiles(pSrcNZBInfo);
|
||||
delete pSrcNZBInfo;
|
||||
|
||||
return true;
|
||||
@@ -1258,6 +1261,7 @@ bool QueueCoordinator::SplitQueueEntries(DownloadQueue* pDownloadQueue, FileList
|
||||
if (pSrcNZBInfo->GetFileList()->empty())
|
||||
{
|
||||
pDownloadQueue->GetQueue()->Remove(pSrcNZBInfo);
|
||||
g_pDiskState->DiscardFiles(pSrcNZBInfo);
|
||||
delete pSrcNZBInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -62,6 +62,206 @@ extern Options* g_pOptions;
|
||||
|
||||
const int MAX_ID = 1000000000;
|
||||
|
||||
|
||||
class GroupSorter
|
||||
{
|
||||
public:
|
||||
enum ESortCriteria
|
||||
{
|
||||
scName,
|
||||
scSize,
|
||||
scRemainingSize,
|
||||
scAge,
|
||||
scCategory,
|
||||
scPriority
|
||||
};
|
||||
|
||||
enum ESortOrder
|
||||
{
|
||||
soAscending,
|
||||
soDescending,
|
||||
soAuto
|
||||
};
|
||||
|
||||
private:
|
||||
NZBList* m_pNZBList;
|
||||
QueueEditor::ItemList* m_pSortItemList;
|
||||
ESortCriteria m_eSortCriteria;
|
||||
ESortOrder m_eSortOrder;
|
||||
|
||||
void AlignSelectedGroups();
|
||||
|
||||
public:
|
||||
GroupSorter(NZBList* pNZBList, QueueEditor::ItemList* pSortItemList) :
|
||||
m_pNZBList(pNZBList), m_pSortItemList(pSortItemList) {}
|
||||
bool Execute(const char* szSort);
|
||||
bool operator()(NZBInfo* pNZBInfo1, NZBInfo* pNZBInfo2) const;
|
||||
};
|
||||
|
||||
bool GroupSorter::Execute(const char* szSort)
|
||||
{
|
||||
if (!strcasecmp(szSort, "name") || !strcasecmp(szSort, "name+") || !strcasecmp(szSort, "name-"))
|
||||
{
|
||||
m_eSortCriteria = scName;
|
||||
}
|
||||
else if (!strcasecmp(szSort, "size") || !strcasecmp(szSort, "size+") || !strcasecmp(szSort, "size-"))
|
||||
{
|
||||
m_eSortCriteria = scSize;
|
||||
}
|
||||
else if (!strcasecmp(szSort, "left") || !strcasecmp(szSort, "left+") || !strcasecmp(szSort, "left-"))
|
||||
{
|
||||
m_eSortCriteria = scRemainingSize;
|
||||
}
|
||||
else if (!strcasecmp(szSort, "age") || !strcasecmp(szSort, "age+") || !strcasecmp(szSort, "age-"))
|
||||
{
|
||||
m_eSortCriteria = scAge;
|
||||
}
|
||||
else if (!strcasecmp(szSort, "category") || !strcasecmp(szSort, "category+") || !strcasecmp(szSort, "category-"))
|
||||
{
|
||||
m_eSortCriteria = scCategory;
|
||||
}
|
||||
else if (!strcasecmp(szSort, "priority") || !strcasecmp(szSort, "priority+") || !strcasecmp(szSort, "priority-"))
|
||||
{
|
||||
m_eSortCriteria = scPriority;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not sort groups: incorrect sort order (%s)", szSort);
|
||||
return false;
|
||||
}
|
||||
|
||||
char lastCh = szSort[strlen(szSort) - 1];
|
||||
if (lastCh == '+')
|
||||
{
|
||||
m_eSortOrder = soAscending;
|
||||
}
|
||||
else if (lastCh == '-')
|
||||
{
|
||||
m_eSortOrder = soDescending;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_eSortOrder = soAuto;
|
||||
}
|
||||
|
||||
AlignSelectedGroups();
|
||||
|
||||
NZBList tempList = *m_pNZBList;
|
||||
|
||||
ESortOrder eOrigSortOrder = m_eSortOrder;
|
||||
if (m_eSortOrder == soAuto && m_eSortCriteria == scPriority)
|
||||
{
|
||||
m_eSortOrder = soDescending;
|
||||
}
|
||||
|
||||
std::sort(m_pNZBList->begin(), m_pNZBList->end(), *this);
|
||||
|
||||
if (eOrigSortOrder == soAuto && tempList == *m_pNZBList)
|
||||
{
|
||||
m_eSortOrder = m_eSortOrder == soDescending ? soAscending : soDescending;
|
||||
std::sort(m_pNZBList->begin(), m_pNZBList->end(), *this);
|
||||
}
|
||||
|
||||
tempList.clear(); // prevent destroying of elements
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GroupSorter::operator()(NZBInfo* pNZBInfo1, NZBInfo* pNZBInfo2) const
|
||||
{
|
||||
// if list of ID is empty - sort all items
|
||||
bool bSortItem1 = m_pSortItemList->empty();
|
||||
bool bSortItem2 = m_pSortItemList->empty();
|
||||
|
||||
for (QueueEditor::ItemList::iterator it = m_pSortItemList->begin(); it != m_pSortItemList->end(); it++)
|
||||
{
|
||||
QueueEditor::EditItem* pItem = *it;
|
||||
bSortItem1 |= pItem->m_pNZBInfo == pNZBInfo1;
|
||||
bSortItem2 |= pItem->m_pNZBInfo == pNZBInfo2;
|
||||
}
|
||||
|
||||
if (!bSortItem1 || !bSortItem2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (m_eSortOrder == soDescending)
|
||||
{
|
||||
std::swap(pNZBInfo1, pNZBInfo2);
|
||||
}
|
||||
|
||||
switch (m_eSortCriteria)
|
||||
{
|
||||
case scName:
|
||||
ret = strcmp(pNZBInfo1->GetName(), pNZBInfo2->GetName()) < 0;
|
||||
break;
|
||||
|
||||
case scSize:
|
||||
ret = pNZBInfo1->GetSize() < pNZBInfo2->GetSize();
|
||||
break;
|
||||
|
||||
case scRemainingSize:
|
||||
ret = pNZBInfo1->GetRemainingSize() - pNZBInfo1->GetPausedSize() <
|
||||
pNZBInfo2->GetRemainingSize() - pNZBInfo2->GetPausedSize();
|
||||
break;
|
||||
|
||||
case scAge:
|
||||
ret = pNZBInfo1->GetMinTime() > pNZBInfo2->GetMinTime();
|
||||
break;
|
||||
|
||||
case scCategory:
|
||||
ret = strcmp(pNZBInfo1->GetCategory(), pNZBInfo2->GetCategory()) < 0;
|
||||
break;
|
||||
|
||||
case scPriority:
|
||||
ret = pNZBInfo1->GetPriority() < pNZBInfo2->GetPriority();
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GroupSorter::AlignSelectedGroups()
|
||||
{
|
||||
NZBInfo* pLastNZBInfo = NULL;
|
||||
unsigned int iLastNum = 0;
|
||||
unsigned int iNum = 0;
|
||||
while (iNum < m_pNZBList->size())
|
||||
{
|
||||
NZBInfo* pNZBInfo = m_pNZBList->at(iNum);
|
||||
|
||||
bool bSelected = false;
|
||||
for (QueueEditor::ItemList::iterator it = m_pSortItemList->begin(); it != m_pSortItemList->end(); it++)
|
||||
{
|
||||
QueueEditor::EditItem* pItem = *it;
|
||||
if (pItem->m_pNZBInfo == pNZBInfo)
|
||||
{
|
||||
bSelected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bSelected)
|
||||
{
|
||||
if (pLastNZBInfo && iNum - iLastNum > 1)
|
||||
{
|
||||
m_pNZBList->erase(m_pNZBList->begin() + iNum);
|
||||
m_pNZBList->insert(m_pNZBList->begin() + iLastNum + 1, pNZBInfo);
|
||||
iLastNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
iLastNum = iNum;
|
||||
}
|
||||
pLastNZBInfo = pNZBInfo;
|
||||
}
|
||||
iNum++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QueueEditor::EditItem::EditItem(FileInfo* pFileInfo, NZBInfo* pNZBInfo, int iOffset)
|
||||
{
|
||||
m_pFileInfo = pFileInfo;
|
||||
@@ -109,14 +309,9 @@ void QueueEditor::PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause)
|
||||
*/
|
||||
void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
|
||||
{
|
||||
if (pFileInfo->GetNZBInfo()->GetDeleting())
|
||||
{
|
||||
detail("Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
}
|
||||
pFileInfo->GetNZBInfo()->PrintMessage(
|
||||
pFileInfo->GetNZBInfo()->GetDeleting() ? Message::mkDetail : Message::mkInfo,
|
||||
"Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
g_pQueueCoordinator->DeleteQueueEntry(m_pDownloadQueue, pFileInfo);
|
||||
}
|
||||
|
||||
@@ -205,7 +400,7 @@ bool QueueEditor::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameL
|
||||
{
|
||||
return g_pPrePostProcessor->EditList(pDownloadQueue, pIDList, eAction, iOffset, szText);
|
||||
}
|
||||
else if (DownloadQueue::eaHistoryDelete <= eAction && eAction <= DownloadQueue::eaHistoryMarkGood)
|
||||
else if (DownloadQueue::eaHistoryDelete <= eAction && eAction <= DownloadQueue::eaHistorySetName)
|
||||
{
|
||||
return g_pHistoryCoordinator->EditList(pDownloadQueue, pIDList, eAction, iOffset, szText);
|
||||
}
|
||||
@@ -251,6 +446,9 @@ bool QueueEditor::InternEditList(ItemList* pItemList,
|
||||
case DownloadQueue::eaGroupMerge:
|
||||
return MergeGroups(pItemList);
|
||||
|
||||
case DownloadQueue::eaGroupSort:
|
||||
return SortGroups(pItemList, szText);
|
||||
|
||||
case DownloadQueue::eaFileSplit:
|
||||
return SplitGroup(pItemList, szText);
|
||||
|
||||
@@ -984,6 +1182,12 @@ bool QueueEditor::SplitGroup(ItemList* pItemList, const char* szName)
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool QueueEditor::SortGroups(ItemList* pItemList, const char* szSort)
|
||||
{
|
||||
GroupSorter sorter(m_pDownloadQueue->GetQueue(), pItemList);
|
||||
return sorter.Execute(szSort);
|
||||
}
|
||||
|
||||
void QueueEditor::ReorderFiles(ItemList* pItemList)
|
||||
{
|
||||
if (pItemList->size() == 0)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
class QueueEditor
|
||||
{
|
||||
private:
|
||||
public:
|
||||
class EditItem
|
||||
{
|
||||
public:
|
||||
@@ -45,6 +45,7 @@ private:
|
||||
|
||||
typedef std::vector<EditItem*> ItemList;
|
||||
|
||||
private:
|
||||
DownloadQueue* m_pDownloadQueue;
|
||||
|
||||
private:
|
||||
@@ -60,6 +61,7 @@ private:
|
||||
void SetNZBName(NZBInfo* pNZBInfo, const char* szName);
|
||||
bool CanCleanupDisk(NZBInfo* pNZBInfo);
|
||||
bool MergeGroups(ItemList* pItemList);
|
||||
bool SortGroups(ItemList* pItemList, const char* szSort);
|
||||
bool SplitGroup(ItemList* pItemList, const char* szName);
|
||||
bool DeleteUrl(NZBInfo* pNZBInfo, DownloadQueue::EEditAction eAction);
|
||||
void ReorderFiles(ItemList* pItemList);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -47,9 +47,11 @@
|
||||
#include "Util.h"
|
||||
#include "NZBFile.h"
|
||||
#include "Scanner.h"
|
||||
#include "DiskState.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern Scanner* g_pScanner;
|
||||
extern DiskState* g_pDiskState;
|
||||
|
||||
UrlDownloader::UrlDownloader() : WebDownloader()
|
||||
{
|
||||
@@ -453,6 +455,7 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
|
||||
if (bDeleteObj)
|
||||
{
|
||||
g_pDiskState->DiscardFiles(pNZBInfo);
|
||||
delete pNZBInfo;
|
||||
}
|
||||
}
|
||||
@@ -490,6 +493,7 @@ bool UrlCoordinator::DeleteQueueEntry(DownloadQueue* pDownloadQueue, NZBInfo* pN
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pDiskState->DiscardFiles(pNZBInfo);
|
||||
delete pNZBInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -61,7 +61,7 @@ extern void Reload();
|
||||
const char* g_szMessageRequestNames[] =
|
||||
{ "N/A", "Download", "Pause/Unpause", "List", "Set download rate", "Dump debug",
|
||||
"Edit queue", "Log", "Quit", "Reload", "Version", "Post-queue", "Write log", "Scan",
|
||||
"Pause/Unpause postprocessor", "History", "Download URL" };
|
||||
"Pause/Unpause postprocessor", "History" };
|
||||
|
||||
const unsigned int g_iMessageRequestSizes[] =
|
||||
{ 0,
|
||||
@@ -78,10 +78,118 @@ const unsigned int g_iMessageRequestSizes[] =
|
||||
sizeof(SNZBPostQueueRequest),
|
||||
sizeof(SNZBWriteLogRequest),
|
||||
sizeof(SNZBScanRequest),
|
||||
sizeof(SNZBHistoryRequest),
|
||||
sizeof(SNZBDownloadUrlRequest)
|
||||
sizeof(SNZBHistoryRequest)
|
||||
};
|
||||
|
||||
|
||||
|
||||
class BinCommand
|
||||
{
|
||||
protected:
|
||||
Connection* m_pConnection;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
void SendBoolResponse(bool bSuccess, const char* szText);
|
||||
|
||||
public:
|
||||
virtual ~BinCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; }
|
||||
};
|
||||
|
||||
class DownloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PauseUnpauseBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class EditQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SetDownloadRateBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DumpDebugBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ReloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PostQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class WriteLogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScanBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class HistoryBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UrlQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
|
||||
//*****************************************************************
|
||||
// BinProcessor
|
||||
|
||||
@@ -182,10 +290,6 @@ void BinRpcProcessor::Dispatch()
|
||||
command = new HistoryBinCommand();
|
||||
break;
|
||||
|
||||
case eRemoteRequestDownloadUrl:
|
||||
command = new DownloadUrlBinCommand();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
|
||||
break;
|
||||
@@ -330,30 +434,59 @@ void DownloadBinCommand::Execute()
|
||||
}
|
||||
|
||||
int iBufLen = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
char* pRecvBuffer = (char*)malloc(iBufLen);
|
||||
char* szNZBContent = (char*)malloc(iBufLen);
|
||||
|
||||
if (!m_pConnection->Recv(pRecvBuffer, iBufLen))
|
||||
if (!m_pConnection->Recv(szNZBContent, iBufLen))
|
||||
{
|
||||
error("invalid request");
|
||||
free(pRecvBuffer);
|
||||
free(szNZBContent);
|
||||
return;
|
||||
}
|
||||
|
||||
int iPriority = ntohl(DownloadRequest.m_iPriority);
|
||||
bool bAddPaused = ntohl(DownloadRequest.m_bAddPaused);
|
||||
bool bAddTop = ntohl(DownloadRequest.m_bAddFirst);
|
||||
int iDupeMode = ntohl(DownloadRequest.m_iDupeMode);
|
||||
int iDupeScore = ntohl(DownloadRequest.m_iDupeScore);
|
||||
|
||||
bool bOK = g_pScanner->AddExternalFile(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory,
|
||||
iPriority, NULL, 0, dmScore, NULL, bAddTop, bAddPaused, NULL, NULL, pRecvBuffer, iBufLen, NULL) != Scanner::asFailed;
|
||||
bool bOK = false;
|
||||
|
||||
if (!strncasecmp(szNZBContent, "http://", 6) || !strncasecmp(szNZBContent, "https://", 7))
|
||||
{
|
||||
// add url
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
pNZBInfo->SetKind(NZBInfo::nkUrl);
|
||||
pNZBInfo->SetURL(szNZBContent);
|
||||
pNZBInfo->SetFilename(DownloadRequest.m_szNZBFilename);
|
||||
pNZBInfo->SetCategory(DownloadRequest.m_szCategory);
|
||||
pNZBInfo->SetPriority(iPriority);
|
||||
pNZBInfo->SetAddUrlPaused(bAddPaused);
|
||||
pNZBInfo->SetDupeKey(DownloadRequest.m_szDupeKey);
|
||||
pNZBInfo->SetDupeScore(iDupeScore);
|
||||
pNZBInfo->SetDupeMode((EDupeMode)iDupeMode);
|
||||
|
||||
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
|
||||
pDownloadQueue->GetQueue()->Add(pNZBInfo, bAddTop);
|
||||
pDownloadQueue->Save();
|
||||
DownloadQueue::Unlock();
|
||||
|
||||
bOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bOK = g_pScanner->AddExternalFile(DownloadRequest.m_szNZBFilename, DownloadRequest.m_szCategory, iPriority,
|
||||
DownloadRequest.m_szDupeKey, iDupeScore, (EDupeMode)iDupeMode, NULL, bAddTop, bAddPaused,
|
||||
NULL, NULL, szNZBContent, iBufLen, NULL) != Scanner::asFailed;
|
||||
}
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, bOK ? "Collection %s added to queue" : "Download Request failed for %s",
|
||||
Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
Util::BaseFileName(DownloadRequest.m_szNZBFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
SendBoolResponse(bOK, tmp);
|
||||
|
||||
free(pRecvBuffer);
|
||||
free(szNZBContent);
|
||||
}
|
||||
|
||||
void ListBinCommand::Execute()
|
||||
@@ -637,7 +770,7 @@ void LogBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
Log::Messages* pMessages = g_pLog->LockMessages();
|
||||
MessageList* pMessages = g_pLog->LockMessages();
|
||||
|
||||
int iNrEntries = ntohl(LogRequest.m_iLines);
|
||||
unsigned int iIDFrom = ntohl(LogRequest.m_iIDFrom);
|
||||
@@ -972,6 +1105,8 @@ void HistoryBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
bool bShowHidden = ntohl(HistoryRequest.m_bHidden);
|
||||
|
||||
SNZBHistoryResponse HistoryResponse;
|
||||
memset(&HistoryResponse, 0, sizeof(HistoryResponse));
|
||||
HistoryResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
@@ -985,16 +1120,27 @@ void HistoryBinCommand::Execute()
|
||||
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
|
||||
|
||||
// calculate required buffer size for nzbs
|
||||
int iNrEntries = pDownloadQueue->GetHistory()->size();
|
||||
int iNrEntries = 0;
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
if (pHistoryInfo->GetKind() != HistoryInfo::hkDup || bShowHidden)
|
||||
{
|
||||
iNrEntries++;
|
||||
}
|
||||
}
|
||||
bufsize += iNrEntries * sizeof(SNZBHistoryResponseEntry);
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
bufsize += strlen(szNicename) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
if (pHistoryInfo->GetKind() != HistoryInfo::hkDup || bShowHidden)
|
||||
{
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
bufsize += strlen(szNicename) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
buf = (char*) malloc(bufsize);
|
||||
@@ -1004,41 +1150,52 @@ void HistoryBinCommand::Execute()
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) bufptr;
|
||||
pListAnswer->m_iID = htonl(pHistoryInfo->GetID());
|
||||
pListAnswer->m_iKind = htonl((int)pHistoryInfo->GetKind());
|
||||
pListAnswer->m_tTime = htonl((int)pHistoryInfo->GetTime());
|
||||
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
pListAnswer->m_iNicenameLen = htonl(strlen(szNicename) + 1);
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
|
||||
if (pHistoryInfo->GetKind() != HistoryInfo::hkDup || bShowHidden)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
|
||||
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
|
||||
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatuses()->CalcTotalStatus());
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
pListAnswer->m_iUrlStatus = htonl(pNZBInfo->GetUrlStatus());
|
||||
}
|
||||
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) bufptr;
|
||||
pListAnswer->m_iID = htonl(pHistoryInfo->GetID());
|
||||
pListAnswer->m_iKind = htonl((int)pHistoryInfo->GetKind());
|
||||
pListAnswer->m_tTime = htonl((int)pHistoryInfo->GetTime());
|
||||
|
||||
bufptr += sizeof(SNZBHistoryResponseEntry);
|
||||
strcpy(bufptr, szNicename);
|
||||
bufptr += ntohl(pListAnswer->m_iNicenameLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pListAnswer->m_iNicenameLen = htonl(ntohl(pListAnswer->m_iNicenameLen) + 4 - (size_t)bufptr % 4);
|
||||
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
pListAnswer->m_iNicenameLen = htonl(strlen(szNicename) + 1);
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
|
||||
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
|
||||
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatuses()->CalcTotalStatus());
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDup && bShowHidden)
|
||||
{
|
||||
DupInfo* pDupInfo = pHistoryInfo->GetDupInfo();
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
Util::SplitInt64(pDupInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
pListAnswer->m_iUrlStatus = htonl(pNZBInfo->GetUrlStatus());
|
||||
}
|
||||
|
||||
bufptr += sizeof(SNZBHistoryResponseEntry);
|
||||
strcpy(bufptr, szNicename);
|
||||
bufptr += ntohl(pListAnswer->m_iNicenameLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pListAnswer->m_iNicenameLen = htonl(ntohl(pListAnswer->m_iNicenameLen) + 4 - (size_t)bufptr % 4);
|
||||
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,42 +1215,3 @@ void HistoryBinCommand::Execute()
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void DownloadUrlBinCommand::Execute()
|
||||
{
|
||||
SNZBDownloadUrlRequest DownloadUrlRequest;
|
||||
if (!ReceiveRequest(&DownloadUrlRequest, sizeof(DownloadUrlRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
URL url(DownloadUrlRequest.m_szURL);
|
||||
if (!url.IsValid())
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Url %s is not valid", DownloadUrlRequest.m_szURL);
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
pNZBInfo->SetKind(NZBInfo::nkUrl);
|
||||
pNZBInfo->SetURL(DownloadUrlRequest.m_szURL);
|
||||
pNZBInfo->SetFilename(DownloadUrlRequest.m_szNZBFilename);
|
||||
pNZBInfo->SetCategory(DownloadUrlRequest.m_szCategory);
|
||||
pNZBInfo->SetPriority(ntohl(DownloadUrlRequest.m_iPriority));
|
||||
pNZBInfo->SetAddUrlPaused(ntohl(DownloadUrlRequest.m_bAddPaused));
|
||||
|
||||
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
|
||||
pDownloadQueue->GetQueue()->Add(pNZBInfo, ntohl(DownloadUrlRequest.m_bAddFirst));
|
||||
pDownloadQueue->Save();
|
||||
DownloadQueue::Unlock();
|
||||
|
||||
info("Request: Queue url %s", DownloadUrlRequest.m_szURL);
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Url %s added to queue", DownloadUrlRequest.m_szURL);
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,116 +44,4 @@ public:
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
};
|
||||
|
||||
class BinCommand
|
||||
{
|
||||
protected:
|
||||
Connection* m_pConnection;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
void SendBoolResponse(bool bSuccess, const char* szText);
|
||||
|
||||
public:
|
||||
virtual ~BinCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; }
|
||||
};
|
||||
|
||||
class DownloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PauseUnpauseBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class EditQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SetDownloadRateBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DumpDebugBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ReloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PostQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class WriteLogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScanBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class HistoryBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DownloadUrlBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UrlQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef MESSAGEBASE_H
|
||||
#define MESSAGEBASE_H
|
||||
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6225; // = "nzb-XX" (protocol version)
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6228; // = "nzb-XX" (protocol version)
|
||||
static const int NZBREQUESTFILENAMESIZE = 512;
|
||||
static const int NZBREQUESTPASSWORDSIZE = 32;
|
||||
|
||||
@@ -61,8 +61,7 @@ enum eRemoteRequest
|
||||
eRemoteRequestPostQueue,
|
||||
eRemoteRequestWriteLog,
|
||||
eRemoteRequestScan,
|
||||
eRemoteRequestHistory,
|
||||
eRemoteRequestDownloadUrl
|
||||
eRemoteRequestHistory
|
||||
};
|
||||
|
||||
// Possible values for field "m_iAction" of struct "SNZBPauseUnpauseRequest":
|
||||
@@ -102,11 +101,14 @@ struct SNZBResponseBase
|
||||
struct SNZBDownloadRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
char m_szFilename[NZBREQUESTFILENAMESIZE]; // Name of nzb-file, may contain full path (local path on client) or only filename
|
||||
char m_szNZBFilename[NZBREQUESTFILENAMESIZE];// Name of nzb-file. For URLs can be empty, then the filename is read from URL download response
|
||||
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
|
||||
int32_t m_bAddFirst; // 1 - add file to the top of download queue
|
||||
int32_t m_bAddPaused; // 1 - pause added files
|
||||
int32_t m_iPriority; // Priority for files (0 - default)
|
||||
int32_t m_iDupeScore; // Duplicate score
|
||||
int32_t m_iDupeMode; // Duplicate mode (EDupeMode)
|
||||
char m_szDupeKey[NZBREQUESTFILENAMESIZE]; // Duplicate key
|
||||
int32_t m_iTrailingDataLength; // Length of nzb-file in bytes
|
||||
//char m_szContent[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
@@ -437,6 +439,7 @@ struct SNZBScanResponse
|
||||
struct SNZBHistoryRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bHidden; // 0 - only return visible records, 1 - also return hidden records
|
||||
};
|
||||
|
||||
// history response
|
||||
@@ -453,12 +456,13 @@ struct SNZBHistoryResponse
|
||||
struct SNZBHistoryResponseEntry
|
||||
{
|
||||
int32_t m_iID; // History-ID
|
||||
int32_t m_iKind; // Kind of Item: 1 - Collection (NZB), 2 - URL
|
||||
int32_t m_iKind; // Kind of Item: 1 - Collection (NZB), 2 - URL, 3 - DUP (hidden record)
|
||||
int32_t m_tTime; // When the item was added to history. time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
|
||||
int32_t m_iNicenameLen; // Length of Nicename-string (m_szNicename), following to this record
|
||||
// for Collection items (m_iKind = 1)
|
||||
// for Collection and Dup items (m_iKind = 1 or 2)
|
||||
int32_t m_iSizeLo; // Size of all files in bytes, Low 32-bits of 64-bit value
|
||||
int32_t m_iSizeHi; // Size of all files in bytes, High 32-bits of 64-bit value
|
||||
// for Collection items (m_iKind = 1)
|
||||
int32_t m_iFileCount; // Initial number of files included in NZB-file
|
||||
int32_t m_iParStatus; // See NZBInfo::EParStatus
|
||||
int32_t m_iScriptStatus; // See NZBInfo::EScriptStatus
|
||||
@@ -468,25 +472,4 @@ struct SNZBHistoryResponseEntry
|
||||
//char m_szNicename[m_iNicenameLen]; // variable sized
|
||||
};
|
||||
|
||||
// download url request
|
||||
struct SNZBDownloadUrlRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
char m_szURL[NZBREQUESTFILENAMESIZE]; // url to nzb-file
|
||||
char m_szNZBFilename[NZBREQUESTFILENAMESIZE];// Name of nzb-file. Can be empty, then the filename is read from URL download response
|
||||
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
|
||||
int32_t m_bAddFirst; // 1 - add url to the top of download queue
|
||||
int32_t m_bAddPaused; // 1 - pause added files
|
||||
int32_t m_iPriority; // Priority for files (0 - default)
|
||||
};
|
||||
|
||||
// download url response
|
||||
struct SNZBDownloadUrlResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -159,15 +159,26 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
/*
|
||||
* Sends a message to the running nzbget process.
|
||||
*/
|
||||
bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
|
||||
bool RemoteClient::RequestServerDownload(const char* szNZBFilename, const char* szNZBContent,
|
||||
const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority,
|
||||
const char* szDupeKey, int iDupeMode, int iDupeScore)
|
||||
{
|
||||
// Read the file into the buffer
|
||||
char* szBuffer = NULL;
|
||||
int iLength = 0;
|
||||
if (!Util::LoadFileIntoBuffer(szFilename, &szBuffer, &iLength))
|
||||
char* szBuffer = NULL;
|
||||
int iLength = 0;
|
||||
bool bIsUrl = !strncasecmp(szNZBContent, "http://", 6) || !strncasecmp(szNZBContent, "https://", 7);
|
||||
if (bIsUrl)
|
||||
{
|
||||
printf("Could not load file %s\n", szFilename);
|
||||
return false;
|
||||
iLength = strlen(szNZBContent) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Util::LoadFileIntoBuffer(szNZBContent, &szBuffer, &iLength))
|
||||
{
|
||||
printf("Could not load file %s\n", szNZBContent);
|
||||
return false;
|
||||
}
|
||||
iLength--;
|
||||
}
|
||||
|
||||
bool OK = InitConnection();
|
||||
@@ -178,10 +189,21 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
DownloadRequest.m_bAddFirst = htonl(bAddFirst);
|
||||
DownloadRequest.m_bAddPaused = htonl(bAddPaused);
|
||||
DownloadRequest.m_iPriority = htonl(iPriority);
|
||||
DownloadRequest.m_iTrailingDataLength = htonl(iLength - 1);
|
||||
DownloadRequest.m_iDupeMode = htonl(iDupeMode);
|
||||
DownloadRequest.m_iDupeScore = htonl(iDupeScore);
|
||||
DownloadRequest.m_iTrailingDataLength = htonl(iLength);
|
||||
|
||||
DownloadRequest.m_szNZBFilename[0] = '\0';
|
||||
if (!Util::EmptyStr(szNZBFilename))
|
||||
{
|
||||
strncpy(DownloadRequest.m_szNZBFilename, szNZBFilename, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
else if (!bIsUrl)
|
||||
{
|
||||
strncpy(DownloadRequest.m_szNZBFilename, szNZBContent, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadRequest.m_szNZBFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
strncpy(DownloadRequest.m_szFilename, szFilename, NZBREQUESTFILENAMESIZE - 1);
|
||||
DownloadRequest.m_szFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
DownloadRequest.m_szCategory[0] = '\0';
|
||||
if (szCategory)
|
||||
{
|
||||
@@ -189,6 +211,13 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
}
|
||||
DownloadRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
DownloadRequest.m_szDupeKey[0] = '\0';
|
||||
if (!Util::EmptyStr(szDupeKey))
|
||||
{
|
||||
strncpy(DownloadRequest.m_szDupeKey, szDupeKey, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadRequest.m_szDupeKey[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
if (!m_pConnection->Send((char*)(&DownloadRequest), sizeof(DownloadRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
@@ -196,7 +225,7 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pConnection->Send(szBuffer, iLength);
|
||||
m_pConnection->Send(bIsUrl ? szNZBContent : szBuffer, iLength);
|
||||
OK = ReceiveBoolResponse();
|
||||
m_pConnection->Disconnect();
|
||||
}
|
||||
@@ -1087,12 +1116,13 @@ bool RemoteClient::RequestScan(bool bSyncMode)
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestHistory()
|
||||
bool RemoteClient::RequestHistory(bool bWithHidden)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBHistoryRequest HistoryRequest;
|
||||
InitMessageBase(&HistoryRequest.m_MessageBase, eRemoteRequestHistory, sizeof(HistoryRequest));
|
||||
HistoryRequest.m_bHidden = htonl(bWithHidden);
|
||||
|
||||
if (!m_pConnection->Send((char*)(&HistoryRequest), sizeof(HistoryRequest)))
|
||||
{
|
||||
@@ -1143,8 +1173,12 @@ bool RemoteClient::RequestHistory()
|
||||
HistoryInfo::EKind eKind = (HistoryInfo::EKind)ntohl(pListAnswer->m_iKind);
|
||||
const char* szNicename = pBufPtr + sizeof(SNZBHistoryResponseEntry);
|
||||
|
||||
if (eKind == HistoryInfo::hkNzb)
|
||||
if (eKind == HistoryInfo::hkNzb || eKind == HistoryInfo::hkDup)
|
||||
{
|
||||
char szFiles[20];
|
||||
snprintf(szFiles, sizeof(szFiles), "%i files, ", ntohl(pListAnswer->m_iFileCount));
|
||||
szFiles[20 - 1] = '\0';
|
||||
|
||||
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
|
||||
|
||||
char szSize[20];
|
||||
@@ -1152,17 +1186,20 @@ bool RemoteClient::RequestHistory()
|
||||
|
||||
const char* szParStatusText[] = { "", "", ", Par failed", ", Par successful", ", Repair possible", ", Repair needed" };
|
||||
const char* szScriptStatusText[] = { "", ", Script status unknown", ", Script failed", ", Script successful" };
|
||||
int iParStatus = ntohl(pListAnswer->m_iParStatus);
|
||||
int iScriptStatus = ntohl(pListAnswer->m_iScriptStatus);
|
||||
|
||||
printf("[%i] %s (%i files, %s%s%s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
ntohl(pListAnswer->m_iFileCount), szSize,
|
||||
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
|
||||
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
|
||||
printf("[%i] %s (%s%s%s%s%s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
(eKind == HistoryInfo::hkDup ? "Hidden, " : ""),
|
||||
(eKind == HistoryInfo::hkDup ? "" : szFiles), szSize,
|
||||
(eKind == HistoryInfo::hkDup ? "" : szParStatusText[iParStatus]),
|
||||
(eKind == HistoryInfo::hkDup ? "" : szScriptStatusText[iScriptStatus]));
|
||||
}
|
||||
else if (eKind == HistoryInfo::hkUrl)
|
||||
{
|
||||
const char* szUrlStatusText[] = { "", "", "Url download successful", "Url download failed", "" };
|
||||
const char* szUrlStatusText[] = { "", "", "Url download successful", "Url download failed", "", "Nzb scan skipped", "Nzb scan failed" };
|
||||
|
||||
printf("[%i] %s (%s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
printf("[%i] %s (URL, %s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
szUrlStatusText[ntohl(pListAnswer->m_iUrlStatus)]);
|
||||
}
|
||||
|
||||
@@ -1177,44 +1214,3 @@ bool RemoteClient::RequestHistory()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBDownloadUrlRequest DownloadUrlRequest;
|
||||
InitMessageBase(&DownloadUrlRequest.m_MessageBase, eRemoteRequestDownloadUrl, sizeof(DownloadUrlRequest));
|
||||
DownloadUrlRequest.m_bAddFirst = htonl(bAddFirst);
|
||||
DownloadUrlRequest.m_bAddPaused = htonl(bAddPaused);
|
||||
DownloadUrlRequest.m_iPriority = htonl(iPriority);
|
||||
|
||||
strncpy(DownloadUrlRequest.m_szURL, szURL, NZBREQUESTFILENAMESIZE - 1);
|
||||
DownloadUrlRequest.m_szURL[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
DownloadUrlRequest.m_szCategory[0] = '\0';
|
||||
if (szCategory)
|
||||
{
|
||||
strncpy(DownloadUrlRequest.m_szCategory, szCategory, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadUrlRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
DownloadUrlRequest.m_szNZBFilename[0] = '\0';
|
||||
if (szNZBFilename)
|
||||
{
|
||||
strncpy(DownloadUrlRequest.m_szNZBFilename, szNZBFilename, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadUrlRequest.m_szNZBFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&DownloadUrlRequest), sizeof(DownloadUrlRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
}
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -60,7 +60,9 @@ public:
|
||||
RemoteClient();
|
||||
~RemoteClient();
|
||||
void SetVerbose(bool bVerbose) { m_bVerbose = bVerbose; };
|
||||
bool RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
|
||||
bool RequestServerDownload(const char* szNZBFilename, const char* szNZBContent, const char* szCategory,
|
||||
bool bAddFirst, bool bAddPaused, int iPriority,
|
||||
const char* szDupeKey, int iDupeMode, int iDupeScore);
|
||||
bool RequestServerList(bool bFiles, bool bGroups, const char* szPattern);
|
||||
bool RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAction iAction);
|
||||
bool RequestServerSetDownloadRate(int iRate);
|
||||
@@ -74,8 +76,7 @@ public:
|
||||
bool RequestPostQueue();
|
||||
bool RequestWriteLog(int iKind, const char* szText);
|
||||
bool RequestScan(bool bSyncMode);
|
||||
bool RequestHistory();
|
||||
bool RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
|
||||
bool RequestHistory(bool bWithHidden);
|
||||
void BuildFileList(SNZBListResponse* pListResponse, const char* pTrailingData, DownloadQueue* pDownloadQueue);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -81,6 +81,7 @@ void WebProcessor::Execute()
|
||||
m_bGZip =false;
|
||||
char szAuthInfo[1024];
|
||||
szAuthInfo[0] = '\0';
|
||||
m_eUserAccess = uaControl;
|
||||
|
||||
// reading http header
|
||||
char szBuffer[1024];
|
||||
@@ -176,10 +177,10 @@ void WebProcessor::Execute()
|
||||
|
||||
debug("Final URL=%s", m_szUrl);
|
||||
|
||||
if (strlen(g_pOptions->GetControlPassword()) > 0 &&
|
||||
!(strlen(g_pOptions->GetAuthorizedIP()) > 0 && IsAuthorizedIP(m_pConnection->GetRemoteAddr())))
|
||||
if (!Util::EmptyStr(g_pOptions->GetControlPassword()) &&
|
||||
!(!Util::EmptyStr(g_pOptions->GetAuthorizedIP()) && IsAuthorizedIP(m_pConnection->GetRemoteAddr())))
|
||||
{
|
||||
if (strlen(szAuthInfo) == 0)
|
||||
if (Util::EmptyStr(szAuthInfo))
|
||||
{
|
||||
SendAuthResponse();
|
||||
return;
|
||||
@@ -188,8 +189,26 @@ void WebProcessor::Execute()
|
||||
// Authorization
|
||||
char* pw = strchr(szAuthInfo, ':');
|
||||
if (pw) *pw++ = '\0';
|
||||
if ((strlen(g_pOptions->GetControlUsername()) > 0 && strcmp(szAuthInfo, g_pOptions->GetControlUsername())) ||
|
||||
(pw && strcmp(pw, g_pOptions->GetControlPassword())))
|
||||
|
||||
if ((Util::EmptyStr(g_pOptions->GetControlUsername()) ||
|
||||
!strcmp(szAuthInfo, g_pOptions->GetControlUsername())) &&
|
||||
pw && !strcmp(pw, g_pOptions->GetControlPassword()))
|
||||
{
|
||||
m_eUserAccess = uaControl;
|
||||
}
|
||||
else if (!Util::EmptyStr(g_pOptions->GetRestrictedUsername()) &&
|
||||
!strcmp(szAuthInfo, g_pOptions->GetRestrictedUsername()) &&
|
||||
pw && !strcmp(pw, g_pOptions->GetRestrictedPassword()))
|
||||
{
|
||||
m_eUserAccess = uaRestricted;
|
||||
}
|
||||
else if (!Util::EmptyStr(g_pOptions->GetAddUsername()) &&
|
||||
!strcmp(szAuthInfo, g_pOptions->GetAddUsername()) &&
|
||||
pw && !strcmp(pw, g_pOptions->GetAddPassword()))
|
||||
{
|
||||
m_eUserAccess = uaAdd;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Request received on port %i from %s, but username or password invalid (%s:%s)",
|
||||
g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr(), szAuthInfo, pw);
|
||||
@@ -249,13 +268,14 @@ void WebProcessor::Dispatch()
|
||||
XmlRpcProcessor processor;
|
||||
processor.SetRequest(m_szRequest);
|
||||
processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost);
|
||||
processor.SetUserAccess((XmlRpcProcessor::EUserAccess)m_eUserAccess);
|
||||
processor.SetUrl(m_szUrl);
|
||||
processor.Execute();
|
||||
SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pOptions->GetWebDir() || strlen(g_pOptions->GetWebDir()) == 0)
|
||||
if (Util::EmptyStr(g_pOptions->GetWebDir()))
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,11 +38,19 @@ public:
|
||||
hmOptions
|
||||
};
|
||||
|
||||
enum EUserAccess
|
||||
{
|
||||
uaControl,
|
||||
uaRestricted,
|
||||
uaAdd
|
||||
};
|
||||
|
||||
private:
|
||||
Connection* m_pConnection;
|
||||
char* m_szRequest;
|
||||
char* m_szUrl;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
EUserAccess m_eUserAccess;
|
||||
bool m_bGZip;
|
||||
char* m_szOrigin;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "Maintenance.h"
|
||||
#include "StatMeter.h"
|
||||
#include "ArticleWriter.h"
|
||||
#include "DiskState.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern Scanner* g_pScanner;
|
||||
@@ -58,6 +59,7 @@ extern ServerPool* g_pServerPool;
|
||||
extern Maintenance* g_pMaintenance;
|
||||
extern StatMeter* g_pStatMeter;
|
||||
extern ArticleCache* g_pArticleCache;
|
||||
extern DiskState* g_pDiskState;
|
||||
extern void ExitProc();
|
||||
extern void Reload();
|
||||
|
||||
@@ -136,10 +138,12 @@ public:
|
||||
class LogXmlCommand: public XmlCommand
|
||||
{
|
||||
protected:
|
||||
virtual Log::Messages* LockMessages();
|
||||
int m_iIDFrom;
|
||||
int m_iNrEntries;
|
||||
virtual MessageList* LockMessages();
|
||||
virtual void UnlockMessages();
|
||||
public:
|
||||
virtual void Execute();
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class NzbInfoXmlCommand: public XmlCommand
|
||||
@@ -280,7 +284,7 @@ public:
|
||||
class LogUpdateXmlCommand: public LogXmlCommand
|
||||
{
|
||||
protected:
|
||||
virtual Log::Messages* LockMessages();
|
||||
virtual MessageList* LockMessages();
|
||||
virtual void UnlockMessages();
|
||||
};
|
||||
|
||||
@@ -296,6 +300,38 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LoadLogXmlCommand: public LogXmlCommand
|
||||
{
|
||||
private:
|
||||
MessageList m_messages;
|
||||
int m_iNZBID;
|
||||
NZBInfo* m_pNZBInfo;
|
||||
protected:
|
||||
virtual void Execute();
|
||||
virtual MessageList* LockMessages();
|
||||
virtual void UnlockMessages();
|
||||
};
|
||||
|
||||
class TestServerXmlCommand: public XmlCommand
|
||||
{
|
||||
private:
|
||||
char* m_szErrText;
|
||||
|
||||
class TestConnection : public NNTPConnection
|
||||
{
|
||||
protected:
|
||||
TestServerXmlCommand* m_pOwner;
|
||||
virtual void PrintError(const char* szErrMsg) { m_pOwner->PrintError(szErrMsg); }
|
||||
public:
|
||||
TestConnection(NewsServer* pNewsServer, TestServerXmlCommand* pOwner):
|
||||
NNTPConnection(pNewsServer), m_pOwner(pOwner) {}
|
||||
};
|
||||
|
||||
void PrintError(const char* szErrMsg);
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
|
||||
//*****************************************************************
|
||||
// XmlRpcProcessor
|
||||
@@ -317,6 +353,7 @@ XmlRpcProcessor::~XmlRpcProcessor()
|
||||
void XmlRpcProcessor::SetUrl(const char* szUrl)
|
||||
{
|
||||
m_szUrl = strdup(szUrl);
|
||||
WebUtil::URLDecode(m_szUrl);
|
||||
}
|
||||
|
||||
|
||||
@@ -354,9 +391,13 @@ void XmlRpcProcessor::Execute()
|
||||
void XmlRpcProcessor::Dispatch()
|
||||
{
|
||||
char* szRequest = m_szRequest;
|
||||
|
||||
char szMethodName[100];
|
||||
szMethodName[0] = '\0';
|
||||
|
||||
char szRequestId[100];
|
||||
szRequestId[0] = '\0';
|
||||
|
||||
if (m_eHttpMethod == hmGet)
|
||||
{
|
||||
szRequest = m_szUrl + 1;
|
||||
@@ -367,6 +408,7 @@ void XmlRpcProcessor::Dispatch()
|
||||
if (pend)
|
||||
{
|
||||
int iLen = (int)(pend - pstart - 1 < (int)sizeof(szMethodName) - 1 ? pend - pstart - 1 : (int)sizeof(szMethodName) - 1);
|
||||
iLen = iLen >= sizeof(szMethodName) ? sizeof(szMethodName) - 1 : iLen;
|
||||
strncpy(szMethodName, pstart + 1, iLen);
|
||||
szMethodName[iLen] = '\0';
|
||||
szRequest = pend + 1;
|
||||
@@ -388,9 +430,16 @@ void XmlRpcProcessor::Dispatch()
|
||||
int iValueLen = 0;
|
||||
if (const char* szMethodPtr = WebUtil::JsonFindField(m_szRequest, "method", &iValueLen))
|
||||
{
|
||||
iValueLen = iValueLen >= sizeof(szMethodName) ? sizeof(szMethodName) - 1 : iValueLen;
|
||||
strncpy(szMethodName, szMethodPtr + 1, iValueLen - 2);
|
||||
szMethodName[iValueLen - 2] = '\0';
|
||||
}
|
||||
if (const char* szRequestIdPtr = WebUtil::JsonFindField(m_szRequest, "id", &iValueLen))
|
||||
{
|
||||
iValueLen = iValueLen >= sizeof(szRequestId) ? sizeof(szRequestId) - 1 : iValueLen;
|
||||
strncpy(szRequestId, szRequestIdPtr, iValueLen);
|
||||
szRequestId[iValueLen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
debug("MethodName=%s", szMethodName);
|
||||
@@ -405,9 +454,10 @@ void XmlRpcProcessor::Dispatch()
|
||||
command->SetRequest(szRequest);
|
||||
command->SetProtocol(m_eProtocol);
|
||||
command->SetHttpMethod(m_eHttpMethod);
|
||||
command->SetUserAccess(m_eUserAccess);
|
||||
command->PrepareParams();
|
||||
command->Execute();
|
||||
BuildResponse(command->GetResponse(), command->GetCallbackFunc(), command->GetFault());
|
||||
BuildResponse(command->GetResponse(), command->GetCallbackFunc(), command->GetFault(), szRequestId);
|
||||
delete command;
|
||||
}
|
||||
}
|
||||
@@ -470,17 +520,18 @@ void XmlRpcProcessor::MutliCall()
|
||||
command->SetProtocol(rpXmlRpc);
|
||||
command->PrepareParams();
|
||||
command->Execute();
|
||||
BuildResponse(command->GetResponse(), "", command->GetFault());
|
||||
BuildResponse(command->GetResponse(), "", command->GetFault(), NULL);
|
||||
delete command;
|
||||
}
|
||||
else
|
||||
{
|
||||
cStringBuilder.Append("</data></array>");
|
||||
BuildResponse(cStringBuilder.GetBuffer(), "", false);
|
||||
BuildResponse(cStringBuilder.GetBuffer(), "", false, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void XmlRpcProcessor::BuildResponse(const char* szResponse, const char* szCallbackFunc, bool bFault)
|
||||
void XmlRpcProcessor::BuildResponse(const char* szResponse, const char* szCallbackFunc,
|
||||
bool bFault, const char* szRequestId)
|
||||
{
|
||||
const char XML_HEADER[] = "<?xml version=\"1.0\"?>\n<methodResponse>\n";
|
||||
const char XML_FOOTER[] = "</methodResponse>";
|
||||
@@ -490,6 +541,8 @@ void XmlRpcProcessor::BuildResponse(const char* szResponse, const char* szCallba
|
||||
const char XML_FAULT_CLOSE[] = "</value></fault>\n";
|
||||
|
||||
const char JSON_HEADER[] = "{\n\"version\" : \"1.1\",\n";
|
||||
const char JSON_ID_OPEN[] = "\"id\" : ";
|
||||
const char JSON_ID_CLOSE[] = ",\n";
|
||||
const char JSON_FOOTER[] = "\n}";
|
||||
const char JSON_OK_OPEN[] = "\"result\" : ";
|
||||
const char JSON_OK_CLOSE[] = "";
|
||||
@@ -516,6 +569,12 @@ void XmlRpcProcessor::BuildResponse(const char* szResponse, const char* szCallba
|
||||
}
|
||||
m_cResponse.Append(szCallbackHeader);
|
||||
m_cResponse.Append(szHeader);
|
||||
if (!bXmlRpc && szRequestId && *szRequestId)
|
||||
{
|
||||
m_cResponse.Append(JSON_ID_OPEN);
|
||||
m_cResponse.Append(szRequestId);
|
||||
m_cResponse.Append(JSON_ID_CLOSE);
|
||||
}
|
||||
m_cResponse.Append(szOpenTag);
|
||||
m_cResponse.Append(szResponse);
|
||||
m_cResponse.Append(szCloseTag);
|
||||
@@ -529,7 +588,19 @@ XmlCommand* XmlRpcProcessor::CreateCommand(const char* szMethodName)
|
||||
{
|
||||
XmlCommand* command = NULL;
|
||||
|
||||
if (!strcasecmp(szMethodName, "pause") || !strcasecmp(szMethodName, "pausedownload") ||
|
||||
if (m_eUserAccess == uaAdd &&
|
||||
!(!strcasecmp(szMethodName, "append") || !strcasecmp(szMethodName, "appendurl") ||
|
||||
!strcasecmp(szMethodName, "version")))
|
||||
{
|
||||
command = new ErrorXmlCommand(401, "Access denied");
|
||||
warn("Received request \"%s\" from add-user, access denied", szMethodName);
|
||||
}
|
||||
else if (m_eUserAccess == uaRestricted && !strcasecmp(szMethodName, "saveconfig"))
|
||||
{
|
||||
command = new ErrorXmlCommand(401, "Access denied");
|
||||
warn("Received request \"%s\" from restricted user, access denied", szMethodName);
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "pause") || !strcasecmp(szMethodName, "pausedownload") ||
|
||||
!strcasecmp(szMethodName, "pausedownload2"))
|
||||
{
|
||||
command = new PauseUnpauseXmlCommand(true, PauseUnpauseXmlCommand::paDownload);
|
||||
@@ -595,6 +666,10 @@ XmlCommand* XmlRpcProcessor::CreateCommand(const char* szMethodName)
|
||||
{
|
||||
command = new ClearLogXmlCommand();
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "loadlog"))
|
||||
{
|
||||
command = new LoadLogXmlCommand();
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "scan"))
|
||||
{
|
||||
command = new ScanXmlCommand();
|
||||
@@ -683,6 +758,10 @@ XmlCommand* XmlRpcProcessor::CreateCommand(const char* szMethodName)
|
||||
{
|
||||
command = new ResetServerVolumeXmlCommand();
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "testserver"))
|
||||
{
|
||||
command = new TestServerXmlCommand();
|
||||
}
|
||||
else
|
||||
{
|
||||
command = new ErrorXmlCommand(1, "Invalid procedure");
|
||||
@@ -820,6 +899,10 @@ bool XmlCommand::NextParamAsInt(int* iValue)
|
||||
}
|
||||
*iValue = atoi(szParam + 1);
|
||||
m_szRequestPtr = szParam + 1;
|
||||
while (strchr("-+0123456789&", *m_szRequestPtr))
|
||||
{
|
||||
m_szRequestPtr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (IsJson())
|
||||
@@ -866,12 +949,12 @@ bool XmlCommand::NextParamAsBool(bool* bValue)
|
||||
|
||||
if (IsJson())
|
||||
{
|
||||
if (!strcmp(szParam, "true"))
|
||||
if (!strncmp(szParam, "true", 4))
|
||||
{
|
||||
*bValue = true;
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp(szParam, "false"))
|
||||
else if (!strncmp(szParam, "false", 5))
|
||||
{
|
||||
*bValue = false;
|
||||
return true;
|
||||
@@ -934,7 +1017,7 @@ bool XmlCommand::NextParamAsStr(char** szValue)
|
||||
}
|
||||
szParam++; // skip '='
|
||||
int iLen = 0;
|
||||
char* szParamEnd = strchr(m_szRequestPtr, '&');
|
||||
char* szParamEnd = strchr(szParam, '&');
|
||||
if (szParamEnd)
|
||||
{
|
||||
iLen = (int)(szParamEnd - szParam);
|
||||
@@ -1032,7 +1115,6 @@ ErrorXmlCommand::ErrorXmlCommand(int iErrCode, const char* szErrText)
|
||||
|
||||
void ErrorXmlCommand::Execute()
|
||||
{
|
||||
error("Received unsupported request: %s", m_szErrText);
|
||||
BuildErrorResponse(m_iErrCode, m_szErrText);
|
||||
}
|
||||
|
||||
@@ -1335,33 +1417,33 @@ void StatusXmlCommand::Execute()
|
||||
// struct[] log(idfrom, entries)
|
||||
void LogXmlCommand::Execute()
|
||||
{
|
||||
int iIDFrom = 0;
|
||||
int iNrEntries = 0;
|
||||
if (!NextParamAsInt(&iIDFrom) || !NextParamAsInt(&iNrEntries) || (iNrEntries > 0 && iIDFrom > 0))
|
||||
m_iIDFrom = 0;
|
||||
m_iNrEntries = 0;
|
||||
if (!NextParamAsInt(&m_iIDFrom) || !NextParamAsInt(&m_iNrEntries) || (m_iNrEntries > 0 && m_iIDFrom > 0))
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("iIDFrom=%i", iIDFrom);
|
||||
debug("iNrEntries=%i", iNrEntries);
|
||||
debug("iIDFrom=%i", m_iIDFrom);
|
||||
debug("iNrEntries=%i", m_iNrEntries);
|
||||
|
||||
AppendResponse(IsJson() ? "[\n" : "<array><data>\n");
|
||||
Log::Messages* pMessages = LockMessages();
|
||||
MessageList* pMessages = LockMessages();
|
||||
|
||||
int iStart = pMessages->size();
|
||||
if (iNrEntries > 0)
|
||||
if (m_iNrEntries > 0)
|
||||
{
|
||||
if (iNrEntries > (int)pMessages->size())
|
||||
if (m_iNrEntries > (int)pMessages->size())
|
||||
{
|
||||
iNrEntries = pMessages->size();
|
||||
m_iNrEntries = pMessages->size();
|
||||
}
|
||||
iStart = pMessages->size() - iNrEntries;
|
||||
iStart = pMessages->size() - m_iNrEntries;
|
||||
}
|
||||
if (iIDFrom > 0 && !pMessages->empty())
|
||||
if (m_iIDFrom > 0 && !pMessages->empty())
|
||||
{
|
||||
iNrEntries = pMessages->size();
|
||||
iStart = iIDFrom - pMessages->front()->GetID();
|
||||
m_iNrEntries = pMessages->size();
|
||||
iStart = m_iIDFrom - pMessages->front()->GetID();
|
||||
if (iStart < 0)
|
||||
{
|
||||
iStart = 0;
|
||||
@@ -1412,7 +1494,7 @@ void LogXmlCommand::Execute()
|
||||
AppendResponse(IsJson() ? "\n]" : "</data></array>\n");
|
||||
}
|
||||
|
||||
Log::Messages* LogXmlCommand::LockMessages()
|
||||
MessageList* LogXmlCommand::LockMessages()
|
||||
{
|
||||
return g_pLog->LockMessages();
|
||||
}
|
||||
@@ -1470,6 +1552,7 @@ void ListFilesXmlCommand::Execute()
|
||||
"<member><name>Category</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Priority</name><value><i4>%i</i4></value></member>\n" // deprecated, use "Priority" of group instead
|
||||
"<member><name>ActiveDownloads</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Progress</name><value><i4>%u</i4></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
const char* JSON_LIST_ITEM =
|
||||
@@ -1491,7 +1574,8 @@ void ListFilesXmlCommand::Execute()
|
||||
"\"DestDir\" : \"%s\",\n"
|
||||
"\"Category\" : \"%s\",\n"
|
||||
"\"Priority\" : %i,\n" // deprecated, use "Priority" of group instead
|
||||
"\"ActiveDownloads\" : %i\n"
|
||||
"\"ActiveDownloads\" : %i,\n"
|
||||
"\"Progress\" : %i\n"
|
||||
"}";
|
||||
|
||||
int iItemBufSize = 10240;
|
||||
@@ -1519,12 +1603,15 @@ void ListFilesXmlCommand::Execute()
|
||||
char* xmlCategory = EncodeStr(pFileInfo->GetNZBInfo()->GetCategory());
|
||||
char* xmlNZBNicename = EncodeStr(pFileInfo->GetNZBInfo()->GetName());
|
||||
|
||||
int iProgress = pFileInfo->GetFailedSize() == 0 && pFileInfo->GetSuccessSize() == 0 ? 0 :
|
||||
(int)(1000 - pFileInfo->GetRemainingSize() * 1000 / (pFileInfo->GetSize() - pFileInfo->GetMissedSize()));
|
||||
|
||||
snprintf(szItemBuf, iItemBufSize, IsJson() ? JSON_LIST_ITEM : XML_LIST_ITEM,
|
||||
pFileInfo->GetID(), iFileSizeLo, iFileSizeHi, iRemainingSizeLo, iRemainingSizeHi,
|
||||
pFileInfo->GetTime(), BoolToStr(pFileInfo->GetFilenameConfirmed()),
|
||||
BoolToStr(pFileInfo->GetPaused()), pFileInfo->GetNZBInfo()->GetID(), xmlNZBNicename,
|
||||
xmlNZBNicename, xmlNZBFilename, xmlSubject, xmlFilename, xmlDestDir, xmlCategory,
|
||||
pFileInfo->GetNZBInfo()->GetPriority(), pFileInfo->GetActiveDownloads());
|
||||
pFileInfo->GetNZBInfo()->GetPriority(), pFileInfo->GetActiveDownloads(), iProgress);
|
||||
szItemBuf[iItemBufSize-1] = '\0';
|
||||
|
||||
free(xmlNZBFilename);
|
||||
@@ -1551,148 +1638,150 @@ void ListFilesXmlCommand::Execute()
|
||||
void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
|
||||
{
|
||||
const char* XML_NZB_ITEM_START =
|
||||
"<member><name>NZBID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>NZBName</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>NZBNicename</name><value><string>%s</string></value></member>\n" // deprecated, use "NZBName" instead
|
||||
"<member><name>Kind</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>URL</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>NZBFilename</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DestDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FinalDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Category</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ParStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UnpackStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>MoveStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ScriptStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DeleteStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>MarkStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UrlStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>MinPostTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>MaxPostTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>TotalArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>SuccessArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FailedArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Health</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>CriticalHealth</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DupeKey</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DupeScore</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DupeMode</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Deleted</name><value><boolean>%s</boolean></value></member>\n" // deprecated, use "DeleteStatus" instead
|
||||
"<member><name>DownloadedSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PostTotalTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>ParTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RepairTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>UnpackTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Parameters</name><value><array><data>\n";
|
||||
"<member><name>NZBID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>NZBName</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>NZBNicename</name><value><string>%s</string></value></member>\n" // deprecated, use "NZBName" instead
|
||||
"<member><name>Kind</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>URL</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>NZBFilename</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DestDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FinalDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Category</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ParStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UnpackStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>MoveStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ScriptStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DeleteStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>MarkStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UrlStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>MinPostTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>MaxPostTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>TotalArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>SuccessArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FailedArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Health</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>CriticalHealth</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DupeKey</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>DupeScore</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DupeMode</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Deleted</name><value><boolean>%s</boolean></value></member>\n" // deprecated, use "DeleteStatus" instead
|
||||
"<member><name>DownloadedSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PostTotalTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>ParTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RepairTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>UnpackTimeSec</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>MessageCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Parameters</name><value><array><data>\n";
|
||||
|
||||
const char* XML_NZB_ITEM_SCRIPT_START =
|
||||
"</data></array></value></member>\n"
|
||||
"<member><name>ScriptStatuses</name><value><array><data>\n";
|
||||
"</data></array></value></member>\n"
|
||||
"<member><name>ScriptStatuses</name><value><array><data>\n";
|
||||
|
||||
const char* XML_NZB_ITEM_STATS_START =
|
||||
"</data></array></value></member>\n"
|
||||
"<member><name>ServerStats</name><value><array><data>\n";
|
||||
"</data></array></value></member>\n"
|
||||
"<member><name>ServerStats</name><value><array><data>\n";
|
||||
|
||||
const char* XML_NZB_ITEM_END =
|
||||
"</data></array></value></member>\n";
|
||||
"</data></array></value></member>\n";
|
||||
|
||||
const char* JSON_NZB_ITEM_START =
|
||||
"\"NZBID\" : %i,\n"
|
||||
"\"NZBName\" : \"%s\",\n"
|
||||
"\"NZBNicename\" : \"%s\",\n" // deprecated, use NZBName instead
|
||||
"\"Kind\" : \"%s\",\n"
|
||||
"\"URL\" : \"%s\",\n"
|
||||
"\"NZBFilename\" : \"%s\",\n"
|
||||
"\"DestDir\" : \"%s\",\n"
|
||||
"\"FinalDir\" : \"%s\",\n"
|
||||
"\"Category\" : \"%s\",\n"
|
||||
"\"ParStatus\" : \"%s\",\n"
|
||||
"\"UnpackStatus\" : \"%s\",\n"
|
||||
"\"MoveStatus\" : \"%s\",\n"
|
||||
"\"ScriptStatus\" : \"%s\",\n"
|
||||
"\"DeleteStatus\" : \"%s\",\n"
|
||||
"\"MarkStatus\" : \"%s\",\n"
|
||||
"\"UrlStatus\" : \"%s\",\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
"\"FileSizeMB\" : %i,\n"
|
||||
"\"FileCount\" : %i,\n"
|
||||
"\"MinPostTime\" : %i,\n"
|
||||
"\"MaxPostTime\" : %i,\n"
|
||||
"\"TotalArticles\" : %i,\n"
|
||||
"\"SuccessArticles\" : %i,\n"
|
||||
"\"FailedArticles\" : %i,\n"
|
||||
"\"Health\" : %i,\n"
|
||||
"\"CriticalHealth\" : %i,\n"
|
||||
"\"DupeKey\" : \"%s\",\n"
|
||||
"\"DupeScore\" : %i,\n"
|
||||
"\"DupeMode\" : \"%s\",\n"
|
||||
"\"Deleted\" : %s,\n" // deprecated, use "DeleteStatus" instead
|
||||
"\"DownloadedSizeLo\" : %u,\n"
|
||||
"\"DownloadedSizeHi\" : %u,\n"
|
||||
"\"DownloadedSizeMB\" : %i,\n"
|
||||
"\"DownloadTimeSec\" : %i,\n"
|
||||
"\"PostTotalTimeSec\" : %i,\n"
|
||||
"\"ParTimeSec\" : %i,\n"
|
||||
"\"RepairTimeSec\" : %i,\n"
|
||||
"\"UnpackTimeSec\" : %i,\n"
|
||||
"\"Parameters\" : [\n";
|
||||
"\"NZBID\" : %i,\n"
|
||||
"\"NZBName\" : \"%s\",\n"
|
||||
"\"NZBNicename\" : \"%s\",\n" // deprecated, use NZBName instead
|
||||
"\"Kind\" : \"%s\",\n"
|
||||
"\"URL\" : \"%s\",\n"
|
||||
"\"NZBFilename\" : \"%s\",\n"
|
||||
"\"DestDir\" : \"%s\",\n"
|
||||
"\"FinalDir\" : \"%s\",\n"
|
||||
"\"Category\" : \"%s\",\n"
|
||||
"\"ParStatus\" : \"%s\",\n"
|
||||
"\"UnpackStatus\" : \"%s\",\n"
|
||||
"\"MoveStatus\" : \"%s\",\n"
|
||||
"\"ScriptStatus\" : \"%s\",\n"
|
||||
"\"DeleteStatus\" : \"%s\",\n"
|
||||
"\"MarkStatus\" : \"%s\",\n"
|
||||
"\"UrlStatus\" : \"%s\",\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
"\"FileSizeMB\" : %i,\n"
|
||||
"\"FileCount\" : %i,\n"
|
||||
"\"MinPostTime\" : %i,\n"
|
||||
"\"MaxPostTime\" : %i,\n"
|
||||
"\"TotalArticles\" : %i,\n"
|
||||
"\"SuccessArticles\" : %i,\n"
|
||||
"\"FailedArticles\" : %i,\n"
|
||||
"\"Health\" : %i,\n"
|
||||
"\"CriticalHealth\" : %i,\n"
|
||||
"\"DupeKey\" : \"%s\",\n"
|
||||
"\"DupeScore\" : %i,\n"
|
||||
"\"DupeMode\" : \"%s\",\n"
|
||||
"\"Deleted\" : %s,\n" // deprecated, use "DeleteStatus" instead
|
||||
"\"DownloadedSizeLo\" : %u,\n"
|
||||
"\"DownloadedSizeHi\" : %u,\n"
|
||||
"\"DownloadedSizeMB\" : %i,\n"
|
||||
"\"DownloadTimeSec\" : %i,\n"
|
||||
"\"PostTotalTimeSec\" : %i,\n"
|
||||
"\"ParTimeSec\" : %i,\n"
|
||||
"\"RepairTimeSec\" : %i,\n"
|
||||
"\"UnpackTimeSec\" : %i,\n"
|
||||
"\"MessageCount\" : %i,\n"
|
||||
"\"Parameters\" : [\n";
|
||||
|
||||
const char* JSON_NZB_ITEM_SCRIPT_START =
|
||||
"],\n"
|
||||
"\"ScriptStatuses\" : [\n";
|
||||
"],\n"
|
||||
"\"ScriptStatuses\" : [\n";
|
||||
|
||||
const char* JSON_NZB_ITEM_STATS_START =
|
||||
"],\n"
|
||||
"\"ServerStats\" : [\n";
|
||||
"],\n"
|
||||
"\"ServerStats\" : [\n";
|
||||
|
||||
const char* JSON_NZB_ITEM_END =
|
||||
"],\n";
|
||||
"]\n";
|
||||
|
||||
const char* XML_PARAMETER_ITEM =
|
||||
"<value><struct>\n"
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Value</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
"<value><struct>\n"
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Value</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
const char* JSON_PARAMETER_ITEM =
|
||||
"{\n"
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"Value\" : \"%s\"\n"
|
||||
"}";
|
||||
"{\n"
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"Value\" : \"%s\"\n"
|
||||
"}";
|
||||
|
||||
const char* XML_SCRIPT_ITEM =
|
||||
"<value><struct>\n"
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Status</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
"<value><struct>\n"
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Status</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
const char* JSON_SCRIPT_ITEM =
|
||||
"{\n"
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"Status\" : \"%s\"\n"
|
||||
"}";
|
||||
"{\n"
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"Status\" : \"%s\"\n"
|
||||
"}";
|
||||
|
||||
const char* XML_STAT_ITEM =
|
||||
"<value><struct>\n"
|
||||
"<member><name>ServerID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>SuccessArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FailedArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
"<value><struct>\n"
|
||||
"<member><name>ServerID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>SuccessArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FailedArticles</name><value><i4>%i</i4></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
const char* JSON_STAT_ITEM =
|
||||
"{\n"
|
||||
"\"ServerID\" : %i,\n"
|
||||
"\"SuccessArticles\" : %i,\n"
|
||||
"\"FailedArticles\" : %i\n"
|
||||
"}";
|
||||
"{\n"
|
||||
"\"ServerID\" : %i,\n"
|
||||
"\"SuccessArticles\" : %i,\n"
|
||||
"\"FailedArticles\" : %i\n"
|
||||
"}";
|
||||
|
||||
const char* szKindName[] = { "NZB", "URL" };
|
||||
const char* szParStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS", "REPAIR_POSSIBLE", "MANUAL" };
|
||||
@@ -1700,7 +1789,7 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
|
||||
const char* szMoveStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
|
||||
const char* szScriptStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
|
||||
const char* szDeleteStatusName[] = { "NONE", "MANUAL", "HEALTH", "DUPE", "BAD" };
|
||||
const char* szMarkStatusName[] = { "NONE", "BAD", "GOOD" };
|
||||
const char* szMarkStatusName[] = { "NONE", "BAD", "GOOD", "SUCCESS" };
|
||||
const char* szUrlStatusName[] = { "NONE", "UNKNOWN", "SUCCESS", "FAILURE", "UNKNOWN", "SCAN_SKIPPED", "SCAN_FAILURE" };
|
||||
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
|
||||
|
||||
@@ -1715,6 +1804,8 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
|
||||
Util::SplitInt64(pNZBInfo->GetDownloadedSize(), &iDownloadedSizeHi, &iDownloadedSizeLo);
|
||||
iDownloadedSizeMB = (int)(pNZBInfo->GetDownloadedSize() / 1024 / 1024);
|
||||
|
||||
int iMessageCount = pNZBInfo->GetMessageCount() > 0 ? pNZBInfo->GetMessageCount() : pNZBInfo->GetCachedMessageCount();
|
||||
|
||||
char* xmlURL = EncodeStr(pNZBInfo->GetURL());
|
||||
char* xmlNZBFilename = EncodeStr(pNZBInfo->GetFilename());
|
||||
char* xmlNZBNicename = EncodeStr(pNZBInfo->GetName());
|
||||
@@ -1739,7 +1830,7 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
|
||||
BoolToStr(pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone),
|
||||
iDownloadedSizeLo, iDownloadedSizeHi, iDownloadedSizeMB, pNZBInfo->GetDownloadSec(),
|
||||
pNZBInfo->GetPostInfo() && pNZBInfo->GetPostInfo()->GetStartTime() ? time(NULL) - pNZBInfo->GetPostInfo()->GetStartTime() : pNZBInfo->GetPostTotalSec(),
|
||||
pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec());
|
||||
pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec(), iMessageCount);
|
||||
|
||||
free(xmlURL);
|
||||
free(xmlNZBNicename);
|
||||
@@ -1913,7 +2004,7 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie
|
||||
|
||||
if (iLogEntries > 0 && pPostInfo)
|
||||
{
|
||||
PostInfo::Messages* pMessages = pPostInfo->LockMessages();
|
||||
MessageList* pMessages = pPostInfo->GetNZBInfo()->LockCachedMessages();
|
||||
if (!pMessages->empty())
|
||||
{
|
||||
if (iLogEntries > (int)pMessages->size())
|
||||
@@ -1939,7 +2030,7 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie
|
||||
AppendResponse(szItemBuf);
|
||||
}
|
||||
}
|
||||
pPostInfo->UnlockMessages();
|
||||
pPostInfo->GetNZBInfo()->UnlockCachedMessages();
|
||||
}
|
||||
|
||||
AppendResponse(IsJson() ? JSON_POSTQUEUE_ITEM_END : XML_POSTQUEUE_ITEM_END);
|
||||
@@ -2027,6 +2118,10 @@ void ListGroupsXmlCommand::Execute()
|
||||
AppendResponse(szItemBuf);
|
||||
|
||||
AppendNZBInfoFields(pNZBInfo);
|
||||
if (IsJson())
|
||||
{
|
||||
AppendResponse(",\n");
|
||||
}
|
||||
AppendPostInfoFields(pNZBInfo->GetPostInfo(), iNrEntries, false);
|
||||
|
||||
AppendResponse(IsJson() ? JSON_LIST_ITEM_END : XML_LIST_ITEM_END);
|
||||
@@ -2101,6 +2196,7 @@ EditCommandEntry EditCommandNameMap[] = {
|
||||
{ DownloadQueue::eaGroupSetDupeKey, "GroupSetDupeKey" },
|
||||
{ DownloadQueue::eaGroupSetDupeScore, "GroupSetDupeScore" },
|
||||
{ DownloadQueue::eaGroupSetDupeMode, "GroupSetDupeMode" },
|
||||
{ DownloadQueue::eaGroupSort, "GroupSort" },
|
||||
{ DownloadQueue::eaPostDelete, "PostDelete" },
|
||||
{ DownloadQueue::eaHistoryDelete, "HistoryDelete" },
|
||||
{ DownloadQueue::eaHistoryFinalDelete, "HistoryFinalDelete" },
|
||||
@@ -2114,6 +2210,9 @@ EditCommandEntry EditCommandNameMap[] = {
|
||||
{ DownloadQueue::eaHistorySetDupeBackup, "HistorySetDupeBackup" },
|
||||
{ DownloadQueue::eaHistoryMarkBad, "HistoryMarkBad" },
|
||||
{ DownloadQueue::eaHistoryMarkGood, "HistoryMarkGood" },
|
||||
{ DownloadQueue::eaHistoryMarkSuccess, "HistoryMarkSuccess" },
|
||||
{ DownloadQueue::eaHistorySetCategory, "HistorySetCategory" },
|
||||
{ DownloadQueue::eaHistorySetName, "HistorySetName" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
@@ -2387,6 +2486,10 @@ void PostQueueXmlCommand::Execute()
|
||||
AppendResponse(szItemBuf);
|
||||
|
||||
AppendNZBInfoFields(pPostInfo->GetNZBInfo());
|
||||
if (IsJson())
|
||||
{
|
||||
AppendResponse(",\n");
|
||||
}
|
||||
AppendPostInfoFields(pPostInfo, iNrEntries, true);
|
||||
|
||||
AppendResponse(IsJson() ? JSON_POSTQUEUE_ITEM_END : XML_POSTQUEUE_ITEM_END);
|
||||
@@ -2485,44 +2588,22 @@ void HistoryXmlCommand::Execute()
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>RemainingFileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>HistoryTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Status</name><value><string>%s</string></value></member>\n";
|
||||
|
||||
const char* XML_HISTORY_ITEM_LOG_START =
|
||||
"<member><name>Log</name><value><array><data>\n";
|
||||
|
||||
const char* XML_HISTORY_ITEM_END =
|
||||
"</data></array></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
"<member><name>Status</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Log</name><value><array><data></data></array></value></member>\n"; // Deprected, always empty
|
||||
|
||||
const char* JSON_HISTORY_ITEM_START =
|
||||
"{\n"
|
||||
"\"ID\" : %i,\n" // Deprecated, use "NZBID" instead
|
||||
"\"ID\" : %i,\n" // Deprecated, use "NZBID" instead
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"RemainingFileCount\" : %i,\n"
|
||||
"\"HistoryTime\" : %i,\n"
|
||||
"\"Status\" : \"%s\",\n";
|
||||
"\"Status\" : \"%s\",\n"
|
||||
"\"Log\" : [],\n"; // Deprected, always empty
|
||||
|
||||
const char* JSON_HISTORY_ITEM_LOG_START =
|
||||
"\"Log\" : [\n";
|
||||
const char* XML_HISTORY_ITEM_END =
|
||||
"</struct></value>";
|
||||
|
||||
const char* JSON_HISTORY_ITEM_END =
|
||||
"]\n"
|
||||
"}";
|
||||
|
||||
const char* XML_LOG_ITEM =
|
||||
"<value><struct>\n"
|
||||
"<member><name>ID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Kind</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Time</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>Text</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
const char* JSON_LOG_ITEM =
|
||||
"{\n"
|
||||
"\"ID\" : %i,\n"
|
||||
"\"Kind\" : \"%s\",\n"
|
||||
"\"Time\" : %i,\n"
|
||||
"\"Text\" : \"%s\"\n"
|
||||
"}";
|
||||
|
||||
const char* XML_HISTORY_DUP_ITEM =
|
||||
@@ -2555,10 +2636,9 @@ void HistoryXmlCommand::Execute()
|
||||
"\"DupeScore\" : %i,\n"
|
||||
"\"DupeMode\" : \"%s\",\n"
|
||||
"\"DupStatus\" : \"%s\",\n"
|
||||
"\"Status\" : \"%s\",\n";
|
||||
"\"Status\" : \"%s\"\n";
|
||||
|
||||
const char* szDupStatusName[] = { "UNKNOWN", "SUCCESS", "FAILURE", "DELETED", "DUPE", "BAD", "GOOD" };
|
||||
const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"};
|
||||
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
|
||||
|
||||
bool bDup = false;
|
||||
@@ -2629,34 +2709,6 @@ void HistoryXmlCommand::Execute()
|
||||
AppendNZBInfoFields(pNZBInfo);
|
||||
}
|
||||
|
||||
AppendResponse(IsJson() ? JSON_HISTORY_ITEM_LOG_START : XML_HISTORY_ITEM_LOG_START);
|
||||
|
||||
if (pNZBInfo)
|
||||
{
|
||||
// Log-Messages
|
||||
NZBInfo::Messages* pMessages = pNZBInfo->LockMessages();
|
||||
if (!pMessages->empty())
|
||||
{
|
||||
int iLogIndex = 0;
|
||||
for (NZBInfo::Messages::iterator it = pMessages->begin(); it != pMessages->end(); it++)
|
||||
{
|
||||
Message* pMessage = *it;
|
||||
char* xmltext = EncodeStr(pMessage->GetText());
|
||||
snprintf(szItemBuf, iItemBufSize, IsJson() ? JSON_LOG_ITEM : XML_LOG_ITEM,
|
||||
pMessage->GetID(), szMessageType[pMessage->GetKind()], pMessage->GetTime(), xmltext);
|
||||
szItemBuf[iItemBufSize-1] = '\0';
|
||||
free(xmltext);
|
||||
|
||||
if (IsJson() && iLogIndex++ > 0)
|
||||
{
|
||||
AppendResponse(",\n");
|
||||
}
|
||||
AppendResponse(szItemBuf);
|
||||
}
|
||||
}
|
||||
pNZBInfo->UnlockMessages();
|
||||
}
|
||||
|
||||
AppendResponse(IsJson() ? JSON_HISTORY_ITEM_END : XML_HISTORY_ITEM_END);
|
||||
}
|
||||
free(szItemBuf);
|
||||
@@ -2779,7 +2831,8 @@ void ConfigXmlCommand::Execute()
|
||||
Options::OptEntry* pOptEntry = *it;
|
||||
|
||||
char* xmlName = EncodeStr(pOptEntry->GetName());
|
||||
char* xmlValue = EncodeStr(pOptEntry->GetValue());
|
||||
char* xmlValue = EncodeStr(m_eUserAccess == XmlRpcProcessor::uaRestricted &&
|
||||
pOptEntry->Restricted() ? "***" : pOptEntry->GetValue());
|
||||
|
||||
// option values can sometimes have unlimited length
|
||||
int iValLen = strlen(xmlValue);
|
||||
@@ -2843,7 +2896,8 @@ void LoadConfigXmlCommand::Execute()
|
||||
Options::OptEntry* pOptEntry = *it;
|
||||
|
||||
char* xmlName = EncodeStr(pOptEntry->GetName());
|
||||
char* xmlValue = EncodeStr(pOptEntry->GetValue());
|
||||
char* xmlValue = EncodeStr(m_eUserAccess == XmlRpcProcessor::uaRestricted &&
|
||||
pOptEntry->Restricted() ? "***" : pOptEntry->GetValue());
|
||||
|
||||
// option values can sometimes have unlimited length
|
||||
int iValLen = strlen(xmlValue);
|
||||
@@ -3342,7 +3396,7 @@ void StartUpdateXmlCommand::Execute()
|
||||
}
|
||||
|
||||
// struct[] logupdate(idfrom, entries)
|
||||
Log::Messages* LogUpdateXmlCommand::LockMessages()
|
||||
MessageList* LogUpdateXmlCommand::LockMessages()
|
||||
{
|
||||
return g_pMaintenance->LockMessages();
|
||||
}
|
||||
@@ -3538,3 +3592,101 @@ void ResetServerVolumeXmlCommand::Execute()
|
||||
|
||||
BuildBoolResponse(bOK);
|
||||
}
|
||||
|
||||
// struct[] loadlog(nzbid, logidfrom, logentries)
|
||||
void LoadLogXmlCommand::Execute()
|
||||
{
|
||||
m_pNZBInfo = NULL;
|
||||
m_iNZBID = 0;
|
||||
if (!NextParamAsInt(&m_iNZBID))
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
LogXmlCommand::Execute();
|
||||
}
|
||||
|
||||
MessageList* LoadLogXmlCommand::LockMessages()
|
||||
{
|
||||
// TODO: optimize for m_iIDFrom and m_iNrEntries
|
||||
g_pDiskState->LoadNZBMessages(m_iNZBID, &m_messages);
|
||||
|
||||
if (m_messages.empty())
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
|
||||
m_pNZBInfo = pDownloadQueue->GetQueue()->Find(m_iNZBID);
|
||||
if (m_pNZBInfo)
|
||||
{
|
||||
return m_pNZBInfo->LockCachedMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadQueue::Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return &m_messages;
|
||||
}
|
||||
|
||||
void LoadLogXmlCommand::UnlockMessages()
|
||||
{
|
||||
if (m_pNZBInfo)
|
||||
{
|
||||
m_pNZBInfo->UnlockCachedMessages();
|
||||
DownloadQueue::Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// string testserver(string host, int port, string username, string password, bool encryption, string cipher, int timeout);
|
||||
void TestServerXmlCommand::Execute()
|
||||
{
|
||||
const char* XML_RESPONSE_STR_BODY = "<string>%s</string>";
|
||||
const char* JSON_RESPONSE_STR_BODY = "\"%s\"";
|
||||
|
||||
if (!CheckSafeMethod())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* szHost;
|
||||
int iPort;
|
||||
char* szUsername;
|
||||
char* szPassword;
|
||||
bool bEncryption;
|
||||
char* szCipher;
|
||||
int iTimeout;
|
||||
|
||||
if (!NextParamAsStr(&szHost) || !NextParamAsInt(&iPort) || !NextParamAsStr(&szUsername) ||
|
||||
!NextParamAsStr(&szPassword) || !NextParamAsBool(&bEncryption) ||
|
||||
!NextParamAsStr(&szCipher) || !NextParamAsInt(&iTimeout))
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
NewsServer server(0, true, "test server", szHost, iPort, szUsername, szPassword, false, bEncryption, szCipher, 1, 0, 0, 0);
|
||||
TestConnection* pConnection = new TestConnection(&server, this);
|
||||
pConnection->SetTimeout(iTimeout == 0 ? g_pOptions->GetArticleTimeout() : iTimeout);
|
||||
pConnection->SetSuppressErrors(false);
|
||||
m_szErrText = NULL;
|
||||
|
||||
bool bOK = pConnection->Connect();
|
||||
|
||||
char szContent[1024];
|
||||
snprintf(szContent, 1024, IsJson() ? JSON_RESPONSE_STR_BODY : XML_RESPONSE_STR_BODY,
|
||||
bOK ? "" : Util::EmptyStr(m_szErrText) ? "Unknown error" : m_szErrText);
|
||||
szContent[1024-1] = '\0';
|
||||
|
||||
AppendResponse(szContent);
|
||||
|
||||
delete pConnection;
|
||||
}
|
||||
|
||||
void TestServerXmlCommand::PrintError(const char* szErrMsg)
|
||||
{
|
||||
if (!m_szErrText)
|
||||
{
|
||||
m_szErrText = EncodeStr(szErrMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,24 +48,33 @@ public:
|
||||
hmGet
|
||||
};
|
||||
|
||||
enum EUserAccess
|
||||
{
|
||||
uaControl,
|
||||
uaRestricted,
|
||||
uaAdd
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szRequest;
|
||||
const char* m_szContentType;
|
||||
ERpcProtocol m_eProtocol;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
EUserAccess m_eUserAccess;
|
||||
char* m_szUrl;
|
||||
StringBuilder m_cResponse;
|
||||
|
||||
void Dispatch();
|
||||
XmlCommand* CreateCommand(const char* szMethodName);
|
||||
void MutliCall();
|
||||
void BuildResponse(const char* szResponse, const char* szCallbackFunc, bool bFault);
|
||||
void BuildResponse(const char* szResponse, const char* szCallbackFunc, bool bFault, const char* szRequestId);
|
||||
|
||||
public:
|
||||
XmlRpcProcessor();
|
||||
~XmlRpcProcessor();
|
||||
void Execute();
|
||||
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
void SetUserAccess(EUserAccess eUserAccess) { m_eUserAccess = eUserAccess; }
|
||||
void SetUrl(const char* szUrl);
|
||||
void SetRequest(char* szRequest) { m_szRequest = szRequest; }
|
||||
const char* GetResponse() { return m_cResponse.GetBuffer(); }
|
||||
@@ -83,6 +92,7 @@ protected:
|
||||
bool m_bFault;
|
||||
XmlRpcProcessor::ERpcProtocol m_eProtocol;
|
||||
XmlRpcProcessor::EHttpMethod m_eHttpMethod;
|
||||
XmlRpcProcessor::EUserAccess m_eUserAccess;
|
||||
|
||||
void BuildErrorResponse(int iErrCode, const char* szErrText, ...);
|
||||
void BuildBoolResponse(bool bOK);
|
||||
@@ -106,6 +116,7 @@ public:
|
||||
void SetRequest(char* szRequest) { m_szRequest = szRequest; m_szRequestPtr = m_szRequest; }
|
||||
void SetProtocol(XmlRpcProcessor::ERpcProtocol eProtocol) { m_eProtocol = eProtocol; }
|
||||
void SetHttpMethod(XmlRpcProcessor::EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
void SetUserAccess(XmlRpcProcessor::EUserAccess eUserAccess) { m_eUserAccess = eUserAccess; }
|
||||
const char* GetResponse() { return m_StringBuilder.GetBuffer(); }
|
||||
const char* GetCallbackFunc() { return m_szCallbackFunc; }
|
||||
bool GetFault() { return m_bFault; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -179,7 +179,7 @@ void debug(const char* msg, ...)
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDebugTarget() : Options::mtScreen;
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkDebug, tmp2);
|
||||
g_pLog->AddMessage(Message::mkDebug, tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
@@ -205,7 +205,7 @@ void error(const char* msg, ...)
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetErrorTarget() : Options::mtBoth;
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkError, tmp2);
|
||||
g_pLog->AddMessage(Message::mkError, tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
@@ -230,7 +230,7 @@ void warn(const char* msg, ...)
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetWarningTarget() : Options::mtScreen;
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkWarning, tmp2);
|
||||
g_pLog->AddMessage(Message::mkWarning, tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
@@ -255,7 +255,7 @@ void info(const char* msg, ...)
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetInfoTarget() : Options::mtScreen;
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkInfo, tmp2);
|
||||
g_pLog->AddMessage(Message::mkInfo, tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
@@ -280,7 +280,7 @@ void detail(const char* msg, ...)
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDetailTarget() : Options::mtScreen;
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkDetail, tmp2);
|
||||
g_pLog->AddMessage(Message::mkDetail, tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
@@ -334,18 +334,28 @@ Message::~ Message()
|
||||
free(m_szText);
|
||||
}
|
||||
|
||||
void Log::Clear()
|
||||
MessageList::~MessageList()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
Clear();
|
||||
}
|
||||
|
||||
void MessageList::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
clear();
|
||||
}
|
||||
|
||||
void Log::Clear()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
m_Messages.Clear();
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void Log::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
void Log::AddMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
Message* pMessage = new Message(++m_iIDGen, eKind, time(NULL), szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
@@ -361,7 +371,7 @@ void Log::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
}
|
||||
}
|
||||
|
||||
Log::Messages* Log::LockMessages()
|
||||
MessageList* Log::LockMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
@@ -433,7 +443,7 @@ void Log::RotateLog()
|
||||
char szMessage[1024];
|
||||
snprintf(szMessage, 1024, "Deleting old log-file %s\n", filename);
|
||||
szMessage[1024-1] = '\0';
|
||||
g_pLog->AppendMessage(Message::mkInfo, szMessage);
|
||||
g_pLog->AddMessage(Message::mkInfo, szMessage);
|
||||
|
||||
remove(szFullFilename);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -76,6 +76,15 @@ public:
|
||||
const char* GetText() { return m_szText; }
|
||||
};
|
||||
|
||||
typedef std::deque<Message*> MessageListBase;
|
||||
|
||||
class MessageList: public MessageListBase
|
||||
{
|
||||
public:
|
||||
~MessageList();
|
||||
void Clear();
|
||||
};
|
||||
|
||||
class Debuggable
|
||||
{
|
||||
protected:
|
||||
@@ -86,12 +95,11 @@ protected:
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
typedef std::deque<Message*> Messages;
|
||||
typedef std::list<Debuggable*> Debuggables;
|
||||
|
||||
private:
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
MessageList m_Messages;
|
||||
Debuggables m_Debuggables;
|
||||
Mutex m_mutexDebug;
|
||||
char* m_szLogFilename;
|
||||
@@ -102,7 +110,7 @@ private:
|
||||
#endif
|
||||
|
||||
void Filelog(const char* msg, ...);
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
void AddMessage(Message::EKind eKind, const char* szText);
|
||||
void RotateLog();
|
||||
|
||||
friend void error(const char* msg, ...);
|
||||
@@ -121,7 +129,7 @@ private:
|
||||
public:
|
||||
Log();
|
||||
~Log();
|
||||
Messages* LockMessages();
|
||||
MessageList* LockMessages();
|
||||
void UnlockMessages();
|
||||
void Clear();
|
||||
void ResetLog();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -132,7 +132,14 @@ void EnvironmentStrings::InitFromCurrentProcess()
|
||||
for (int i = 0; (*g_szEnvironmentVariables)[i]; i++)
|
||||
{
|
||||
char* szVar = (*g_szEnvironmentVariables)[i];
|
||||
Append(strdup(szVar));
|
||||
// Ignore all env vars set by NZBGet.
|
||||
// This is to avoid the passing of env vars after program update (when NZBGet is
|
||||
// started from a script which was started by a previous instance of NZBGet).
|
||||
// Format: NZBXX_YYYY (XX are any two characters, YYYY are any number of any characters).
|
||||
if (!(!strncmp(szVar, "NZB", 3) && strlen(szVar) > 5 && szVar[5] == '_'))
|
||||
{
|
||||
Append(strdup(szVar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +209,7 @@ ScriptController::ScriptController()
|
||||
m_bTerminated = false;
|
||||
m_bDetached = false;
|
||||
m_hProcess = 0;
|
||||
m_environmentStrings.InitFromCurrentProcess();
|
||||
ResetEnv();
|
||||
|
||||
m_mutexRunning.Lock();
|
||||
m_RunningScripts.push_back(this);
|
||||
@@ -225,9 +232,13 @@ ScriptController::~ScriptController()
|
||||
|
||||
void ScriptController::UnregisterRunningScript()
|
||||
{
|
||||
m_mutexRunning.Lock();
|
||||
m_RunningScripts.erase(std::find(m_RunningScripts.begin(), m_RunningScripts.end(), this));
|
||||
m_mutexRunning.Unlock();
|
||||
m_mutexRunning.Lock();
|
||||
RunningScripts::iterator it = std::find(m_RunningScripts.begin(), m_RunningScripts.end(), this);
|
||||
if (it != m_RunningScripts.end())
|
||||
{
|
||||
m_RunningScripts.erase(it);
|
||||
}
|
||||
m_mutexRunning.Unlock();
|
||||
}
|
||||
|
||||
void ScriptController::ResetEnv()
|
||||
@@ -401,6 +412,8 @@ int ScriptController::Execute()
|
||||
|
||||
CreatePipe(&hReadPipe, &hWritePipe, &SecurityAttributes, 0);
|
||||
|
||||
SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
STARTUPINFO StartupInfo;
|
||||
memset(&StartupInfo, 0, sizeof(StartupInfo));
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
@@ -422,15 +435,15 @@ int ScriptController::Execute()
|
||||
szErrMsg[255-1] = '\0';
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
{
|
||||
error("Could not start %s: %s", m_szInfoName, szErrMsg);
|
||||
PrintMessage(Message::mkError, "Could not start %s: %s", m_szInfoName, szErrMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not start %s: error %i", m_szInfoName, dwErrCode);
|
||||
PrintMessage(Message::mkError, "Could not start %s: error %i", m_szInfoName, dwErrCode);
|
||||
}
|
||||
if (!Util::FileExists(m_szScript))
|
||||
{
|
||||
error("Could not find file %s", m_szScript);
|
||||
PrintMessage(Message::mkError, "Could not find file %s", m_szScript);
|
||||
}
|
||||
free(szEnvironmentStrings);
|
||||
return -1;
|
||||
@@ -455,7 +468,7 @@ int ScriptController::Execute()
|
||||
// create the pipe
|
||||
if (pipe(p))
|
||||
{
|
||||
error("Could not open pipe: errno %i", errno);
|
||||
PrintMessage(Message::mkError, "Could not open pipe: errno %i", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -469,7 +482,7 @@ int ScriptController::Execute()
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
error("Could not start %s: errno %i", m_szInfoName, errno);
|
||||
PrintMessage(Message::mkError, "Could not start %s: errno %i", m_szInfoName, errno);
|
||||
free(pEnvironmentStrings);
|
||||
return -1;
|
||||
}
|
||||
@@ -529,7 +542,7 @@ int ScriptController::Execute()
|
||||
m_pReadpipe = fdopen(pipein, "r");
|
||||
if (!m_pReadpipe)
|
||||
{
|
||||
error("Could not open pipe to %s", m_szInfoName);
|
||||
PrintMessage(Message::mkError, "Could not open pipe to %s", m_szInfoName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -637,6 +650,12 @@ void ScriptController::Terminate()
|
||||
// wait 60 seconds for process to terminate
|
||||
WaitForSingleObject(m_hProcess, 60 * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dExitCode = 0;
|
||||
GetExitCodeProcess(m_hProcess, &dExitCode);
|
||||
bOK = dExitCode != STILL_ACTIVE;
|
||||
}
|
||||
#else
|
||||
pid_t hKillProcess = m_hProcess;
|
||||
if (getpgid(hKillProcess) == hKillProcess)
|
||||
@@ -682,6 +701,12 @@ void ScriptController::Detach()
|
||||
fclose(pReadpipe);
|
||||
}
|
||||
|
||||
void ScriptController::Resume()
|
||||
{
|
||||
m_bTerminated = false;
|
||||
m_bDetached = false;
|
||||
m_hProcess = 0;
|
||||
}
|
||||
|
||||
bool ScriptController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -92,6 +92,7 @@ public:
|
||||
virtual ~ScriptController();
|
||||
int Execute();
|
||||
void Terminate();
|
||||
void Resume();
|
||||
void Detach();
|
||||
static void TerminateAll();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -215,6 +215,13 @@ void Thread::Stop()
|
||||
m_bStopped = true;
|
||||
}
|
||||
|
||||
void Thread::Resume()
|
||||
{
|
||||
debug("Resuming Thread");
|
||||
|
||||
m_bStopped = false;
|
||||
}
|
||||
|
||||
bool Thread::Kill()
|
||||
{
|
||||
debug("Killing Thread");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
virtual void Resume();
|
||||
bool Kill();
|
||||
|
||||
bool IsStopped() { return m_bStopped; };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -260,6 +260,14 @@ StringBuilder::~StringBuilder()
|
||||
free(m_szBuffer);
|
||||
}
|
||||
|
||||
void StringBuilder::Clear()
|
||||
{
|
||||
free(m_szBuffer);
|
||||
m_szBuffer = NULL;
|
||||
m_iBufferSize = 0;
|
||||
m_iUsedSize = 0;
|
||||
}
|
||||
|
||||
void StringBuilder::Append(const char* szStr)
|
||||
{
|
||||
int iPartLen = strlen(szStr);
|
||||
@@ -972,6 +980,30 @@ void Util::ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize)
|
||||
#endif
|
||||
}
|
||||
|
||||
void Util::GetExeFileName(const char* argv0, char* szBuffer, int iBufSize)
|
||||
{
|
||||
#ifdef WIN32
|
||||
GetModuleFileName(NULL, szBuffer, iBufSize);
|
||||
#else
|
||||
// Linux
|
||||
int r = readlink("/proc/self/exe", szBuffer, iBufSize-1);
|
||||
if (r > 0)
|
||||
{
|
||||
szBuffer[r] = '\0';
|
||||
return;
|
||||
}
|
||||
// FreeBSD
|
||||
r = readlink("/proc/curproc/file", szBuffer, iBufSize-1);
|
||||
if (r > 0)
|
||||
{
|
||||
szBuffer[r] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
ExpandFileName(argv0, szBuffer, iBufSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Util::FormatFileSize(char * szBuffer, int iBufLen, long long lFileSize)
|
||||
{
|
||||
if (lFileSize > 1024 * 1024 * 1000)
|
||||
@@ -1014,6 +1046,14 @@ bool Util::MatchFileExt(const char* szFilename, const char* szExtensionList, con
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (strchr(szExt, '*') || strchr(szExt, '?'))
|
||||
{
|
||||
WildMask mask(szExt);
|
||||
if (mask.Match(szFilename))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1040,6 +1080,28 @@ char* Util::GetLastErrorMessage(char* szBuffer, int iBufLen)
|
||||
return szBuffer;
|
||||
}
|
||||
|
||||
void Util::FormatSpeed(int iBytesPerSecond, char* szBuffer, int iBufSize)
|
||||
{
|
||||
if (iBytesPerSecond >= 100 * 1024 * 1024)
|
||||
{
|
||||
snprintf(szBuffer, iBufSize, "%i MB/s", iBytesPerSecond / 1024 / 1024);
|
||||
}
|
||||
else if (iBytesPerSecond >= 10 * 1024 * 1024)
|
||||
{
|
||||
snprintf(szBuffer, iBufSize, "%0.1f MB/s", (float)iBytesPerSecond / 1024.0 / 1024.0);
|
||||
}
|
||||
else if (iBytesPerSecond >= 1024 * 1000)
|
||||
{
|
||||
snprintf(szBuffer, iBufSize, "%0.2f MB/s", (float)iBytesPerSecond / 1024.0 / 1024.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szBuffer, iBufSize, "%i KB/s", iBytesPerSecond / 1024);
|
||||
}
|
||||
|
||||
szBuffer[iBufSize - 1] = '\0';
|
||||
}
|
||||
|
||||
void Util::InitVersionRevision()
|
||||
{
|
||||
#ifndef WIN32
|
||||
@@ -1279,7 +1341,7 @@ inline int days_from_0(int year)
|
||||
}
|
||||
inline int days_from_1970(int year)
|
||||
{
|
||||
static const int days_from_0_to_1970 = days_from_0(1970);
|
||||
static const int days_from_0_to_1970 = 719162; // days_from_0(1970);
|
||||
return days_from_0(year) - days_from_0_to_1970;
|
||||
}
|
||||
inline int days_from_1jan(int year,int month,int day)
|
||||
@@ -1318,6 +1380,11 @@ inline time_t internal_timegm(tm const *t)
|
||||
return result;
|
||||
}
|
||||
|
||||
time_t Util::Timegm(tm const *t)
|
||||
{
|
||||
return internal_timegm(t);
|
||||
}
|
||||
|
||||
// prevent PC from going to sleep
|
||||
void Util::SetStandByMode(bool bStandBy)
|
||||
{
|
||||
@@ -1326,11 +1393,6 @@ void Util::SetStandByMode(bool bStandBy)
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t Util::Timegm(tm const *t)
|
||||
{
|
||||
return internal_timegm(t);
|
||||
}
|
||||
|
||||
static unsigned long crc32_tab[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@@ -2030,6 +2092,38 @@ BreakLoop:
|
||||
*output = '\0';
|
||||
}
|
||||
|
||||
void WebUtil::URLDecode(char* raw)
|
||||
{
|
||||
char* output = raw;
|
||||
for (char* p = raw;;)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '\0':
|
||||
goto BreakLoop;
|
||||
case '%':
|
||||
{
|
||||
p++;
|
||||
unsigned char c1 = *p++;
|
||||
unsigned char c2 = *p++;
|
||||
c1 = '0' <= c1 && c1 <= '9' ? c1 - '0' : 'A' <= c1 && c1 <= 'F' ? c1 - 'A' + 10 :
|
||||
'a' <= c1 && c1 <= 'f' ? c1 - 'a' + 10 : 0;
|
||||
c2 = '0' <= c2 && c2 <= '9' ? c2 - '0' : 'A' <= c2 && c2 <= 'F' ? c2 - 'A' + 10 :
|
||||
'a' <= c2 && c2 <= 'f' ? c2 - 'a' + 10 : 0;
|
||||
unsigned char ch = (c1 << 4) + c2;
|
||||
*output++ = (char)ch;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*output++ = *p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BreakLoop:
|
||||
|
||||
*output = '\0';
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
bool WebUtil::Utf8ToAnsi(char* szBuffer, int iBufLen)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
~StringBuilder();
|
||||
void Append(const char* szStr);
|
||||
const char* GetBuffer() { return m_szBuffer; }
|
||||
void Clear();
|
||||
};
|
||||
|
||||
class Util
|
||||
@@ -109,10 +110,12 @@ public:
|
||||
static void FixExecPermission(const char* szFilename);
|
||||
#endif
|
||||
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
static void GetExeFileName(const char* argv0, char* szBuffer, int iBufSize);
|
||||
static void FormatFileSize(char* szBuffer, int iBufLen, long long lFileSize);
|
||||
static bool SameFilename(const char* szFilename1, const char* szFilename2);
|
||||
static bool MatchFileExt(const char* szFilename, const char* szExtensionList, const char* szListSeparator);
|
||||
static char* GetLastErrorMessage(char* szBuffer, int iBufLen);
|
||||
static void FormatSpeed(int iBytesPerSecond, char* szBuffer, int iBufSize);
|
||||
|
||||
/*
|
||||
* Split command line int arguments.
|
||||
@@ -235,6 +238,12 @@ public:
|
||||
*/
|
||||
static void HttpUnquote(char* raw);
|
||||
|
||||
/*
|
||||
* Decodes URL-string.
|
||||
* The string is decoded on the place overwriting the content of raw-data.
|
||||
*/
|
||||
static void URLDecode(char* raw);
|
||||
|
||||
#ifdef WIN32
|
||||
static bool Utf8ToAnsi(char* szBuffer, int iBufLen);
|
||||
static bool AnsiToUtf8(char* szBuffer, int iBufLen);
|
||||
|
||||
@@ -201,3 +201,24 @@ void InstallUninstallServiceCheck(int argc, char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsServiceRunning()
|
||||
{
|
||||
SC_HANDLE scm = OpenSCManager(0, 0, 0);
|
||||
if (!scm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SC_HANDLE hService = OpenService(scm, "NZBGet", SERVICE_QUERY_STATUS);
|
||||
SERVICE_STATUS ServiceStatus;
|
||||
bool bRunning = false;
|
||||
if (hService && QueryServiceStatus(hService, &ServiceStatus))
|
||||
{
|
||||
bRunning = ServiceStatus.dwCurrentState != SERVICE_STOPPED;
|
||||
}
|
||||
|
||||
CloseServiceHandle(scm);
|
||||
|
||||
return bRunning;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,5 +30,6 @@ typedef void (*RunProc)(void);
|
||||
|
||||
void InstallUninstallServiceCheck(int argc, char *argv[]);
|
||||
void StartService(RunProc RunProcPtr);
|
||||
bool IsServiceRunning();
|
||||
|
||||
#endif
|
||||
|
||||
1138
daemon/windows/WinConsole.cpp
Normal file
1138
daemon/windows/WinConsole.cpp
Normal file
File diff suppressed because it is too large
Load Diff
106
daemon/windows/WinConsole.h
Normal file
106
daemon/windows/WinConsole.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2014-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WINCONSOLE_H
|
||||
#define WINCONSOLE_H
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
class WinConsole : public Thread
|
||||
{
|
||||
private:
|
||||
bool m_bAppMode;
|
||||
char** m_pDefaultArguments;
|
||||
char** m_pInitialArguments;
|
||||
int m_iInitialArgumentCount;
|
||||
HWND m_hTrayWindow;
|
||||
NOTIFYICONDATA* m_pNidIcon;
|
||||
UINT UM_TASKBARCREATED;
|
||||
HMENU m_hMenu;
|
||||
HINSTANCE m_hInstance;
|
||||
bool m_bModal;
|
||||
HFONT m_hLinkFont;
|
||||
HFONT m_hNameFont;
|
||||
HFONT m_hTitleFont;
|
||||
HCURSOR m_hHandCursor;
|
||||
HICON m_hAboutIcon;
|
||||
HICON m_hRunningIcon;
|
||||
HICON m_hIdleIcon;
|
||||
HICON m_hWorkingIcon;
|
||||
HICON m_hPausedIcon;
|
||||
bool m_bAutostart;
|
||||
bool m_bTray;
|
||||
bool m_bConsole;
|
||||
bool m_bWebUI;
|
||||
bool m_bAutoParam;
|
||||
bool m_bRunning;
|
||||
bool m_bRunningService;
|
||||
|
||||
void CreateResources();
|
||||
void CreateTrayIcon();
|
||||
void ShowWebUI();
|
||||
void ShowMenu();
|
||||
void ShowInExplorer(const char* szFileName);
|
||||
void ShowAboutBox();
|
||||
void OpenConfigFileInTextEdit();
|
||||
void ShowPrefsDialog();
|
||||
void SavePrefs();
|
||||
void LoadPrefs();
|
||||
void ApplyPrefs();
|
||||
void ShowRunningDialog();
|
||||
void CheckRunning();
|
||||
void UpdateTrayIcon();
|
||||
void BuildMenu();
|
||||
void ShowCategoryDir(int iCatIndex);
|
||||
void SetupConfigFile();
|
||||
void SetupScripts();
|
||||
void ShowFactoryResetDialog();
|
||||
void ResetFactoryDefaults();
|
||||
|
||||
static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType);
|
||||
static LRESULT CALLBACK TrayWndProcStat(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
LRESULT TrayWndProc(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
BOOL AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
BOOL PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
BOOL RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
BOOL FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
protected:
|
||||
virtual void Run();
|
||||
|
||||
public:
|
||||
WinConsole();
|
||||
~WinConsole();
|
||||
virtual void Stop();
|
||||
void InitAppMode();
|
||||
bool GetAppMode() { return m_bAppMode; }
|
||||
void SetupFirstStart();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -71,7 +71,7 @@
|
||||
/* Define to 1 if spinlocks are supported */
|
||||
#define HAVE_SPINLOCK
|
||||
|
||||
#define VERSION "14.2"
|
||||
#define VERSION "15.0"
|
||||
|
||||
/* Suppress warnings */
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
@@ -81,6 +81,11 @@
|
||||
|
||||
#define _USE_32BIT_TIME_T
|
||||
|
||||
#if _WIN32_WINNT < 0x0501
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// detection of memory leaks
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
|
||||
@@ -586,7 +586,7 @@ bool Par2Repairer::LoadPacketsFromFile(string filename)
|
||||
|
||||
// Remember that the file was processed
|
||||
bool success = diskFileMap.Insert(diskfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1285,7 +1285,7 @@ bool Par2Repairer::VerifySourceFiles(void)
|
||||
|
||||
// Remember that we have processed this file
|
||||
bool success = diskFileMap.Insert(diskfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
// Do the actual verification
|
||||
if (!VerifyDataFile(diskfile, sourcefile))
|
||||
finalresult = false;
|
||||
@@ -1347,7 +1347,7 @@ bool Par2Repairer::VerifyExtraFiles(const list<CommandLine::ExtraFile> &extrafil
|
||||
|
||||
// Remember that we have processed this file
|
||||
bool success = diskFileMap.Insert(diskfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
|
||||
// Do the actual verification
|
||||
VerifyDataFile(diskfile, 0);
|
||||
@@ -2031,7 +2031,7 @@ bool Par2Repairer::RenameTargetFiles(void)
|
||||
return false;
|
||||
|
||||
bool success = diskFileMap.Insert(targetfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
|
||||
// We no longer have a target file
|
||||
sourcefile->SetTargetExists(false);
|
||||
@@ -2063,7 +2063,7 @@ bool Par2Repairer::RenameTargetFiles(void)
|
||||
return false;
|
||||
|
||||
bool success = diskFileMap.Insert(targetfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
|
||||
// This file is now the target file
|
||||
sourcefile->SetTargetExists(true);
|
||||
@@ -2112,7 +2112,7 @@ bool Par2Repairer::CreateTargetFiles(void)
|
||||
|
||||
// Remember this file
|
||||
bool success = diskFileMap.Insert(targetfile);
|
||||
assert(success);
|
||||
assert(success); (void)success;
|
||||
|
||||
u64 offset = 0;
|
||||
vector<DataBlock>::iterator tb = sourcefile->TargetBlocks();
|
||||
|
||||
124
linux/build-info.txt
Normal file
124
linux/build-info.txt
Normal file
@@ -0,0 +1,124 @@
|
||||
About
|
||||
-----
|
||||
"build-nzbget" is a bash script which is used to build universal installer
|
||||
for Linux. The script compiles NZBGet for each supported CPU-architecture
|
||||
and then packs all produced files into an installer package.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
To use the script you need a Linux (virtual) machine.
|
||||
|
||||
Building
|
||||
--------
|
||||
This script was written to work with toolchain from uClibc's Buildroot-project.
|
||||
|
||||
1. Create directory where you want to keep your files to compile NZBGet. Choose
|
||||
the path wisely because it cannot be changed later without rebuilding all
|
||||
toolchains again;
|
||||
|
||||
2. Put the build script 'build-nzbget' into that directory;
|
||||
|
||||
3. Create subdirectories:
|
||||
toolchain - for toolchains;
|
||||
nzbget - for source code of NZBGet;
|
||||
output - to store the results of build script;
|
||||
setup - for extra files required for installer;
|
||||
|
||||
4. Build toolchain for one CPU-architecture (see below);
|
||||
4.1. Download Buildroot distribution archive from http://buildroot.uclibc.org/download.html
|
||||
(tested with version "buildroot-2015.02");
|
||||
4.2. Unpack the tarball into 'toolchain'-directory;
|
||||
4.3. Rename the buildroot-directory according to the target CPU-architecture name;
|
||||
Be careful here, after the toolchain is built the directory cannot be renamed
|
||||
or moved, you will have to rebuild the toolchain if you want another name;
|
||||
4.4. Run 'make nconfig';
|
||||
4.5. Configure toolchain:
|
||||
- Target architecture:
|
||||
- choose your target architecture;
|
||||
- Build options:
|
||||
- libraries (both static and shared);
|
||||
- Toolchain:
|
||||
- Kernel Headers (Manually specified Linux version);
|
||||
- (2.6.30) linux version;
|
||||
- Custom kernel headers series (2.6.x);
|
||||
- Enable large file (files > 2 GB) support;
|
||||
- Enable IPv6 support;
|
||||
- Enable toolchain locale/i18n support;
|
||||
- GCC compiler Version (gcc 4.9.x);
|
||||
- Enable C++ support;
|
||||
- Build cross gdb for the host;
|
||||
- Target packages:
|
||||
- Libraries:
|
||||
- Compression and decompression: zlib;
|
||||
- Crypto: openssl;
|
||||
- JSON/XML: libxml2;
|
||||
- Text and terminal handling: ncurses;
|
||||
- Save configuration and exit;
|
||||
4.6. Do few extra manual adjustments:
|
||||
- in the file '.config' in the buildroot directory activate define to
|
||||
build 'ubacktrace';
|
||||
- in 'packages/ncurses/ncurses.mk' add extra configure parameters to
|
||||
option 'NCURSES_CONF_OPTS‘ (without quotation marks):
|
||||
"--with-fallbacks=xterm xterm-color xterm-256color xterm-16color linux vt100 vt200";
|
||||
- in 'packages/openssl/openssl.mk' replace 'zlib-dynamic' with 'zlib';
|
||||
4.7. Run 'make' to build the toolchain. It may take an hour or so depending
|
||||
on your hardware;
|
||||
|
||||
5. Now you should have a working toolchain for one CPU-architecture, let's
|
||||
test it.
|
||||
5.1. Change to the ROOTBUILD-directory and run the build script:
|
||||
|
||||
./nzbget-build release bin <CPU-Architecture>
|
||||
|
||||
5.2. The script creates subdirectory 'nzbget/trunk' and checkouts the source
|
||||
code of NZBGet from subversion repository;
|
||||
5.3. Then the source code is compiled for chosen CPU-architecture;
|
||||
5.4. After the compiling a distribution binary archive for the chosen
|
||||
CPU-architecture is put into output-directory;
|
||||
|
||||
6. Build unrar and 7za for the CPU-architecture:
|
||||
6.1. Download source of unrar; Compile for target, either manually or
|
||||
using script 'build-unpack';
|
||||
6.2. Put the compiled binaries of unrar and 7za into setup-directory, add
|
||||
suffix '-arch' to unrar and 7za names, for example 'unrar-armel';
|
||||
6.3. Copy license-files from unrar and 7-Zip projects using names
|
||||
'license-unrar.txt' and 'license-7zip.txt';
|
||||
|
||||
7. Now you can build installer for that one CPU-architecture:
|
||||
7.1. If you build for CPU-architecture which is not supported by NZBGet's
|
||||
universal installer you have to edit the script 'build-nzbget' and
|
||||
add the architecture name into variable 'ALLTARGETS';
|
||||
7.2. Run the build script with:
|
||||
|
||||
./nzbget-build release installer <CPU-Architecture>
|
||||
|
||||
7.3. The created installer supports only one CPU-Architecture;
|
||||
7.8. Run the installer on the target machine (with target CPU-Architecture);
|
||||
|
||||
8. Repeat step for each CPU-Architecture you intend to build the installer for;
|
||||
|
||||
9. To build installer for all CPU-Architectures listed in variable 'ALLTARGETS'
|
||||
of the script run the script without choosing CPU-Architecture:
|
||||
|
||||
./nzbget-build release installer
|
||||
|
||||
10. When the script is run without any parameters:
|
||||
10.1. NZBGet is compiled twice for each CPU-Architecture listed in
|
||||
'ALLTARGETS': once in release mode and once in debug mode;
|
||||
10.2. Two installers are built: one for release and another for debug.
|
||||
|
||||
Special functions
|
||||
-----------------
|
||||
By default the script builds from trunk/HEAD. To specify another tag or branch
|
||||
pass it to the script, for example to build a tagged version 14.2:
|
||||
|
||||
./nzbget-build release bin tags/14.2
|
||||
|
||||
Installers can built only for version 15.0 (starting from revision r1279).
|
||||
Distribution archives can be built for older versions too.
|
||||
|
||||
To build certain revision pass it to the script, for example
|
||||
|
||||
./nzbget-build release bin r1279
|
||||
|
||||
To cleanup the output directory before building pass parameter 'cleanup'.
|
||||
349
linux/build-nzbget
Executable file
349
linux/build-nzbget
Executable file
@@ -0,0 +1,349 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This file is part of nzbget
|
||||
#
|
||||
# Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# $Revision$
|
||||
# $Date$
|
||||
#
|
||||
|
||||
# Setup strict bash error handling
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
|
||||
# Uncomment next line for debuging
|
||||
#set -x
|
||||
|
||||
ALLTARGETS="dist i686 x86_64 armel armhf mipsel mipseb ppc6xx ppc500"
|
||||
ROOT=`pwd`
|
||||
ROOTPATH=$PATH
|
||||
OUTPUTDIR=$ROOT/output
|
||||
|
||||
echo "Usage:"
|
||||
echo " $(basename $0) [targets] [output] [revision] [reppath] [configs] [cleanup]"
|
||||
echo " targets : all (default) $ALLTARGETS"
|
||||
echo " output : bin installer"
|
||||
echo " revision : head (default) rXXXX work"
|
||||
echo " reppath : trunk (default) tags/XXX branches/XXX"
|
||||
echo " configs : release debug (default) release-nostrip debug-strip"
|
||||
echo " cleanup : cleanup output directory before building"
|
||||
echo
|
||||
|
||||
|
||||
# Parsing command line
|
||||
|
||||
BUILD=no
|
||||
TARGETS=""
|
||||
OUTPUTS=""
|
||||
REVISION=""
|
||||
REPPATH=""
|
||||
CONFIGS=""
|
||||
CLEAN=no
|
||||
|
||||
for PARAM in "$@"
|
||||
do
|
||||
case $PARAM in
|
||||
release|release-nostrip|debug|debug-strip)
|
||||
# using xargs to trim spaces
|
||||
CONFIGS=`echo "$CONFIGS $PARAM" | xargs`
|
||||
;;
|
||||
trunk|tags/*|branches/*)
|
||||
REPPATH="$PARAM"
|
||||
;;
|
||||
head|work|r[0-9]|r[0-9][0-9]|r[0-9][0-9][0-9]|r[0-9][0-9][0-9][0-9])
|
||||
REVISION="$PARAM"
|
||||
;;
|
||||
clean|cleanup)
|
||||
CLEAN=yes
|
||||
;;
|
||||
bin|installer)
|
||||
# using xargs to trim spaces
|
||||
OUTPUTS=`echo "$OUTPUTS $PARAM" | xargs`
|
||||
;;
|
||||
*)
|
||||
if [[ " $ALLTARGETS " == *" $PARAM "* ]]; then
|
||||
# using xargs to trim spaces
|
||||
TARGETS=`echo "$TARGETS $PARAM" | xargs`
|
||||
if [ "$PARAM" == "all" ]; then
|
||||
PARAM=$ALLTARGETS
|
||||
fi
|
||||
elif [ -d toolchain/$PARAM ]; then
|
||||
# non-standard target but the toolchain exist
|
||||
# using xargs to trim spaces
|
||||
TARGETS=`echo "$TARGETS $PARAM" | xargs`
|
||||
else
|
||||
echo "Invalid parameter: $PARAM"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
if [ "$TARGETS" == "" ]; then
|
||||
TARGETS="$ALLTARGETS"
|
||||
fi
|
||||
|
||||
if [ "$OUTPUTS" == "" ]; then
|
||||
OUTPUTS="bin installer"
|
||||
fi
|
||||
|
||||
if [ "$REVISION" == "" ]; then
|
||||
REVISION="head"
|
||||
fi
|
||||
|
||||
if [ "$REPPATH" == "" ]; then
|
||||
REPPATH="trunk"
|
||||
fi
|
||||
|
||||
if [ "$CONFIGS" == "" ]; then
|
||||
CONFIGS="release debug"
|
||||
fi
|
||||
|
||||
echo "Active configuration:"
|
||||
echo " targets : $TARGETS"
|
||||
echo " outputs : $OUTPUTS"
|
||||
echo " revision : $REVISION"
|
||||
echo " reppath : $REPPATH"
|
||||
echo " configs : $CONFIGS"
|
||||
echo " cleanup : $CLEAN"
|
||||
echo
|
||||
|
||||
|
||||
# Checkout and update from svn
|
||||
|
||||
cd nzbget
|
||||
|
||||
if [ ! -d $REPPATH ]; then
|
||||
echo "Initial checkout for $REPPATH"
|
||||
svn co https://svn.code.sf.net/p/nzbget/code/$REPPATH $REPPATH
|
||||
fi
|
||||
|
||||
BUILDDIR=$ROOT/nzbget/$REPPATH
|
||||
|
||||
cd $BUILDDIR
|
||||
|
||||
if [ "$REVISION" != "work" ]; then
|
||||
echo "Updating to $REVISION"
|
||||
svn -r $REVISION up
|
||||
touch Makefile.in configure config.h.in
|
||||
fi
|
||||
|
||||
|
||||
# File name format for output files
|
||||
|
||||
VERSION=`grep "AM_INIT_AUTOMAKE(nzbget, " configure.ac`
|
||||
VERSION=`expr "$VERSION" : '.*, \(.*\))'`
|
||||
REVISION=`svnversion`
|
||||
|
||||
BASENAME="nzbget-$VERSION"
|
||||
if [ `expr "$VERSION" : ".*-testing"` != 0 ]; then
|
||||
BASENAME="$BASENAME-r$REVISION"
|
||||
fi
|
||||
|
||||
|
||||
# Building
|
||||
|
||||
mkdir -p $OUTPUTDIR
|
||||
|
||||
if [ "$CLEAN" == "yes" ]; then
|
||||
rm -r -f $OUTPUTDIR/*
|
||||
fi
|
||||
|
||||
for CONFIG in $CONFIGS; do
|
||||
|
||||
case $CONFIG in
|
||||
release)
|
||||
SUFFIX=""
|
||||
;;
|
||||
debug)
|
||||
SUFFIX="-debug"
|
||||
;;
|
||||
debug-strip)
|
||||
SUFFIX="-debug-strip"
|
||||
;;
|
||||
release-nostrip)
|
||||
SUFFIX="-nostrip"
|
||||
;;
|
||||
esac
|
||||
|
||||
for OUTPUT in $OUTPUTS; do
|
||||
if [ "$OUTPUT" == "bin" ]; then
|
||||
for TARGET in $TARGETS; do
|
||||
|
||||
cd $BUILDDIR
|
||||
|
||||
echo "Building in `pwd` for $TARGET ($CONFIG)"
|
||||
|
||||
case $TARGET in
|
||||
mipsel|i?86|x86_64)
|
||||
ARCH=$TARGET
|
||||
;;
|
||||
mipseb)
|
||||
ARCH=mips
|
||||
;;
|
||||
arm*)
|
||||
ARCH=arm
|
||||
;;
|
||||
ppc*)
|
||||
ARCH=powerpc
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$TARGET" == "dist" ]; then
|
||||
if [ ! -f $OUTPUTDIR/$BASENAME.tar.gz ]; then
|
||||
./configure
|
||||
make dist
|
||||
cp nzbget-$VERSION.tar.gz $OUTPUTDIR/$BASENAME.tar.gz
|
||||
fi
|
||||
else
|
||||
PATH=:$ROOTPATH
|
||||
TOOLCHAIN_ROOT=$ROOT/toolchain/$TARGET
|
||||
PATH=$TOOLCHAIN_ROOT/output/host/usr/bin:$PATH
|
||||
|
||||
STRIP=""
|
||||
if [ $CONFIG == "debug-strip" -o $CONFIG == "release" ]; then
|
||||
STRIP="-s"
|
||||
fi
|
||||
|
||||
case $CONFIG in
|
||||
debug|debug-strip)
|
||||
LIBPREF="$TOOLCHAIN_ROOT/output/staging/usr" LDFLAGS="-static $STRIP" \
|
||||
LIBS="-lcrypto -ldl -lz -lubacktrace" CXXFLAGS="-g -fasynchronous-unwind-tables" \
|
||||
./configure --host=$ARCH-linux --enable-debug
|
||||
;;
|
||||
release|release-nostrip)
|
||||
LIBPREF="$TOOLCHAIN_ROOT/output/staging/usr" LDFLAGS="-static $STRIP" \
|
||||
LIBS="-lcrypto -ldl -lz" ./configure --host=$ARCH-linux
|
||||
;;
|
||||
esac
|
||||
|
||||
make clean && make
|
||||
|
||||
rm -r -f $OUTPUTDIR/install
|
||||
make DESTDIR=$OUTPUTDIR/install install
|
||||
|
||||
cd $OUTPUTDIR
|
||||
rm -r -f nzbget
|
||||
mkdir -p nzbget
|
||||
mv install/usr/local/bin/nzbget nzbget
|
||||
mv install/usr/local/share/doc/nzbget/* nzbget
|
||||
rm nzbget/AUTHORS
|
||||
mv install/usr/local/share/nzbget/webui nzbget
|
||||
mv install/usr/local/share/nzbget/scripts nzbget
|
||||
CONFTEMPLATE=nzbget/webui/nzbget.conf.template
|
||||
mv install/usr/local/share/nzbget/nzbget.conf $CONFTEMPLATE
|
||||
|
||||
rm -r -f $OUTPUTDIR/install
|
||||
|
||||
# adjusting nzbget.conf
|
||||
sed 's:^MainDir=.*:MainDir=${AppDir}/downloads:' -i $CONFTEMPLATE
|
||||
sed 's:^DestDir=.*:DestDir=${MainDir}/completed:' -i $CONFTEMPLATE
|
||||
sed 's:^InterDir=.*:InterDir=${MainDir}/intermediate:' -i $CONFTEMPLATE
|
||||
sed 's:^WebDir=.*:WebDir=${AppDir}/webui:' -i $CONFTEMPLATE
|
||||
sed 's:^ScriptDir=.*:ScriptDir=${AppDir}/scripts:' -i $CONFTEMPLATE
|
||||
sed 's:^LogFile=.*:LogFile=${MainDir}/nzbget.log:' -i $CONFTEMPLATE
|
||||
sed 's:^ConfigTemplate=.*:ConfigTemplate=${AppDir}/webui/nzbget.conf.template:' -i $CONFTEMPLATE
|
||||
sed 's:^AuthorizedIP=.*:AuthorizedIP=127.0.0.1:' -i $CONFTEMPLATE
|
||||
|
||||
tar -czf $BASENAME-bin-linux-$TARGET$SUFFIX.tar.gz nzbget
|
||||
|
||||
rm -r -f nzbget
|
||||
|
||||
echo "Completed build in `pwd` for $TARGET ($CONFIG)"
|
||||
fi
|
||||
done
|
||||
elif [ "$OUTPUT" == "installer" ]; then
|
||||
echo "Creating installer for $CONFIG..."
|
||||
|
||||
cd $OUTPUTDIR
|
||||
|
||||
# checking if all targets exists
|
||||
for TARGET in $TARGETS
|
||||
do
|
||||
ALLEXISTS="yes"
|
||||
if [ "$TARGET" != "dist" ]; then
|
||||
if [ ! -f $BASENAME-bin-linux-$TARGET$SUFFIX.tar.gz ]; then
|
||||
echo "Could not find $BASENAME-bin-linux-$TARGET$SUFFIX.tar.gz"
|
||||
ALLEXISTS="no"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ALLEXISTS" == "no" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
echo "Unpacking targets..."
|
||||
rm -r -f nzbget
|
||||
for TARGET in $TARGETS
|
||||
do
|
||||
ALLEXISTS="yes"
|
||||
if [ "$TARGET" != "dist" ]; then
|
||||
tar -xzf $BASENAME-bin-linux-$TARGET$SUFFIX.tar.gz
|
||||
mv nzbget/nzbget nzbget/nzbget-$TARGET
|
||||
cp ../setup/unrar-$TARGET nzbget
|
||||
cp ../setup/7za-$TARGET nzbget
|
||||
fi
|
||||
done
|
||||
|
||||
# adjusting nzbget.conf
|
||||
sed 's:^UnrarCmd=unrar:UnrarCmd=${AppDir}/unrar:' -i nzbget/webui/nzbget.conf.template
|
||||
sed 's:^SevenZipCmd=7z:SevenZipCmd=${AppDir}/7za:' -i nzbget/webui/nzbget.conf.template
|
||||
|
||||
INSTFILE=$BASENAME-bin-linux$SUFFIX.run
|
||||
|
||||
echo "Building installer package..."
|
||||
cp $BUILDDIR/linux/installer.sh $INSTFILE
|
||||
cp $BUILDDIR/linux/package-info.json nzbget/webui
|
||||
cp $BUILDDIR/linux/install-update.sh nzbget
|
||||
cp ../setup/license-unrar.txt nzbget
|
||||
cp ../setup/license-7zip.txt nzbget
|
||||
|
||||
# creating payload
|
||||
cd nzbget
|
||||
tar czf - * > ../$INSTFILE.data
|
||||
cd ..
|
||||
|
||||
# creating installer script
|
||||
sed "s:^TITLE=$:TITLE=\"$BASENAME$SUFFIX\":" -i $INSTFILE
|
||||
DISTTARGETS="${TARGETS/dist/}"
|
||||
DISTTARGETS=`echo "$DISTTARGETS" | xargs`
|
||||
sed "s:^DISTARCHS=$:DISTARCHS=\"$DISTTARGETS\":" -i $INSTFILE
|
||||
|
||||
PAYLOAD=`stat -c%s "$INSTFILE.data"`
|
||||
sed "s:^PAYLOAD=$:PAYLOAD=$PAYLOAD:" -i $INSTFILE
|
||||
|
||||
MD5=`md5sum "$INSTFILE.data" | cut -b-32`
|
||||
sed "s:^MD5=$:MD5=\"$MD5\":" -i $INSTFILE
|
||||
|
||||
HEADER=`stat -c%s "$INSTFILE"`
|
||||
LEN=${#HEADER}
|
||||
HEADER=`expr $HEADER + $LEN`
|
||||
sed "s:^HEADER=$:HEADER=$HEADER:" -i $INSTFILE
|
||||
|
||||
# attaching payload
|
||||
cat $INSTFILE.data >> $INSTFILE
|
||||
rm $INSTFILE.data
|
||||
chmod +x $INSTFILE
|
||||
|
||||
rm -r nzbget
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
180
linux/build-unpack
Executable file
180
linux/build-unpack
Executable file
@@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This file is part of nzbget
|
||||
#
|
||||
# Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# $Revision$
|
||||
# $Date$
|
||||
#
|
||||
|
||||
# Setup strict bash error handling
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
|
||||
# Uncomment next line for debuging
|
||||
#set -x
|
||||
|
||||
ALLTARGETS="i686 x86_64 armel armhf mipsel mipseb ppc6xx ppc500"
|
||||
ROOT=`pwd`
|
||||
OUTPUTDIR=$ROOT/setup
|
||||
BUILDDIR=temp
|
||||
|
||||
echo "Usage:"
|
||||
echo " $(basename $0) [targets] [clean] [unpacker]"
|
||||
echo " unpacker - unrar, 7zip."
|
||||
echo
|
||||
|
||||
|
||||
# Parsing command line
|
||||
|
||||
TARGETS=""
|
||||
CLEAN=no
|
||||
UNPACKERS=""
|
||||
|
||||
for PARAM in "$@"
|
||||
do
|
||||
case $PARAM in
|
||||
clean|cleanup)
|
||||
CLEAN=yes
|
||||
;;
|
||||
unrar|7zip)
|
||||
# using xargs to trim spaces
|
||||
UNPACKERS=`echo "$UNPACKERS $PARAM" | xargs`
|
||||
;;
|
||||
*)
|
||||
if [ -d toolchain/$PARAM ]; then
|
||||
TARGETS=`echo "$TARGETS $PARAM" | xargs`
|
||||
else
|
||||
echo "Invalid parameter: $PARAM"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
if [ "$TARGETS" == "" ]; then
|
||||
TARGETS="$ALLTARGETS"
|
||||
fi
|
||||
|
||||
if [ "$UNPACKERS" == "" ]; then
|
||||
UNPACKERS="unrar 7zip"
|
||||
fi
|
||||
|
||||
echo "Active configuration:"
|
||||
echo " targets : $TARGETS"
|
||||
echo " unpackers : $UNPACKERS"
|
||||
echo " cleanup : $CLEAN"
|
||||
echo
|
||||
|
||||
|
||||
# Building
|
||||
|
||||
for UNPACKER in $UNPACKERS; do
|
||||
|
||||
case $UNPACKER in
|
||||
unrar)
|
||||
EXENAME=unrar
|
||||
;;
|
||||
7zip)
|
||||
EXENAME=7za
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$CLEAN" == "yes" ]; then
|
||||
rm -r -f $OUTPUTDIR/$EXENAME-*
|
||||
fi
|
||||
|
||||
|
||||
for TARGET in $TARGETS; do
|
||||
|
||||
case $TARGET in
|
||||
mipsel|i?86|x86_64)
|
||||
ARCH=$TARGET
|
||||
ENDIAN=little
|
||||
;;
|
||||
mipseb)
|
||||
ARCH=mips
|
||||
ENDIAN=big
|
||||
;;
|
||||
arm*)
|
||||
ARCH=arm
|
||||
ENDIAN=little
|
||||
;;
|
||||
ppc*)
|
||||
ARCH=powerpc
|
||||
ENDIAN=big
|
||||
;;
|
||||
esac
|
||||
|
||||
TOOLCHAIN_ROOT=$ROOT/toolchain/$TARGET
|
||||
rm -rf "$ROOT/$BUILDDIR/$UNPACKER"
|
||||
cd $ROOT/$BUILDDIR
|
||||
|
||||
case $UNPACKER in
|
||||
unrar)
|
||||
tar xzf unrarsrc-*.tar.gz
|
||||
cd unrar
|
||||
sed 's:^CXX=g++:#CXX=g++:' -i makefile
|
||||
sed 's:^STRIP=strip:#STRIP=strip:' -i makefile
|
||||
sed 's:^LDFLAGS=:LDFLAGS=-static :' -i makefile
|
||||
sed 's:^CXXFLAGS=-O2:#CXXFLAGS=-O2:' -i makefile
|
||||
if test "$ENDIAN" = "big"; then
|
||||
sed 's:^DEFINES=:DEFINES=-DBIG_ENDIAN :' -i makefile
|
||||
fi
|
||||
|
||||
EXEDIR=
|
||||
LICENSE=license.txt
|
||||
BUILDTARGET=
|
||||
;;
|
||||
7zip)
|
||||
tar xjf p7zip_*_src_all.tar.bz2
|
||||
rm -rf 7zip
|
||||
mkdir 7zip
|
||||
mv p7zip_*/* 7zip
|
||||
find p7zip_* -maxdepth 0 -type d -exec rm -r {} \;
|
||||
cd 7zip
|
||||
rm makefile.machine
|
||||
cp makefile.linux_any_cpu_gcc_4.X makefile.machine
|
||||
sed 's:^CXX=g++:#CXX=g++:' -i makefile.machine
|
||||
sed 's:^CC=gcc:#CC=gcc:' -i makefile.machine
|
||||
|
||||
EXEDIR=bin/
|
||||
LICENSE=DOC/License.txt
|
||||
BUILDTARGET=$EXENAME
|
||||
;;
|
||||
esac
|
||||
|
||||
cd $ROOT/$BUILDDIR/$UNPACKER
|
||||
|
||||
make clean
|
||||
|
||||
CXX=$TOOLCHAIN_ROOT/output/host/usr/bin/$ARCH-linux-g++ \
|
||||
CC=$TOOLCHAIN_ROOT/output/host/usr/bin/$ARCH-linux-gcc \
|
||||
STRIP=$TOOLCHAIN_ROOT/output/host/usr/bin/$ARCH-linux-strip \
|
||||
CXXFLAGS=-g \
|
||||
LDFLAGS=-static \
|
||||
make $BUILDTARGET
|
||||
|
||||
cp $EXEDIR$EXENAME ../../setup/$EXENAME-$TARGET
|
||||
cp $LICENSE ../../setup/license-$UNPACKER.txt
|
||||
|
||||
echo "Completed build for $TARGET ($UNPACKER)"
|
||||
done
|
||||
done
|
||||
|
||||
116
linux/install-update.sh
Executable file
116
linux/install-update.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This file is part of nzbget
|
||||
#
|
||||
# Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
BASE_URL="http://nzbget.net/download"
|
||||
|
||||
if test "$NZBUP_PROCESSID" = ""; then
|
||||
echo "This file is not supposed to be executed directly. To update NZBGet please choose Settings -> SYSTEM -> Check for update in the web-interface."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INSTALLERCFG=`cat "$NZBOP_APPDIR/installer.cfg" 2>/dev/null`
|
||||
if test "$INSTALLERCFG" = ""; then
|
||||
echo "[ERROR] File \"installer.cfg\" is missing in the installation directory. Please reinstall NZBGet."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Downloading version information..."
|
||||
UPDATE_INFO_LINK=`cat "$NZBOP_APPDIR/webui/package-info.json" | sed -n 's/^.*update-info-link.*: "\(.*\)".*/\1/p'`
|
||||
"$NZBOP_APPBIN" -B webget "$NZBOP_TEMPDIR/NZBGET_UPDATE.txt" "$UPDATE_INFO_LINK" 2>/dev/null
|
||||
if test "$?" != "0"; then
|
||||
echo "[ERROR] Download failed, please try again later"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test "$NZBUP_BRANCH" = "TESTING"; then
|
||||
VER_FIELD="testing-version"
|
||||
elif test "$NZBUP_BRANCH" = "STABLE"; then
|
||||
VER_FIELD="stable-version"
|
||||
else
|
||||
echo "[ERROR] Unsupported branch $NZBUP_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VER=`cat "$NZBOP_TEMPDIR/NZBGET_UPDATE.txt" | sed -n "s/^.*$VER_FIELD.*: \"\(.*\)\".*/\1/p"`
|
||||
rm -f "$NZBOP_TEMPDIR/NZBGET_UPDATE.txt"
|
||||
|
||||
INSTALLER="nzbget-$VER-bin-linux.run"
|
||||
echo "Downloading $INSTALLER..."
|
||||
rm -f "$NZBOP_TEMPDIR/$INSTALLER"
|
||||
"$NZBOP_APPBIN" -B webget "$NZBOP_TEMPDIR/$INSTALLER" "$BASE_URL/$INSTALLER" 2>/dev/null
|
||||
if test "$?" != "0"; then
|
||||
echo "[ERROR] Download failed, please try again later"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Updating NZBGet..."
|
||||
echo "..."
|
||||
sh "$NZBOP_TEMPDIR/$INSTALLER" --update --destdir "$NZBOP_APPDIR"
|
||||
if test "$?" != "0"; then
|
||||
echo "[ERROR] Update failed, installer terminated with error status"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$NZBOP_TEMPDIR/$INSTALLER"
|
||||
echo "..."
|
||||
echo "Update completed"
|
||||
|
||||
echo "Restarting NZBGet..."
|
||||
sleep 1
|
||||
echo "[NZB] QUIT"
|
||||
|
||||
echo "Waiting for NZBGet to terminate"
|
||||
PSOPT="-A"
|
||||
OPTWORKING=`ps $PSOPT` 2>/dev/null
|
||||
if test "$?" != "0"; then
|
||||
PSOPT=""
|
||||
fi
|
||||
while true
|
||||
do
|
||||
RUNNING=`ps $PSOPT | sed -n "s/^\s*$NZBUP_PROCESSID\s.*/&/p"`
|
||||
if test "$RUNNING" = ""; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Starting NZBGet..."
|
||||
|
||||
# Recreating command line used to start NZBGet
|
||||
CMDLINE=
|
||||
NUM=1
|
||||
while true
|
||||
do
|
||||
PARAMNAME="NZBUP_CMDLINE$NUM"
|
||||
eval PARAM="\$NZBUP_CMDLINE${NUM}"
|
||||
if test "$PARAM" = ""; then
|
||||
break
|
||||
fi
|
||||
if test "$CMDLINE" != ""; then
|
||||
CMDLINE="$CMDLINE "
|
||||
fi
|
||||
CMDLINE="$CMDLINE\"$PARAM\""
|
||||
NUM=$((NUM + 1))
|
||||
done
|
||||
|
||||
# Starting NZBGet
|
||||
eval "$NZBOP_APPBIN" $CMDLINE
|
||||
|
||||
exit 0
|
||||
437
linux/installer.sh
Executable file
437
linux/installer.sh
Executable file
@@ -0,0 +1,437 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This file is part of nzbget
|
||||
#
|
||||
# Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
# Strict error handling for debugging
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
|
||||
# Installer title
|
||||
TITLE=
|
||||
# Size of installer script (package header)
|
||||
HEADER=
|
||||
# Size of tar.gz archive (package payload)
|
||||
PAYLOAD=
|
||||
# Md5 sum of payload
|
||||
MD5=
|
||||
# List of included CPU architecture binaries
|
||||
DISTARCHS=
|
||||
|
||||
SILENT=no
|
||||
ALLARCHS="$DISTARCHS all"
|
||||
ARCH=""
|
||||
SELECT=auto
|
||||
OUTDIR="nzbget"
|
||||
PRINTEDTITLE=no
|
||||
JUSTUNPACK=no
|
||||
UPDATE=no
|
||||
VERIFY=yes
|
||||
|
||||
Info()
|
||||
{
|
||||
if test "$SILENT" = "no"; then
|
||||
echo "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
Error()
|
||||
{
|
||||
Info "ERROR: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
ValidArch()
|
||||
{
|
||||
LIMARCH=`echo " $ALLARCHS " | sed "s/ $1 //"`
|
||||
if test " $ALLARCHS " = "$LIMARCH"; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
PrintArch()
|
||||
{
|
||||
if ValidArch $1; then
|
||||
Info "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
PrintHelp()
|
||||
{
|
||||
if test "$PRINTEDTITLE" = "no"; then
|
||||
Info "Installer for $TITLE"
|
||||
Info ""
|
||||
fi
|
||||
Info "This installer supports Linux kernel 2.6 or newer and the following CPU architectures:"
|
||||
PrintArch "i686" " i686 - x86, 32 or 64 Bit"
|
||||
PrintArch "x86_64" " x86_64 - x86, 64 Bit"
|
||||
PrintArch "armel" " armel - ARMv5/v6 (ARM9 and ARM11 families)"
|
||||
PrintArch "armhf" " armhf - ARMv7 (Cortex family)"
|
||||
PrintArch "mipsel" " mipsel - MIPS (little endian)"
|
||||
PrintArch "mipseb" " mipseb - MIPS (big endian)"
|
||||
PrintArch "ppc6xx" " ppc6xx - PowerPC 6xx (603e series)"
|
||||
PrintArch "ppc500" " ppc500 - PowerPC e500 (core e500v1/e500v2)"
|
||||
Info ""
|
||||
Info "Usage: sh $(basename $0) [options]"
|
||||
Info " --help - print this help"
|
||||
Info " --arch <cpu> - set CPU-architecture"
|
||||
Info " --destdir <path> - set destination directory"
|
||||
Info " --list - list package content"
|
||||
Info " --unpack - just unpack, skip setup"
|
||||
Info " --silent - silent mode"
|
||||
Info " --nocheck - skip integrity check"
|
||||
Info " --tar <args> - run custom tar command on archive"
|
||||
}
|
||||
|
||||
Verify()
|
||||
{
|
||||
REQSIZE=$((HEADER + PAYLOAD))
|
||||
ACTSIZE=`stat -c%s "$0" 2>/dev/null | cat`
|
||||
if test "$ACTSIZE" = ""; then
|
||||
NUM=1
|
||||
for FIELD in `ls -l "$0" 2>/dev/null`
|
||||
do
|
||||
if test "$NUM" = 5; then
|
||||
ACTSIZE="$FIELD"
|
||||
break
|
||||
fi
|
||||
NUM=$((NUM + 1))
|
||||
done
|
||||
fi
|
||||
if test "$REQSIZE" != "$ACTSIZE"; then
|
||||
Error "Corrupted installer package detected: file size mismatch."
|
||||
fi
|
||||
|
||||
ACTMD5=`dd "if=$0" bs=$HEADER skip=1 2>/dev/null | md5sum 2>/dev/null | cut -b-32 2>/dev/null | cat`
|
||||
LEN=${#ACTMD5}
|
||||
if test "$LEN" = "32" -a "$MD5" != "$ACTMD5"; then
|
||||
Error "Corrupted installer package detected: checksum mismatch."
|
||||
fi
|
||||
}
|
||||
|
||||
DetectEndianness()
|
||||
{
|
||||
# Sixth byte of any executable indicates endianness
|
||||
ENDBYTE=`dd if=/bin/sh bs=1 count=6 2>/dev/null | sed -n 's/ELF.\(.*\)/\1/p'`
|
||||
|
||||
ENDIAN=unknown
|
||||
if test $ENDBYTE="\x01"; then
|
||||
ENDIAN=little
|
||||
elif test $ENDBYTE="\x02"; then
|
||||
ENDIAN=big
|
||||
fi
|
||||
}
|
||||
|
||||
DetectArch()
|
||||
{
|
||||
OS=`uname -s`
|
||||
if test "$OS" != "Linux"; then
|
||||
PrintHelp
|
||||
Error "Operating system ($OS) isn't supported by this installer."
|
||||
fi
|
||||
|
||||
if test "$UPDATE" = "yes"; then
|
||||
ARCH=`cat "$OUTDIR/installer.cfg" 2>/dev/null | sed -n 's/^arch=\(.*\)$/\1/p'`
|
||||
SELECT=`cat "$OUTDIR/installer.cfg" 2>/dev/null | sed -n 's/^select=\(.*\)$/\1/p'`
|
||||
fi
|
||||
|
||||
if test "$ARCH" = ""; then
|
||||
CPU=`uname -m`
|
||||
case $CPU in
|
||||
i386|i686)
|
||||
ARCH=i686
|
||||
;;
|
||||
x86_64)
|
||||
ARCH=x86_64
|
||||
;;
|
||||
mips)
|
||||
ARCH=mipsx
|
||||
;;
|
||||
armv5*|armv6*|armel)
|
||||
ARCH=armel
|
||||
;;
|
||||
armv7*|armv8*)
|
||||
ARCH=armhf
|
||||
;;
|
||||
ppc)
|
||||
ARCH=ppcx
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$ARCH" = ""; then
|
||||
MIPS=`cat /proc/cpuinfo | sed -n 's/.*:.*\(mips\).*/&/p'`
|
||||
if test "$MIPS" != ""; then
|
||||
ARCH=mipsx
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$ARCH" = "mipsx"; then
|
||||
DetectEndianness
|
||||
if test "$ENDIAN" = "big"; then
|
||||
ARCH=mipseb
|
||||
else
|
||||
ARCH=mipsel
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$ARCH" = "ppcx"; then
|
||||
E500=`cat /proc/cpuinfo | sed -n 's/.*:.*\(e500\).*/&/p'`
|
||||
if test "$E500" != ""; then
|
||||
ARCH=ppc500
|
||||
else
|
||||
ARCH=ppc6xx
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$ARCH" = ""; then
|
||||
PrintHelp
|
||||
Error "CPU architecture ($CPU) isn't supported by this installer."
|
||||
fi
|
||||
|
||||
if ! ValidArch $ARCH; then
|
||||
Error "CPU architecture ($ARCH) isn't supported by this installer."
|
||||
fi
|
||||
}
|
||||
|
||||
Unpack()
|
||||
{
|
||||
# Prepare list of files to ignore
|
||||
EXARCHS=""
|
||||
if test "$JUSTUNPACK" = "no" -a "$ARCH" != "all"; then
|
||||
rm -f /tmp/nzbget-installer.tmp
|
||||
for TARG in $ALLARCHS
|
||||
do
|
||||
if test "$TARG" != "$ARCH"; then
|
||||
echo "nzbget-$TARG" >> /tmp/nzbget-installer.tmp
|
||||
echo "unrar-$TARG" >> /tmp/nzbget-installer.tmp
|
||||
echo "7za-$TARG" >> /tmp/nzbget-installer.tmp
|
||||
EXARCHS="-X /tmp/nzbget-installer.tmp"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Unpack (skip ignorable files)
|
||||
mkdir -p $OUTDIR
|
||||
dd "if=$0" bs=$HEADER skip=1 2> /dev/null | gzip -cd | ( cd $OUTDIR; tar x $EXARCHS 2>&1 ) || { Error "Unpacking failed."; kill -15 $$; }
|
||||
|
||||
if test "$EXARCHS" != ""; then
|
||||
rm -f /tmp/nzbget-installer.tmp
|
||||
fi
|
||||
|
||||
# Rename unpacked binaries files and store arch selection
|
||||
if test "$JUSTUNPACK" = "no" -a "$ARCH" != "all"; then
|
||||
OLDDIR=`pwd`
|
||||
cd $OUTDIR;
|
||||
rm -f nzbget
|
||||
rm -f unrar
|
||||
mv nzbget-$ARCH nzbget
|
||||
mv unrar-$ARCH unrar
|
||||
mv 7za-$ARCH 7za
|
||||
echo "arch=$ARCH" > "installer.cfg"
|
||||
echo "select=$SELECT" >> "installer.cfg"
|
||||
cd $OLDDIR
|
||||
fi
|
||||
}
|
||||
|
||||
TAR()
|
||||
{
|
||||
dd "if=$0" bs=$HEADER skip=1 2> /dev/null | gzip -cd | tar "$ARG" $@
|
||||
exit $?
|
||||
}
|
||||
|
||||
Configure()
|
||||
{
|
||||
cd $OUTDIR
|
||||
QUICKHELP=no
|
||||
|
||||
if test ! -f nzbget.conf; then
|
||||
cp ./webui/nzbget.conf.template nzbget.conf
|
||||
|
||||
MEMFREE=`cat /proc/meminfo | sed -n 's/^MemFree: *\([0-9]*\).*/\1/p' 2>/dev/null | cat`
|
||||
MEMCACHED=`cat /proc/meminfo | sed -n 's/^Cached: *\([0-9]*\).*/\1/p' 2>/dev/null | cat`
|
||||
if test "$MEMFREE" != "" -a "$MEMCACHED" != ""; then
|
||||
MEMFREE=$(((MEMFREE + MEMCACHED) / 1024))
|
||||
Info " Free memory detected: $MEMFREE MB"
|
||||
if test $MEMFREE -gt 250; then
|
||||
Info " Activating article cache (ArticleCache=100)"
|
||||
sed 's:^ArticleCache=.*:ArticleCache=100:' -i nzbget.conf
|
||||
Info " Increasing write buffer (WriteBuffer=1024)"
|
||||
sed 's:^WriteBuffer=.*:WriteBuffer=1024:' -i nzbget.conf
|
||||
Info " Increasing par repair buffer (ParBuffer=100)"
|
||||
sed 's:^ParBuffer=.*:ParBuffer=100:' -i nzbget.conf
|
||||
elif test $MEMFREE -gt 25; then
|
||||
Info " Increasing write buffer (WriteBuffer=256)"
|
||||
sed 's:^WriteBuffer=.*:WriteBuffer=256:' -i nzbget.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
BOGOLIST=`cat /proc/cpuinfo | sed -n 's/^bogomips\s*:\s\([0-9]*\).*/\1/pI' 2>/dev/null | cat`
|
||||
if test "$BOGOLIST" != ""; then
|
||||
BOGOMIPS=0
|
||||
for CPU1 in $BOGOLIST
|
||||
do
|
||||
BOGOMIPS=$((BOGOMIPS + CPU1))
|
||||
done
|
||||
Info " CPU speed detected: $BOGOMIPS BogoMIPS"
|
||||
if test $BOGOMIPS -lt 4000; then
|
||||
Info " Disabling download during par check/repair (ParPauseQueue=yes)"
|
||||
sed 's:^ParPauseQueue=.*:ParPauseQueue=yes:' -i nzbget.conf
|
||||
Info " Disabling download during unpack (UnpackPauseQueue=yes)"
|
||||
sed 's:^UnpackPauseQueue=.*:UnpackPauseQueue=yes:' -i nzbget.conf
|
||||
Info " Disabling download during post-processing (ScriptPauseQueue=yes)"
|
||||
sed 's:^ScriptPauseQueue=.*:ScriptPauseQueue=yes:' -i nzbget.conf
|
||||
else
|
||||
Info " Simultaneous download and post-processing is on"
|
||||
fi
|
||||
fi
|
||||
|
||||
QUICKHELP=yes
|
||||
fi
|
||||
}
|
||||
|
||||
# ParseCommandLine
|
||||
while true
|
||||
do
|
||||
PARAM=${1:-}
|
||||
case $PARAM in
|
||||
-h|--help)
|
||||
PrintHelp
|
||||
exit 0
|
||||
;;
|
||||
--silent)
|
||||
SILENT=yes
|
||||
shift
|
||||
;;
|
||||
--arch)
|
||||
ARCH=${2:-}
|
||||
SELECT=manual
|
||||
if ! ValidArch $ARCH; then
|
||||
PrintHelp
|
||||
Info ""
|
||||
Error "Bad argument ($ARCH) to option --arch."
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--destdir)
|
||||
OUTDIR=${2:-}
|
||||
if test "$OUTDIR" = ""; then
|
||||
PrintHelp
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--unpack)
|
||||
JUSTUNPACK=yes
|
||||
shift
|
||||
;;
|
||||
--list)
|
||||
ARG=t
|
||||
TAR
|
||||
exit $?
|
||||
;;
|
||||
--tar)
|
||||
ARG=${2:-}
|
||||
if test "$ARG" = ""; then
|
||||
PrintHelp
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
TAR
|
||||
exit $?
|
||||
;;
|
||||
--update)
|
||||
UPDATE=yes
|
||||
shift
|
||||
;;
|
||||
--nocheck)
|
||||
VERIFY=no
|
||||
shift
|
||||
;;
|
||||
"")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
PrintHelp
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
Info "Installer for $TITLE"
|
||||
if test "$SILENT" = "no"; then
|
||||
PRINTEDTITLE=yes
|
||||
fi
|
||||
|
||||
if test "$VERIFY" = "yes"; then
|
||||
Info "Verifying package..."
|
||||
Verify
|
||||
fi
|
||||
|
||||
if test "$JUSTUNPACK" = "no"; then
|
||||
Info "Checking system..."
|
||||
DetectArch
|
||||
if test "$SELECT" = "manual"; then
|
||||
Info "CPU-Architecture: $ARCH (manually set)"
|
||||
else
|
||||
Info "CPU-Architecture: $ARCH"
|
||||
fi
|
||||
fi
|
||||
|
||||
Info "Unpacking..."
|
||||
Unpack
|
||||
|
||||
ABSOUTDIR=`cd "$OUTDIR"; pwd`
|
||||
|
||||
if test "$JUSTUNPACK" = "no"; then
|
||||
Info "Configuring..."
|
||||
Configure
|
||||
|
||||
Info "Installation completed"
|
||||
|
||||
if test "$QUICKHELP" = "yes" -a "$SILENT" = "no"; then
|
||||
Info ""
|
||||
Info "Quick help (from nzbget-directory):"
|
||||
Info " ./nzbget -s - start nzbget in console mode"
|
||||
Info " ./nzbget -D - start nzbget in daemon mode (in background)"
|
||||
Info " ./nzbget -C - connect to background process"
|
||||
Info " ./nzbget -Q - stop background process"
|
||||
Info " ./nzbget -h - help screen with all commands"
|
||||
Info ""
|
||||
Info "Successfully installed into $ABSOUTDIR"
|
||||
IP=""
|
||||
{
|
||||
IP=`ifconfig | sed -rn 's/.*r:([^ ]+) .*/\1/p' | head -n 1` || true
|
||||
} > /dev/null 2>&1
|
||||
if test "$IP" = ""; then
|
||||
IP="localhost"
|
||||
fi
|
||||
Info "Web-interface runs on http://$IP:6789"
|
||||
else
|
||||
Info "Successfully installed into $ABSOUTDIR"
|
||||
fi
|
||||
Info "For support please visit http://nzbget.net/forum"
|
||||
else
|
||||
Info "Unpacked into $ABSOUTDIR"
|
||||
fi
|
||||
|
||||
exit
|
||||
#END-OF-INSTALLER
|
||||
4
linux/package-info.json
Normal file
4
linux/package-info.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"update-info-link": "http://nzbget.net/info/nzbget-version-linux.json",
|
||||
"install-script": "install-update.sh"
|
||||
}
|
||||
199
nzbget.conf
199
nzbget.conf
@@ -85,8 +85,14 @@ ScriptDir=${MainDir}/scripts
|
||||
|
||||
# Lock-file for daemon-mode, POSIX only.
|
||||
#
|
||||
# If the option is not empty, NZBGet creates the file and writes process-id
|
||||
# (PID) into it. That info can be used in shell scripts.
|
||||
# When started in daemon mode the program creates the lock file and
|
||||
# writes process-id (PID) into it. That info can be used in shell
|
||||
# scripts. If the lock file can not be created or the lock to the file
|
||||
# can not be acquired the daemon terminates, preventing unintentional
|
||||
# starting of multiple daemons.
|
||||
#
|
||||
# Set to empty value to disable the creating of the lock-file and the
|
||||
# check for another running instance (not recommended).
|
||||
LockFile=${MainDir}/nzbget.lock
|
||||
|
||||
# Where to store log file, if it needs to be created.
|
||||
@@ -196,6 +202,16 @@ Server1.Cipher=
|
||||
# Maximum number of simultaneous connections to this server (0-999).
|
||||
Server1.Connections=4
|
||||
|
||||
# Server retention time (days).
|
||||
#
|
||||
# How long the articles are stored on the news server. The articles
|
||||
# whose age exceed the defined server retention time are not tried on
|
||||
# this news server, the articles are instead considered failed on this
|
||||
# news server.
|
||||
#
|
||||
# Value "0" disables retention check.
|
||||
Server1.Retention=0
|
||||
|
||||
# Second server, on level 0.
|
||||
|
||||
#Server2.Level=0
|
||||
@@ -258,6 +274,52 @@ ControlUsername=nzbget
|
||||
# Set to empty value to disable authorization request.
|
||||
ControlPassword=tegbzn6789
|
||||
|
||||
# User name for restricted access.
|
||||
#
|
||||
# Restricted user can control the program with few restrictions. He
|
||||
# has access to web-interface and can see most program settings. He
|
||||
# can not change program settings and can not view security related
|
||||
# options or options provided by extension scripts.
|
||||
#
|
||||
# Use this user to connect to NZBGet from other programs and web-sites.
|
||||
#
|
||||
# In terms of RPC-API the user:
|
||||
# - cannot use method "saveconfig";
|
||||
# - methods "config" and "saveconfig" return string "***" for
|
||||
# options those content is protected from the user.
|
||||
#
|
||||
# Set to empty value to disable restricted user.
|
||||
#
|
||||
# NOTE: Don't forget to change default username/password of the control
|
||||
# user (options <ControlUsername> and <ControlPassword>).
|
||||
RestrictedUsername=
|
||||
|
||||
# Password for restricted access.
|
||||
#
|
||||
# Set to empty value to disable password check.
|
||||
RestrictedPassword=
|
||||
|
||||
# User name to add downloads via RPC-API.
|
||||
#
|
||||
# Use the AddUsername/AddPassword to give other programs or web-services
|
||||
# access to NZBGet with only two permissions:
|
||||
# - add new downloads using RPC-method "append";
|
||||
# - check program version using RPC-method "version".
|
||||
#
|
||||
# In a case the program/web-service needs more rights use the restricted
|
||||
# user instead (options <RestrictedUsername> and <RestrictedPassword>).
|
||||
#
|
||||
# Set to empty value to disable add-user.
|
||||
#
|
||||
# NOTE: Don't forget to change default username/password of the control
|
||||
# user (options <ControlUsername> and <ControlPassword>).
|
||||
AddUsername=
|
||||
|
||||
# Password for user with add downloads access.
|
||||
#
|
||||
# Set to empty value to disable password check.
|
||||
AddPassword=
|
||||
|
||||
# Secure control of NZBGet server (yes, no).
|
||||
#
|
||||
# Activate the option if you want to access NZBGet built-in web-server
|
||||
@@ -278,7 +340,8 @@ SecureKey=
|
||||
# IP-addresses allowed to connect without authorization.
|
||||
#
|
||||
# Comma separated list of privileged IPs for easy access to NZBGet
|
||||
# built-in web-server (web-interface and RPC).
|
||||
# built-in web-server (web-interface and RPC). The connected clients
|
||||
# have full unrestricted access.
|
||||
#
|
||||
# Example: 127.0.0.1,192.168.178.2.
|
||||
#
|
||||
@@ -707,27 +770,29 @@ CrcCheck=yes
|
||||
|
||||
# How many retries should be attempted if a download error occurs (0-99).
|
||||
#
|
||||
# 1) If download fails because of "article or group not found error" the
|
||||
# program tries another news server.
|
||||
#
|
||||
# 2) If download fails because of interrupted connection, the program
|
||||
# tries the same server again until connection can be established.
|
||||
#
|
||||
# In both cases 1) and 2) option <Retries> is not used.
|
||||
#
|
||||
# If download however fails because of incomplete article, CRC-error or other
|
||||
# error not mentioned above the program tries to redownload the article from
|
||||
# the same news server as many times as defined in option <Retries>. If all
|
||||
# If download fails because of incomplete or damaged article or due to
|
||||
# CRC-error the program tries to redownload the article from the same
|
||||
# news server as many times as defined in option <Retries>. If all
|
||||
# attempts fail the program tries another news server.
|
||||
#
|
||||
# If download fails because of "article or group not found error" the
|
||||
# program tries another news server without retrying on the failed server.
|
||||
#
|
||||
# If download fails because of interrupted connection the program
|
||||
# tries another news server or the same server after the block interval
|
||||
# expires.
|
||||
Retries=3
|
||||
|
||||
# Set the interval between retries (seconds).
|
||||
# Wait interval between retries (seconds).
|
||||
#
|
||||
# If download of an article fails because of interrupted connection
|
||||
# the server is temporary blocked until the retry interval expires.
|
||||
RetryInterval=10
|
||||
|
||||
# Set connection timeout for article downloading (seconds).
|
||||
# Connection timeout for article downloading (seconds).
|
||||
ArticleTimeout=60
|
||||
|
||||
# Set connection timeout for URL fetching (seconds).
|
||||
# Connection timeout for URL fetching (seconds).
|
||||
#
|
||||
# This includes fetching of nzb-files via URLs and fetching of RSS feeds.
|
||||
UrlTimeout=60
|
||||
@@ -858,7 +923,6 @@ WriteLog=append
|
||||
# (option <WriteLog> is set to "rotate").
|
||||
RotateLog=3
|
||||
|
||||
|
||||
# How error messages must be printed (screen, log, both, none).
|
||||
ErrorTarget=both
|
||||
|
||||
@@ -869,23 +933,29 @@ WarningTarget=both
|
||||
InfoTarget=both
|
||||
|
||||
# How detail messages must be printed (screen, log, both, none).
|
||||
DetailTarget=both
|
||||
DetailTarget=log
|
||||
|
||||
# How debug messages must be printed (screen, log, both, none).
|
||||
#
|
||||
# Debug-messages can be printed only if the program was compiled in
|
||||
# debug-mode: "./configure --enable-debug".
|
||||
DebugTarget=both
|
||||
DebugTarget=log
|
||||
|
||||
# Number of messages stored in buffer and available for remote
|
||||
# clients (messages).
|
||||
LogBufferSize=1000
|
||||
|
||||
# Create a log of all broken files (yes ,no).
|
||||
# Create log for each downloaded nzb-file (yes, no).
|
||||
#
|
||||
# The messages are saved for each download separately and can be viewed
|
||||
# at any time in download details dialog or history details dialog.
|
||||
NzbLog=yes
|
||||
|
||||
# Create a log of all broken files (yes, no).
|
||||
#
|
||||
# It is a text file placed near downloaded files, which contains
|
||||
# the names of broken files.
|
||||
CreateBrokenLog=yes
|
||||
BrokenLog=yes
|
||||
|
||||
# Create memory dump (core-file) on abnormal termination, Linux only (yes, no).
|
||||
#
|
||||
@@ -1148,9 +1218,13 @@ ParThreads=0
|
||||
|
||||
# Files to ignore during par-check.
|
||||
#
|
||||
# List of file extensions or file names to ignore by par-rename and
|
||||
# par-check. The entries must be separated with commas. The entries
|
||||
# can be file extensions or any text the file name may end with.
|
||||
# List of file extensions, file names or file masks to ignore by
|
||||
# par-rename and par-check. The entries must be separated with
|
||||
# commas.
|
||||
#
|
||||
# The entries must be separated with commas. The entries can be file
|
||||
# extensions, file names or file masks containing wildcard
|
||||
# characters * and ?.
|
||||
#
|
||||
# If par-rename or par-check detect missing or damaged files they
|
||||
# will ignore files matching this option and will not initiate
|
||||
@@ -1170,8 +1244,9 @@ ParIgnoreExt=.sfv, .nzb, .nfo
|
||||
# None - do nothing (continue download).
|
||||
#
|
||||
# NOTE: For automatic duplicate handling option must be set to "Delete"
|
||||
# or "None". If it is set to "Pause" you will need to manually unpause
|
||||
# another duplicate (if any exists in queue). See also option <DupeCheck>.
|
||||
# or "None". If it is set to "Pause" you will need to manually return
|
||||
# another duplicate to queue (if any exists in history). See also
|
||||
# option <DupeCheck>.
|
||||
HealthCheck=delete
|
||||
|
||||
# Maximum allowed time for par-repair (minutes).
|
||||
@@ -1212,20 +1287,6 @@ ParPauseQueue=no
|
||||
# from download queue after successful check/repair.
|
||||
ParCleanupQueue=yes
|
||||
|
||||
# Files to delete after successful check/repair.
|
||||
#
|
||||
# List of file extensions or file names to delete after successful
|
||||
# download. The entries must be separated with commas. The entries
|
||||
# can be file extensions or any text the file name may end with.
|
||||
#
|
||||
# Files or extensions listed here are also ignored by par-rename
|
||||
# and par-check.
|
||||
#
|
||||
# NOTE: See also option <ParIgnoreExt>.
|
||||
#
|
||||
# Example: .par2, .sfv
|
||||
ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
|
||||
|
||||
|
||||
##############################################################################
|
||||
### UNPACK ###
|
||||
@@ -1262,6 +1323,24 @@ UnpackCleanupDisk=yes
|
||||
#
|
||||
# Example: /usr/bin/unrar.
|
||||
#
|
||||
# The option can also contain extra switches to pass to unrar. To the
|
||||
# here defined command line NZBGet adds the following switches:
|
||||
# x -y -p- -o+ *.rar ./_unpack/
|
||||
#
|
||||
# Switch "x" is added only if neither "x" nor "e" were defined in
|
||||
# the option (this allows you to use switch "e" instead of "x"). switch
|
||||
# "-o+" is added only if neither "-o+" nor "-o-" were defined
|
||||
# in the command line. All other paramaters are always added. Parameter
|
||||
# "-p-" is replaced with "-ppassword" if a password is set for nzb-file.
|
||||
#
|
||||
# Examples:
|
||||
# 1) ignore file attributes (pemissions):
|
||||
# /usr/bin/unrar x -ai;
|
||||
# 2) decrease priority of unrar-process:
|
||||
# nice -n 19 unrar.
|
||||
#
|
||||
# For other useful switches refer to unrar documentation.
|
||||
#
|
||||
# If unrar is in your PATH you may leave the path part and set only
|
||||
# the executable name ("unrar" on POSIX or "unrar.exe" on Windows).
|
||||
UnrarCmd=unrar
|
||||
@@ -1270,10 +1349,43 @@ UnrarCmd=unrar
|
||||
#
|
||||
# Example: /usr/bin/7z.
|
||||
#
|
||||
# Similar to option <UnrarCmd> this option can also include extra switches.
|
||||
#
|
||||
# If 7-Zip binary is in your PATH you may leave the path part and set only
|
||||
# the executable name ("7z" or "7za" on POSIX or "7z.exe" on Windows).
|
||||
SevenZipCmd=7z
|
||||
|
||||
# Files to delete after successful download.
|
||||
#
|
||||
# List of file extensions, file names or file masks to delete after
|
||||
# successful download. If either unpack or par-check fail the cleanup is
|
||||
# not performed. If neither unpack nor par-check were made (because they
|
||||
# were disabled or the download doesn't contain archives and/or par-files
|
||||
# the cleanup is performed if the health is 100%.
|
||||
#
|
||||
# The entries must be separated with commas. The entries can be file
|
||||
# extensions, file names or file masks containing wildcard
|
||||
# characters * and ?.
|
||||
#
|
||||
# Files listed here are also ignored by par-rename and par-check.
|
||||
#
|
||||
# NOTE: See also option <ParIgnoreExt>.
|
||||
#
|
||||
# Example: .par2, .sfv
|
||||
ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
|
||||
|
||||
# Path to file containing unpack passwords.
|
||||
#
|
||||
# If the option is set the program will try all passwords from the file
|
||||
# when unpacking the archives. The file must be a text file containing
|
||||
# one password per line.
|
||||
#
|
||||
# If an nzb-file has a defined password (in the post-processing settings)
|
||||
# then the password-file is not used for that nzb-file.
|
||||
#
|
||||
# NOTE: Trying multiple passwords is a time consuming task. Whenever possible
|
||||
# passwords should be set per nzb-file in their post-processing settings.
|
||||
UnpackPassFile=
|
||||
|
||||
##############################################################################
|
||||
### EXTENSION SCRIPTS ###
|
||||
@@ -1534,13 +1646,14 @@ PostScript=
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
ScanScript=
|
||||
|
||||
# List of queue scripts to execute after a nzb-file is added to queue.
|
||||
# List of queue scripts to execute on queue events.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. Only
|
||||
# filenames without path must be used. All scripts must be stored in directory
|
||||
# pointed by option <ScriptDir>.
|
||||
#
|
||||
# The scripts are executed each time a new file is added to queue.
|
||||
# The scripts are executed on certain queue events such as adding
|
||||
# a new nzb-file to queue, etc.
|
||||
#
|
||||
# Example: DeleteQueueSamples.sh, NzbAddedNotify.py.
|
||||
#
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".\daemon\connect;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2"
|
||||
AdditionalIncludeDirectories=".\daemon\connect;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@@ -61,7 +61,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib Winmm.lib dbghelp.lib ssleay32MTd.lib libeay32MTd.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib Winmm.lib gdi32.lib shell32.lib dbghelp.lib ssleay32MTd.lib libeay32MTd.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
@@ -115,7 +115,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".\daemon\connect;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2"
|
||||
AdditionalIncludeDirectories=".\daemon\connect;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
@@ -136,7 +136,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib Winmm.lib ssleay32MT.lib libeay32MT.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib gdi32.lib shell32.lib Winmm.lib ssleay32MT.lib libeay32MT.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
LinkIncremental="0"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
@@ -480,6 +480,14 @@
|
||||
RelativePath=".\daemon\windows\win32.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\daemon\windows\WinConsole.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\daemon\windows\WinConsole.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="postprocess"
|
||||
@@ -918,6 +926,34 @@
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="resources"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\windows\resources\mainicon.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windows\resources\nzbget.rc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windows\resources\resource.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windows\resources\trayicon_idle.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windows\resources\trayicon_paused.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windows\resources\trayicon_working.ico"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
||||
75
nzbgetd
75
nzbgetd
@@ -1,75 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script used to start and stop the nzbget usenet service
|
||||
#
|
||||
# Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
|
||||
# Copyright (C) 2009-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
# --- CONFIGURATION -----------------------------------------------
|
||||
# Location of the nzbget executable
|
||||
NZBGET_BINARY="/usr/local/bin/nzbget"
|
||||
|
||||
# Additional options, e. g. config file location:
|
||||
# NZBGET_OPTS="-c /mnt/hdd/tools/nzbget/conf/nzbget.conf"
|
||||
NZBGET_OPTS=""
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
|
||||
if [ -z "$1" ] ; then
|
||||
case `echo "$0" | sed 's:^.*/\(.*\):\1:g'` in
|
||||
S??*) rc="start" ;;
|
||||
K??*) rc="stop" ;;
|
||||
*) rc="usage" ;;
|
||||
esac
|
||||
else
|
||||
rc="$1"
|
||||
fi
|
||||
|
||||
case "$rc" in
|
||||
start)
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -D
|
||||
;;
|
||||
stop)
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -Q
|
||||
;;
|
||||
restart)
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -Q
|
||||
sleep 10 # since stop is backgrounded
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -D
|
||||
;;
|
||||
status)
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -L S
|
||||
;;
|
||||
pstatus)
|
||||
retval=$(pgrep -l -f nzbget > /dev/null ; echo $?)
|
||||
if [ "$retval" = "0" ] ; then
|
||||
echo " ------- nzbget *is* running -------"
|
||||
ps -Ho user,pid,cmd:32,pcpu -C nzbget
|
||||
exit 0
|
||||
else
|
||||
echo " ------- nzbget is *not* running -------"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|pstatus|usage}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -478,7 +478,15 @@ void InstallSignalHandlers()
|
||||
}
|
||||
} else {
|
||||
int speed = [(NSNumber*)[status objectForKey:@"DownloadRate"] integerValue];
|
||||
info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.Downloading", nil), speed / 1024];
|
||||
if (speed >= 1024 * 1024 * 10) {
|
||||
info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingMB10", nil), speed / 1024 / 1024];
|
||||
}
|
||||
else if (speed >= 1024 * 1024) {
|
||||
info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingMB", nil), (float)speed / 1024.0 / 1024.0];
|
||||
}
|
||||
else {
|
||||
info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingKB", nil), speed / 1024];
|
||||
}
|
||||
preventSleep = YES;
|
||||
|
||||
if (speed > 0) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>13.0-testing-r1011M</string>
|
||||
<string>15.0-testing</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
@@ -25,7 +25,7 @@
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2007-2014 Andrey Prygunkov</string>
|
||||
<string>Copyright © 2007-2015 Andrey Prygunkov</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainApp</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
"Status.Downloading"="Downloading at %i KB/s";
|
||||
"Status.DownloadingKB"="Downloading at %i KB/s";
|
||||
"Status.DownloadingMB"="Downloading at %1.1f MB/s";
|
||||
"Status.DownloadingMB10"="Downloading at %i MB/s";
|
||||
"Status.Post-Processing"="Post-Processing";
|
||||
"Status.Fetching NZBs"="Fetching NZBs";
|
||||
"Status.Fetching Feeds"="Fetching Feeds";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# E-Mail post-processing script for NZBGet
|
||||
#
|
||||
# Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -35,6 +35,9 @@
|
||||
##############################################################################
|
||||
### OPTIONS ###
|
||||
|
||||
# When to send the message (Always, OnFailure).
|
||||
#SendMail=Always
|
||||
|
||||
# Email address you want this email to be sent from.
|
||||
#From="NZBGet" <myaccount@gmail.com>
|
||||
|
||||
@@ -71,10 +74,10 @@
|
||||
# is usually deleted by cleanup-script and therefore is not sent.
|
||||
#BrokenLog=yes
|
||||
|
||||
# Append post-processing log to the message (Always, Never, OnFailure).
|
||||
# Append nzb log to the message (Always, Never, OnFailure).
|
||||
#
|
||||
# Add the post-processing log of active job.
|
||||
#PostProcessLog=OnFailure
|
||||
# Add the download and post-processing log of active job.
|
||||
#NzbLog=OnFailure
|
||||
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
##############################################################################
|
||||
@@ -93,11 +96,12 @@ except ImportError:
|
||||
# Exit codes used by NZBGet
|
||||
POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_ERROR=94
|
||||
POSTPROCESS_NONE=95
|
||||
|
||||
# Check if the script is called from nzbget 11.0 or later
|
||||
if not 'NZBPP_TOTALSTATUS' in os.environ:
|
||||
# Check if the script is called from nzbget 15.0 or later
|
||||
if not 'NZBOP_NZBLOG' in os.environ:
|
||||
print('*** NZBGet post-processing script ***')
|
||||
print('This script is supposed to be called from nzbget (13.0 or later).')
|
||||
print('This script is supposed to be called from nzbget (15.0 or later).')
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
print('[DETAIL] Script successfully started')
|
||||
@@ -122,6 +126,11 @@ if total_status == 'SUCCESS' and os.environ['NZBPP_SCRIPTSTATUS'] == 'FAILURE':
|
||||
status = 'WARNING/SCRIPT'
|
||||
|
||||
success = total_status == 'SUCCESS'
|
||||
|
||||
if success and os.environ.get('NZBPO_SENDMAIL') == 'OnFailure':
|
||||
print('[INFO] Skipping sending of message for successful download')
|
||||
sys.exit(POSTPROCESS_NONE)
|
||||
|
||||
if success:
|
||||
subject = 'Success for "%s"' % (os.environ['NZBPP_NZBNAME'])
|
||||
text = 'Download of "%s" has successfully completed.' % (os.environ['NZBPP_NZBNAME'])
|
||||
@@ -132,8 +141,8 @@ else:
|
||||
text += '\nStatus: %s' % status
|
||||
|
||||
if os.environ.get('NZBPO_STATISTICS') == 'yes' or \
|
||||
os.environ.get('NZBPO_POSTPROCESSLOG') == 'Always' or \
|
||||
(os.environ.get('NZBPO_POSTPROCESSLOG') == 'OnFailure' and not success):
|
||||
os.environ.get('NZBPO_NZBLOG') == 'Always' or \
|
||||
(os.environ.get('NZBPO_NZBLOG') == 'OnFailure' and not success):
|
||||
# To get statistics or the post-processing log we connect to NZBGet via XML-RPC.
|
||||
# For more info visit http://nzbget.net/RPC_API_reference
|
||||
# First we need to know connection info: host, port and password of NZBGet server.
|
||||
@@ -203,7 +212,7 @@ if os.environ.get('NZBPO_FILELIST') == 'yes':
|
||||
text += '\n' + os.path.join(dirname, filename)[len(os.environ['NZBPP_DIRECTORY']) + 1:]
|
||||
files = True
|
||||
if not files:
|
||||
text += '\n<no files found>'
|
||||
text += '\n<no files found in the destination directory (moved by a script?)>'
|
||||
|
||||
# add _brokenlog.txt (if exists)
|
||||
if os.environ.get('NZBPO_BROKENLOG') == 'yes':
|
||||
@@ -212,22 +221,20 @@ if os.environ.get('NZBPO_BROKENLOG') == 'yes':
|
||||
text += '\n\nBrokenlog:\n' + open(brokenlog, 'r').read().strip()
|
||||
|
||||
# add post-processing log
|
||||
if os.environ.get('NZBPO_POSTPROCESSLOG') == 'Always' or \
|
||||
(os.environ.get('NZBPO_POSTPROCESSLOG') == 'OnFailure' and not success):
|
||||
# To get the post-processing log we call method "postqueue", which returns
|
||||
# the list of post-processing job.
|
||||
# The first item in the list is current job. This item has a field 'Log',
|
||||
# containing an array of log-entries.
|
||||
if os.environ.get('NZBPO_NZBLOG') == 'Always' or \
|
||||
(os.environ.get('NZBPO_NZBLOG') == 'OnFailure' and not success):
|
||||
|
||||
# To get the item log we connect to NZBGet via XML-RPC and call
|
||||
# method "loadlog", which returns the log for a given nzb item.
|
||||
# For more info visit http://nzbget.net/RPC_API_reference
|
||||
|
||||
# Call remote method 'postqueue'. The only parameter tells how many log-entries to return as maximum.
|
||||
postqueue = server.postqueue(10000)
|
||||
|
||||
# Get field 'Log' from the first post-processing job
|
||||
log = postqueue[0]['Log']
|
||||
# Call remote method 'loadlog'
|
||||
nzbid = int(os.environ['NZBPP_NZBID'])
|
||||
log = server.loadlog(nzbid, 0, 10000)
|
||||
|
||||
# Now iterate through entries and save them to message text
|
||||
if len(log) > 0:
|
||||
text += '\n\nPost-processing log:';
|
||||
text += '\n\nNzb-log:';
|
||||
for entry in log:
|
||||
text += '\n%s\t%s\t%s' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text'])
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Logger post-processing script for NZBGet
|
||||
#
|
||||
# Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -26,10 +26,10 @@
|
||||
##############################################################################
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
|
||||
# Save post-processing log into a file.
|
||||
# Save nzb log into a file.
|
||||
#
|
||||
# This script saves post-processing log of nzb-file into file
|
||||
# _postprocesslog.txt in the destination directory.
|
||||
# This script saves the download and post-processing log of nzb-file
|
||||
# into file _nzblog.txt in the destination directory.
|
||||
#
|
||||
# NOTE: This script requires Python to be installed on your system.
|
||||
|
||||
@@ -50,20 +50,18 @@ POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_NONE=95
|
||||
POSTPROCESS_ERROR=94
|
||||
|
||||
# Check if the script is called from nzbget 11.0 or later
|
||||
if not 'NZBOP_SCRIPTDIR' in os.environ:
|
||||
# Check if the script is called from nzbget 15.0 or later
|
||||
if not 'NZBOP_NZBLOG' in os.environ:
|
||||
print('*** NZBGet post-processing script ***')
|
||||
print('This script is supposed to be called from nzbget (11.0 or later).')
|
||||
print('This script is supposed to be called from nzbget (15.0 or later).')
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
if not os.path.exists(os.environ['NZBPP_DIRECTORY']):
|
||||
print('Destination directory doesn\'t exist, exiting')
|
||||
sys.exit(POSTPROCESS_NONE)
|
||||
|
||||
# To get the post-processing log we connect to NZBGet via XML-RPC
|
||||
# and call method "postqueue", which returns the list of post-processing job.
|
||||
# The first item in the list is current job. This item has a field 'Log',
|
||||
# containing an array of log-entries.
|
||||
# To get the item log we connect to NZBGet via XML-RPC and call
|
||||
# method "loadlog", which returns the log for a given nzb item.
|
||||
# For more info visit http://nzbget.net/RPC_API_reference
|
||||
|
||||
# First we need to know connection info: host, port and password of NZBGet server.
|
||||
@@ -82,15 +80,13 @@ rpcUrl = 'http://%s:%s@%s:%s/xmlrpc' % (username, password, host, port);
|
||||
# Create remote server object
|
||||
server = ServerProxy(rpcUrl)
|
||||
|
||||
# Call remote method 'postqueue'. The only parameter tells how many log-entries to return as maximum.
|
||||
postqueue = server.postqueue(10000)
|
||||
|
||||
# Get field 'Log' from the first post-processing job
|
||||
log = postqueue[0]['Log']
|
||||
# Call remote method 'loadlog'
|
||||
nzbid = int(os.environ['NZBPP_NZBID'])
|
||||
log = server.loadlog(nzbid, 0, 10000)
|
||||
|
||||
# Now iterate through entries and save them to the output file
|
||||
if len(log) > 0:
|
||||
f = open('%s/_postprocesslog.txt' % os.environ['NZBPP_DIRECTORY'], 'wb')
|
||||
f = open('%s/_nzblog.txt' % os.environ['NZBPP_DIRECTORY'], 'wb')
|
||||
for entry in log:
|
||||
f.write((u'%s\t%s\t%s\n' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text'])).encode('utf8'))
|
||||
f.close()
|
||||
|
||||
213
webui/config.js
213
webui/config.js
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,6 +39,7 @@ var Options = (new function($)
|
||||
this.options;
|
||||
this.postParamConfig;
|
||||
this.categories = [];
|
||||
this.restricted = false;
|
||||
|
||||
// State
|
||||
var _this = this;
|
||||
@@ -62,6 +63,7 @@ var Options = (new function($)
|
||||
RPC.call('config', [], function(_options) {
|
||||
_this.options = _options;
|
||||
initCategories();
|
||||
_this.restricted = _this.option('ControlPort') === '***';
|
||||
|
||||
// loading config templates and build list of post-processing parameters
|
||||
_this.postParamConfig = [];
|
||||
@@ -643,7 +645,7 @@ var Config = (new function($)
|
||||
|
||||
/*** GENERATE HTML PAGE *****************************************************************/
|
||||
|
||||
function buildOptionsContent(section)
|
||||
function buildOptionsContent(section, extensionsec)
|
||||
{
|
||||
var html = '';
|
||||
|
||||
@@ -653,6 +655,13 @@ var Config = (new function($)
|
||||
|
||||
for (var i=0, op=0; i < section.options.length; i++)
|
||||
{
|
||||
if (i > 0 && extensionsec && Options.restricted)
|
||||
{
|
||||
// in restricted mode don't show any options for extension scripts,
|
||||
// option's content is hidden content anyway (***)
|
||||
break;
|
||||
}
|
||||
|
||||
var option = section.options[i];
|
||||
if (!option.template)
|
||||
{
|
||||
@@ -867,14 +876,23 @@ var Config = (new function($)
|
||||
|
||||
if (hasoptions)
|
||||
{
|
||||
html += '<div class="' + section.id + ' multiid' + multiid + ' multiset">';
|
||||
html += '<button type="button" class="btn config-delete" data-multiid="' + multiid + ' multiset" ' +
|
||||
html += '<div class="' + section.id + ' multiid' + multiid + ' multiset multiset-toolbar">';
|
||||
html += '<button type="button" class="btn config-button config-delete" data-multiid="' + multiid + '" ' +
|
||||
'onclick="Config.deleteSet(this, \'' + setname + '\',\'' + section.id + '\')">Delete ' + setname + multiid + '</button>';
|
||||
html += ' <button type="button" class="btn config-button" data-multiid="' + multiid + '" ' +
|
||||
'onclick="Config.moveSet(this, \'' + setname + '\',\'' + section.id + '\', \'up\')">Move Up</button>';
|
||||
html += ' <button type="button" class="btn config-button" data-multiid="' + multiid + '" ' +
|
||||
'onclick="Config.moveSet(this, \'' + setname + '\',\'' + section.id + '\', \'down\')">Move Down</button>';
|
||||
if (setname.toLowerCase() === 'feed')
|
||||
{
|
||||
html += ' <button type="button" class="btn config-previewfeed config-feed" data-multiid="' + multiid + ' multiset" ' +
|
||||
html += ' <button type="button" class="btn config-button" data-multiid="' + multiid + '" ' +
|
||||
'onclick="Config.previewFeed(this, \'' + setname + '\',\'' + section.id + '\')">Preview Feed</button>';
|
||||
}
|
||||
if (setname.toLowerCase() === 'server')
|
||||
{
|
||||
html += ' <button type="button" class="btn config-button" data-multiid="' + multiid + '" ' +
|
||||
'onclick="Config.testConnection(this, \'' + setname + '\',\'' + section.id + '\')">Test Connection</button>';
|
||||
}
|
||||
html += '<hr>';
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -917,7 +935,7 @@ var Config = (new function($)
|
||||
{
|
||||
var html = $('<li><a href="#' + section.id + '">' + section.name + '</a></li>');
|
||||
$ConfigNav.append(html);
|
||||
var content = buildOptionsContent(section);
|
||||
var content = buildOptionsContent(section, k > 0);
|
||||
$ConfigData.append(content);
|
||||
added = true;
|
||||
}
|
||||
@@ -1209,37 +1227,57 @@ var Config = (new function($)
|
||||
|
||||
function reformatSection(section, setname)
|
||||
{
|
||||
var oldMultiId = -1;
|
||||
var newMultiId = 0;
|
||||
var hasOptions = false;
|
||||
var lastMultiId = 0;
|
||||
for (var j=0; j < section.options.length; j++)
|
||||
{
|
||||
var option = section.options[j];
|
||||
if (!option.template)
|
||||
{
|
||||
if (option.multiid !== oldMultiId)
|
||||
if (option.multiid !== lastMultiId && option.multiid !== lastMultiId + 1)
|
||||
{
|
||||
oldMultiId = option.multiid;
|
||||
newMultiId++;
|
||||
|
||||
// reformat multiid
|
||||
var div = $('#' + setname + oldMultiId);
|
||||
div.attr('id', setname + newMultiId);
|
||||
|
||||
// update captions
|
||||
$('.config-settitle.' + section.id + '.multiid' + oldMultiId, $ConfigData).text(setname + newMultiId);
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-multicaption', $ConfigData).text(setname + newMultiId + '.');
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-delete', $ConfigData).text('Delete ' + setname + newMultiId).attr('data-multiid', newMultiId);
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-feed', $ConfigData).attr('data-multiid', newMultiId);
|
||||
|
||||
//update class
|
||||
$('.' + section.id + '.multiid' + oldMultiId, $ConfigData).removeClass('multiid' + oldMultiId).addClass('multiid' + newMultiId);
|
||||
reformatSet(section, setname, option.multiid, lastMultiId + 1);
|
||||
}
|
||||
lastMultiId = option.multiid;
|
||||
hasOptions = true;
|
||||
}
|
||||
}
|
||||
|
||||
// update add-button
|
||||
var addButton = $('.config-add.' + section.id, $ConfigData);
|
||||
addButton.text('Add ' + (hasOptions ? 'another ' : '') + setname);
|
||||
}
|
||||
|
||||
function reformatSet(section, setname, oldMultiId, newMultiId)
|
||||
{
|
||||
for (var j=0; j < section.options.length; j++)
|
||||
{
|
||||
var option = section.options[j];
|
||||
if (!option.template && option.multiid == oldMultiId)
|
||||
{
|
||||
// reformat multiid
|
||||
var div = $('#' + setname + oldMultiId);
|
||||
div.attr('id', setname + newMultiId);
|
||||
|
||||
// update captions
|
||||
$('.config-settitle.' + section.id + '.multiid' + oldMultiId, $ConfigData).text(setname + newMultiId);
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-multicaption', $ConfigData).text(setname + newMultiId + '.');
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-delete', $ConfigData).text('Delete ' + setname + newMultiId);
|
||||
|
||||
//update data id
|
||||
$('.' + section.id + '.multiid' + oldMultiId + ' .config-button', $ConfigData).attr('data-multiid', newMultiId);
|
||||
|
||||
//update class
|
||||
$('.' + section.id + '.multiid' + oldMultiId, $ConfigData).removeClass('multiid' + oldMultiId).addClass('multiid' + newMultiId);
|
||||
|
||||
// update input id
|
||||
var oldFormId = option.formId;
|
||||
option.formId = option.formId.replace(new RegExp(option.multiid), newMultiId);
|
||||
$('#' + oldFormId).attr('id', option.formId);
|
||||
|
||||
// update label data-optid
|
||||
$('a[data-optid=' + oldFormId + ']').attr('data-optid', option.formId);
|
||||
|
||||
// update editor id
|
||||
$('#' + oldFormId + '_Editor').attr('id', option.formId + '_Editor');
|
||||
|
||||
@@ -1249,12 +1287,8 @@ var Config = (new function($)
|
||||
option.multiid = newMultiId;
|
||||
}
|
||||
}
|
||||
|
||||
// update add-button
|
||||
var addButton = $('.config-add.' + section.id, $ConfigData);
|
||||
addButton.text('Add ' + (newMultiId > 0 ? 'another ' : '') + setname);
|
||||
}
|
||||
|
||||
|
||||
this.addSet = function(setname, sectionId)
|
||||
{
|
||||
// find section
|
||||
@@ -1322,6 +1356,31 @@ var Config = (new function($)
|
||||
});
|
||||
}
|
||||
|
||||
this.moveSet = function(control, setname, sectionId, direction)
|
||||
{
|
||||
var id1 = parseInt($(control).attr('data-multiid'));
|
||||
var id2 = direction === 'down' ? id1 + 1 : id1 - 1;
|
||||
|
||||
// swap options in two sets
|
||||
var opts1 = $('.' + sectionId + '.multiid' + (direction === 'down' ? id1 : id2), $ConfigData);
|
||||
var opts2 = $('.' + sectionId + '.multiid' + (direction === 'down' ? id2 : id1), $ConfigData);
|
||||
|
||||
if (opts1.length === 0 || opts2.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
opts1.first().before(opts2);
|
||||
|
||||
// reformat remaining sets (captions, input IDs, etc.)
|
||||
var section = findSectionById(sectionId);
|
||||
reformatSet(section, setname, id2, 10000 + id2);
|
||||
reformatSet(section, setname, id1, id2);
|
||||
reformatSet(section, setname, 10000 + id2, id1);
|
||||
|
||||
section.modified = true;
|
||||
}
|
||||
|
||||
this.viewMode = function()
|
||||
{
|
||||
compactMode = !compactMode;
|
||||
@@ -1411,6 +1470,56 @@ var Config = (new function($)
|
||||
getOptionValue(findOptionByName('Feed' + multiid + '.Priority')));
|
||||
}
|
||||
|
||||
/*** TEST SERVER ********************************************************************/
|
||||
|
||||
var connecting = false;
|
||||
|
||||
this.testConnection = function(control, setname, sectionId)
|
||||
{
|
||||
if (connecting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
connecting = true;
|
||||
$('#Notif_Config_TestConnectionProgress').fadeIn(function() {
|
||||
var multiid = parseInt($(control).attr('data-multiid'));
|
||||
var timeout = Math.min(parseInt(getOptionValue(findOptionByName('ArticleTimeout'))), 10);
|
||||
RPC.call('testserver', [
|
||||
getOptionValue(findOptionByName('Server' + multiid + '.Host')),
|
||||
parseInt(getOptionValue(findOptionByName('Server' + multiid + '.Port'))),
|
||||
getOptionValue(findOptionByName('Server' + multiid + '.Username')),
|
||||
getOptionValue(findOptionByName('Server' + multiid + '.Password')),
|
||||
getOptionValue(findOptionByName('Server' + multiid + '.Encryption')) === 'yes',
|
||||
getOptionValue(findOptionByName('Server' + multiid + '.Cipher')),
|
||||
timeout
|
||||
],
|
||||
function(errtext) {
|
||||
$('#Notif_Config_TestConnectionProgress').fadeOut(function() {
|
||||
if (errtext == '')
|
||||
{
|
||||
Notification.show('#Notif_Config_TestConnectionOK');
|
||||
}
|
||||
else
|
||||
{
|
||||
AlertDialog.showModal('Connection test failed', errtext);
|
||||
}
|
||||
});
|
||||
connecting = false;
|
||||
},
|
||||
function(message, resultObj) {
|
||||
$('#Notif_Config_TestConnectionProgress').fadeOut(function() {
|
||||
if (resultObj && resultObj.error && resultObj.error.message)
|
||||
{
|
||||
message = resultObj.error.message;
|
||||
}
|
||||
AlertDialog.showModal('Connection test failed', message);
|
||||
connecting = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*** SAVE ********************************************************************/
|
||||
|
||||
function getOptionValue(option)
|
||||
@@ -2445,6 +2554,7 @@ var UpdateDialog = (new function($)
|
||||
var UpdateInfo;
|
||||
var lastUpTimeSec;
|
||||
var installing = false;
|
||||
var logReceived = false;
|
||||
|
||||
this.init = function()
|
||||
{
|
||||
@@ -2487,7 +2597,7 @@ var UpdateDialog = (new function($)
|
||||
|
||||
$UpdateDialog.modal({backdrop: 'static'});
|
||||
|
||||
RPC.call('readurl', ['http://nzbget.net/info/nzbget-version.php?nocache=' + new Date().getTime(), 'version info'], loadedUpstreamInfo, error);
|
||||
RPC.call('readurl', ['http://nzbget.net/info/nzbget-version.json?nocache=' + new Date().getTime(), 'version info'], loadedUpstreamInfo, error);
|
||||
}
|
||||
|
||||
function error(e)
|
||||
@@ -2651,7 +2761,7 @@ var UpdateDialog = (new function($)
|
||||
|
||||
if (!script)
|
||||
{
|
||||
alert('Something is wrong with a package configuration file "package-info.json".');
|
||||
alert('Something is wrong with the package configuration file "package-info.json".');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2687,16 +2797,24 @@ var UpdateDialog = (new function($)
|
||||
{
|
||||
RPC.call('logupdate', [0, 100], function(data)
|
||||
{
|
||||
updateLogTable(data);
|
||||
setTimeout(updateLog, 500);
|
||||
},
|
||||
function()
|
||||
{
|
||||
// rpc-failure: the program has been terminated. Waiting for new instance.
|
||||
setLogContentAndScroll($UpdateProgressDialog_Log.html() + '\n' + 'NZBGet has been terminated. Waiting for restart...');
|
||||
setTimeout(checkStatus, 500);
|
||||
},
|
||||
1000);
|
||||
logReceived = logReceived || data.length > 0;
|
||||
if (logReceived && data.length === 0)
|
||||
{
|
||||
terminated();
|
||||
}
|
||||
else
|
||||
{
|
||||
updateLogTable(data);
|
||||
setTimeout(updateLog, 500);
|
||||
}
|
||||
}, terminated);
|
||||
}
|
||||
|
||||
function terminated()
|
||||
{
|
||||
// rpc-failure: the program has been terminated. Waiting for new instance.
|
||||
setLogContentAndScroll($UpdateProgressDialog_Log.html() + '\n' + 'NZBGet has been terminated. Waiting for restart...');
|
||||
setTimeout(checkStatus, 500);
|
||||
}
|
||||
|
||||
function setLogContentAndScroll(html)
|
||||
@@ -2734,7 +2852,10 @@ var UpdateDialog = (new function($)
|
||||
{
|
||||
// the old instance is not restarted yet
|
||||
// waiting 0.5 sec. and retrying
|
||||
setTimeout(checkStatus, 500);
|
||||
if ($('#UpdateProgressDialog').is(':visible'))
|
||||
{
|
||||
setTimeout(checkStatus, 500);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2749,9 +2870,11 @@ var UpdateDialog = (new function($)
|
||||
function()
|
||||
{
|
||||
// Failure, waiting 0.5 sec. and retrying
|
||||
setTimeout(checkStatus, 500);
|
||||
},
|
||||
1000);
|
||||
if ($('#UpdateProgressDialog').is(':visible'))
|
||||
{
|
||||
setTimeout(checkStatus, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}(jQuery));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -79,7 +79,7 @@ var Downloads = (new function($)
|
||||
$DownloadsRecordsPerPage = $('#DownloadsRecordsPerPage');
|
||||
$DownloadsTable_Name = $('#DownloadsTable_Name');
|
||||
|
||||
var recordsPerPage = UISettings.read('$DownloadsRecordsPerPage', 10);
|
||||
var recordsPerPage = UISettings.read('DownloadsRecordsPerPage', 10);
|
||||
$DownloadsRecordsPerPage.val(recordsPerPage);
|
||||
|
||||
$DownloadsTable.fasttable(
|
||||
@@ -100,8 +100,8 @@ var Downloads = (new function($)
|
||||
});
|
||||
|
||||
$DownloadsTable.on('click', 'a', itemClick);
|
||||
$DownloadsTable.on('click', 'tbody div.check',
|
||||
function(event) { $DownloadsTable.fasttable('itemCheckClick', this.parentNode.parentNode, event); });
|
||||
$DownloadsTable.on('click', UISettings.rowSelect ? 'tbody tr' : 'tbody div.check',
|
||||
function(event) { $DownloadsTable.fasttable('itemCheckClick', UISettings.rowSelect ? this : this.parentNode.parentNode, event); });
|
||||
$DownloadsTable.on('click', 'thead div.check',
|
||||
function() { $DownloadsTable.fasttable('titleCheckClick') });
|
||||
$DownloadsTable.on('mousedown', Util.disableShiftMouseDown);
|
||||
@@ -109,7 +109,7 @@ var Downloads = (new function($)
|
||||
|
||||
this.applyTheme = function()
|
||||
{
|
||||
$DownloadsTable.fasttable('setPageSize', UISettings.read('$DownloadsRecordsPerPage', 10),
|
||||
$DownloadsTable.fasttable('setPageSize', UISettings.read('DownloadsRecordsPerPage', 10),
|
||||
UISettings.miniTheme ? 1 : 5, !UISettings.miniTheme);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ var Downloads = (new function($)
|
||||
$('#DownloadsTable_Category').css('width', DownloadsUI.calcCategoryColumnWidth());
|
||||
}
|
||||
|
||||
RPC.call('listgroups', [100], groups_loaded);
|
||||
RPC.call('listgroups', [], groups_loaded);
|
||||
}
|
||||
|
||||
function groups_loaded(_groups)
|
||||
@@ -303,7 +303,7 @@ var Downloads = (new function($)
|
||||
this.recordsPerPageChange = function()
|
||||
{
|
||||
var val = $DownloadsRecordsPerPage.val();
|
||||
UISettings.write('$DownloadsRecordsPerPage', val);
|
||||
UISettings.write('DownloadsRecordsPerPage', val);
|
||||
$DownloadsTable.fasttable('setPageSize', val);
|
||||
}
|
||||
|
||||
@@ -334,6 +334,7 @@ var Downloads = (new function($)
|
||||
function itemClick(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var nzbid = $(this).attr('data-nzbid');
|
||||
var area = $(this).attr('data-area');
|
||||
$(this).blur();
|
||||
@@ -352,7 +353,7 @@ var Downloads = (new function($)
|
||||
|
||||
/*** CHECKMARKS ******************************************************/
|
||||
|
||||
function checkBuildEditIDList(allowPostProcess, allowUrl)
|
||||
function checkBuildEditIDList(allowPostProcess, allowUrl, allowEmpty)
|
||||
{
|
||||
var checkedRows = $DownloadsTable.fasttable('checkedRows');
|
||||
|
||||
@@ -378,7 +379,7 @@ var Downloads = (new function($)
|
||||
}
|
||||
}
|
||||
|
||||
if (checkedEditIDs.length === 0)
|
||||
if (checkedEditIDs.length === 0 && !allowEmpty)
|
||||
{
|
||||
Notification.show('#Notif_Downloads_Select');
|
||||
return null;
|
||||
@@ -546,6 +547,13 @@ var Downloads = (new function($)
|
||||
notification = '';
|
||||
RPC.call('editqueue', [EditAction, EditOffset, '', checkedEditIDs], editCompleted);
|
||||
}
|
||||
|
||||
this.sort = function(order)
|
||||
{
|
||||
var checkedEditIDs = checkBuildEditIDList(true, true, true);
|
||||
notification = '#Notif_Downloads_Sorted';
|
||||
RPC.call('editqueue', ['GroupSort', 0, order, checkedEditIDs], editCompleted);
|
||||
}
|
||||
}(jQuery));
|
||||
|
||||
|
||||
@@ -703,26 +711,13 @@ var DownloadsUI = (new function($)
|
||||
{
|
||||
switch (group.Status)
|
||||
{
|
||||
case "REPAIRING":
|
||||
break;
|
||||
case "LOADING_PARS":
|
||||
case "VERIFYING_SOURCES":
|
||||
case "VERIFYING_REPAIRED":
|
||||
case "UNPACKING":
|
||||
case "RENAMING":
|
||||
text = group.PostInfoText;
|
||||
break;
|
||||
case "EXECUTING_SCRIPT":
|
||||
if (group.Log && group.Log.length > 0)
|
||||
{
|
||||
text = group.Log[group.Log.length-1].Text;
|
||||
// remove "for <nzb-name>" from label text
|
||||
text = text.replace(' for ' + group.NZBName, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
text = group.PostInfoText;
|
||||
}
|
||||
text = group.PostInfoText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
285
webui/edit.js
285
webui/edit.js
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,7 +39,6 @@ var DownloadsEditDialog = (new function($)
|
||||
|
||||
// Controls
|
||||
var $DownloadsEditDialog;
|
||||
var $DownloadsLogTable;
|
||||
var $DownloadsFileTable;
|
||||
var $DownloadsEdit_ParamData;
|
||||
var $ServStatsTable;
|
||||
@@ -70,17 +69,7 @@ var DownloadsEditDialog = (new function($)
|
||||
$('#DownloadsEdit_Back').click(backClick);
|
||||
$('#DownloadsEdit_Category').change(categoryChange);
|
||||
|
||||
$DownloadsLogTable = $('#DownloadsEdit_LogTable');
|
||||
$DownloadsLogTable.fasttable(
|
||||
{
|
||||
filterInput: '#DownloadsEdit_LogTable_filter',
|
||||
pagerContainer: '#DownloadsEdit_LogTable_pager',
|
||||
filterCaseSensitive: false,
|
||||
pageSize: 100,
|
||||
maxPages: 3,
|
||||
hasHeader: true,
|
||||
renderCellCallback: logTableRenderCellCallback
|
||||
});
|
||||
LogTab.init('Downloads');
|
||||
|
||||
$DownloadsFileTable = $('#DownloadsEdit_FileTable');
|
||||
$DownloadsFileTable.fasttable(
|
||||
@@ -105,8 +94,8 @@ var DownloadsEditDialog = (new function($)
|
||||
renderCellCallback: EditUI.servStatsTableRenderCellCallback
|
||||
});
|
||||
|
||||
$DownloadsFileTable.on('click', 'tbody div.check',
|
||||
function(event) { $DownloadsFileTable.fasttable('itemCheckClick', this.parentNode.parentNode, event); });
|
||||
$DownloadsFileTable.on('click', UISettings.rowSelect ? 'tbody tr' : 'tbody div.check',
|
||||
function(event) { $DownloadsFileTable.fasttable('itemCheckClick', UISettings.rowSelect ? this : this.parentNode.parentNode, event); });
|
||||
$DownloadsFileTable.on('click', 'thead div.check',
|
||||
function() { $DownloadsFileTable.fasttable('titleCheckClick') });
|
||||
$DownloadsFileTable.on('mousedown', Util.disableShiftMouseDown);
|
||||
@@ -114,7 +103,7 @@ var DownloadsEditDialog = (new function($)
|
||||
$DownloadsEditDialog.on('hidden', function()
|
||||
{
|
||||
// cleanup
|
||||
$DownloadsLogTable.fasttable('update', []);
|
||||
LogTab.reset('Downloads');
|
||||
$DownloadsFileTable.fasttable('update', []);
|
||||
$DownloadsEdit_ParamData.empty();
|
||||
clearTimeout(refreshTimer);
|
||||
@@ -225,7 +214,6 @@ var DownloadsEditDialog = (new function($)
|
||||
$('#DownloadsEdit_DupeScore').val(group.DupeScore);
|
||||
$('#DownloadsEdit_DupeMode').val(group.DupeMode);
|
||||
|
||||
$DownloadsLogTable.fasttable('update', []);
|
||||
$DownloadsFileTable.fasttable('update', []);
|
||||
|
||||
var postParamConfig = ParamTab.createPostParamConfig();
|
||||
@@ -243,7 +231,7 @@ var DownloadsEditDialog = (new function($)
|
||||
var dupeCheck = Options.option('DupeCheck') === 'yes';
|
||||
Util.show('#DownloadsEdit_Dupe', dupeCheck);
|
||||
var postParam = postParamConfig[0].options.length > 0 && group.Kind === 'NZB';
|
||||
var postLog = group.postprocess && group.Log.length > 0;
|
||||
var postLog = group.MessageCount > 0;
|
||||
Util.show('#DownloadsEdit_Param', postParam);
|
||||
Util.show('#DownloadsEdit_Log', postLog);
|
||||
|
||||
@@ -291,8 +279,8 @@ var DownloadsEditDialog = (new function($)
|
||||
$DownloadsEditDialog.restoreTab();
|
||||
|
||||
$('#DownloadsEdit_FileTable_filter').val('');
|
||||
$('#DownloadsEdit_LogTable_filter').val('');
|
||||
$('#DownloadsEdit_LogTable_pagerBlock').hide();
|
||||
|
||||
LogTab.reset('Downloads');
|
||||
|
||||
files = null;
|
||||
logFilled = false;
|
||||
@@ -359,10 +347,10 @@ var DownloadsEditDialog = (new function($)
|
||||
}
|
||||
}});
|
||||
|
||||
if (tab === '#DownloadsEdit_LogTab' && !logFilled && curGroup.postprocess &&
|
||||
curGroup.Log && curGroup.Log.length > 0)
|
||||
if (tab === '#DownloadsEdit_LogTab' && !logFilled && (curGroup.postprocess || curGroup.MessageCount > 0))
|
||||
{
|
||||
fillLog();
|
||||
LogTab.fill('Downloads', curGroup);
|
||||
logFilled = true;
|
||||
}
|
||||
|
||||
if (tab === '#DownloadsEdit_FileTab' && files === null)
|
||||
@@ -576,64 +564,6 @@ var DownloadsEditDialog = (new function($)
|
||||
:saveParam();
|
||||
}
|
||||
|
||||
/*** TAB: LOG *************************************************************************/
|
||||
|
||||
function fillLog()
|
||||
{
|
||||
logFilled = true;
|
||||
var data = [];
|
||||
|
||||
for (var i=0; i < curGroup.Log.length; i++)
|
||||
{
|
||||
var message = curGroup.Log[i];
|
||||
|
||||
var kind;
|
||||
switch (message.Kind)
|
||||
{
|
||||
case 'INFO': kind = '<span class="label label-status label-success">info</span>'; break;
|
||||
case 'DETAIL': kind = '<span class="label label-status label-info">detail</span>'; break;
|
||||
case 'WARNING': kind = '<span class="label label-status label-warning">warning</span>'; break;
|
||||
case 'ERROR': kind = '<span class="label label-status label-important">error</span>'; break;
|
||||
case 'DEBUG': kind = '<span class="label label-status">debug</span>'; break;
|
||||
}
|
||||
|
||||
var text = Util.textToHtml(message.Text);
|
||||
var time = Util.formatDateTime(message.Time + UISettings.timeZoneCorrection*60*60);
|
||||
var fields;
|
||||
|
||||
if (!UISettings.miniTheme)
|
||||
{
|
||||
fields = [kind, time, text];
|
||||
}
|
||||
else
|
||||
{
|
||||
var info = kind + ' <span class="label">' + time + '</span> ' + text;
|
||||
fields = [info];
|
||||
}
|
||||
|
||||
var item =
|
||||
{
|
||||
id: message,
|
||||
fields: fields,
|
||||
search: message.Kind + ' ' + time + ' ' + message.Text
|
||||
};
|
||||
|
||||
data.unshift(item);
|
||||
}
|
||||
|
||||
$DownloadsLogTable.fasttable('update', data);
|
||||
$DownloadsLogTable.fasttable('setCurPage', 1);
|
||||
Util.show('#DownloadsEdit_LogTable_pagerBlock', data.length > 100);
|
||||
}
|
||||
|
||||
function logTableRenderCellCallback(cell, index, item)
|
||||
{
|
||||
if (index === 0)
|
||||
{
|
||||
cell.width = '65px';
|
||||
}
|
||||
}
|
||||
|
||||
/*** TAB: FILES *************************************************************************/
|
||||
|
||||
function fillFiles()
|
||||
@@ -805,7 +735,7 @@ var DownloadsEditDialog = (new function($)
|
||||
}
|
||||
break;
|
||||
case 'split':
|
||||
if (file.ActiveDownloads > 0 || file.FileSizeLo !== file.RemainingSizeLo)
|
||||
if (file.ActiveDownloads > 0 || file.Progress > 0)
|
||||
{
|
||||
splitError = true;
|
||||
}
|
||||
@@ -1157,6 +1087,114 @@ var ParamTab = (new function($)
|
||||
}(jQuery));
|
||||
|
||||
|
||||
/*** LOG TAB FOR EDIT DIALOGS ************************************************************/
|
||||
|
||||
var LogTab = (new function($)
|
||||
{
|
||||
'use strict'
|
||||
|
||||
this.init = function(name)
|
||||
{
|
||||
var recordsPerPage = UISettings.read('ItemLogRecordsPerPage', 10);
|
||||
$('#' + name + 'LogRecordsPerPage').val(recordsPerPage);
|
||||
|
||||
var $LogTable = $('#' + name + 'Edit_LogTable');
|
||||
$LogTable.fasttable(
|
||||
{
|
||||
filterInput: '#' + name + 'Edit_LogTable_filter',
|
||||
pagerContainer: '#' + name + 'Edit_LogTable_pager',
|
||||
filterCaseSensitive: false,
|
||||
pageSize: recordsPerPage,
|
||||
maxPages: 3,
|
||||
hasHeader: true,
|
||||
renderCellCallback: logTableRenderCellCallback
|
||||
});
|
||||
}
|
||||
|
||||
this.reset = function(name)
|
||||
{
|
||||
var $LogTable = $('#' + name + 'Edit_LogTable');
|
||||
$LogTable.fasttable('update', []);
|
||||
|
||||
$('#' + name + 'Edit_LogTable_filter').val('');
|
||||
}
|
||||
|
||||
this.fill = function(name, item)
|
||||
{
|
||||
function logLoaded(log)
|
||||
{
|
||||
$('#' + name + 'EditDialog .loading-block').hide();
|
||||
var $LogTable = $('#' + name + 'Edit_LogTable');
|
||||
var data = [];
|
||||
|
||||
for (var i=0; i < log.length; i++)
|
||||
{
|
||||
var message = log[i];
|
||||
|
||||
var kind;
|
||||
switch (message.Kind)
|
||||
{
|
||||
case 'INFO': kind = '<span class="label label-status label-success">info</span>'; break;
|
||||
case 'DETAIL': kind = '<span class="label label-status label-info">detail</span>'; break;
|
||||
case 'WARNING': kind = '<span class="label label-status label-warning">warning</span>'; break;
|
||||
case 'ERROR': kind = '<span class="label label-status label-important">error</span>'; break;
|
||||
case 'DEBUG': kind = '<span class="label label-status">debug</span>'; break;
|
||||
}
|
||||
|
||||
var text = Util.textToHtml(message.Text);
|
||||
var time = Util.formatDateTime(message.Time + UISettings.timeZoneCorrection*60*60);
|
||||
var fields;
|
||||
|
||||
if (!UISettings.miniTheme)
|
||||
{
|
||||
fields = [kind, time, text];
|
||||
}
|
||||
else
|
||||
{
|
||||
var info = kind + ' <span class="label">' + time + '</span> ' + text;
|
||||
fields = [info];
|
||||
}
|
||||
|
||||
var item =
|
||||
{
|
||||
id: message,
|
||||
fields: fields,
|
||||
search: message.Kind + ' ' + time + ' ' + message.Text
|
||||
};
|
||||
|
||||
data.unshift(item);
|
||||
}
|
||||
|
||||
$LogTable.fasttable('update', data);
|
||||
$LogTable.fasttable('setCurPage', 1);
|
||||
}
|
||||
|
||||
var recordsPerPage = UISettings.read('ItemLogRecordsPerPage', 10);
|
||||
$('#' + name + 'LogRecordsPerPage').val(recordsPerPage);
|
||||
|
||||
$('#' + name + 'EditDialog .loading-block').show();
|
||||
RPC.call('loadlog', [item.NZBID, 0, 1000], logLoaded);
|
||||
}
|
||||
|
||||
function logTableRenderCellCallback(cell, index, item)
|
||||
{
|
||||
if (index === 0)
|
||||
{
|
||||
cell.width = '65px';
|
||||
}
|
||||
}
|
||||
|
||||
this.recordsPerPageChange = function(name)
|
||||
{
|
||||
var val = $('#' + name + 'LogRecordsPerPage').val();
|
||||
UISettings.write('ItemLogRecordsPerPage', val);
|
||||
var $LogTable = $('#' + name + 'Edit_LogTable');
|
||||
$LogTable.fasttable('setPageSize', val);
|
||||
}
|
||||
|
||||
}(jQuery));
|
||||
|
||||
|
||||
/*** DOWNLOAD MULTI EDIT DIALOG ************************************************************/
|
||||
|
||||
var DownloadsMultiDialog = (new function($)
|
||||
@@ -1497,6 +1535,7 @@ var HistoryEditDialog = (new function()
|
||||
var lastPage;
|
||||
var lastFullscreen;
|
||||
var saveCompleted;
|
||||
var logFilled;
|
||||
|
||||
this.init = function()
|
||||
{
|
||||
@@ -1508,11 +1547,14 @@ var HistoryEditDialog = (new function()
|
||||
$('#HistoryEdit_Return, #HistoryEdit_ReturnURL').click(itemReturn);
|
||||
$('#HistoryEdit_Reprocess').click(itemReprocess);
|
||||
$('#HistoryEdit_Redownload').click(itemRedownload);
|
||||
$('#HistoryEdit_Param, #HistoryEdit_Dupe').click(tabClick);
|
||||
$('#HistoryEdit_Param, #HistoryEdit_Dupe, #HistoryEdit_Log').click(tabClick);
|
||||
$('#HistoryEdit_Back').click(backClick);
|
||||
$('#HistoryEdit_MarkSuccess').click(itemSuccess);
|
||||
$('#HistoryEdit_MarkGood').click(itemGood);
|
||||
$('#HistoryEdit_MarkBad').click(itemBad);
|
||||
|
||||
LogTab.init('History');
|
||||
|
||||
$ServStatsTable = $('#HistoryEdit_ServStatsTable');
|
||||
$ServStatsTable.fasttable(
|
||||
{
|
||||
@@ -1527,6 +1569,7 @@ var HistoryEditDialog = (new function()
|
||||
$HistoryEditDialog.on('hidden', function ()
|
||||
{
|
||||
$HistoryEdit_ParamData.empty();
|
||||
LogTab.reset('History');
|
||||
// resume updates
|
||||
Refresher.resume();
|
||||
});
|
||||
@@ -1603,14 +1646,23 @@ var HistoryEditDialog = (new function()
|
||||
(hist.Kind === 'DUP' ? 'hidden' : hist.Kind) + '</span>');
|
||||
}
|
||||
|
||||
$('#HistoryEdit_NZBName').val(hist.Name);
|
||||
|
||||
if (hist.Kind !== 'DUP')
|
||||
{
|
||||
$('#HistoryEdit_Category').text(hist.Category);
|
||||
// Category
|
||||
var v = $('#HistoryEdit_Category');
|
||||
DownloadsUI.fillCategoryCombo(v);
|
||||
v.val(hist.Category);
|
||||
if (v.val() != hist.Category)
|
||||
{
|
||||
v.append($('<option selected="selected"></option>').text(hist.Category));
|
||||
}
|
||||
}
|
||||
|
||||
if (hist.Kind === 'NZB')
|
||||
{
|
||||
$('#HistoryEdit_Path').text(hist.FinalDir !== '' ? hist.FinalDir : hist.DestDir);
|
||||
$('#HistoryEdit_Path').val(hist.FinalDir !== '' ? hist.FinalDir : hist.DestDir);
|
||||
|
||||
var size = Util.formatSizeMB(hist.FileSizeMB, hist.FileSizeLo);
|
||||
var completion = hist.SuccessArticles + hist.FailedArticles > 0 ? Util.round0(hist.SuccessArticles * 100.0 / (hist.SuccessArticles + hist.FailedArticles)) + '%' : '--';
|
||||
@@ -1655,6 +1707,8 @@ var HistoryEditDialog = (new function()
|
||||
Util.show('#HistoryEdit_CategoryGroup', hist.Kind !== 'DUP');
|
||||
Util.show('#HistoryEdit_DupGroup', hist.Kind === 'DUP');
|
||||
var dupeCheck = Options.option('DupeCheck') === 'yes';
|
||||
Util.show('#HistoryEdit_MarkSuccess', dupeCheck && ((hist.Kind === 'NZB' && hist.MarkStatus !== 'SUCCESS') || (hist.Kind === 'DUP' && hist.DupStatus !== 'SUCCESS')) &&
|
||||
hist.Status.substr(0, 7) !== 'SUCCESS');
|
||||
Util.show('#HistoryEdit_MarkGood', dupeCheck && ((hist.Kind === 'NZB' && hist.MarkStatus !== 'GOOD') || (hist.Kind === 'DUP' && hist.DupStatus !== 'GOOD')));
|
||||
Util.show('#HistoryEdit_MarkBad', dupeCheck && hist.Kind !== 'URL');
|
||||
Util.show('#HistoryEdit_Dupe', dupeCheck);
|
||||
@@ -1672,6 +1726,9 @@ var HistoryEditDialog = (new function()
|
||||
postParams = ParamTab.buildPostParamTab($HistoryEdit_ParamData, postParamConfig, curHist.Parameters);
|
||||
}
|
||||
|
||||
var postLog = hist.MessageCount > 0;
|
||||
Util.show('#HistoryEdit_Log', postLog);
|
||||
|
||||
EditUI.buildDNZBLinks(curHist.Parameters ? curHist.Parameters : [], 'HistoryEdit_DNZB');
|
||||
|
||||
enableAllButtons();
|
||||
@@ -1681,10 +1738,14 @@ var HistoryEditDialog = (new function()
|
||||
$('#HistoryEdit_ServStatsTab').hide();
|
||||
$('#HistoryEdit_TimeStatsTab').hide();
|
||||
$('#HistoryEdit_DupeTab').hide();
|
||||
$('#HistoryEdit_LogTab').hide();
|
||||
$('#HistoryEdit_Back').hide();
|
||||
$('#HistoryEdit_BackSpace').show();
|
||||
$HistoryEditDialog.restoreTab();
|
||||
|
||||
LogTab.reset('History');
|
||||
|
||||
logFilled = false;
|
||||
notification = null;
|
||||
|
||||
$HistoryEditDialog.modal({backdrop: 'static'});
|
||||
@@ -1754,6 +1815,12 @@ var HistoryEditDialog = (new function()
|
||||
$HistoryEditDialog.switchTab($('#HistoryEdit_GeneralTab'), lastPage,
|
||||
e.shiftKey || !UISettings.slideAnimation ? 0 : 500,
|
||||
{fullscreen: lastFullscreen, mini: UISettings.miniTheme});
|
||||
|
||||
if (tab === '#HistoryEdit_LogTab' && !logFilled && curHist.MessageCount > 0)
|
||||
{
|
||||
LogTab.fill('History', curHist);
|
||||
logFilled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function backClick(e)
|
||||
@@ -1811,7 +1878,8 @@ var HistoryEditDialog = (new function()
|
||||
e.preventDefault();
|
||||
if (curHist.SuccessArticles > 0)
|
||||
{
|
||||
ConfirmDialog.showModal('HistoryEditRedownloadConfirmDialog', doItemRedownload);
|
||||
ConfirmDialog.showModal('HistoryEditRedownloadConfirmDialog', doItemRedownload,
|
||||
function () { HistoryUI.confirmMulti(false); });
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1836,7 +1904,7 @@ var HistoryEditDialog = (new function()
|
||||
|
||||
function reprocess()
|
||||
{
|
||||
notification = '#Notif_History_Reproces';
|
||||
notification = '#Notif_History_Reprocess';
|
||||
RPC.call('editqueue', ['HistoryProcess', 0, '', [curHist.ID]], completed);
|
||||
}
|
||||
|
||||
@@ -1857,13 +1925,50 @@ var HistoryEditDialog = (new function()
|
||||
disableAllButtons();
|
||||
notification = null;
|
||||
saveCompleted = completed;
|
||||
saveDupeKey();
|
||||
saveName();
|
||||
}
|
||||
|
||||
function saveName()
|
||||
{
|
||||
var name = $('#HistoryEdit_NZBName').val();
|
||||
name !== curHist.Name && !curHist.postprocess ?
|
||||
RPC.call('editqueue', ['HistorySetName', 0, name, [curHist.ID]], function()
|
||||
{
|
||||
notification = '#Notif_History_Saved';
|
||||
saveCategory();
|
||||
})
|
||||
:saveCategory();
|
||||
}
|
||||
|
||||
function saveCategory()
|
||||
{
|
||||
var category = $('#HistoryEdit_Category').val();
|
||||
category !== curHist.Category && curHist.Kind !== 'DUP' ?
|
||||
RPC.call('editqueue', ['HistorySetCategory', 0, category, [curHist.ID]], function()
|
||||
{
|
||||
notification = '#Notif_History_Saved';
|
||||
saveDupeKey();
|
||||
})
|
||||
: saveDupeKey();
|
||||
}
|
||||
|
||||
function itemSuccess(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
ConfirmDialog.showModal('HistoryEditSuccessConfirmDialog', doItemSuccess, function () { HistoryUI.confirmMulti(false); });
|
||||
}
|
||||
|
||||
function doItemSuccess()
|
||||
{
|
||||
disableAllButtons();
|
||||
notification = '#Notif_History_Marked';
|
||||
RPC.call('editqueue', ['HistoryMarkSuccess', 0, '', [curHist.ID]], completed);
|
||||
}
|
||||
|
||||
function itemGood(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
ConfirmDialog.showModal('HistoryEditGoodConfirmDialog', doItemGood);
|
||||
ConfirmDialog.showModal('HistoryEditGoodConfirmDialog', doItemGood, function () { HistoryUI.confirmMulti(false); });
|
||||
}
|
||||
|
||||
function doItemGood()
|
||||
@@ -1876,7 +1981,7 @@ var HistoryEditDialog = (new function()
|
||||
function itemBad(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
ConfirmDialog.showModal('HistoryEditBadConfirmDialog', doItemBad);
|
||||
ConfirmDialog.showModal('HistoryEditBadConfirmDialog', doItemBad, function () { HistoryUI.confirmMulti(false); });
|
||||
}
|
||||
|
||||
function doItemBad()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -60,10 +60,13 @@ var Feeds = (new function($)
|
||||
{
|
||||
var item = menuItemTemplate.clone();
|
||||
var name = Options.option('Feed' + i + '.Name');
|
||||
var a = $('a', item);
|
||||
var a = $('span', item);
|
||||
a.text(name !== '' ? name : 'Feed' + i);
|
||||
a.attr('data-id', i);
|
||||
a.click(viewFeed);
|
||||
var im = $('button', item);
|
||||
im.click(fetchFeed);
|
||||
im.attr('data-id', i);
|
||||
insertPos.before(item);
|
||||
}
|
||||
}
|
||||
@@ -77,11 +80,20 @@ var Feeds = (new function($)
|
||||
FeedDialog.showModal(id);
|
||||
}
|
||||
|
||||
function fetchFeed()
|
||||
{
|
||||
var id = parseInt($(this).attr('data-id'));
|
||||
RPC.call('fetchfeed', [id], function()
|
||||
{
|
||||
Notification.show('#Notif_Feeds_Fetch');
|
||||
});
|
||||
}
|
||||
|
||||
this.fetchAll = function()
|
||||
{
|
||||
RPC.call('fetchfeed', [0], function()
|
||||
{
|
||||
Notification.show('#Notif_Feeds_FetchAll');
|
||||
Notification.show('#Notif_Feeds_Fetch');
|
||||
});
|
||||
}
|
||||
}(jQuery));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -78,8 +78,8 @@ var History = (new function($)
|
||||
});
|
||||
|
||||
$HistoryTable.on('click', 'a', editClick);
|
||||
$HistoryTable.on('click', 'tbody div.check',
|
||||
function(event) { $HistoryTable.fasttable('itemCheckClick', this.parentNode.parentNode, event); });
|
||||
$HistoryTable.on('click', UISettings.rowSelect ? 'tbody tr' : 'tbody div.check',
|
||||
function(event) { $HistoryTable.fasttable('itemCheckClick', UISettings.rowSelect ? this : this.parentNode.parentNode, event); });
|
||||
$HistoryTable.on('click', 'thead div.check',
|
||||
function() { $HistoryTable.fasttable('titleCheckClick') });
|
||||
$HistoryTable.on('mousedown', Util.disableShiftMouseDown);
|
||||
@@ -269,7 +269,7 @@ var History = (new function($)
|
||||
}
|
||||
}
|
||||
|
||||
this.deleteClick = function()
|
||||
this.actionClick = function(action)
|
||||
{
|
||||
var checkedRows = $HistoryTable.fasttable('checkedRows');
|
||||
if (checkedRows.length == 0)
|
||||
@@ -279,6 +279,7 @@ var History = (new function($)
|
||||
}
|
||||
|
||||
var hasNzb = false;
|
||||
var hasUrl = false;
|
||||
var hasDup = false;
|
||||
var hasFailed = false;
|
||||
for (var i = 0; i < history.length; i++)
|
||||
@@ -287,23 +288,73 @@ var History = (new function($)
|
||||
if (checkedRows.indexOf(hist.ID) > -1)
|
||||
{
|
||||
hasNzb |= hist.Kind === 'NZB';
|
||||
hasUrl |= hist.Kind === 'URL';
|
||||
hasDup |= hist.Kind === 'DUP';
|
||||
hasFailed |= hist.ParStatus === 'FAILURE' || hist.UnpackStatus === 'FAILURE';
|
||||
}
|
||||
}
|
||||
|
||||
HistoryUI.deleteConfirm(historyDelete, hasNzb, hasDup, hasFailed, true);
|
||||
switch (action)
|
||||
{
|
||||
case 'DELETE':
|
||||
notification = '#Notif_History_Deleted';
|
||||
HistoryUI.deleteConfirm(historyAction, hasNzb, hasDup, hasFailed, true);
|
||||
break;
|
||||
|
||||
case 'REPROCESS':
|
||||
if (hasUrl || hasDup)
|
||||
{
|
||||
Notification.show('#Notif_History_CantReprocess');
|
||||
return;
|
||||
}
|
||||
notification = '#Notif_History_Reprocess';
|
||||
historyAction('HistoryProcess');
|
||||
break;
|
||||
|
||||
case 'REDOWNLOAD':
|
||||
if (hasDup)
|
||||
{
|
||||
Notification.show('#Notif_History_CantRedownload');
|
||||
return;
|
||||
}
|
||||
notification = '#Notif_History_Returned';
|
||||
ConfirmDialog.showModal('HistoryEditRedownloadConfirmDialog',
|
||||
function () { historyAction('HistoryRedownload') },
|
||||
function () { HistoryUI.confirmMulti(checkedRows.length > 1); });
|
||||
break;
|
||||
|
||||
case 'MARKSUCCESS':
|
||||
case 'MARKGOOD':
|
||||
case 'MARKBAD':
|
||||
if (hasUrl)
|
||||
{
|
||||
Notification.show('#Notif_History_CantMark');
|
||||
return;
|
||||
}
|
||||
notification = '#Notif_History_Marked';
|
||||
|
||||
ConfirmDialog.showModal(action === 'MARKSUCCESS' ? 'HistoryEditSuccessConfirmDialog' :
|
||||
action === 'MARKGOOD' ? 'HistoryEditGoodConfirmDialog' : 'HistoryEditBadConfirmDialog',
|
||||
function () // action
|
||||
{
|
||||
historyAction(action === 'MARKSUCCESS' ? 'HistoryMarkSuccess' :
|
||||
action === 'MARKGOOD' ? 'HistoryMarkGood' :'HistoryMarkBad');
|
||||
},
|
||||
function (_dialog) // init
|
||||
{
|
||||
HistoryUI.confirmMulti(checkedRows.length > 1);
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function historyDelete(command)
|
||||
function historyAction(command)
|
||||
{
|
||||
Refresher.pause();
|
||||
|
||||
var IDs = $HistoryTable.fasttable('checkedRows');
|
||||
|
||||
RPC.call('editqueue', [command, 0, '', [IDs]], function()
|
||||
{
|
||||
notification = '#Notif_History_Deleted';
|
||||
editCompleted();
|
||||
});
|
||||
}
|
||||
@@ -321,6 +372,7 @@ var History = (new function($)
|
||||
function editClick(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var histid = $(this).attr('histid');
|
||||
$(this).blur();
|
||||
@@ -456,14 +508,7 @@ var HistoryUI = (new function($)
|
||||
function init(_dialog)
|
||||
{
|
||||
dialog = _dialog;
|
||||
|
||||
if (!multi)
|
||||
{
|
||||
var html = $('#ConfirmDialog_Text').html();
|
||||
html = html.replace(/records/g, 'record');
|
||||
$('#ConfirmDialog_Text').html(html);
|
||||
}
|
||||
|
||||
HistoryUI.confirmMulti(multi);
|
||||
$('#HistoryDeleteConfirmDialog_Hide', dialog).prop('checked', true);
|
||||
Util.show($('#HistoryDeleteConfirmDialog_Options', dialog), hasNzb && dupeCheck);
|
||||
Util.show($('#HistoryDeleteConfirmDialog_Simple', dialog), !(hasNzb && dupeCheck));
|
||||
@@ -483,5 +528,15 @@ var HistoryUI = (new function($)
|
||||
|
||||
ConfirmDialog.showModal('HistoryDeleteConfirmDialog', action, init);
|
||||
}
|
||||
|
||||
|
||||
this.confirmMulti = function(multi)
|
||||
{
|
||||
if (multi === undefined || !multi)
|
||||
{
|
||||
var html = $('#ConfirmDialog_Text').html();
|
||||
html = html.replace(/records/g, 'record');
|
||||
html = html.replace(/nzbs/g, 'nzb');
|
||||
$('#ConfirmDialog_Text').html(html);
|
||||
}
|
||||
}
|
||||
}(jQuery));
|
||||
|
||||
160
webui/index.html
160
webui/index.html
@@ -2,7 +2,7 @@
|
||||
<!--
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -252,7 +252,7 @@
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown" title="RSS Feeds"><i class="icon-rss"></i><span class="btn-caption"> Feeds </span><span class="phone-only inline"> </span><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu" id="RssMenu">
|
||||
<li class="menu-header">RSS Feeds</li>
|
||||
<li class="feed-menu-template hide"><a href="#">Feed1</a></li>
|
||||
<li class="feed-menu-template hide"><a href="#" title="Show feed"><table><tr><td><span></span></td><td><button class="btn btn-primary" title="Fetch feed">Fetch</button></td></tr></table></a></li>
|
||||
<li class="divider" id="RssMenu_Divider"></li>
|
||||
<li><a href="#" onclick="Feeds.fetchAll()">Fetch All Feeds</a></li>
|
||||
</ul>
|
||||
@@ -286,10 +286,10 @@
|
||||
<tr>
|
||||
<th><div class="check img-check"></div></th>
|
||||
<th width="95px">Status</th>
|
||||
<th id="DownloadsTable_Name">Name</th>
|
||||
<th id="DownloadsTable_Category">Category</th>
|
||||
<th width="30px" class="text-right">Age</th>
|
||||
<th width="120px"><div style="float:left; position:relative; width:50%; text-align:left;">Size</div><div style="float:right; position:relative; width:50%; text-align:right;">Left</div></th>
|
||||
<th id="DownloadsTable_Name"><a href="#" onclick="Downloads.sort('name')">Name</a></th>
|
||||
<th id="DownloadsTable_Category"><a href="#" onclick="Downloads.sort('category')">Category</a></th>
|
||||
<th width="30px" class="text-right"><a href="#" onclick="Downloads.sort('age')">Age</a></th>
|
||||
<th width="120px"><div style="float:left; position:relative; width:50%; text-align:left;"><a href="#"onclick="Downloads.sort('size')">Size</a></div><div style="float:right; position:relative; width:50%; text-align:right;"><a href="#" onclick="Downloads.sort('left')">Left</a></div></th>
|
||||
<th width="58px" class="text-right">Est. Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -316,9 +316,18 @@
|
||||
|
||||
<div class="btn-toolbar form-inline section-toolbar" id ="HistoryTab_Toolbar">
|
||||
<div class="btn-group">
|
||||
<button class="btn" onclick="History.deleteClick()" title="Delete selected records"><i class="icon-trash"></i><span class="btn-caption"> Delete</span></button>
|
||||
<button class="btn" onclick="History.actionClick('DELETE')" title="Delete selected records"><i class="icon-trash"></i><span class="btn-caption"> Delete</span></button>
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown" title="More actions"><span class="btn-caption"> More </span><span class="phone-only inline"> </span><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="menu-header">Actions</li>
|
||||
<li><a href="#" id="HistoryTab_Reprocess" onclick="History.actionClick('REPROCESS')"><i class="icon-process"></i> Post-Process Again</a></li>
|
||||
<li><a href="#" id="HistoryTab_Redownload" onclick="History.actionClick('REDOWNLOAD')"><i class="icon-downloads"></i> Download Again</a></li>
|
||||
<li><a href="#" id="HistoryTab_MarkSuccess" onclick="History.actionClick('MARKSUCCESS')"><i class="icon-ok"></i> Mark as Success</a></li>
|
||||
<li><a href="#" id="HistoryTab_MarkGood" onclick="History.actionClick('MARKGOOD')"><i class="icon-plus"></i> Mark as Good</a></li>
|
||||
<li><a href="#" id="HistoryTab_MarkBad" onclick="History.actionClick('MARKBAD')"><i class="icon-minus"></i> Mark as Bad</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- STATUS FILTER BUTTONS -->
|
||||
<div class="btn-group phone-hide">
|
||||
<button class="btn history-filter btn-inverse" onclick="History.filter('ALL')" title="Show All">All <span class="badge badge-active" id="History_Badge_ALL">?</span></button>
|
||||
@@ -1019,10 +1028,29 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-tab hide" id="DownloadsEdit_LogTab">
|
||||
<div class="loading-block">
|
||||
<img src="img/transmit.gif"></img>
|
||||
</div>
|
||||
<div>
|
||||
<div class="row-fluid">
|
||||
<div class="pull-left">Post-Processing Messages</div>
|
||||
<div class="pull-right" style="margin-bottom:10px;"><input id="DownloadsEdit_LogTable_filter" class="search-query" placeholder="Search" type="text"></div>
|
||||
<div class="form-inline clearfix modal-toolbox">
|
||||
<div id="DownloadsLogRecordsPerPageBlock" class="pull-left toolbox-length">
|
||||
<select size="1" id="DownloadsLogRecordsPerPage" onchange="LogTab.recordsPerPageChange('Downloads')">
|
||||
<option value="5">5</option>
|
||||
<option selected="selected" value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
<option value="200">200</option>
|
||||
<option value="500">500</option>
|
||||
<option value="1000">1000</option>
|
||||
</select><span class="records-label"> records per page</span>
|
||||
</div>
|
||||
<div id="DownloadsEdit_LogTable_filterBlock">
|
||||
<input id="DownloadsEdit_LogTable_filter" class="search-query" placeholder="Search" type="text">
|
||||
</div>
|
||||
<div id ="DownloadsEdit_LogTable_pagerBlock" class="pull-right"><div class="pagination" id ="DownloadsEdit_LogTable_pager"></div></div>
|
||||
</div>
|
||||
<div id="DownloadsEdit_LogBlock">
|
||||
<table class="table table-striped table-bordered datatable" id="DownloadsEdit_LogTable" style="margin-bottom:15px;">
|
||||
@@ -1030,7 +1058,6 @@
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pull-right hide" id="DownloadsEdit_LogTable_pagerBlock"><div class="pagination" id ="DownloadsEdit_LogTable_pager"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1258,6 +1285,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="HistoryEdit_NZBNameGroup">Name</label>
|
||||
<div class="controls" id="HistoryEdit_NZBNameGroup">
|
||||
<input type="text" class="input-xlarge" id="HistoryEdit_NZBName" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" id="HistoryEdit_URLGroup">
|
||||
<label class="control-label" for="HistoryEdit_URL">Link</label>
|
||||
<div class="controls">
|
||||
@@ -1268,14 +1302,15 @@
|
||||
<div class="control-group" id="HistoryEdit_CategoryGroup">
|
||||
<label class="control-label" for="HistoryEdit_Category">Category</label>
|
||||
<div class="controls">
|
||||
<span class="input-medium uneditable-input" id="HistoryEdit_Category"></span>
|
||||
<select id="HistoryEdit_Category">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" id="HistoryEdit_PathGroup">
|
||||
<label class="control-label" for="HistoryEdit_Path">Destination</label>
|
||||
<div class="controls">
|
||||
<span class="uneditable-mulitline-input" id="HistoryEdit_Path"></span>
|
||||
<input type="text" class="input-xlarge" id="HistoryEdit_Path" readonly="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1291,8 +1326,7 @@
|
||||
|
||||
<div class="control-group control-group-last" id="HistoryEdit_DupGroup">
|
||||
<div class="controls">
|
||||
This hidden history record has no information other than status.
|
||||
It remains in history for duplicate check.
|
||||
This hidden history record has little information. It remains in history mostly for duplicate check.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1301,6 +1335,7 @@
|
||||
<div class="modal-bottom-toolbar">
|
||||
<button class="btn" data-tab="HistoryEdit_ParamTab" id="HistoryEdit_Param" title="Post-processing parameters">Postprocess <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="HistoryEdit_DupeTab" id="HistoryEdit_Dupe" title="Duplicate properties">Dupe <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="HistoryEdit_LogTab" data-fullscreen="true" id="HistoryEdit_Log" title="Post-processing messages">Log <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1316,6 +1351,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-tab hide" id="HistoryEdit_LogTab">
|
||||
<div class="loading-block">
|
||||
<img src="img/transmit.gif"></img>
|
||||
</div>
|
||||
<div>
|
||||
<div class="form-inline clearfix modal-toolbox">
|
||||
<div id="HistoryLogRecordsPerPageBlock" class="pull-left toolbox-length">
|
||||
<select size="1" id="HistoryLogRecordsPerPage" onchange="LogTab.recordsPerPageChange('History')">
|
||||
<option value="5">5</option>
|
||||
<option selected="selected" value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
<option value="200">200</option>
|
||||
<option value="500">500</option>
|
||||
<option value="1000">1000</option>
|
||||
</select><span class="records-label"> records per page</span>
|
||||
</div>
|
||||
<div id="HistoryEdit_LogTable_filterBlock">
|
||||
<input id="HistoryEdit_LogTable_filter" class="search-query" placeholder="Search" type="text">
|
||||
</div>
|
||||
<div id ="HistoryEdit_LogTable_pagerBlock" class="pull-right"><div class="pagination" id ="HistoryEdit_LogTable_pager"></div></div>
|
||||
</div>
|
||||
<div id="HistoryEdit_LogBlock">
|
||||
<table class="table table-striped table-bordered datatable" id="HistoryEdit_LogTable" style="margin-bottom:15px;">
|
||||
<thead><tr><th width="65px">Kind</th><th width="170px" class="text-center">Time</th><th>Text</th></tr></thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-tab padded-tab hide" id="HistoryEdit_ServStatsTab">
|
||||
<div>
|
||||
<div id="HistoryEdit_ServStatsBlock">
|
||||
@@ -1392,8 +1461,9 @@
|
||||
<li><a href="#" id="HistoryEdit_Return"><i class="icon-downloads"></i> Download Remaining Files</a></li>
|
||||
<li><a href="#" id="HistoryEdit_ReturnURL"><i class="icon-downloads"></i> Download Again</a></li>
|
||||
<li><a href="#" id="HistoryEdit_Redownload"><i class="icon-downloads"></i> Download Again</a></li>
|
||||
<li><a href="#" id="HistoryEdit_MarkGood"><i class="icon-ok"></i> Mark as Good</a></li>
|
||||
<li><a href="#" id="HistoryEdit_MarkBad"><i class="icon-remove"></i> Mark as Bad</a></li>
|
||||
<li><a href="#" id="HistoryEdit_MarkSuccess"><i class="icon-ok"></i> Mark as Success</a></li>
|
||||
<li><a href="#" id="HistoryEdit_MarkGood"><i class="icon-plus"></i> Mark as Good</a></li>
|
||||
<li><a href="#" id="HistoryEdit_MarkBad"><i class="icon-minus"></i> Mark as Bad</a></li>
|
||||
<li class="menu-header" id="HistoryEdit_DNZB_Section">Indexer Links</li>
|
||||
<li><a href="#" target="_blank" class="HistoryEdit_DNZB" id="HistoryEdit_DNZB_Details"><i class="icon-postcard"></i> Details</a></li>
|
||||
<li><a href="#" target="_blank" class="HistoryEdit_DNZB" id="HistoryEdit_DNZB_MoreInfo"><i class="icon-link"></i> More Info</a></li>
|
||||
@@ -1890,22 +1960,40 @@
|
||||
<div id="HistoryEditRedownloadConfirmDialog_Title">History</div>
|
||||
<div id="HistoryEditRedownloadConfirmDialog_Text">
|
||||
<p>
|
||||
Download this nzb again?
|
||||
Download selected nzbs again?
|
||||
</p>
|
||||
<p class="confirm-help-block">
|
||||
All downloaded files will be deleted and the nzb-file will be downloaded again from scratch.
|
||||
All downloaded files will be deleted and the nzbs will be downloaded again from scratch.
|
||||
</p>
|
||||
</div>
|
||||
<div id="HistoryEditRedownloadConfirmDialog_OK">Download Again</div>
|
||||
</div>
|
||||
|
||||
<!-- *** MARK AS SUCCESS CURRENT HISTORY RECORD CONFIRMATION DIALOG DATA ******************************** -->
|
||||
|
||||
<div class="hide" id="HistoryEditSuccessConfirmDialog">
|
||||
<div id="HistoryEditSuccessConfirmDialog_Title">History</div>
|
||||
<div id="HistoryEditSuccessConfirmDialog_Text">
|
||||
<p>
|
||||
Mark selected history records as success?
|
||||
</p>
|
||||
<p class="confirm-help-block">
|
||||
Marking has an effect on duplicate handling and RSS.<br>Records marked as success
|
||||
considered successfully downloaded and processed. This is useful for downloads repaired
|
||||
or processed outside of NZBGet. Duplicates with higher duplicate scores may be downloaded
|
||||
in the future.
|
||||
</p>
|
||||
</div>
|
||||
<div id="HistoryEditSuccessConfirmDialog_OK">Mark Success</div>
|
||||
</div>
|
||||
|
||||
<!-- *** MARK AS GOOD CURRENT HISTORY RECORD CONFIRMATION DIALOG DATA ******************************** -->
|
||||
|
||||
<div class="hide" id="HistoryEditGoodConfirmDialog">
|
||||
<div id="HistoryEditGoodConfirmDialog_Title">History</div>
|
||||
<div id="HistoryEditGoodConfirmDialog_Text">
|
||||
<p>
|
||||
Mark this history record as good?
|
||||
Mark selected history records as good?
|
||||
</p>
|
||||
<p class="confirm-help-block">
|
||||
Marking has an effect on duplicate handling and RSS.<br>For titles marked as good no more duplicates
|
||||
@@ -1921,7 +2009,7 @@
|
||||
<div id="HistoryEditBadConfirmDialog_Title">History</div>
|
||||
<div id="HistoryEditBadConfirmDialog_Text">
|
||||
<p>
|
||||
Mark this history record as Bad?
|
||||
Mark selected history records as Bad?
|
||||
</p>
|
||||
<p class="confirm-help-block">
|
||||
Marking has an effect on duplicate handling and RSS.<br>If dupe-backups exist in the history
|
||||
@@ -2420,6 +2508,10 @@
|
||||
<strong>URLs cannot be merged or paused</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Downloads_Sorted" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<strong>Sorted</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Edit_Select" data-duration="2000" class="alert alert-error alert-center alert-center-small hide">
|
||||
<strong>Please select records first</strong>
|
||||
</div>
|
||||
@@ -2440,7 +2532,7 @@
|
||||
<strong>Returned to Queue</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_History_Reproces" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<div id="Notif_History_Reprocess" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<strong>Post-Processing</strong>
|
||||
</div>
|
||||
|
||||
@@ -2452,11 +2544,23 @@
|
||||
<strong>Please select records first</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_History_CantMark" data-duration="2000" class="alert alert-error alert-center alert-center-small hide">
|
||||
<strong>Cannot mark URL-records</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_History_Marked" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<strong>Marked</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Feeds_FetchAll" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<div id="Notif_History_CantReprocess" data-duration="2000" class="alert alert-error alert-center alert-center-medium hide">
|
||||
<strong>Cannot post-process URL- or hidden records</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_History_CantRedownload" data-duration="2000" class="alert alert-error alert-center alert-center-medium hide">
|
||||
<strong>Cannot redownload hidden records</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Feeds_Fetch" data-duration="1000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<strong>Fetching new items</strong>
|
||||
</div>
|
||||
|
||||
@@ -2505,5 +2609,13 @@
|
||||
<strong>Volume reset</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Config_TestConnectionProgress" data-duration="20000" class="alert alert-inverse alert-center alert-center-small hide">
|
||||
<strong>Testing connection...</strong>
|
||||
</div>
|
||||
|
||||
<div id="Notif_Config_TestConnectionOK" data-duration="1000" class="alert alert-success alert-center alert-center-small hide">
|
||||
<strong>Connection successful</strong>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user