mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-03 11:37:46 -05:00
Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69d40c11fd | ||
|
|
58893710d8 | ||
|
|
6c6f781510 | ||
|
|
569ec22ee8 | ||
|
|
b06d3eca86 | ||
|
|
dcf63b4db7 | ||
|
|
06e7573572 | ||
|
|
639e0b6bfb | ||
|
|
f2073ff920 | ||
|
|
4ba2e07d94 | ||
|
|
91515b20e5 | ||
|
|
7226e1c186 | ||
|
|
98c2dd46b7 | ||
|
|
f0b08dbd63 | ||
|
|
25ddfd5659 | ||
|
|
7450b97871 | ||
|
|
9f7e0ee972 | ||
|
|
ae7719e948 | ||
|
|
9a92896678 | ||
|
|
ab0723adda | ||
|
|
13b98fca83 | ||
|
|
5901998cb5 | ||
|
|
9ddd73368e | ||
|
|
12daa683e5 | ||
|
|
5f71c4a5a7 | ||
|
|
13db817395 | ||
|
|
84f4cf2f33 | ||
|
|
0d67e322a3 | ||
|
|
374f706354 | ||
|
|
f7cefadf33 | ||
|
|
c111a114b9 | ||
|
|
2cd3f0fc68 | ||
|
|
92db59116e | ||
|
|
760aed68fb | ||
|
|
e612257c28 | ||
|
|
31208a5816 | ||
|
|
a03e7cd550 | ||
|
|
02b33fb559 | ||
|
|
a9ed53daa8 | ||
|
|
a3c460ed40 | ||
|
|
df11d1acb4 | ||
|
|
e49d4c59af | ||
|
|
5dc9c07a58 | ||
|
|
3bb0751c86 | ||
|
|
a3b3921bea | ||
|
|
b19d26aee8 | ||
|
|
7fae337360 | ||
|
|
80debf521a | ||
|
|
528133482e | ||
|
|
a98bbd7d0d | ||
|
|
2681fe187b | ||
|
|
e16cab67fb | ||
|
|
50e2e0cf37 | ||
|
|
d2d20f29c1 | ||
|
|
53f4992eeb | ||
|
|
3ae1be1ca4 | ||
|
|
ce1e1b61e7 | ||
|
|
cac25ed290 | ||
|
|
8ed0b70df5 | ||
|
|
d72071c8ed | ||
|
|
ba05dfc202 | ||
|
|
f3adab5690 | ||
|
|
b1b5405809 | ||
|
|
99fcd164ac | ||
|
|
eacfacc5a2 | ||
|
|
3404b544de | ||
|
|
3604534850 | ||
|
|
2e18021e08 | ||
|
|
2e19382ccc | ||
|
|
a6dc20dc8e | ||
|
|
a1bef9146e | ||
|
|
61f18f81b7 | ||
|
|
129125faa1 | ||
|
|
b97c987f66 | ||
|
|
53e504d974 | ||
|
|
5885258c35 | ||
|
|
2034ea97d2 | ||
|
|
2cc38a85df | ||
|
|
ccd509b70c | ||
|
|
bab43d8d30 | ||
|
|
ed4761db37 | ||
|
|
db7bc4314f | ||
|
|
8a21626bf6 | ||
|
|
804f8ab085 | ||
|
|
3593990dd6 | ||
|
|
3a38a2c7c6 | ||
|
|
16aef2e7a8 | ||
|
|
bf992195e8 | ||
|
|
2fb0fd1113 | ||
|
|
709c9856c9 | ||
|
|
9e9ef3120f | ||
|
|
a7525ae6f9 | ||
|
|
5e0e91f671 | ||
|
|
09f863f3af | ||
|
|
87e8d479d8 | ||
|
|
fb8c6b9cd3 | ||
|
|
bc98b0582c | ||
|
|
84388785e7 | ||
|
|
4c519cf646 | ||
|
|
f28c049c12 | ||
|
|
33dbbcb0b5 | ||
|
|
7f6cbd137f | ||
|
|
facd8cd41f | ||
|
|
e269d8f062 | ||
|
|
dd141e4cf5 | ||
|
|
f18ee92a23 | ||
|
|
b25a88683b | ||
|
|
9dc2b8c71b | ||
|
|
2ef393531a | ||
|
|
0c1fce27a2 | ||
|
|
606cf56150 | ||
|
|
af8451e16e | ||
|
|
203a828bbd | ||
|
|
a990078884 | ||
|
|
3e5bd203f3 | ||
|
|
042979d122 | ||
|
|
11c464ed46 | ||
|
|
070054a814 | ||
|
|
5841cf5002 | ||
|
|
6dda360986 | ||
|
|
12ff14b397 | ||
|
|
20aa83e0f7 | ||
|
|
4c8c7ef46b | ||
|
|
43a6717394 | ||
|
|
b4fc57977b | ||
|
|
4f9dbdadc3 | ||
|
|
418acb052f | ||
|
|
c741297d84 | ||
|
|
55fb4df411 | ||
|
|
35643b0207 | ||
|
|
45753410df | ||
|
|
b58de541b3 | ||
|
|
3d577777bb | ||
|
|
a0e9c537a3 | ||
|
|
a2d87de7b9 |
3
.gitignore
vendored
Executable file → Normal file
3
.gitignore
vendored
Executable file → Normal file
@@ -61,3 +61,6 @@ ipch/
|
||||
# NZBGet specific
|
||||
nzbget
|
||||
code_revision.cpp
|
||||
*.temp
|
||||
*.pyc
|
||||
pytest.ini
|
||||
|
||||
102
ChangeLog
102
ChangeLog
@@ -1,3 +1,105 @@
|
||||
nzbget-18.0:
|
||||
- automatic deobfuscation of rar-archives without par-files:
|
||||
- obfuscated downloads not having par-files can now be successfully
|
||||
unpacked;
|
||||
- also helps with downloads where rar-files were obfuscated before
|
||||
creating par-files;
|
||||
- new options "RarRename" and "UnpackIgnoreExt";
|
||||
- multi post-processing:
|
||||
- in addition to classic post-processing strategy where items are
|
||||
processed one after another it is now possible to post-process
|
||||
multiple items at the same time;
|
||||
- new option "PostStrategy" to choose from four: sequential, balanced,
|
||||
aggressive, rocket;
|
||||
- in "balanced" strategy downloads needing repair do not block other
|
||||
items which are processed sequentially but simultaneously with
|
||||
repairing item;
|
||||
- in "aggressive" mode up to three items are post-processed at the same
|
||||
time and in "rocket" mode up to six items (including up to two repair
|
||||
tasks);
|
||||
- unified extension scripts settings:
|
||||
- options "PostScript", "QueueScript", "ScanScript" and "FeedScript"
|
||||
were replaced with one option "Extensions";
|
||||
- users don't need to know the technical details os extension scripts as
|
||||
all scripts are now can be selected at one place;
|
||||
- easier activation of complex extension scripts which previously needed
|
||||
to be selected in multiple options for their proper work;
|
||||
- reordering download queue with drag and drop in web-interface:
|
||||
- new actions "GroupMoveBefore" and "GroupMoveAfter" in API-method
|
||||
"editqueue";
|
||||
- priorities are now displayed as a column instead of badge; that makes it
|
||||
possible to manually sort on priority;
|
||||
- removed vertical lines in tables; looks better in combination with new
|
||||
priority column;
|
||||
- keyboard shortcuts in web-interface;
|
||||
- improved UI to prevent accidental deletion of many items:
|
||||
- visual indication of records selected on other pages;
|
||||
- extra warning when deleting many records from history;
|
||||
- additional options in "custom pause dialog";
|
||||
- better handing of damaged par2-files in par-renamer:
|
||||
- if par-renamer can't load a (damaged) par2-file then another par2-file
|
||||
is downloaded and par-renamer tries again;
|
||||
- reverted non-strict par2-filename matching to handle article subjects
|
||||
with non-parseable filenames;
|
||||
- better handling of obfuscated par-files;
|
||||
- splitted option "Retries" into "ArticleRetries" and "UrlRetries"; option
|
||||
"RetryInterval" into "ArticleInterval" and "UrlInterval";
|
||||
- scheduler tasks can be started at program launch:
|
||||
- use asterisk as TaskX.Time;
|
||||
- graceful termination of scheduler scripts:
|
||||
- scripts receive signal SIGINT (CTRL+BREAK on Windows) before
|
||||
termination;
|
||||
- added support for nZEDb attributes in rss feeds;
|
||||
- better cleanup handling: if parameter "unpack" is disabled for an nzb-file
|
||||
the cleanup isn't performed for it;
|
||||
- fields containing passwords are now displayed as protected fields;
|
||||
- showing password-badge for nzbs with passwords;
|
||||
- allow control of what tab is shown when opening web-interface:
|
||||
add "#downloads", "#history", "#messages" or "#settings" to the URL,
|
||||
for example "http://localhost:6789/#history" or
|
||||
"http://localhost:6789/index.html#history";
|
||||
- functional testing to ensure program quality:
|
||||
- implemented built-in simple nntp server to be used for functional
|
||||
testing;
|
||||
- created a number of tests;
|
||||
- new features come with additional tests;
|
||||
- improved API-method "append" in combination with duplicate check; method
|
||||
returns nzb-id also for items added straight to history;
|
||||
- removed parameter "offset" from api-method "editqueue":
|
||||
- when needed the "offset" is now passed within parameter "Args" as
|
||||
string;
|
||||
- old method signature is supported for compatibility;
|
||||
- improved error reporting on feed parse errors;
|
||||
- highlighting selected rows with alternative colors;
|
||||
- improved selecting of par2-file for repair;
|
||||
- splitted config section "Download Queue" and moved many options into new
|
||||
section "Connection";
|
||||
- disabled SSLv3 in built-in web-server;
|
||||
- multiple recipients in the example pp-script "EMail.py";
|
||||
- added compatibility with openssl 1.1.0;
|
||||
- fixed TLS handshake error when using GnuTLS;
|
||||
- fixed: sorting of selected items may give wrong results;
|
||||
- fixed: search box filter in feed view were not reset.
|
||||
|
||||
nzbget-17.1:
|
||||
- adjustments and fixes for "Retry failed articles" function, better handling
|
||||
of certain corner cases;
|
||||
- partial compatibility with gcc 4.8;
|
||||
- removed unnecessary debug logging to javascript console;
|
||||
- improved error reporting on certain file operations;
|
||||
- corrected option description;
|
||||
- corrected text in history delete confirmation dialog;
|
||||
- fixed performance issue on certain Windows systems;
|
||||
- fixed: root drive paths on Windows could not be used (for example
|
||||
"NzbDir=N:\");
|
||||
- fixed hanging after marking as BAD from queue script;
|
||||
- fixed: old nzbget.exe was deleted even when installing into a new directory
|
||||
(Windows only);
|
||||
- fixed: compilation error if configured with unit tests but without par-module;
|
||||
- fixed crash on malformed articles;
|
||||
- fixed javascript error on Chrome for Linux;
|
||||
- fixed compilation error if configured without TLS.
|
||||
|
||||
nzbget-17.0:
|
||||
- reworked the full source code base to utilize modern C++ features:
|
||||
- with the main motivation to make the code nicer and more fun to work
|
||||
|
||||
56
Makefile.am
56
Makefile.am
@@ -90,14 +90,20 @@ nzbget_SOURCES = \
|
||||
daemon/postprocess/DupeMatcher.h \
|
||||
daemon/postprocess/ParChecker.cpp \
|
||||
daemon/postprocess/ParChecker.h \
|
||||
daemon/postprocess/ParCoordinator.cpp \
|
||||
daemon/postprocess/ParCoordinator.h \
|
||||
daemon/postprocess/ParParser.cpp \
|
||||
daemon/postprocess/ParParser.h \
|
||||
daemon/postprocess/ParRenamer.cpp \
|
||||
daemon/postprocess/ParRenamer.h \
|
||||
daemon/postprocess/PrePostProcessor.cpp \
|
||||
daemon/postprocess/PrePostProcessor.h \
|
||||
daemon/postprocess/RarRenamer.cpp \
|
||||
daemon/postprocess/RarRenamer.h \
|
||||
daemon/postprocess/RarReader.cpp \
|
||||
daemon/postprocess/RarReader.h \
|
||||
daemon/postprocess/Rename.cpp \
|
||||
daemon/postprocess/Rename.h \
|
||||
daemon/postprocess/Repair.cpp \
|
||||
daemon/postprocess/Repair.h \
|
||||
daemon/postprocess/Unpack.cpp \
|
||||
daemon/postprocess/Unpack.h \
|
||||
daemon/queue/DiskState.cpp \
|
||||
@@ -146,6 +152,16 @@ nzbget_SOURCES = \
|
||||
daemon/util/FileSystem.h \
|
||||
daemon/util/Util.cpp \
|
||||
daemon/util/Util.h \
|
||||
daemon/nserv/NServMain.h \
|
||||
daemon/nserv/NServMain.cpp \
|
||||
daemon/nserv/NServFrontend.h \
|
||||
daemon/nserv/NServFrontend.cpp \
|
||||
daemon/nserv/NntpServer.h \
|
||||
daemon/nserv/NntpServer.cpp \
|
||||
daemon/nserv/NzbGenerator.h \
|
||||
daemon/nserv/NzbGenerator.cpp \
|
||||
daemon/nserv/YEncoder.h \
|
||||
daemon/nserv/YEncoder.cpp \
|
||||
code_revision.cpp
|
||||
|
||||
if WITH_PAR2
|
||||
@@ -174,8 +190,6 @@ nzbget_SOURCES += \
|
||||
lib/par2/md5.cpp \
|
||||
lib/par2/md5.h \
|
||||
lib/par2/par2cmdline.h \
|
||||
lib/par2/par2creatorsourcefile.cpp \
|
||||
lib/par2/par2creatorsourcefile.h \
|
||||
lib/par2/par2fileformat.cpp \
|
||||
lib/par2/par2fileformat.h \
|
||||
lib/par2/par2repairer.cpp \
|
||||
@@ -205,6 +219,7 @@ AM_CPPFLAGS = \
|
||||
-I$(srcdir)/daemon/queue \
|
||||
-I$(srcdir)/daemon/remote \
|
||||
-I$(srcdir)/daemon/util \
|
||||
-I$(srcdir)/daemon/nserv \
|
||||
-I$(srcdir)/lib/par2
|
||||
|
||||
if WITH_TESTS
|
||||
@@ -217,15 +232,21 @@ nzbget_SOURCES += \
|
||||
tests/main/CommandLineParserTest.cpp \
|
||||
tests/main/OptionsTest.cpp \
|
||||
tests/feed/FeedFilterTest.cpp \
|
||||
tests/postprocess/ParCheckerTest.cpp \
|
||||
tests/postprocess/ParRenamerTest.cpp \
|
||||
tests/postprocess/DupeMatcherTest.cpp \
|
||||
tests/postprocess/RarRenamerTest.cpp \
|
||||
tests/postprocess/RarReaderTest.cpp \
|
||||
tests/queue/NzbFileTest.cpp \
|
||||
tests/nntp/ServerPoolTest.cpp \
|
||||
tests/util/FileSystemTest.cpp \
|
||||
tests/util/NStringTest.cpp \
|
||||
tests/util/UtilTest.cpp
|
||||
|
||||
if WITH_PAR2
|
||||
nzbget_SOURCES += \
|
||||
tests/postprocess/ParCheckerTest.cpp \
|
||||
tests/postprocess/ParRenamerTest.cpp
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS += \
|
||||
-I$(srcdir)/lib/catch \
|
||||
-I$(srcdir)/tests/suite
|
||||
@@ -362,7 +383,28 @@ testdata_FILES = \
|
||||
tests/testdata/parchecker/testfile.par2 \
|
||||
tests/testdata/parchecker/testfile.vol00+1.PAR2 \
|
||||
tests/testdata/parchecker/testfile.vol01+2.PAR2 \
|
||||
tests/testdata/parchecker/testfile.vol03+3.PAR2
|
||||
tests/testdata/parchecker/testfile.vol03+3.PAR2 \
|
||||
tests/testdata/rarrenamer/testfile3.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.rar \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.r00 \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.r01 \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part03.rar
|
||||
|
||||
# Install
|
||||
dist_doc_DATA = $(doc_FILES)
|
||||
|
||||
397
Makefile.in
vendored
397
Makefile.in
vendored
@@ -84,8 +84,6 @@ bin_PROGRAMS = nzbget$(EXEEXT)
|
||||
@WITH_PAR2_TRUE@ lib/par2/md5.cpp \
|
||||
@WITH_PAR2_TRUE@ lib/par2/md5.h \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2cmdline.h \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2creatorsourcefile.cpp \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2creatorsourcefile.h \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2fileformat.cpp \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2fileformat.h \
|
||||
@WITH_PAR2_TRUE@ lib/par2/par2repairer.cpp \
|
||||
@@ -112,16 +110,20 @@ bin_PROGRAMS = nzbget$(EXEEXT)
|
||||
@WITH_TESTS_TRUE@ tests/main/CommandLineParserTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/main/OptionsTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/feed/FeedFilterTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/postprocess/ParCheckerTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/postprocess/ParRenamerTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/postprocess/DupeMatcherTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/postprocess/RarRenamerTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/postprocess/RarReaderTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/queue/NzbFileTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/nntp/ServerPoolTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/util/FileSystemTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/util/NStringTest.cpp \
|
||||
@WITH_TESTS_TRUE@ tests/util/UtilTest.cpp
|
||||
|
||||
@WITH_TESTS_TRUE@am__append_3 = \
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@am__append_3 = \
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@ tests/postprocess/ParCheckerTest.cpp \
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@ tests/postprocess/ParRenamerTest.cpp
|
||||
|
||||
@WITH_TESTS_TRUE@am__append_4 = \
|
||||
@WITH_TESTS_TRUE@ -I$(srcdir)/lib/catch \
|
||||
@WITH_TESTS_TRUE@ -I$(srcdir)/tests/suite
|
||||
|
||||
@@ -191,18 +193,21 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
|
||||
daemon/postprocess/DupeMatcher.h \
|
||||
daemon/postprocess/ParChecker.cpp \
|
||||
daemon/postprocess/ParChecker.h \
|
||||
daemon/postprocess/ParCoordinator.cpp \
|
||||
daemon/postprocess/ParCoordinator.h \
|
||||
daemon/postprocess/ParParser.cpp \
|
||||
daemon/postprocess/ParParser.h \
|
||||
daemon/postprocess/ParRenamer.cpp \
|
||||
daemon/postprocess/ParRenamer.h \
|
||||
daemon/postprocess/PrePostProcessor.cpp \
|
||||
daemon/postprocess/PrePostProcessor.h \
|
||||
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
|
||||
daemon/queue/DiskState.cpp daemon/queue/DiskState.h \
|
||||
daemon/queue/DownloadInfo.cpp daemon/queue/DownloadInfo.h \
|
||||
daemon/queue/DupeCoordinator.cpp \
|
||||
daemon/postprocess/RarRenamer.cpp \
|
||||
daemon/postprocess/RarRenamer.h \
|
||||
daemon/postprocess/RarReader.cpp \
|
||||
daemon/postprocess/RarReader.h daemon/postprocess/Rename.cpp \
|
||||
daemon/postprocess/Rename.h daemon/postprocess/Repair.cpp \
|
||||
daemon/postprocess/Repair.h daemon/postprocess/Unpack.cpp \
|
||||
daemon/postprocess/Unpack.h daemon/queue/DiskState.cpp \
|
||||
daemon/queue/DiskState.h daemon/queue/DownloadInfo.cpp \
|
||||
daemon/queue/DownloadInfo.h daemon/queue/DupeCoordinator.cpp \
|
||||
daemon/queue/DupeCoordinator.h \
|
||||
daemon/queue/HistoryCoordinator.cpp \
|
||||
daemon/queue/HistoryCoordinator.h daemon/queue/NzbFile.cpp \
|
||||
@@ -223,21 +228,26 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
|
||||
daemon/util/Thread.cpp daemon/util/Thread.h \
|
||||
daemon/util/Service.cpp daemon/util/Service.h \
|
||||
daemon/util/FileSystem.cpp daemon/util/FileSystem.h \
|
||||
daemon/util/Util.cpp daemon/util/Util.h code_revision.cpp \
|
||||
lib/par2/commandline.cpp lib/par2/commandline.h \
|
||||
lib/par2/crc.cpp lib/par2/crc.h lib/par2/creatorpacket.cpp \
|
||||
lib/par2/creatorpacket.h lib/par2/criticalpacket.cpp \
|
||||
lib/par2/criticalpacket.h lib/par2/datablock.cpp \
|
||||
lib/par2/datablock.h lib/par2/descriptionpacket.cpp \
|
||||
lib/par2/descriptionpacket.h lib/par2/diskfile.cpp \
|
||||
lib/par2/diskfile.h lib/par2/filechecksummer.cpp \
|
||||
lib/par2/filechecksummer.h lib/par2/galois.cpp \
|
||||
lib/par2/galois.h lib/par2/letype.h lib/par2/mainpacket.cpp \
|
||||
lib/par2/mainpacket.h lib/par2/md5.cpp lib/par2/md5.h \
|
||||
lib/par2/par2cmdline.h lib/par2/par2creatorsourcefile.cpp \
|
||||
lib/par2/par2creatorsourcefile.h lib/par2/par2fileformat.cpp \
|
||||
lib/par2/par2fileformat.h lib/par2/par2repairer.cpp \
|
||||
lib/par2/par2repairer.h lib/par2/par2repairersourcefile.cpp \
|
||||
daemon/util/Util.cpp daemon/util/Util.h \
|
||||
daemon/nserv/NServMain.h daemon/nserv/NServMain.cpp \
|
||||
daemon/nserv/NServFrontend.h daemon/nserv/NServFrontend.cpp \
|
||||
daemon/nserv/NntpServer.h daemon/nserv/NntpServer.cpp \
|
||||
daemon/nserv/NzbGenerator.h daemon/nserv/NzbGenerator.cpp \
|
||||
daemon/nserv/YEncoder.h daemon/nserv/YEncoder.cpp \
|
||||
code_revision.cpp lib/par2/commandline.cpp \
|
||||
lib/par2/commandline.h lib/par2/crc.cpp lib/par2/crc.h \
|
||||
lib/par2/creatorpacket.cpp lib/par2/creatorpacket.h \
|
||||
lib/par2/criticalpacket.cpp lib/par2/criticalpacket.h \
|
||||
lib/par2/datablock.cpp lib/par2/datablock.h \
|
||||
lib/par2/descriptionpacket.cpp lib/par2/descriptionpacket.h \
|
||||
lib/par2/diskfile.cpp lib/par2/diskfile.h \
|
||||
lib/par2/filechecksummer.cpp lib/par2/filechecksummer.h \
|
||||
lib/par2/galois.cpp lib/par2/galois.h lib/par2/letype.h \
|
||||
lib/par2/mainpacket.cpp lib/par2/mainpacket.h lib/par2/md5.cpp \
|
||||
lib/par2/md5.h lib/par2/par2cmdline.h \
|
||||
lib/par2/par2fileformat.cpp lib/par2/par2fileformat.h \
|
||||
lib/par2/par2repairer.cpp lib/par2/par2repairer.h \
|
||||
lib/par2/par2repairersourcefile.cpp \
|
||||
lib/par2/par2repairersourcefile.h lib/par2/parheaders.cpp \
|
||||
lib/par2/parheaders.h lib/par2/recoverypacket.cpp \
|
||||
lib/par2/recoverypacket.h lib/par2/reedsolomon.cpp \
|
||||
@@ -248,19 +258,19 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
|
||||
tests/suite/TestMain.h tests/suite/TestUtil.cpp \
|
||||
tests/suite/TestUtil.h tests/main/CommandLineParserTest.cpp \
|
||||
tests/main/OptionsTest.cpp tests/feed/FeedFilterTest.cpp \
|
||||
tests/postprocess/ParCheckerTest.cpp \
|
||||
tests/postprocess/ParRenamerTest.cpp \
|
||||
tests/postprocess/DupeMatcherTest.cpp \
|
||||
tests/postprocess/RarRenamerTest.cpp \
|
||||
tests/postprocess/RarReaderTest.cpp \
|
||||
tests/queue/NzbFileTest.cpp tests/nntp/ServerPoolTest.cpp \
|
||||
tests/util/FileSystemTest.cpp tests/util/NStringTest.cpp \
|
||||
tests/util/UtilTest.cpp
|
||||
tests/util/UtilTest.cpp tests/postprocess/ParCheckerTest.cpp \
|
||||
tests/postprocess/ParRenamerTest.cpp
|
||||
@WITH_PAR2_TRUE@am__objects_1 = commandline.$(OBJEXT) crc.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ creatorpacket.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ criticalpacket.$(OBJEXT) datablock.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ descriptionpacket.$(OBJEXT) diskfile.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ filechecksummer.$(OBJEXT) galois.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ mainpacket.$(OBJEXT) md5.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ par2creatorsourcefile.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ par2fileformat.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ par2repairer.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@ par2repairersourcefile.$(OBJEXT) \
|
||||
@@ -272,13 +282,15 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
|
||||
@WITH_TESTS_TRUE@ CommandLineParserTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ OptionsTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ FeedFilterTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ ParCheckerTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ ParRenamerTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ DupeMatcherTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ NzbFileTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ RarRenamerTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ RarReaderTest.$(OBJEXT) NzbFileTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ ServerPoolTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ FileSystemTest.$(OBJEXT) \
|
||||
@WITH_TESTS_TRUE@ NStringTest.$(OBJEXT) UtilTest.$(OBJEXT)
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@am__objects_3 = \
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@ ParCheckerTest.$(OBJEXT) \
|
||||
@WITH_PAR2_TRUE@@WITH_TESTS_TRUE@ ParRenamerTest.$(OBJEXT)
|
||||
am_nzbget_OBJECTS = Connection.$(OBJEXT) TlsSocket.$(OBJEXT) \
|
||||
WebDownloader.$(OBJEXT) FeedScript.$(OBJEXT) \
|
||||
NzbScript.$(OBJEXT) PostScript.$(OBJEXT) QueueScript.$(OBJEXT) \
|
||||
@@ -294,10 +306,10 @@ am_nzbget_OBJECTS = Connection.$(OBJEXT) TlsSocket.$(OBJEXT) \
|
||||
Decoder.$(OBJEXT) NewsServer.$(OBJEXT) \
|
||||
NntpConnection.$(OBJEXT) ServerPool.$(OBJEXT) \
|
||||
StatMeter.$(OBJEXT) Cleanup.$(OBJEXT) DupeMatcher.$(OBJEXT) \
|
||||
ParChecker.$(OBJEXT) ParCoordinator.$(OBJEXT) \
|
||||
ParParser.$(OBJEXT) ParRenamer.$(OBJEXT) \
|
||||
PrePostProcessor.$(OBJEXT) Unpack.$(OBJEXT) \
|
||||
DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
|
||||
ParChecker.$(OBJEXT) ParParser.$(OBJEXT) ParRenamer.$(OBJEXT) \
|
||||
PrePostProcessor.$(OBJEXT) RarRenamer.$(OBJEXT) \
|
||||
RarReader.$(OBJEXT) Rename.$(OBJEXT) Repair.$(OBJEXT) \
|
||||
Unpack.$(OBJEXT) DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
|
||||
DupeCoordinator.$(OBJEXT) HistoryCoordinator.$(OBJEXT) \
|
||||
NzbFile.$(OBJEXT) QueueCoordinator.$(OBJEXT) \
|
||||
QueueEditor.$(OBJEXT) Scanner.$(OBJEXT) \
|
||||
@@ -306,8 +318,10 @@ am_nzbget_OBJECTS = Connection.$(OBJEXT) TlsSocket.$(OBJEXT) \
|
||||
WebServer.$(OBJEXT) XmlRpc.$(OBJEXT) Log.$(OBJEXT) \
|
||||
NString.$(OBJEXT) Observer.$(OBJEXT) Script.$(OBJEXT) \
|
||||
Thread.$(OBJEXT) Service.$(OBJEXT) FileSystem.$(OBJEXT) \
|
||||
Util.$(OBJEXT) code_revision.$(OBJEXT) $(am__objects_1) \
|
||||
$(am__objects_2)
|
||||
Util.$(OBJEXT) NServMain.$(OBJEXT) NServFrontend.$(OBJEXT) \
|
||||
NntpServer.$(OBJEXT) NzbGenerator.$(OBJEXT) YEncoder.$(OBJEXT) \
|
||||
code_revision.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
|
||||
$(am__objects_3)
|
||||
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
|
||||
nzbget_LDADD = $(LDADD)
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
@@ -443,6 +457,8 @@ mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
ncurses_CFLAGS = @ncurses_CFLAGS@
|
||||
ncurses_LIBS = @ncurses_LIBS@
|
||||
nettle_CFLAGS = @nettle_CFLAGS@
|
||||
nettle_LIBS = @nettle_LIBS@
|
||||
oldincludedir = @oldincludedir@
|
||||
openssl_CFLAGS = @openssl_CFLAGS@
|
||||
openssl_LIBS = @openssl_LIBS@
|
||||
@@ -504,18 +520,21 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
|
||||
daemon/postprocess/DupeMatcher.h \
|
||||
daemon/postprocess/ParChecker.cpp \
|
||||
daemon/postprocess/ParChecker.h \
|
||||
daemon/postprocess/ParCoordinator.cpp \
|
||||
daemon/postprocess/ParCoordinator.h \
|
||||
daemon/postprocess/ParParser.cpp \
|
||||
daemon/postprocess/ParParser.h \
|
||||
daemon/postprocess/ParRenamer.cpp \
|
||||
daemon/postprocess/ParRenamer.h \
|
||||
daemon/postprocess/PrePostProcessor.cpp \
|
||||
daemon/postprocess/PrePostProcessor.h \
|
||||
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
|
||||
daemon/queue/DiskState.cpp daemon/queue/DiskState.h \
|
||||
daemon/queue/DownloadInfo.cpp daemon/queue/DownloadInfo.h \
|
||||
daemon/queue/DupeCoordinator.cpp \
|
||||
daemon/postprocess/RarRenamer.cpp \
|
||||
daemon/postprocess/RarRenamer.h \
|
||||
daemon/postprocess/RarReader.cpp \
|
||||
daemon/postprocess/RarReader.h daemon/postprocess/Rename.cpp \
|
||||
daemon/postprocess/Rename.h daemon/postprocess/Repair.cpp \
|
||||
daemon/postprocess/Repair.h daemon/postprocess/Unpack.cpp \
|
||||
daemon/postprocess/Unpack.h daemon/queue/DiskState.cpp \
|
||||
daemon/queue/DiskState.h daemon/queue/DownloadInfo.cpp \
|
||||
daemon/queue/DownloadInfo.h daemon/queue/DupeCoordinator.cpp \
|
||||
daemon/queue/DupeCoordinator.h \
|
||||
daemon/queue/HistoryCoordinator.cpp \
|
||||
daemon/queue/HistoryCoordinator.h daemon/queue/NzbFile.cpp \
|
||||
@@ -536,14 +555,20 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
|
||||
daemon/util/Thread.cpp daemon/util/Thread.h \
|
||||
daemon/util/Service.cpp daemon/util/Service.h \
|
||||
daemon/util/FileSystem.cpp daemon/util/FileSystem.h \
|
||||
daemon/util/Util.cpp daemon/util/Util.h code_revision.cpp \
|
||||
$(am__append_1) $(am__append_2)
|
||||
daemon/util/Util.cpp daemon/util/Util.h \
|
||||
daemon/nserv/NServMain.h daemon/nserv/NServMain.cpp \
|
||||
daemon/nserv/NServFrontend.h daemon/nserv/NServFrontend.cpp \
|
||||
daemon/nserv/NntpServer.h daemon/nserv/NntpServer.cpp \
|
||||
daemon/nserv/NzbGenerator.h daemon/nserv/NzbGenerator.cpp \
|
||||
daemon/nserv/YEncoder.h daemon/nserv/YEncoder.cpp \
|
||||
code_revision.cpp $(am__append_1) $(am__append_2) \
|
||||
$(am__append_3)
|
||||
AM_CPPFLAGS = -I$(srcdir)/daemon/connect -I$(srcdir)/daemon/extension \
|
||||
-I$(srcdir)/daemon/feed -I$(srcdir)/daemon/frontend \
|
||||
-I$(srcdir)/daemon/main -I$(srcdir)/daemon/nntp \
|
||||
-I$(srcdir)/daemon/postprocess -I$(srcdir)/daemon/queue \
|
||||
-I$(srcdir)/daemon/remote -I$(srcdir)/daemon/util \
|
||||
-I$(srcdir)/lib/par2 $(am__append_3)
|
||||
-I$(srcdir)/daemon/nserv -I$(srcdir)/lib/par2 $(am__append_4)
|
||||
EXTRA_DIST = \
|
||||
$(windows_FILES) \
|
||||
$(osx_FILES) \
|
||||
@@ -675,7 +700,28 @@ testdata_FILES = \
|
||||
tests/testdata/parchecker/testfile.par2 \
|
||||
tests/testdata/parchecker/testfile.vol00+1.PAR2 \
|
||||
tests/testdata/parchecker/testfile.vol01+2.PAR2 \
|
||||
tests/testdata/parchecker/testfile.vol03+3.PAR2
|
||||
tests/testdata/parchecker/testfile.vol03+3.PAR2 \
|
||||
tests/testdata/rarrenamer/testfile3.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.rar \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.r00 \
|
||||
tests/testdata/rarrenamer/testfile3oldnam.r01 \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3encdata.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile3encnam.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5encdata.part03.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part01.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part02.rar \
|
||||
tests/testdata/rarrenamer/testfile5encnam.part03.rar
|
||||
|
||||
|
||||
# Install
|
||||
@@ -834,19 +880,22 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoggableFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Maintenance.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NCursesFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NServFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NServMain.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NString.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NStringTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NewsServer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NntpConnection.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NntpServer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NzbFile.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NzbFileTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NzbGenerator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NzbScript.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Observer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Options.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionsTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParChecker.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParCheckerTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParParser.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParRenamer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParRenamerTest.Po@am__quote@
|
||||
@@ -855,8 +904,14 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueEditor.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueScript.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarReader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarReaderTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarRenamer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarRenamerTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RemoteClient.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RemoteServer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Rename.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Repair.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ScanScript.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Scanner.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Scheduler.Po@am__quote@
|
||||
@@ -879,6 +934,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebDownloader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebServer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/YEncoder.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/code_revision.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandline.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Po@am__quote@
|
||||
@@ -892,7 +948,6 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mainpacket.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nzbget.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2creatorsourcefile.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2fileformat.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2repairer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2repairersourcefile.Po@am__quote@
|
||||
@@ -1406,20 +1461,6 @@ ParChecker.obj: daemon/postprocess/ParChecker.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParChecker.obj `if test -f 'daemon/postprocess/ParChecker.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParChecker.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParChecker.cpp'; fi`
|
||||
|
||||
ParCoordinator.o: daemon/postprocess/ParCoordinator.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCoordinator.o -MD -MP -MF "$(DEPDIR)/ParCoordinator.Tpo" -c -o ParCoordinator.o `test -f 'daemon/postprocess/ParCoordinator.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParCoordinator.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCoordinator.Tpo" "$(DEPDIR)/ParCoordinator.Po"; else rm -f "$(DEPDIR)/ParCoordinator.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/ParCoordinator.cpp' object='ParCoordinator.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCoordinator.o `test -f 'daemon/postprocess/ParCoordinator.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParCoordinator.cpp
|
||||
|
||||
ParCoordinator.obj: daemon/postprocess/ParCoordinator.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCoordinator.obj -MD -MP -MF "$(DEPDIR)/ParCoordinator.Tpo" -c -o ParCoordinator.obj `if test -f 'daemon/postprocess/ParCoordinator.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParCoordinator.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParCoordinator.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCoordinator.Tpo" "$(DEPDIR)/ParCoordinator.Po"; else rm -f "$(DEPDIR)/ParCoordinator.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/ParCoordinator.cpp' object='ParCoordinator.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCoordinator.obj `if test -f 'daemon/postprocess/ParCoordinator.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParCoordinator.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParCoordinator.cpp'; fi`
|
||||
|
||||
ParParser.o: daemon/postprocess/ParParser.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParParser.o -MD -MP -MF "$(DEPDIR)/ParParser.Tpo" -c -o ParParser.o `test -f 'daemon/postprocess/ParParser.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParParser.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParParser.Tpo" "$(DEPDIR)/ParParser.Po"; else rm -f "$(DEPDIR)/ParParser.Tpo"; exit 1; fi
|
||||
@@ -1462,6 +1503,62 @@ PrePostProcessor.obj: daemon/postprocess/PrePostProcessor.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o PrePostProcessor.obj `if test -f 'daemon/postprocess/PrePostProcessor.cpp'; then $(CYGPATH_W) 'daemon/postprocess/PrePostProcessor.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/PrePostProcessor.cpp'; fi`
|
||||
|
||||
RarRenamer.o: daemon/postprocess/RarRenamer.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarRenamer.o -MD -MP -MF "$(DEPDIR)/RarRenamer.Tpo" -c -o RarRenamer.o `test -f 'daemon/postprocess/RarRenamer.cpp' || echo '$(srcdir)/'`daemon/postprocess/RarRenamer.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarRenamer.Tpo" "$(DEPDIR)/RarRenamer.Po"; else rm -f "$(DEPDIR)/RarRenamer.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/RarRenamer.cpp' object='RarRenamer.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarRenamer.o `test -f 'daemon/postprocess/RarRenamer.cpp' || echo '$(srcdir)/'`daemon/postprocess/RarRenamer.cpp
|
||||
|
||||
RarRenamer.obj: daemon/postprocess/RarRenamer.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarRenamer.obj -MD -MP -MF "$(DEPDIR)/RarRenamer.Tpo" -c -o RarRenamer.obj `if test -f 'daemon/postprocess/RarRenamer.cpp'; then $(CYGPATH_W) 'daemon/postprocess/RarRenamer.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/RarRenamer.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarRenamer.Tpo" "$(DEPDIR)/RarRenamer.Po"; else rm -f "$(DEPDIR)/RarRenamer.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/RarRenamer.cpp' object='RarRenamer.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarRenamer.obj `if test -f 'daemon/postprocess/RarRenamer.cpp'; then $(CYGPATH_W) 'daemon/postprocess/RarRenamer.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/RarRenamer.cpp'; fi`
|
||||
|
||||
RarReader.o: daemon/postprocess/RarReader.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarReader.o -MD -MP -MF "$(DEPDIR)/RarReader.Tpo" -c -o RarReader.o `test -f 'daemon/postprocess/RarReader.cpp' || echo '$(srcdir)/'`daemon/postprocess/RarReader.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarReader.Tpo" "$(DEPDIR)/RarReader.Po"; else rm -f "$(DEPDIR)/RarReader.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/RarReader.cpp' object='RarReader.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarReader.o `test -f 'daemon/postprocess/RarReader.cpp' || echo '$(srcdir)/'`daemon/postprocess/RarReader.cpp
|
||||
|
||||
RarReader.obj: daemon/postprocess/RarReader.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarReader.obj -MD -MP -MF "$(DEPDIR)/RarReader.Tpo" -c -o RarReader.obj `if test -f 'daemon/postprocess/RarReader.cpp'; then $(CYGPATH_W) 'daemon/postprocess/RarReader.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/RarReader.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarReader.Tpo" "$(DEPDIR)/RarReader.Po"; else rm -f "$(DEPDIR)/RarReader.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/RarReader.cpp' object='RarReader.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarReader.obj `if test -f 'daemon/postprocess/RarReader.cpp'; then $(CYGPATH_W) 'daemon/postprocess/RarReader.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/RarReader.cpp'; fi`
|
||||
|
||||
Rename.o: daemon/postprocess/Rename.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Rename.o -MD -MP -MF "$(DEPDIR)/Rename.Tpo" -c -o Rename.o `test -f 'daemon/postprocess/Rename.cpp' || echo '$(srcdir)/'`daemon/postprocess/Rename.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Rename.Tpo" "$(DEPDIR)/Rename.Po"; else rm -f "$(DEPDIR)/Rename.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Rename.cpp' object='Rename.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Rename.o `test -f 'daemon/postprocess/Rename.cpp' || echo '$(srcdir)/'`daemon/postprocess/Rename.cpp
|
||||
|
||||
Rename.obj: daemon/postprocess/Rename.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Rename.obj -MD -MP -MF "$(DEPDIR)/Rename.Tpo" -c -o Rename.obj `if test -f 'daemon/postprocess/Rename.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Rename.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Rename.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Rename.Tpo" "$(DEPDIR)/Rename.Po"; else rm -f "$(DEPDIR)/Rename.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Rename.cpp' object='Rename.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Rename.obj `if test -f 'daemon/postprocess/Rename.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Rename.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Rename.cpp'; fi`
|
||||
|
||||
Repair.o: daemon/postprocess/Repair.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Repair.o -MD -MP -MF "$(DEPDIR)/Repair.Tpo" -c -o Repair.o `test -f 'daemon/postprocess/Repair.cpp' || echo '$(srcdir)/'`daemon/postprocess/Repair.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Repair.Tpo" "$(DEPDIR)/Repair.Po"; else rm -f "$(DEPDIR)/Repair.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Repair.cpp' object='Repair.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Repair.o `test -f 'daemon/postprocess/Repair.cpp' || echo '$(srcdir)/'`daemon/postprocess/Repair.cpp
|
||||
|
||||
Repair.obj: daemon/postprocess/Repair.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Repair.obj -MD -MP -MF "$(DEPDIR)/Repair.Tpo" -c -o Repair.obj `if test -f 'daemon/postprocess/Repair.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Repair.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Repair.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Repair.Tpo" "$(DEPDIR)/Repair.Po"; else rm -f "$(DEPDIR)/Repair.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Repair.cpp' object='Repair.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Repair.obj `if test -f 'daemon/postprocess/Repair.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Repair.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Repair.cpp'; fi`
|
||||
|
||||
Unpack.o: daemon/postprocess/Unpack.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Unpack.o -MD -MP -MF "$(DEPDIR)/Unpack.Tpo" -c -o Unpack.o `test -f 'daemon/postprocess/Unpack.cpp' || echo '$(srcdir)/'`daemon/postprocess/Unpack.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Unpack.Tpo" "$(DEPDIR)/Unpack.Po"; else rm -f "$(DEPDIR)/Unpack.Tpo"; exit 1; fi
|
||||
@@ -1784,6 +1881,76 @@ Util.obj: daemon/util/Util.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Util.obj `if test -f 'daemon/util/Util.cpp'; then $(CYGPATH_W) 'daemon/util/Util.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/util/Util.cpp'; fi`
|
||||
|
||||
NServMain.o: daemon/nserv/NServMain.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NServMain.o -MD -MP -MF "$(DEPDIR)/NServMain.Tpo" -c -o NServMain.o `test -f 'daemon/nserv/NServMain.cpp' || echo '$(srcdir)/'`daemon/nserv/NServMain.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NServMain.Tpo" "$(DEPDIR)/NServMain.Po"; else rm -f "$(DEPDIR)/NServMain.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NServMain.cpp' object='NServMain.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NServMain.o `test -f 'daemon/nserv/NServMain.cpp' || echo '$(srcdir)/'`daemon/nserv/NServMain.cpp
|
||||
|
||||
NServMain.obj: daemon/nserv/NServMain.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NServMain.obj -MD -MP -MF "$(DEPDIR)/NServMain.Tpo" -c -o NServMain.obj `if test -f 'daemon/nserv/NServMain.cpp'; then $(CYGPATH_W) 'daemon/nserv/NServMain.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NServMain.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NServMain.Tpo" "$(DEPDIR)/NServMain.Po"; else rm -f "$(DEPDIR)/NServMain.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NServMain.cpp' object='NServMain.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NServMain.obj `if test -f 'daemon/nserv/NServMain.cpp'; then $(CYGPATH_W) 'daemon/nserv/NServMain.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NServMain.cpp'; fi`
|
||||
|
||||
NServFrontend.o: daemon/nserv/NServFrontend.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NServFrontend.o -MD -MP -MF "$(DEPDIR)/NServFrontend.Tpo" -c -o NServFrontend.o `test -f 'daemon/nserv/NServFrontend.cpp' || echo '$(srcdir)/'`daemon/nserv/NServFrontend.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NServFrontend.Tpo" "$(DEPDIR)/NServFrontend.Po"; else rm -f "$(DEPDIR)/NServFrontend.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NServFrontend.cpp' object='NServFrontend.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NServFrontend.o `test -f 'daemon/nserv/NServFrontend.cpp' || echo '$(srcdir)/'`daemon/nserv/NServFrontend.cpp
|
||||
|
||||
NServFrontend.obj: daemon/nserv/NServFrontend.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NServFrontend.obj -MD -MP -MF "$(DEPDIR)/NServFrontend.Tpo" -c -o NServFrontend.obj `if test -f 'daemon/nserv/NServFrontend.cpp'; then $(CYGPATH_W) 'daemon/nserv/NServFrontend.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NServFrontend.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NServFrontend.Tpo" "$(DEPDIR)/NServFrontend.Po"; else rm -f "$(DEPDIR)/NServFrontend.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NServFrontend.cpp' object='NServFrontend.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NServFrontend.obj `if test -f 'daemon/nserv/NServFrontend.cpp'; then $(CYGPATH_W) 'daemon/nserv/NServFrontend.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NServFrontend.cpp'; fi`
|
||||
|
||||
NntpServer.o: daemon/nserv/NntpServer.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NntpServer.o -MD -MP -MF "$(DEPDIR)/NntpServer.Tpo" -c -o NntpServer.o `test -f 'daemon/nserv/NntpServer.cpp' || echo '$(srcdir)/'`daemon/nserv/NntpServer.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NntpServer.Tpo" "$(DEPDIR)/NntpServer.Po"; else rm -f "$(DEPDIR)/NntpServer.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NntpServer.cpp' object='NntpServer.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NntpServer.o `test -f 'daemon/nserv/NntpServer.cpp' || echo '$(srcdir)/'`daemon/nserv/NntpServer.cpp
|
||||
|
||||
NntpServer.obj: daemon/nserv/NntpServer.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NntpServer.obj -MD -MP -MF "$(DEPDIR)/NntpServer.Tpo" -c -o NntpServer.obj `if test -f 'daemon/nserv/NntpServer.cpp'; then $(CYGPATH_W) 'daemon/nserv/NntpServer.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NntpServer.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NntpServer.Tpo" "$(DEPDIR)/NntpServer.Po"; else rm -f "$(DEPDIR)/NntpServer.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NntpServer.cpp' object='NntpServer.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NntpServer.obj `if test -f 'daemon/nserv/NntpServer.cpp'; then $(CYGPATH_W) 'daemon/nserv/NntpServer.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NntpServer.cpp'; fi`
|
||||
|
||||
NzbGenerator.o: daemon/nserv/NzbGenerator.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NzbGenerator.o -MD -MP -MF "$(DEPDIR)/NzbGenerator.Tpo" -c -o NzbGenerator.o `test -f 'daemon/nserv/NzbGenerator.cpp' || echo '$(srcdir)/'`daemon/nserv/NzbGenerator.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NzbGenerator.Tpo" "$(DEPDIR)/NzbGenerator.Po"; else rm -f "$(DEPDIR)/NzbGenerator.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NzbGenerator.cpp' object='NzbGenerator.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NzbGenerator.o `test -f 'daemon/nserv/NzbGenerator.cpp' || echo '$(srcdir)/'`daemon/nserv/NzbGenerator.cpp
|
||||
|
||||
NzbGenerator.obj: daemon/nserv/NzbGenerator.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NzbGenerator.obj -MD -MP -MF "$(DEPDIR)/NzbGenerator.Tpo" -c -o NzbGenerator.obj `if test -f 'daemon/nserv/NzbGenerator.cpp'; then $(CYGPATH_W) 'daemon/nserv/NzbGenerator.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NzbGenerator.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NzbGenerator.Tpo" "$(DEPDIR)/NzbGenerator.Po"; else rm -f "$(DEPDIR)/NzbGenerator.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/NzbGenerator.cpp' object='NzbGenerator.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o NzbGenerator.obj `if test -f 'daemon/nserv/NzbGenerator.cpp'; then $(CYGPATH_W) 'daemon/nserv/NzbGenerator.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/NzbGenerator.cpp'; fi`
|
||||
|
||||
YEncoder.o: daemon/nserv/YEncoder.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT YEncoder.o -MD -MP -MF "$(DEPDIR)/YEncoder.Tpo" -c -o YEncoder.o `test -f 'daemon/nserv/YEncoder.cpp' || echo '$(srcdir)/'`daemon/nserv/YEncoder.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/YEncoder.Tpo" "$(DEPDIR)/YEncoder.Po"; else rm -f "$(DEPDIR)/YEncoder.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/YEncoder.cpp' object='YEncoder.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o YEncoder.o `test -f 'daemon/nserv/YEncoder.cpp' || echo '$(srcdir)/'`daemon/nserv/YEncoder.cpp
|
||||
|
||||
YEncoder.obj: daemon/nserv/YEncoder.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT YEncoder.obj -MD -MP -MF "$(DEPDIR)/YEncoder.Tpo" -c -o YEncoder.obj `if test -f 'daemon/nserv/YEncoder.cpp'; then $(CYGPATH_W) 'daemon/nserv/YEncoder.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/YEncoder.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/YEncoder.Tpo" "$(DEPDIR)/YEncoder.Po"; else rm -f "$(DEPDIR)/YEncoder.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nserv/YEncoder.cpp' object='YEncoder.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o YEncoder.obj `if test -f 'daemon/nserv/YEncoder.cpp'; then $(CYGPATH_W) 'daemon/nserv/YEncoder.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nserv/YEncoder.cpp'; fi`
|
||||
|
||||
commandline.o: lib/par2/commandline.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT commandline.o -MD -MP -MF "$(DEPDIR)/commandline.Tpo" -c -o commandline.o `test -f 'lib/par2/commandline.cpp' || echo '$(srcdir)/'`lib/par2/commandline.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/commandline.Tpo" "$(DEPDIR)/commandline.Po"; else rm -f "$(DEPDIR)/commandline.Tpo"; exit 1; fi
|
||||
@@ -1938,20 +2105,6 @@ md5.obj: lib/par2/md5.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o md5.obj `if test -f 'lib/par2/md5.cpp'; then $(CYGPATH_W) 'lib/par2/md5.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/md5.cpp'; fi`
|
||||
|
||||
par2creatorsourcefile.o: lib/par2/par2creatorsourcefile.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2creatorsourcefile.o -MD -MP -MF "$(DEPDIR)/par2creatorsourcefile.Tpo" -c -o par2creatorsourcefile.o `test -f 'lib/par2/par2creatorsourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2creatorsourcefile.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2creatorsourcefile.Tpo" "$(DEPDIR)/par2creatorsourcefile.Po"; else rm -f "$(DEPDIR)/par2creatorsourcefile.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2creatorsourcefile.cpp' object='par2creatorsourcefile.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2creatorsourcefile.o `test -f 'lib/par2/par2creatorsourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2creatorsourcefile.cpp
|
||||
|
||||
par2creatorsourcefile.obj: lib/par2/par2creatorsourcefile.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2creatorsourcefile.obj -MD -MP -MF "$(DEPDIR)/par2creatorsourcefile.Tpo" -c -o par2creatorsourcefile.obj `if test -f 'lib/par2/par2creatorsourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2creatorsourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2creatorsourcefile.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2creatorsourcefile.Tpo" "$(DEPDIR)/par2creatorsourcefile.Po"; else rm -f "$(DEPDIR)/par2creatorsourcefile.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2creatorsourcefile.cpp' object='par2creatorsourcefile.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2creatorsourcefile.obj `if test -f 'lib/par2/par2creatorsourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2creatorsourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2creatorsourcefile.cpp'; fi`
|
||||
|
||||
par2fileformat.o: lib/par2/par2fileformat.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2fileformat.o -MD -MP -MF "$(DEPDIR)/par2fileformat.Tpo" -c -o par2fileformat.o `test -f 'lib/par2/par2fileformat.cpp' || echo '$(srcdir)/'`lib/par2/par2fileformat.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2fileformat.Tpo" "$(DEPDIR)/par2fileformat.Po"; else rm -f "$(DEPDIR)/par2fileformat.Tpo"; exit 1; fi
|
||||
@@ -2134,34 +2287,6 @@ FeedFilterTest.obj: tests/feed/FeedFilterTest.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o FeedFilterTest.obj `if test -f 'tests/feed/FeedFilterTest.cpp'; then $(CYGPATH_W) 'tests/feed/FeedFilterTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/feed/FeedFilterTest.cpp'; fi`
|
||||
|
||||
ParCheckerTest.o: tests/postprocess/ParCheckerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCheckerTest.o -MD -MP -MF "$(DEPDIR)/ParCheckerTest.Tpo" -c -o ParCheckerTest.o `test -f 'tests/postprocess/ParCheckerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParCheckerTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCheckerTest.Tpo" "$(DEPDIR)/ParCheckerTest.Po"; else rm -f "$(DEPDIR)/ParCheckerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParCheckerTest.cpp' object='ParCheckerTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCheckerTest.o `test -f 'tests/postprocess/ParCheckerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParCheckerTest.cpp
|
||||
|
||||
ParCheckerTest.obj: tests/postprocess/ParCheckerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCheckerTest.obj -MD -MP -MF "$(DEPDIR)/ParCheckerTest.Tpo" -c -o ParCheckerTest.obj `if test -f 'tests/postprocess/ParCheckerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParCheckerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParCheckerTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCheckerTest.Tpo" "$(DEPDIR)/ParCheckerTest.Po"; else rm -f "$(DEPDIR)/ParCheckerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParCheckerTest.cpp' object='ParCheckerTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCheckerTest.obj `if test -f 'tests/postprocess/ParCheckerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParCheckerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParCheckerTest.cpp'; fi`
|
||||
|
||||
ParRenamerTest.o: tests/postprocess/ParRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParRenamerTest.o -MD -MP -MF "$(DEPDIR)/ParRenamerTest.Tpo" -c -o ParRenamerTest.o `test -f 'tests/postprocess/ParRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParRenamerTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParRenamerTest.Tpo" "$(DEPDIR)/ParRenamerTest.Po"; else rm -f "$(DEPDIR)/ParRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParRenamerTest.cpp' object='ParRenamerTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParRenamerTest.o `test -f 'tests/postprocess/ParRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParRenamerTest.cpp
|
||||
|
||||
ParRenamerTest.obj: tests/postprocess/ParRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParRenamerTest.obj -MD -MP -MF "$(DEPDIR)/ParRenamerTest.Tpo" -c -o ParRenamerTest.obj `if test -f 'tests/postprocess/ParRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParRenamerTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParRenamerTest.Tpo" "$(DEPDIR)/ParRenamerTest.Po"; else rm -f "$(DEPDIR)/ParRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParRenamerTest.cpp' object='ParRenamerTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParRenamerTest.obj `if test -f 'tests/postprocess/ParRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParRenamerTest.cpp'; fi`
|
||||
|
||||
DupeMatcherTest.o: tests/postprocess/DupeMatcherTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DupeMatcherTest.o -MD -MP -MF "$(DEPDIR)/DupeMatcherTest.Tpo" -c -o DupeMatcherTest.o `test -f 'tests/postprocess/DupeMatcherTest.cpp' || echo '$(srcdir)/'`tests/postprocess/DupeMatcherTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DupeMatcherTest.Tpo" "$(DEPDIR)/DupeMatcherTest.Po"; else rm -f "$(DEPDIR)/DupeMatcherTest.Tpo"; exit 1; fi
|
||||
@@ -2176,6 +2301,34 @@ DupeMatcherTest.obj: tests/postprocess/DupeMatcherTest.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o DupeMatcherTest.obj `if test -f 'tests/postprocess/DupeMatcherTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/DupeMatcherTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/DupeMatcherTest.cpp'; fi`
|
||||
|
||||
RarRenamerTest.o: tests/postprocess/RarRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarRenamerTest.o -MD -MP -MF "$(DEPDIR)/RarRenamerTest.Tpo" -c -o RarRenamerTest.o `test -f 'tests/postprocess/RarRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/RarRenamerTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarRenamerTest.Tpo" "$(DEPDIR)/RarRenamerTest.Po"; else rm -f "$(DEPDIR)/RarRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/RarRenamerTest.cpp' object='RarRenamerTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarRenamerTest.o `test -f 'tests/postprocess/RarRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/RarRenamerTest.cpp
|
||||
|
||||
RarRenamerTest.obj: tests/postprocess/RarRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarRenamerTest.obj -MD -MP -MF "$(DEPDIR)/RarRenamerTest.Tpo" -c -o RarRenamerTest.obj `if test -f 'tests/postprocess/RarRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/RarRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/RarRenamerTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarRenamerTest.Tpo" "$(DEPDIR)/RarRenamerTest.Po"; else rm -f "$(DEPDIR)/RarRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/RarRenamerTest.cpp' object='RarRenamerTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarRenamerTest.obj `if test -f 'tests/postprocess/RarRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/RarRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/RarRenamerTest.cpp'; fi`
|
||||
|
||||
RarReaderTest.o: tests/postprocess/RarReaderTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarReaderTest.o -MD -MP -MF "$(DEPDIR)/RarReaderTest.Tpo" -c -o RarReaderTest.o `test -f 'tests/postprocess/RarReaderTest.cpp' || echo '$(srcdir)/'`tests/postprocess/RarReaderTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarReaderTest.Tpo" "$(DEPDIR)/RarReaderTest.Po"; else rm -f "$(DEPDIR)/RarReaderTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/RarReaderTest.cpp' object='RarReaderTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarReaderTest.o `test -f 'tests/postprocess/RarReaderTest.cpp' || echo '$(srcdir)/'`tests/postprocess/RarReaderTest.cpp
|
||||
|
||||
RarReaderTest.obj: tests/postprocess/RarReaderTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RarReaderTest.obj -MD -MP -MF "$(DEPDIR)/RarReaderTest.Tpo" -c -o RarReaderTest.obj `if test -f 'tests/postprocess/RarReaderTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/RarReaderTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/RarReaderTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/RarReaderTest.Tpo" "$(DEPDIR)/RarReaderTest.Po"; else rm -f "$(DEPDIR)/RarReaderTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/RarReaderTest.cpp' object='RarReaderTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RarReaderTest.obj `if test -f 'tests/postprocess/RarReaderTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/RarReaderTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/RarReaderTest.cpp'; fi`
|
||||
|
||||
NzbFileTest.o: tests/queue/NzbFileTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NzbFileTest.o -MD -MP -MF "$(DEPDIR)/NzbFileTest.Tpo" -c -o NzbFileTest.o `test -f 'tests/queue/NzbFileTest.cpp' || echo '$(srcdir)/'`tests/queue/NzbFileTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NzbFileTest.Tpo" "$(DEPDIR)/NzbFileTest.Po"; else rm -f "$(DEPDIR)/NzbFileTest.Tpo"; exit 1; fi
|
||||
@@ -2245,6 +2398,34 @@ UtilTest.obj: tests/util/UtilTest.cpp
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/util/UtilTest.cpp' object='UtilTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o UtilTest.obj `if test -f 'tests/util/UtilTest.cpp'; then $(CYGPATH_W) 'tests/util/UtilTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/util/UtilTest.cpp'; fi`
|
||||
|
||||
ParCheckerTest.o: tests/postprocess/ParCheckerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCheckerTest.o -MD -MP -MF "$(DEPDIR)/ParCheckerTest.Tpo" -c -o ParCheckerTest.o `test -f 'tests/postprocess/ParCheckerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParCheckerTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCheckerTest.Tpo" "$(DEPDIR)/ParCheckerTest.Po"; else rm -f "$(DEPDIR)/ParCheckerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParCheckerTest.cpp' object='ParCheckerTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCheckerTest.o `test -f 'tests/postprocess/ParCheckerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParCheckerTest.cpp
|
||||
|
||||
ParCheckerTest.obj: tests/postprocess/ParCheckerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParCheckerTest.obj -MD -MP -MF "$(DEPDIR)/ParCheckerTest.Tpo" -c -o ParCheckerTest.obj `if test -f 'tests/postprocess/ParCheckerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParCheckerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParCheckerTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParCheckerTest.Tpo" "$(DEPDIR)/ParCheckerTest.Po"; else rm -f "$(DEPDIR)/ParCheckerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParCheckerTest.cpp' object='ParCheckerTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParCheckerTest.obj `if test -f 'tests/postprocess/ParCheckerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParCheckerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParCheckerTest.cpp'; fi`
|
||||
|
||||
ParRenamerTest.o: tests/postprocess/ParRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParRenamerTest.o -MD -MP -MF "$(DEPDIR)/ParRenamerTest.Tpo" -c -o ParRenamerTest.o `test -f 'tests/postprocess/ParRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParRenamerTest.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParRenamerTest.Tpo" "$(DEPDIR)/ParRenamerTest.Po"; else rm -f "$(DEPDIR)/ParRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParRenamerTest.cpp' object='ParRenamerTest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParRenamerTest.o `test -f 'tests/postprocess/ParRenamerTest.cpp' || echo '$(srcdir)/'`tests/postprocess/ParRenamerTest.cpp
|
||||
|
||||
ParRenamerTest.obj: tests/postprocess/ParRenamerTest.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParRenamerTest.obj -MD -MP -MF "$(DEPDIR)/ParRenamerTest.Tpo" -c -o ParRenamerTest.obj `if test -f 'tests/postprocess/ParRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParRenamerTest.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParRenamerTest.Tpo" "$(DEPDIR)/ParRenamerTest.Po"; else rm -f "$(DEPDIR)/ParRenamerTest.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/postprocess/ParRenamerTest.cpp' object='ParRenamerTest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ParRenamerTest.obj `if test -f 'tests/postprocess/ParRenamerTest.cpp'; then $(CYGPATH_W) 'tests/postprocess/ParRenamerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/postprocess/ParRenamerTest.cpp'; fi`
|
||||
uninstall-info-am:
|
||||
install-dist_docDATA: $(dist_doc_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@@ -2351,7 +2532,7 @@ distclean-tags:
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(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)/posix $(distdir)/scripts $(distdir)/tests/testdata/dupematcher1 $(distdir)/tests/testdata/dupematcher2 $(distdir)/tests/testdata/nzbfile $(distdir)/tests/testdata/parchecker $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib $(distdir)/windows $(distdir)/windows/resources $(distdir)/windows/setup
|
||||
$(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)/posix $(distdir)/scripts $(distdir)/tests/testdata/dupematcher1 $(distdir)/tests/testdata/dupematcher2 $(distdir)/tests/testdata/nzbfile $(distdir)/tests/testdata/parchecker $(distdir)/tests/testdata/rarrenamer $(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 \
|
||||
|
||||
@@ -92,7 +92,10 @@
|
||||
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
|
||||
#undef HAVE_NCURSES_NCURSES_H
|
||||
|
||||
/* Define to 1 to use OpenSSL library for TLS/SSL-support. */
|
||||
/* Define to 1 to use Nettle library for decryption. */
|
||||
#undef HAVE_NETTLE
|
||||
|
||||
/* Define to 1 to use OpenSSL library for TLS/SSL-support and decryption. */
|
||||
#undef HAVE_OPENSSL
|
||||
|
||||
/* Define to 1 if you have the <regex.h> header file. */
|
||||
|
||||
457
configure
vendored
457
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 17.0.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 18.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='17.0'
|
||||
PACKAGE_STRING='nzbget 17.0'
|
||||
PACKAGE_VERSION='18.0'
|
||||
PACKAGE_STRING='nzbget 18.0'
|
||||
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
|
||||
|
||||
ac_unique_file="daemon/main/nzbget.cpp"
|
||||
@@ -721,6 +721,8 @@ openssl_CFLAGS
|
||||
openssl_LIBS
|
||||
gnutls_CFLAGS
|
||||
gnutls_LIBS
|
||||
nettle_CFLAGS
|
||||
nettle_LIBS
|
||||
zlib_CFLAGS
|
||||
zlib_LIBS
|
||||
WITH_TESTS_TRUE
|
||||
@@ -747,6 +749,8 @@ openssl_CFLAGS
|
||||
openssl_LIBS
|
||||
gnutls_CFLAGS
|
||||
gnutls_LIBS
|
||||
nettle_CFLAGS
|
||||
nettle_LIBS
|
||||
zlib_CFLAGS
|
||||
zlib_LIBS'
|
||||
|
||||
@@ -1251,7 +1255,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 17.0 to adapt to many kinds of systems.
|
||||
\`configure' configures nzbget 18.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1322,7 +1326,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of nzbget 17.0:";;
|
||||
short | recursive ) echo "Configuration of nzbget 18.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1369,6 +1373,10 @@ Optional Packages:
|
||||
GnuTLS include directory
|
||||
--with-libgnutls-libraries=DIR
|
||||
GnuTLS library directory
|
||||
--with-libnettle-includes=DIR
|
||||
Nettle include directory
|
||||
--with-libnettle-libraries=DIR
|
||||
Nettle library directory
|
||||
--with-zlib-includes=DIR
|
||||
zlib include directory
|
||||
--with-zlib-libraries=DIR
|
||||
@@ -1399,6 +1407,9 @@ Some influential environment variables:
|
||||
gnutls_CFLAGS
|
||||
C compiler flags for gnutls, overriding pkg-config
|
||||
gnutls_LIBS linker flags for gnutls, overriding pkg-config
|
||||
nettle_CFLAGS
|
||||
C compiler flags for nettle, overriding pkg-config
|
||||
nettle_LIBS linker flags for nettle, overriding pkg-config
|
||||
zlib_CFLAGS C compiler flags for zlib, overriding pkg-config
|
||||
zlib_LIBS linker flags for zlib, overriding pkg-config
|
||||
|
||||
@@ -1466,7 +1477,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
nzbget configure 17.0
|
||||
nzbget configure 18.0
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1480,7 +1491,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 17.0, which was
|
||||
It was created by nzbget $as_me 18.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2276,7 +2287,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='nzbget'
|
||||
VERSION='17.0'
|
||||
VERSION='18.0'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -9797,9 +9808,9 @@ echo "$as_me: error: Couldn't find OpenSSL headers (ssl.h)" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
{ echo "$as_me:$LINENO: checking for library containing CRYPTO_set_locking_callback" >&5
|
||||
echo $ECHO_N "checking for library containing CRYPTO_set_locking_callback... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for library containing ASN1_OBJECT_free" >&5
|
||||
echo $ECHO_N "checking for library containing ASN1_OBJECT_free... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_ASN1_OBJECT_free+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
@@ -9816,11 +9827,11 @@ cat >>conftest.$ac_ext <<_ACEOF
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char CRYPTO_set_locking_callback ();
|
||||
char ASN1_OBJECT_free ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return CRYPTO_set_locking_callback ();
|
||||
return ASN1_OBJECT_free ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@@ -9850,7 +9861,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_search_CRYPTO_set_locking_callback=$ac_res
|
||||
ac_cv_search_ASN1_OBJECT_free=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
@@ -9860,26 +9871,26 @@ fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
if test "${ac_cv_search_ASN1_OBJECT_free+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
if test "${ac_cv_search_ASN1_OBJECT_free+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_CRYPTO_set_locking_callback=no
|
||||
ac_cv_search_ASN1_OBJECT_free=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_CRYPTO_set_locking_callback" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_CRYPTO_set_locking_callback" >&6; }
|
||||
ac_res=$ac_cv_search_CRYPTO_set_locking_callback
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_ASN1_OBJECT_free" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_ASN1_OBJECT_free" >&6; }
|
||||
ac_res=$ac_cv_search_ASN1_OBJECT_free
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
{ echo "$as_me:$LINENO: checking for library containing SSL_library_init" >&5
|
||||
echo $ECHO_N "checking for library containing SSL_library_init... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_SSL_library_init+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for library containing SSL_CTX_new" >&5
|
||||
echo $ECHO_N "checking for library containing SSL_CTX_new... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_SSL_CTX_new+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
@@ -9896,11 +9907,11 @@ cat >>conftest.$ac_ext <<_ACEOF
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char SSL_library_init ();
|
||||
char SSL_CTX_new ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return SSL_library_init ();
|
||||
return SSL_CTX_new ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
@@ -9930,7 +9941,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_search_SSL_library_init=$ac_res
|
||||
ac_cv_search_SSL_CTX_new=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
@@ -9940,21 +9951,21 @@ fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_SSL_library_init+set}" = set; then
|
||||
if test "${ac_cv_search_SSL_CTX_new+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_SSL_library_init+set}" = set; then
|
||||
if test "${ac_cv_search_SSL_CTX_new+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_SSL_library_init=no
|
||||
ac_cv_search_SSL_CTX_new=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_SSL_library_init" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_SSL_library_init" >&6; }
|
||||
ac_res=$ac_cv_search_SSL_library_init
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_SSL_CTX_new" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_SSL_CTX_new" >&6; }
|
||||
ac_res=$ac_cv_search_SSL_CTX_new
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
FOUND=yes
|
||||
@@ -10630,6 +10641,380 @@ echo "$as_me: error: Couldn't find GnuTLS library" >&2;}
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_LIBGNUTLS 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$TLSLIB" = "GnuTLS"; then
|
||||
|
||||
# Check whether --with-libnettle_includes was given.
|
||||
if test "${with_libnettle_includes+set}" = set; then
|
||||
withval=$with_libnettle_includes; CPPFLAGS="${CPPFLAGS} -I${withval}"
|
||||
INCVAL="yes"
|
||||
else
|
||||
INCVAL="no"
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-libnettle_libraries was given.
|
||||
if test "${with_libnettle_libraries+set}" = set; then
|
||||
withval=$with_libnettle_libraries; LDFLAGS="${LDFLAGS} -L${withval}"
|
||||
LIBVAL="yes"
|
||||
else
|
||||
LIBVAL="no"
|
||||
fi
|
||||
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
|
||||
pkg_failed=no
|
||||
{ echo "$as_me:$LINENO: checking for nettle" >&5
|
||||
echo $ECHO_N "checking for nettle... $ECHO_C" >&6; }
|
||||
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$nettle_CFLAGS"; then
|
||||
pkg_cv_nettle_CFLAGS="$nettle_CFLAGS"
|
||||
else
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"nettle\"") >&5
|
||||
($PKG_CONFIG --exists --print-errors "nettle") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; then
|
||||
pkg_cv_nettle_CFLAGS=`$PKG_CONFIG --cflags "nettle" 2>/dev/null`
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$nettle_LIBS"; then
|
||||
pkg_cv_nettle_LIBS="$nettle_LIBS"
|
||||
else
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"nettle\"") >&5
|
||||
($PKG_CONFIG --exists --print-errors "nettle") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; then
|
||||
pkg_cv_nettle_LIBS=`$PKG_CONFIG --libs "nettle" 2>/dev/null`
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
nettle_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "nettle"`
|
||||
else
|
||||
nettle_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "nettle"`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$nettle_PKG_ERRORS" >&5
|
||||
|
||||
{ { echo "$as_me:$LINENO: error: Package requirements (nettle) were not met:
|
||||
|
||||
$nettle_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
Alternatively, you may set the environment variables nettle_CFLAGS
|
||||
and nettle_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
" >&5
|
||||
echo "$as_me: error: Package requirements (nettle) were not met:
|
||||
|
||||
$nettle_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
Alternatively, you may set the environment variables nettle_CFLAGS
|
||||
and nettle_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
elif test $pkg_failed = untried; then
|
||||
{ { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
Alternatively, you may set the environment variables nettle_CFLAGS
|
||||
and nettle_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
|
||||
See \`config.log' for more details." >&5
|
||||
echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
Alternatively, you may set the environment variables nettle_CFLAGS
|
||||
and nettle_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
|
||||
See \`config.log' for more details." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
else
|
||||
nettle_CFLAGS=$pkg_cv_nettle_CFLAGS
|
||||
nettle_LIBS=$pkg_cv_nettle_LIBS
|
||||
{ echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6; }
|
||||
LIBS="${LIBS} $nettle_LIBS"
|
||||
CPPFLAGS="${CPPFLAGS} $nettle_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
if test "${ac_cv_header_nettle_sha_h+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for nettle/sha.h" >&5
|
||||
echo $ECHO_N "checking for nettle/sha.h... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_header_nettle_sha_h+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_header_nettle_sha_h" >&5
|
||||
echo "${ECHO_T}$ac_cv_header_nettle_sha_h" >&6; }
|
||||
else
|
||||
# Is the header compilable?
|
||||
{ echo "$as_me:$LINENO: checking nettle/sha.h usability" >&5
|
||||
echo $ECHO_N "checking nettle/sha.h usability... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <nettle/sha.h>
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_header_compiler=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_compiler=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
|
||||
echo "${ECHO_T}$ac_header_compiler" >&6; }
|
||||
|
||||
# Is the header present?
|
||||
{ echo "$as_me:$LINENO: checking nettle/sha.h presence" >&5
|
||||
echo $ECHO_N "checking nettle/sha.h presence... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <nettle/sha.h>
|
||||
_ACEOF
|
||||
if { (ac_try="$ac_cpp conftest.$ac_ext"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null && {
|
||||
test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
}; then
|
||||
ac_header_preproc=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_preproc=no
|
||||
fi
|
||||
|
||||
rm -f conftest.err conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
|
||||
echo "${ECHO_T}$ac_header_preproc" >&6; }
|
||||
|
||||
# So? What about this header?
|
||||
case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in
|
||||
yes:no: )
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: accepted by the compiler, rejected by the preprocessor!" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: proceeding with the compiler's result" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: proceeding with the compiler's result" >&2;}
|
||||
ac_header_preproc=yes
|
||||
;;
|
||||
no:yes:* )
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: present but cannot be compiled" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: present but cannot be compiled" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: check for missing prerequisite headers?" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: check for missing prerequisite headers?" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: see the Autoconf documentation" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: see the Autoconf documentation" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: section \"Present But Cannot Be Compiled\"" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: proceeding with the preprocessor's result" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: proceeding with the preprocessor's result" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: nettle/sha.h: in the future, the compiler will take precedence" >&5
|
||||
echo "$as_me: WARNING: nettle/sha.h: in the future, the compiler will take precedence" >&2;}
|
||||
( cat <<\_ASBOX
|
||||
## ------------------------------------------- ##
|
||||
## Report this to hugbug@users.sourceforge.net ##
|
||||
## ------------------------------------------- ##
|
||||
_ASBOX
|
||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||
;;
|
||||
esac
|
||||
{ echo "$as_me:$LINENO: checking for nettle/sha.h" >&5
|
||||
echo $ECHO_N "checking for nettle/sha.h... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_header_nettle_sha_h+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_cv_header_nettle_sha_h=$ac_header_preproc
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_header_nettle_sha_h" >&5
|
||||
echo "${ECHO_T}$ac_cv_header_nettle_sha_h" >&6; }
|
||||
|
||||
fi
|
||||
if test $ac_cv_header_nettle_sha_h = yes; then
|
||||
FOUND=yes
|
||||
else
|
||||
FOUND=no
|
||||
fi
|
||||
|
||||
|
||||
if test "$FOUND" = "no"; then
|
||||
{ { echo "$as_me:$LINENO: error: Couldn't find Nettle headers (sha.h)" >&5
|
||||
echo "$as_me: error: Couldn't find Nettle headers (sha.h)" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: checking for library containing nettle_pbkdf2_hmac_sha256" >&5
|
||||
echo $ECHO_N "checking for library containing nettle_pbkdf2_hmac_sha256... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_nettle_pbkdf2_hmac_sha256+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char nettle_pbkdf2_hmac_sha256 ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return nettle_pbkdf2_hmac_sha256 ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' nettle; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_search_nettle_pbkdf2_hmac_sha256=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_nettle_pbkdf2_hmac_sha256+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_nettle_pbkdf2_hmac_sha256+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_nettle_pbkdf2_hmac_sha256=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_nettle_pbkdf2_hmac_sha256" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_nettle_pbkdf2_hmac_sha256" >&6; }
|
||||
ac_res=$ac_cv_search_nettle_pbkdf2_hmac_sha256
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
FOUND=yes
|
||||
else
|
||||
FOUND=no
|
||||
fi
|
||||
|
||||
if test "$FOUND" = "no"; then
|
||||
{ { echo "$as_me:$LINENO: error: Couldn't find Nettle library, required when using GnuTLS" >&5
|
||||
echo "$as_me: error: Couldn't find Nettle library, required when using GnuTLS" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_NETTLE 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
@@ -11825,7 +12210,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 17.0, which was
|
||||
This file was extended by nzbget $as_me 18.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -11878,7 +12263,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
nzbget config.status 17.0
|
||||
nzbget config.status 18.0
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
@@ -12203,6 +12588,8 @@ openssl_CFLAGS!$openssl_CFLAGS$ac_delim
|
||||
openssl_LIBS!$openssl_LIBS$ac_delim
|
||||
gnutls_CFLAGS!$gnutls_CFLAGS$ac_delim
|
||||
gnutls_LIBS!$gnutls_LIBS$ac_delim
|
||||
nettle_CFLAGS!$nettle_CFLAGS$ac_delim
|
||||
nettle_LIBS!$nettle_LIBS$ac_delim
|
||||
zlib_CFLAGS!$zlib_CFLAGS$ac_delim
|
||||
zlib_LIBS!$zlib_LIBS$ac_delim
|
||||
WITH_TESTS_TRUE!$WITH_TESTS_TRUE$ac_delim
|
||||
@@ -12211,7 +12598,7 @@ LIBOBJS!$LIBOBJS$ac_delim
|
||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||
_ACEOF
|
||||
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 17; then
|
||||
break
|
||||
elif $ac_last_try; then
|
||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||
|
||||
43
configure.ac
43
configure.ac
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# This file is part of nzbget. See <http://nzbget.net>.
|
||||
#
|
||||
# Copyright (C) 2008-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-2017 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
|
||||
@@ -21,7 +21,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 17.0, hugbug@users.sourceforge.net)
|
||||
AC_INIT(nzbget, 18.0, hugbug@users.sourceforge.net)
|
||||
AC_CONFIG_AUX_DIR(posix)
|
||||
AC_CANONICAL_TARGET
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
@@ -385,8 +385,8 @@ if test "$USETLS" = "yes"; then
|
||||
AC_MSG_ERROR([Couldn't find OpenSSL headers (ssl.h)])
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
AC_SEARCH_LIBS([CRYPTO_set_locking_callback], [crypto],
|
||||
AC_SEARCH_LIBS([SSL_library_init], [ssl],
|
||||
AC_SEARCH_LIBS([ASN1_OBJECT_free], [crypto],
|
||||
AC_SEARCH_LIBS([SSL_CTX_new], [ssl],
|
||||
FOUND=yes,
|
||||
FOUND=no),
|
||||
FOUND=no)
|
||||
@@ -395,7 +395,7 @@ if test "$USETLS" = "yes"; then
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
TLSLIB="OpenSSL"
|
||||
AC_DEFINE([HAVE_OPENSSL],1,[Define to 1 to use OpenSSL library for TLS/SSL-support.])
|
||||
AC_DEFINE([HAVE_OPENSSL],1,[Define to 1 to use OpenSSL library for TLS/SSL-support and decryption.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -457,6 +457,39 @@ if test "$USETLS" = "yes"; then
|
||||
AC_DEFINE([HAVE_LIBGNUTLS],1,[Define to 1 to use GnuTLS library for TLS/SSL-support.])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$TLSLIB" = "GnuTLS"; then
|
||||
AC_ARG_WITH(libnettle_includes,
|
||||
[AS_HELP_STRING([--with-libnettle-includes=DIR], [Nettle include directory])],
|
||||
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
|
||||
[INCVAL="yes"],
|
||||
[INCVAL="no"])
|
||||
AC_ARG_WITH(libnettle_libraries,
|
||||
[AS_HELP_STRING([--with-libnettle-libraries=DIR], [Nettle library directory])],
|
||||
[LDFLAGS="${LDFLAGS} -L${withval}"]
|
||||
[LIBVAL="yes"],
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES([nettle], [nettle],
|
||||
[LIBS="${LIBS} $nettle_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $nettle_CFLAGS"])
|
||||
fi
|
||||
AC_CHECK_HEADER(nettle/sha.h,
|
||||
FOUND=yes,
|
||||
FOUND=no)
|
||||
if test "$FOUND" = "no"; then
|
||||
AC_MSG_ERROR([Couldn't find Nettle headers (sha.h)])
|
||||
fi
|
||||
AC_SEARCH_LIBS([nettle_pbkdf2_hmac_sha256], [nettle],
|
||||
FOUND=yes,
|
||||
FOUND=no)
|
||||
if test "$FOUND" = "no"; then
|
||||
AC_MSG_ERROR([Couldn't find Nettle library, required when using GnuTLS])
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
AC_DEFINE([HAVE_NETTLE],1,[Define to 1 to use Nettle library for decryption.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$TLSLIB" = ""; then
|
||||
|
||||
@@ -89,6 +89,12 @@ static struct gcry_thread_cbs gcry_threads_Mutex =
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
|
||||
#ifndef CRYPTO_set_locking_callback
|
||||
#define NEED_CRYPTO_LOCKING
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CRYPTO_LOCKING
|
||||
|
||||
/**
|
||||
* Mutexes for OpenSSL
|
||||
*/
|
||||
@@ -108,17 +114,6 @@ static void openssl_locking(int mode, int n, const char* file, int line)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static uint32 openssl_thread_id(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return (uint32)GetCurrentThreadId();
|
||||
#else
|
||||
return (uint32)pthread_self();
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
static struct CRYPTO_dynlock_value* openssl_dynlock_create(const char *file, int line)
|
||||
{
|
||||
return (CRYPTO_dynlock_value*)new Mutex();
|
||||
@@ -143,6 +138,7 @@ static void openssl_dynlock_lock(int mode, struct CRYPTO_dynlock_value *l, const
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NEED_CRYPTO_LOCKING */
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
|
||||
@@ -172,20 +168,22 @@ void TlsSocket::Init()
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
|
||||
#ifdef NEED_CRYPTO_LOCKING
|
||||
for (int i = 0, num = CRYPTO_num_locks(); i < num; i++)
|
||||
{
|
||||
g_OpenSSLMutexes.emplace_back(std::make_unique<Mutex>());
|
||||
}
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
CRYPTO_set_locking_callback(openssl_locking);
|
||||
//CRYPTO_set_id_callback(openssl_thread_id);
|
||||
CRYPTO_set_dynlock_create_callback(openssl_dynlock_create);
|
||||
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
|
||||
CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock);
|
||||
#endif /* NEED_CRYPTO_LOCKING */
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
@@ -287,7 +285,8 @@ bool TlsSocket::Start()
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
const char* priority = !m_cipher.Empty() ? m_cipher.Str() : "NORMAL";
|
||||
const char* priority = !m_cipher.Empty() ? m_cipher.Str() :
|
||||
(m_certFile && m_keyFile ? "NORMAL:!VERS-SSL3.0" : "NORMAL");
|
||||
|
||||
m_retCode = gnutls_priority_set_direct((gnutls_session_t)m_session, priority, nullptr);
|
||||
if (m_retCode != 0)
|
||||
@@ -354,6 +353,12 @@ bool TlsSocket::Start()
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!SSL_CTX_set_options((SSL_CTX*)m_context, SSL_OP_NO_SSLv3))
|
||||
{
|
||||
ReportError("Could not select minimum protocol version for TLS");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_session = SSL_new((SSL_CTX*)m_context);
|
||||
|
||||
@@ -54,7 +54,7 @@ void WebDownloader::Run()
|
||||
|
||||
SetStatus(adRunning);
|
||||
|
||||
int remainedDownloadRetries = g_Options->GetRetries() > 0 ? g_Options->GetRetries() : 1;
|
||||
int remainedDownloadRetries = g_Options->GetUrlRetries() > 0 ? g_Options->GetUrlRetries() : 1;
|
||||
int remainedConnectRetries = remainedDownloadRetries > 10 ? remainedDownloadRetries : 10;
|
||||
if (!m_retry)
|
||||
{
|
||||
@@ -74,9 +74,9 @@ void WebDownloader::Run()
|
||||
((Status == adConnectError) && (remainedConnectRetries > 1)))
|
||||
&& !IsStopped() && !(!m_force && g_Options->GetPauseDownload()))
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_Options->GetRetryInterval());
|
||||
detail("Waiting %i sec to retry", g_Options->GetUrlInterval());
|
||||
int msec = 0;
|
||||
while (!IsStopped() && (msec < g_Options->GetRetryInterval() * 1000) &&
|
||||
while (!IsStopped() && (msec < g_Options->GetUrlInterval() * 1000) &&
|
||||
!(!m_force && g_Options->GetPauseDownload()))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
|
||||
@@ -62,7 +62,7 @@ void FeedScriptController::ExecuteScript(ScriptConfig::Script* script)
|
||||
if (exitCode != FEED_SUCCESS)
|
||||
{
|
||||
infoName[0] = 'F'; // uppercase
|
||||
PrintMessage(Message::mkError, "%s failed", GetInfoName());
|
||||
PrintMessage(Message::mkError, "%s failed", *infoName);
|
||||
m_success = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ void PostScriptController::ExecuteScript(ScriptConfig::Script* script)
|
||||
infoName[0] = 'P'; // uppercase
|
||||
|
||||
SetLogPrefix(nullptr);
|
||||
ScriptStatus::EStatus status = AnalyseExitCode(exitCode);
|
||||
ScriptStatus::EStatus status = AnalyseExitCode(exitCode, infoName);
|
||||
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
@@ -176,7 +176,7 @@ void PostScriptController::PrepareParams(const char* scriptName)
|
||||
PrepareEnvScript(m_postInfo->GetNzbInfo()->GetParameters(), scriptName);
|
||||
}
|
||||
|
||||
ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int exitCode)
|
||||
ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int exitCode, const char* upInfoName)
|
||||
{
|
||||
// The ScriptStatus is accumulated for all scripts:
|
||||
// If any script has failed the status is "failure", etc.
|
||||
@@ -184,28 +184,28 @@ ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int exitCode)
|
||||
switch (exitCode)
|
||||
{
|
||||
case POSTPROCESS_SUCCESS:
|
||||
PrintMessage(Message::mkInfo, "%s successful", GetInfoName());
|
||||
PrintMessage(Message::mkInfo, "%s successful", upInfoName);
|
||||
return ScriptStatus::srSuccess;
|
||||
|
||||
case POSTPROCESS_ERROR:
|
||||
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
|
||||
PrintMessage(Message::mkError, "%s failed", GetInfoName());
|
||||
PrintMessage(Message::mkError, "%s failed", upInfoName);
|
||||
return ScriptStatus::srFailure;
|
||||
|
||||
case POSTPROCESS_NONE:
|
||||
PrintMessage(Message::mkInfo, "%s skipped", GetInfoName());
|
||||
PrintMessage(Message::mkInfo, "%s skipped", upInfoName);
|
||||
return ScriptStatus::srNone;
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
case POSTPROCESS_PARCHECK:
|
||||
if (m_postInfo->GetNzbInfo()->GetParStatus() > NzbInfo::psSkipped)
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s requested par-check/repair, but the collection was already checked", GetInfoName());
|
||||
PrintMessage(Message::mkError, "%s requested par-check/repair, but the collection was already checked", upInfoName);
|
||||
return ScriptStatus::srFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s requested par-check/repair", GetInfoName());
|
||||
PrintMessage(Message::mkInfo, "%s requested par-check/repair", upInfoName);
|
||||
m_postInfo->SetRequestParCheck(true);
|
||||
m_postInfo->SetForceRepair(true);
|
||||
return ScriptStatus::srSuccess;
|
||||
@@ -214,7 +214,7 @@ ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int exitCode)
|
||||
#endif
|
||||
|
||||
default:
|
||||
PrintMessage(Message::mkError, "%s failed (terminated with unknown status)", GetInfoName());
|
||||
PrintMessage(Message::mkError, "%s failed (terminated with unknown status)", upInfoName);
|
||||
return ScriptStatus::srFailure;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ private:
|
||||
ScriptConfig::Script* m_script;
|
||||
|
||||
void PrepareParams(const char* scriptName);
|
||||
ScriptStatus::EStatus AnalyseExitCode(int exitCode);
|
||||
ScriptStatus::EStatus AnalyseExitCode(int exitCode, const char* upInfoName);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,9 +110,9 @@ void QueueScriptController::Run()
|
||||
NzbInfo* nzbInfo = downloadQueue->GetQueue()->Find(m_id);
|
||||
if (nzbInfo)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Cancelling download and deleting %s", *m_nzbName);
|
||||
nzbInfo->PrintMessage(Message::mkWarning, "Cancelling download and deleting %s", *m_nzbName);
|
||||
nzbInfo->SetDeleteStatus(NzbInfo::dsBad);
|
||||
downloadQueue->EditEntry(m_id, DownloadQueue::eaGroupDelete, 0, nullptr);
|
||||
downloadQueue->EditEntry(m_id, DownloadQueue::eaGroupDelete, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,9 +215,7 @@ void QueueScriptController::AddMessage(Message::EKind kind, const char* text)
|
||||
NzbInfo* nzbInfo = QueueScriptCoordinator::FindNzbInfo(downloadQueue, m_id);
|
||||
if (nzbInfo)
|
||||
{
|
||||
SetLogPrefix(nullptr);
|
||||
PrintMessage(Message::mkWarning, "Marking %s as bad", *m_nzbName);
|
||||
SetLogPrefix(m_script->GetDisplayName());
|
||||
nzbInfo->PrintMessage(Message::mkWarning, "Marking %s as bad", *m_nzbName);
|
||||
nzbInfo->SetMarkStatus(NzbInfo::ksBad);
|
||||
}
|
||||
}
|
||||
@@ -338,21 +336,7 @@ bool QueueScriptCoordinator::UsableScript(ScriptConfig::Script& script, NzbInfo*
|
||||
return false;
|
||||
}
|
||||
|
||||
// check queue-scripts
|
||||
const char* queueScript = g_Options->GetQueueScript();
|
||||
if (!Util::EmptyStr(queueScript))
|
||||
{
|
||||
Tokenizer tok(queueScript, ",;");
|
||||
while (const char* scriptName = tok.Next())
|
||||
{
|
||||
if (FileSystem::SameFilename(scriptName, script.GetName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check post-processing-scripts assigned for that nzb
|
||||
// check extension scripts assigned for that nzb
|
||||
for (NzbParameter& parameter : nzbInfo->GetParameters())
|
||||
{
|
||||
const char* varname = parameter.GetName();
|
||||
@@ -370,17 +354,17 @@ bool QueueScriptCoordinator::UsableScript(ScriptConfig::Script& script, NzbInfo*
|
||||
}
|
||||
}
|
||||
|
||||
// for URL-events the post-processing scripts are not assigned yet;
|
||||
// instead we take the default post-processing scripts for the category (or global)
|
||||
// for URL-events the extension scripts are not assigned yet;
|
||||
// instead we take the default extension scripts for the category (or global)
|
||||
if (event == qeUrlCompleted)
|
||||
{
|
||||
const char* postScript = g_Options->GetPostScript();
|
||||
const char* postScript = g_Options->GetExtensions();
|
||||
if (!Util::EmptyStr(nzbInfo->GetCategory()))
|
||||
{
|
||||
Options::Category* categoryObj = g_Options->FindCategory(nzbInfo->GetCategory(), false);
|
||||
if (categoryObj && !Util::EmptyStr(categoryObj->GetPostScript()))
|
||||
if (categoryObj && !Util::EmptyStr(categoryObj->GetExtensions()))
|
||||
{
|
||||
postScript = categoryObj->GetPostScript();
|
||||
postScript = categoryObj->GetExtensions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,22 @@
|
||||
#include "Log.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
class ScanScriptCheck : public NzbScriptController
|
||||
{
|
||||
protected:
|
||||
virtual void ExecuteScript(ScriptConfig::Script* script) { has |= script->GetScanScript(); }
|
||||
bool has = false;
|
||||
friend class ScanScriptController;
|
||||
};
|
||||
|
||||
|
||||
bool ScanScriptController::HasScripts()
|
||||
{
|
||||
ScanScriptCheck check;
|
||||
check.ExecuteScriptList(g_Options->GetExtensions());
|
||||
return check.has;
|
||||
}
|
||||
|
||||
void ScanScriptController::ExecuteScripts(const char* nzbFilename,
|
||||
const char* url, const char* directory, CString* nzbName, CString* category,
|
||||
int* priority, NzbParameterList* parameters, bool* addTop, bool* addPaused,
|
||||
@@ -45,7 +61,18 @@ void ScanScriptController::ExecuteScripts(const char* nzbFilename,
|
||||
scriptController.m_dupeMode = dupeMode;
|
||||
scriptController.m_prefixLen = 0;
|
||||
|
||||
scriptController.ExecuteScriptList(g_Options->GetScanScript());
|
||||
const char* extensions = g_Options->GetExtensions();
|
||||
|
||||
if (!Util::EmptyStr(*category))
|
||||
{
|
||||
Options::Category* categoryObj = g_Options->FindCategory(*category, false);
|
||||
if (categoryObj && !Util::EmptyStr(categoryObj->GetExtensions()))
|
||||
{
|
||||
extensions = categoryObj->GetExtensions();
|
||||
}
|
||||
}
|
||||
|
||||
scriptController.ExecuteScriptList(extensions);
|
||||
}
|
||||
|
||||
void ScanScriptController::ExecuteScript(ScriptConfig::Script* script)
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
const char* directory, CString* nzbName, CString* category, int* priority,
|
||||
NzbParameterList* parameters, bool* addTop, bool* addPaused,
|
||||
CString* dupeKey, int* dupeScore, EDupeMode* dupeMode);
|
||||
static bool HasScripts();
|
||||
|
||||
protected:
|
||||
virtual void ExecuteScript(ScriptConfig::Script* script);
|
||||
|
||||
@@ -69,11 +69,17 @@ void SchedulerScriptController::ExecuteScript(ScriptConfig::Script* script)
|
||||
return;
|
||||
}
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing scheduler-script %s for Task%i", script->GetName(), m_taskId);
|
||||
BString<1024> taskName(" for Task%i", m_taskId);
|
||||
if (m_taskId == 0)
|
||||
{
|
||||
taskName = "";
|
||||
}
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing scheduler-script %s%s", script->GetName(), *taskName);
|
||||
|
||||
SetArgs({script->GetLocation()});
|
||||
|
||||
BString<1024> infoName("scheduler-script %s for Task%i", script->GetName(), m_taskId);
|
||||
BString<1024> infoName("scheduler-script %s%s", script->GetName(), *taskName);
|
||||
SetInfoName(infoName);
|
||||
|
||||
SetLogPrefix(script->GetDisplayName());
|
||||
|
||||
@@ -33,25 +33,14 @@ static const char* SCHEDULER_SCRIPT_SIGNATURE = "SCHEDULER";
|
||||
static const char* FEED_SCRIPT_SIGNATURE = "FEED";
|
||||
static const char* END_SCRIPT_SIGNATURE = " SCRIPT";
|
||||
static const char* QUEUE_EVENTS_SIGNATURE = "### QUEUE EVENTS:";
|
||||
|
||||
|
||||
ScriptConfig::Script::Script(const char* name, const char* location)
|
||||
{
|
||||
m_name = name;
|
||||
m_location = location;
|
||||
m_displayName = name;
|
||||
m_postScript = false;
|
||||
m_scanScript = false;
|
||||
m_queueScript = false;
|
||||
m_schedulerScript = false;
|
||||
m_feedScript = false;
|
||||
}
|
||||
|
||||
static const char* TASK_TIME_SIGNATURE = "### TASK TIME:";
|
||||
static const char* DEFINITION_SIGNATURE = "###";
|
||||
|
||||
void ScriptConfig::InitOptions()
|
||||
{
|
||||
InitScripts();
|
||||
InitConfigTemplates();
|
||||
CreateTasks();
|
||||
}
|
||||
|
||||
bool ScriptConfig::LoadConfig(Options::OptEntries* optEntries)
|
||||
@@ -81,7 +70,7 @@ bool ScriptConfig::LoadConfig(Options::OptEntries* optEntries)
|
||||
|
||||
CString optname;
|
||||
CString optvalue;
|
||||
if (g_Options->SplitOptionString(buf, optname, optvalue))
|
||||
if (Options::SplitOptionString(buf, optname, optvalue))
|
||||
{
|
||||
optEntries->emplace_back(optname, optvalue);
|
||||
}
|
||||
@@ -89,6 +78,8 @@ bool ScriptConfig::LoadConfig(Options::OptEntries* optEntries)
|
||||
|
||||
infile.Close();
|
||||
|
||||
Options::ConvertOldOptions(optEntries);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,7 +171,7 @@ bool ScriptConfig::LoadConfigTemplates(ConfigTemplates* configTemplates)
|
||||
LoadScripts(&scriptList);
|
||||
|
||||
const int beginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
|
||||
const int queueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
|
||||
const int definitionSignatureLen = strlen(DEFINITION_SIGNATURE);
|
||||
|
||||
for (Script& script : scriptList)
|
||||
{
|
||||
@@ -194,6 +185,7 @@ bool ScriptConfig::LoadConfigTemplates(ConfigTemplates* configTemplates)
|
||||
StringBuilder templ;
|
||||
char buf[1024];
|
||||
bool inConfig = false;
|
||||
bool inHeader = false;
|
||||
|
||||
while (infile.ReadLine(buf, sizeof(buf) - 1))
|
||||
{
|
||||
@@ -210,12 +202,13 @@ bool ScriptConfig::LoadConfigTemplates(ConfigTemplates* configTemplates)
|
||||
break;
|
||||
}
|
||||
inConfig = true;
|
||||
inHeader = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skip = !strncmp(buf, QUEUE_EVENTS_SIGNATURE, queueEventsSignatureLen);
|
||||
inHeader &= !strncmp(buf, DEFINITION_SIGNATURE, definitionSignatureLen);
|
||||
|
||||
if (inConfig && !skip)
|
||||
if (inConfig && !inHeader)
|
||||
{
|
||||
templ.Append(buf);
|
||||
}
|
||||
@@ -287,11 +280,6 @@ void ScriptConfig::LoadScripts(Scripts* scripts)
|
||||
|
||||
void ScriptConfig::LoadScriptDir(Scripts* scripts, const char* directory, bool isSubDir)
|
||||
{
|
||||
CharBuffer buffer(1024*10 + 1);
|
||||
|
||||
const int beginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
|
||||
const int queueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
|
||||
|
||||
DirBrowser dir(directory);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
@@ -307,54 +295,10 @@ void ScriptConfig::LoadScriptDir(Scripts* scripts, const char* directory, bool i
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the file contains pp-script-signature
|
||||
DiskFile infile;
|
||||
if (infile.Open(fullFilename, DiskFile::omRead))
|
||||
Script script(scriptName, fullFilename);
|
||||
if (LoadScriptFile(&script))
|
||||
{
|
||||
// read first 10KB of the file and look for signature
|
||||
int readBytes = (int)infile.Read(buffer, buffer.Size() - 1);
|
||||
infile.Close();
|
||||
buffer[readBytes] = '\0';
|
||||
|
||||
// split buffer into lines
|
||||
Tokenizer tok(buffer, "\n\r", true);
|
||||
while (char* line = tok.Next())
|
||||
{
|
||||
if (!strncmp(line, BEGIN_SCRIPT_SIGNATURE, beginSignatureLen) &&
|
||||
strstr(line, END_SCRIPT_SIGNATURE))
|
||||
{
|
||||
bool postScript = strstr(line, POST_SCRIPT_SIGNATURE);
|
||||
bool scanScript = strstr(line, SCAN_SCRIPT_SIGNATURE);
|
||||
bool queueScript = strstr(line, QUEUE_SCRIPT_SIGNATURE);
|
||||
bool schedulerScript = strstr(line, SCHEDULER_SCRIPT_SIGNATURE);
|
||||
bool feedScript = strstr(line, FEED_SCRIPT_SIGNATURE);
|
||||
if (postScript || scanScript || queueScript || schedulerScript || feedScript)
|
||||
{
|
||||
char* queueEvents = nullptr;
|
||||
if (queueScript)
|
||||
{
|
||||
while (char* line = tok.Next())
|
||||
{
|
||||
if (!strncmp(line, QUEUE_EVENTS_SIGNATURE, queueEventsSignatureLen))
|
||||
{
|
||||
queueEvents = line + queueEventsSignatureLen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scripts->emplace_back(scriptName, fullFilename);
|
||||
Script& script = scripts->back();
|
||||
script.SetPostScript(postScript);
|
||||
script.SetScanScript(scanScript);
|
||||
script.SetQueueScript(queueScript);
|
||||
script.SetSchedulerScript(schedulerScript);
|
||||
script.SetFeedScript(feedScript);
|
||||
script.SetQueueEvents(queueEvents);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
scripts->push_back(std::move(script));
|
||||
}
|
||||
}
|
||||
else if (!isSubDir)
|
||||
@@ -365,6 +309,109 @@ void ScriptConfig::LoadScriptDir(Scripts* scripts, const char* directory, bool i
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptConfig::LoadScriptFile(Script* script)
|
||||
{
|
||||
DiskFile infile;
|
||||
if (!infile.Open(script->GetLocation(), DiskFile::omRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CharBuffer buffer(1024 * 10 + 1);
|
||||
|
||||
const int beginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
|
||||
const int queueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
|
||||
const int taskTimeSignatureLen = strlen(TASK_TIME_SIGNATURE);
|
||||
const int definitionSignatureLen = strlen(DEFINITION_SIGNATURE);
|
||||
|
||||
// check if the file contains pp-script-signature
|
||||
// read first 10KB of the file and look for signature
|
||||
int readBytes = (int)infile.Read(buffer, buffer.Size() - 1);
|
||||
infile.Close();
|
||||
buffer[readBytes] = '\0';
|
||||
|
||||
bool postScript = false;
|
||||
bool scanScript = false;
|
||||
bool queueScript = false;
|
||||
bool schedulerScript = false;
|
||||
bool feedScript = false;
|
||||
char* queueEvents = nullptr;
|
||||
char* taskTime = nullptr;
|
||||
|
||||
bool inConfig = false;
|
||||
bool afterConfig = false;
|
||||
|
||||
// Declarations "QUEUE EVENT:" and "TASK TIME:" can be placed:
|
||||
// - in script definition body (between opening and closing script signatures);
|
||||
// - immediately before script definition (before opening script signature);
|
||||
// - immediately after script definition (after closing script signature).
|
||||
// The last two pissibilities are provided to increase compatibility of scripts with older
|
||||
// nzbget versions which do not expect the extra declarations in the script defintion body.
|
||||
|
||||
Tokenizer tok(buffer, "\n\r", true);
|
||||
while (char* line = tok.Next())
|
||||
{
|
||||
if (!strncmp(line, QUEUE_EVENTS_SIGNATURE, queueEventsSignatureLen))
|
||||
{
|
||||
queueEvents = line + queueEventsSignatureLen;
|
||||
}
|
||||
else if (!strncmp(line, TASK_TIME_SIGNATURE, taskTimeSignatureLen))
|
||||
{
|
||||
taskTime = line + taskTimeSignatureLen;
|
||||
}
|
||||
|
||||
bool header = !strncmp(line, DEFINITION_SIGNATURE, definitionSignatureLen);
|
||||
if (!header && !inConfig)
|
||||
{
|
||||
queueEvents = nullptr;
|
||||
taskTime = nullptr;
|
||||
}
|
||||
|
||||
if (!header && afterConfig)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strncmp(line, BEGIN_SCRIPT_SIGNATURE, beginSignatureLen) && strstr(line, END_SCRIPT_SIGNATURE))
|
||||
{
|
||||
if (!inConfig)
|
||||
{
|
||||
inConfig = true;
|
||||
postScript = strstr(line, POST_SCRIPT_SIGNATURE);
|
||||
scanScript = strstr(line, SCAN_SCRIPT_SIGNATURE);
|
||||
queueScript = strstr(line, QUEUE_SCRIPT_SIGNATURE);
|
||||
schedulerScript = strstr(line, SCHEDULER_SCRIPT_SIGNATURE);
|
||||
feedScript = strstr(line, FEED_SCRIPT_SIGNATURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
afterConfig = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(postScript || scanScript || queueScript || schedulerScript || feedScript))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// trim decorations
|
||||
char* p;
|
||||
while (queueEvents && *queueEvents && *(p = queueEvents + strlen(queueEvents) - 1) == '#') *p = '\0';
|
||||
if (queueEvents) queueEvents = Util::Trim(queueEvents);
|
||||
while (taskTime && *taskTime && *(p = taskTime + strlen(taskTime) - 1) == '#') *p = '\0';
|
||||
if (taskTime) taskTime = Util::Trim(taskTime);
|
||||
|
||||
script->SetPostScript(postScript);
|
||||
script->SetScanScript(scanScript);
|
||||
script->SetQueueScript(queueScript);
|
||||
script->SetSchedulerScript(schedulerScript);
|
||||
script->SetFeedScript(feedScript);
|
||||
script->SetQueueEvents(queueEvents);
|
||||
script->SetTaskTime(taskTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BString<1024> ScriptConfig::BuildScriptName(const char* directory, const char* filename, bool isSubDir)
|
||||
{
|
||||
@@ -431,3 +478,23 @@ void ScriptConfig::BuildScriptDisplayNames(Scripts* scripts)
|
||||
script.SetDisplayName(displayName);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptConfig::CreateTasks()
|
||||
{
|
||||
for (Script& script : m_scripts)
|
||||
{
|
||||
if (script.GetSchedulerScript() && !Util::EmptyStr(script.GetTaskTime()))
|
||||
{
|
||||
Tokenizer tok(g_Options->GetExtensions(), ",;");
|
||||
while (const char* scriptName = tok.Next())
|
||||
{
|
||||
if (FileSystem::SameFilename(scriptName, script.GetName()))
|
||||
{
|
||||
g_Options->CreateSchedulerTask(0, script.GetTaskTime(),
|
||||
nullptr, Options::scScript, script.GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
class Script
|
||||
{
|
||||
public:
|
||||
Script(const char* name, const char* location);
|
||||
Script(const char* name, const char* location) :
|
||||
m_name(name), m_location(location), m_displayName(name) {};
|
||||
Script(Script&&) = default;
|
||||
const char* GetName() { return m_name; }
|
||||
const char* GetLocation() { return m_location; }
|
||||
@@ -49,17 +50,20 @@ public:
|
||||
void SetFeedScript(bool feedScript) { m_feedScript = feedScript; }
|
||||
void SetQueueEvents(const char* queueEvents) { m_queueEvents = queueEvents; }
|
||||
const char* GetQueueEvents() { return m_queueEvents; }
|
||||
void SetTaskTime(const char* taskTime) { m_taskTime = taskTime; }
|
||||
const char* GetTaskTime() { return m_taskTime; }
|
||||
|
||||
private:
|
||||
CString m_name;
|
||||
CString m_location;
|
||||
CString m_displayName;
|
||||
bool m_postScript;
|
||||
bool m_scanScript;
|
||||
bool m_queueScript;
|
||||
bool m_schedulerScript;
|
||||
bool m_feedScript;
|
||||
bool m_postScript = false;
|
||||
bool m_scanScript = false;
|
||||
bool m_queueScript = false;
|
||||
bool m_schedulerScript = false;
|
||||
bool m_feedScript = false;
|
||||
CString m_queueEvents;
|
||||
CString m_taskTime;
|
||||
};
|
||||
|
||||
typedef std::list<Script> Scripts;
|
||||
@@ -75,8 +79,6 @@ public:
|
||||
private:
|
||||
Script m_script;
|
||||
CString m_template;
|
||||
|
||||
friend class Options;
|
||||
};
|
||||
|
||||
typedef std::deque<ConfigTemplate> ConfigTemplates;
|
||||
@@ -94,9 +96,11 @@ private:
|
||||
|
||||
void InitScripts();
|
||||
void InitConfigTemplates();
|
||||
void CreateTasks();
|
||||
void LoadScriptDir(Scripts* scripts, const char* directory, bool isSubDir);
|
||||
void BuildScriptDisplayNames(Scripts* scripts);
|
||||
void LoadScripts(Scripts* scripts);
|
||||
bool LoadScriptFile(Script* script);
|
||||
BString<1024>BuildScriptName(const char* directory, const char* filename, bool isSubDir);
|
||||
bool ScriptExists(Scripts* scripts, const char* scriptName);
|
||||
};
|
||||
|
||||
@@ -239,14 +239,7 @@ void FeedCoordinator::StartFeedDownload(FeedInfo* feedInfo, bool force)
|
||||
feedDownloader->Attach(this);
|
||||
feedDownloader->SetFeedInfo(feedInfo);
|
||||
feedDownloader->SetUrl(feedInfo->GetUrl());
|
||||
if (strlen(feedInfo->GetName()) > 0)
|
||||
{
|
||||
feedDownloader->SetInfoName(feedInfo->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
feedDownloader->SetInfoName(NzbInfo::MakeNiceUrlName(feedInfo->GetUrl(), ""));
|
||||
}
|
||||
feedDownloader->SetInfoName(feedInfo->GetName());
|
||||
feedDownloader->SetForce(force || g_Options->GetUrlForce());
|
||||
|
||||
BString<1024> outFilename;
|
||||
@@ -304,7 +297,7 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* feedDownloader)
|
||||
{
|
||||
bool scriptSuccess = true;
|
||||
FeedScriptController::ExecuteScripts(
|
||||
!Util::EmptyStr(feedInfo->GetFeedScript()) ? feedInfo->GetFeedScript(): g_Options->GetFeedScript(),
|
||||
!Util::EmptyStr(feedInfo->GetExtensions()) ? feedInfo->GetExtensions(): g_Options->GetExtensions(),
|
||||
feedInfo->GetOutputFilename(), feedInfo->GetId(), &scriptSuccess);
|
||||
if (!scriptSuccess)
|
||||
{
|
||||
@@ -312,15 +305,13 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* feedDownloader)
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<FeedFile> feedFile = std::make_unique<FeedFile>(feedInfo->GetOutputFilename());
|
||||
bool parsed = feedFile->Parse();
|
||||
FileSystem::DeleteFile(feedInfo->GetOutputFilename());
|
||||
std::unique_ptr<FeedFile> feedFile = parseFeed(feedInfo);
|
||||
|
||||
std::vector<std::unique_ptr<NzbInfo>> addedNzbs;
|
||||
|
||||
{
|
||||
Guard guard(m_downloadsMutex);
|
||||
if (parsed)
|
||||
if (feedFile)
|
||||
{
|
||||
std::unique_ptr<FeedItemList> feedItems = feedFile->DetachFeedItems();
|
||||
addedNzbs = ProcessFeed(feedInfo, feedItems.get());
|
||||
@@ -469,7 +460,7 @@ std::shared_ptr<FeedItemList> FeedCoordinator::ViewFeed(int id)
|
||||
|
||||
return PreviewFeed(feedInfo->GetId(), feedInfo->GetName(), feedInfo->GetUrl(), feedInfo->GetFilter(),
|
||||
feedInfo->GetBacklog(), feedInfo->GetPauseNzb(), feedInfo->GetCategory(),
|
||||
feedInfo->GetPriority(), feedInfo->GetInterval(), feedInfo->GetFeedScript(), 0, nullptr);
|
||||
feedInfo->GetPriority(), feedInfo->GetInterval(), feedInfo->GetExtensions(), 0, nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<FeedItemList> FeedCoordinator::PreviewFeed(int id,
|
||||
@@ -535,14 +526,11 @@ std::shared_ptr<FeedItemList> FeedCoordinator::PreviewFeed(int id,
|
||||
}
|
||||
|
||||
FeedScriptController::ExecuteScripts(
|
||||
!Util::EmptyStr(feedInfo->GetFeedScript()) ? feedInfo->GetFeedScript(): g_Options->GetFeedScript(),
|
||||
!Util::EmptyStr(feedInfo->GetExtensions()) ? feedInfo->GetExtensions(): g_Options->GetExtensions(),
|
||||
feedInfo->GetOutputFilename(), feedInfo->GetId(), nullptr);
|
||||
|
||||
std::unique_ptr<FeedFile> feedFile = std::make_unique<FeedFile>(feedInfo->GetOutputFilename());
|
||||
bool parsed = feedFile->Parse();
|
||||
FileSystem::DeleteFile(feedInfo->GetOutputFilename());
|
||||
|
||||
if (!parsed)
|
||||
std::unique_ptr<FeedFile> feedFile = parseFeed(feedInfo.get());
|
||||
if (!feedFile)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -588,6 +576,21 @@ void FeedCoordinator::FetchFeed(int id)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<FeedFile> FeedCoordinator::parseFeed(FeedInfo* feedInfo)
|
||||
{
|
||||
std::unique_ptr<FeedFile> feedFile = std::make_unique<FeedFile>(feedInfo->GetOutputFilename(), feedInfo->GetName());
|
||||
if (feedFile->Parse())
|
||||
{
|
||||
FileSystem::DeleteFile(feedInfo->GetOutputFilename());
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Feed file %s kept for troubleshooting (will be deleted on next successful feed fetch)", feedInfo->GetOutputFilename());
|
||||
feedFile.reset();
|
||||
}
|
||||
return std::move(feedFile);
|
||||
}
|
||||
|
||||
void FeedCoordinator::DownloadQueueUpdate(Subject* caller, void* aspect)
|
||||
{
|
||||
debug("Notification from URL-Coordinator received");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "Thread.h"
|
||||
#include "WebDownloader.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "FeedFile.h"
|
||||
#include "FeedInfo.h"
|
||||
#include "Observer.h"
|
||||
#include "Util.h"
|
||||
@@ -119,6 +120,7 @@ private:
|
||||
void CleanupHistory();
|
||||
void CleanupCache();
|
||||
void CheckSaveFeeds();
|
||||
std::unique_ptr<FeedFile> parseFeed(FeedInfo* feedInfo);
|
||||
};
|
||||
|
||||
extern FeedCoordinator* g_FeedCoordinator;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
FeedFile::FeedFile(const char* fileName) :
|
||||
m_fileName(fileName)
|
||||
FeedFile::FeedFile(const char* fileName, const char* infoName) :
|
||||
m_fileName(fileName), m_infoName(infoName)
|
||||
{
|
||||
debug("Creating FeedFile");
|
||||
|
||||
@@ -113,7 +113,7 @@ bool FeedFile::Parse()
|
||||
{
|
||||
_bstr_t r(doc->GetparseError()->reason);
|
||||
const char* errMsg = r;
|
||||
error("Error parsing rss feed: %s", errMsg);
|
||||
error("Error parsing rss feed %s: %s", *m_infoName, errMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
//<newznab:attr name="size" value="5423523453534" />
|
||||
if (feedItemInfo.GetSize() == 0)
|
||||
{
|
||||
tag = node->selectSingleNode("newznab:attr[@name='size']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='size'] | nZEDb:attr[@name='size']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -262,7 +262,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
}
|
||||
|
||||
//<newznab:attr name="imdb" value="1588173"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='imdb']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='imdb'] | nZEDb:attr[@name='imdb']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -275,7 +275,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
}
|
||||
|
||||
//<newznab:attr name="rageid" value="33877"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='rageid']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='rageid'] | nZEDb:attr[@name='rageid']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -288,7 +288,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
}
|
||||
|
||||
//<newznab:attr name="tdvdbid" value="33877"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='tvdbid']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='tvdbid'] | nZEDb:attr[@name='tvdbid']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -301,7 +301,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
}
|
||||
|
||||
//<newznab:attr name="tvmazeid" value="33877"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='tvmazeid']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='tvmazeid'] | nZEDb:attr[@name='tvmazeid']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -315,7 +315,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
|
||||
//<newznab:attr name="episode" value="E09"/>
|
||||
//<newznab:attr name="episode" value="9"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='episode']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='episode'] | nZEDb:attr[@name='episode']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -328,7 +328,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
|
||||
//<newznab:attr name="season" value="S03"/>
|
||||
//<newznab:attr name="season" value="3"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='season']");
|
||||
tag = node->selectSingleNode("newznab:attr[@name='season'] | nZEDb:attr[@name='season']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
@@ -339,7 +339,7 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
}
|
||||
}
|
||||
|
||||
MSXML::IXMLDOMNodeListPtr itemList = node->selectNodes("newznab:attr");
|
||||
MSXML::IXMLDOMNodeListPtr itemList = node->selectNodes("newznab:attr | nZEDb:attr");
|
||||
for (int i = 0; i < itemList->Getlength(); i++)
|
||||
{
|
||||
MSXML::IXMLDOMNodePtr node = itemList->Getitem(i);
|
||||
@@ -373,7 +373,7 @@ bool FeedFile::Parse()
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
error("Failed to parse rss feed");
|
||||
error("Failed to parse rss feed %s", *m_infoName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -407,7 +407,8 @@ void FeedFile::Parse_StartElement(const char *name, const char **atts)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_feedItemInfo && !strcmp("newznab:attr", name) &&
|
||||
else if (m_feedItemInfo &&
|
||||
(!strcmp("newznab:attr", name) || !strcmp("nZEDb:attr", name)) &&
|
||||
atts[0] && atts[1] && atts[2] && atts[3] &&
|
||||
!strcmp("name", atts[0]) && !strcmp("value", atts[2]))
|
||||
{
|
||||
@@ -592,6 +593,6 @@ void FeedFile::SAX_error(FeedFile* file, const char *msg, ...)
|
||||
|
||||
// remove trailing CRLF
|
||||
for (char* pend = errMsg + strlen(errMsg) - 1; pend >= errMsg && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
|
||||
error("Error parsing rss feed: %s", errMsg);
|
||||
error("Error parsing rss feed %s: %s", *file->m_infoName, errMsg);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
class FeedFile
|
||||
{
|
||||
public:
|
||||
FeedFile(const char* fileName);
|
||||
FeedFile(const char* fileName, const char* infoName);
|
||||
bool Parse();
|
||||
std::unique_ptr<FeedItemList> DetachFeedItems() { return std::move(m_feedItems); }
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
private:
|
||||
std::unique_ptr<FeedItemList> m_feedItems;
|
||||
CString m_fileName;
|
||||
CString m_infoName;
|
||||
|
||||
void ParseSubject(FeedItemInfo& feedItemInfo);
|
||||
#ifdef WIN32
|
||||
|
||||
@@ -23,16 +23,20 @@
|
||||
#include "Util.h"
|
||||
|
||||
FeedInfo::FeedInfo(int id, const char* name, const char* url, bool backlog, int interval,
|
||||
const char* filter, bool pauseNzb, const char* category, int priority, const char* feedScript) :
|
||||
const char* filter, bool pauseNzb, const char* category, int priority, const char* extensions) :
|
||||
m_backlog(backlog), m_interval(interval), m_pauseNzb(pauseNzb), m_priority(priority)
|
||||
{
|
||||
m_id = id;
|
||||
m_name = name ? name : "";
|
||||
if (m_name.Length() == 0)
|
||||
{
|
||||
m_name.Format("Feed%i", m_id);
|
||||
}
|
||||
m_url = url ? url : "";
|
||||
m_filter = filter ? filter : "";
|
||||
m_filterHash = Util::HashBJ96(m_filter, strlen(m_filter), 0);
|
||||
m_category = category ? category : "";
|
||||
m_feedScript = feedScript ? feedScript : "";
|
||||
m_extensions = extensions ? extensions : "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
FeedInfo(int id, const char* name, const char* url, bool backlog, int interval,
|
||||
const char* filter, bool pauseNzb, const char* category, int priority,
|
||||
const char* feedScript);
|
||||
const char* extensions);
|
||||
int GetId() { return m_id; }
|
||||
const char* GetName() { return m_name; }
|
||||
const char* GetUrl() { return m_url; }
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
bool GetPauseNzb() { return m_pauseNzb; }
|
||||
const char* GetCategory() { return m_category; }
|
||||
int GetPriority() { return m_priority; }
|
||||
const char* GetFeedScript() { return m_feedScript; }
|
||||
const char* GetExtensions() { return m_extensions; }
|
||||
time_t GetLastUpdate() { return m_lastUpdate; }
|
||||
void SetLastUpdate(time_t lastUpdate) { m_lastUpdate = lastUpdate; }
|
||||
bool GetPreview() { return m_preview; }
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
uint32 m_filterHash;
|
||||
bool m_pauseNzb;
|
||||
CString m_category;
|
||||
CString m_feedScript;
|
||||
CString m_extensions;
|
||||
int m_priority;
|
||||
time_t m_lastUpdate = 0;
|
||||
bool m_preview = false;
|
||||
|
||||
@@ -133,7 +133,7 @@ bool Frontend::ServerEditQueue(DownloadQueue::EEditAction action, int offset, in
|
||||
}
|
||||
else
|
||||
{
|
||||
return DownloadQueue::Guard()->EditEntry(id, action, offset, nullptr);
|
||||
return DownloadQueue::Guard()->EditEntry(id, action, CString::FormatStr("%i", offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,8 +72,10 @@ static const char* OPTION_RELOADQUEUE = "ReloadQueue";
|
||||
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";
|
||||
static const char* OPTION_ARTICLERETRIES = "ArticleRetries";
|
||||
static const char* OPTION_ARTICLEINTERVAL = "ArticleInterval";
|
||||
static const char* OPTION_URLRETRIES = "UrlRetries";
|
||||
static const char* OPTION_URLINTERVAL = "UrlInterval";
|
||||
static const char* OPTION_TERMINATETIMEOUT = "TerminateTimeout";
|
||||
static const char* OPTION_CONTINUEPARTIAL = "ContinuePartial";
|
||||
static const char* OPTION_URLCONNECTIONS = "UrlConnections";
|
||||
@@ -87,13 +89,12 @@ static const char* OPTION_PARCHECK = "ParCheck";
|
||||
static const char* OPTION_PARREPAIR = "ParRepair";
|
||||
static const char* OPTION_PARSCAN = "ParScan";
|
||||
static const char* OPTION_PARQUICK = "ParQuick";
|
||||
static const char* OPTION_POSTSTRATEGY = "PostStrategy";
|
||||
static const char* OPTION_PARRENAME = "ParRename";
|
||||
static const char* OPTION_PARBUFFER = "ParBuffer";
|
||||
static const char* OPTION_PARTHREADS = "ParThreads";
|
||||
static const char* OPTION_RARRENAME = "RarRename";
|
||||
static const char* OPTION_HEALTHCHECK = "HealthCheck";
|
||||
static const char* OPTION_SCANSCRIPT = "ScanScript";
|
||||
static const char* OPTION_QUEUESCRIPT = "QueueScript";
|
||||
static const char* OPTION_FEEDSCRIPT = "FeedScript";
|
||||
static const char* OPTION_UMASK = "UMask";
|
||||
static const char* OPTION_UPDATEINTERVAL = "UpdateInterval";
|
||||
static const char* OPTION_CURSESNZBNAME = "CursesNzbName";
|
||||
@@ -119,9 +120,10 @@ 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";
|
||||
static const char* OPTION_EXTENSIONS = "Extensions";
|
||||
static const char* OPTION_EXTCLEANUPDISK = "ExtCleanupDisk";
|
||||
static const char* OPTION_PARIGNOREEXT = "ParIgnoreExt";
|
||||
static const char* OPTION_UNPACKIGNOREEXT = "UnpackIgnoreExt";
|
||||
static const char* OPTION_FEEDHISTORY = "FeedHistory";
|
||||
static const char* OPTION_URLFORCE = "UrlForce";
|
||||
static const char* OPTION_TIMECORRECTION = "TimeCorrection";
|
||||
@@ -155,6 +157,9 @@ static const char* OPTION_RESETLOG = "ResetLog";
|
||||
static const char* OPTION_PARCLEANUPQUEUE = "ParCleanupQueue";
|
||||
static const char* OPTION_DELETECLEANUPDISK = "DeleteCleanupDisk";
|
||||
static const char* OPTION_HISTORYCLEANUPDISK = "HistoryCleanupDisk";
|
||||
static const char* OPTION_SCANSCRIPT = "ScanScript";
|
||||
static const char* OPTION_QUEUESCRIPT = "QueueScript";
|
||||
static const char* OPTION_FEEDSCRIPT = "FeedScript";
|
||||
|
||||
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable", "enabled", "disabled" };
|
||||
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||
@@ -325,6 +330,7 @@ void Options::Init(const char* exeName, const char* configFilename, bool noConfi
|
||||
return;
|
||||
}
|
||||
|
||||
ConvertOldOptions(&m_optEntries);
|
||||
InitOptions();
|
||||
CheckOptions();
|
||||
|
||||
@@ -429,8 +435,10 @@ void Options::InitDefaults()
|
||||
SetOption(OPTION_BROKENLOG, "yes");
|
||||
SetOption(OPTION_NZBLOG, "yes");
|
||||
SetOption(OPTION_DECODE, "yes");
|
||||
SetOption(OPTION_RETRIES, "3");
|
||||
SetOption(OPTION_RETRYINTERVAL, "10");
|
||||
SetOption(OPTION_ARTICLERETRIES, "3");
|
||||
SetOption(OPTION_ARTICLEINTERVAL, "10");
|
||||
SetOption(OPTION_URLRETRIES, "3");
|
||||
SetOption(OPTION_URLINTERVAL, "10");
|
||||
SetOption(OPTION_TERMINATETIMEOUT, "600");
|
||||
SetOption(OPTION_CONTINUEPARTIAL, "no");
|
||||
SetOption(OPTION_URLCONNECTIONS, "4");
|
||||
@@ -444,15 +452,14 @@ void Options::InitDefaults()
|
||||
SetOption(OPTION_PARREPAIR, "yes");
|
||||
SetOption(OPTION_PARSCAN, "extended");
|
||||
SetOption(OPTION_PARQUICK, "yes");
|
||||
SetOption(OPTION_POSTSTRATEGY, "sequential");
|
||||
SetOption(OPTION_PARRENAME, "yes");
|
||||
SetOption(OPTION_PARBUFFER, "16");
|
||||
SetOption(OPTION_PARTHREADS, "1");
|
||||
SetOption(OPTION_RARRENAME, "yes");
|
||||
SetOption(OPTION_HEALTHCHECK, "none");
|
||||
SetOption(OPTION_SCRIPTORDER, "");
|
||||
SetOption(OPTION_POSTSCRIPT, "");
|
||||
SetOption(OPTION_SCANSCRIPT, "");
|
||||
SetOption(OPTION_QUEUESCRIPT, "");
|
||||
SetOption(OPTION_FEEDSCRIPT, "");
|
||||
SetOption(OPTION_EXTENSIONS, "");
|
||||
SetOption(OPTION_DAEMONUSERNAME, "root");
|
||||
SetOption(OPTION_UMASK, "1000");
|
||||
SetOption(OPTION_UPDATEINTERVAL, "200");
|
||||
@@ -485,6 +492,7 @@ void Options::InitDefaults()
|
||||
SetOption(OPTION_UNPACKPAUSEQUEUE, "no");
|
||||
SetOption(OPTION_EXTCLEANUPDISK, "");
|
||||
SetOption(OPTION_PARIGNOREEXT, "");
|
||||
SetOption(OPTION_UNPACKIGNOREEXT, "");
|
||||
SetOption(OPTION_FEEDHISTORY, "7");
|
||||
SetOption(OPTION_URLFORCE, "yes");
|
||||
SetOption(OPTION_TIMECORRECTION, "0");
|
||||
@@ -641,10 +649,7 @@ void Options::InitOptions()
|
||||
|
||||
m_configTemplate = GetOption(OPTION_CONFIGTEMPLATE);
|
||||
m_scriptOrder = GetOption(OPTION_SCRIPTORDER);
|
||||
m_postScript = GetOption(OPTION_POSTSCRIPT);
|
||||
m_scanScript = GetOption(OPTION_SCANSCRIPT);
|
||||
m_queueScript = GetOption(OPTION_QUEUESCRIPT);
|
||||
m_feedScript = GetOption(OPTION_FEEDSCRIPT);
|
||||
m_extensions = GetOption(OPTION_EXTENSIONS);
|
||||
m_controlIp = GetOption(OPTION_CONTROLIP);
|
||||
m_controlUsername = GetOption(OPTION_CONTROLUSERNAME);
|
||||
m_controlPassword = GetOption(OPTION_CONTROLPASSWORD);
|
||||
@@ -663,14 +668,17 @@ void Options::InitOptions()
|
||||
m_unpackPassFile = GetOption(OPTION_UNPACKPASSFILE);
|
||||
m_extCleanupDisk = GetOption(OPTION_EXTCLEANUPDISK);
|
||||
m_parIgnoreExt = GetOption(OPTION_PARIGNOREEXT);
|
||||
m_unpackIgnoreExt = GetOption(OPTION_UNPACKIGNOREEXT);
|
||||
m_shellOverride = GetOption(OPTION_SHELLOVERRIDE);
|
||||
|
||||
m_downloadRate = ParseIntValue(OPTION_DOWNLOADRATE, 10) * 1024;
|
||||
m_articleTimeout = ParseIntValue(OPTION_ARTICLETIMEOUT, 10);
|
||||
m_urlTimeout = ParseIntValue(OPTION_URLTIMEOUT, 10);
|
||||
m_terminateTimeout = ParseIntValue(OPTION_TERMINATETIMEOUT, 10);
|
||||
m_retries = ParseIntValue(OPTION_RETRIES, 10);
|
||||
m_retryInterval = ParseIntValue(OPTION_RETRYINTERVAL, 10);
|
||||
m_articleRetries = ParseIntValue(OPTION_ARTICLERETRIES, 10);
|
||||
m_articleInterval = ParseIntValue(OPTION_ARTICLEINTERVAL, 10);
|
||||
m_urlRetries = ParseIntValue(OPTION_URLRETRIES, 10);
|
||||
m_urlInterval = ParseIntValue(OPTION_URLINTERVAL, 10);
|
||||
m_controlPort = ParseIntValue(OPTION_CONTROLPORT, 10);
|
||||
m_securePort = ParseIntValue(OPTION_SECUREPORT, 10);
|
||||
m_urlConnections = ParseIntValue(OPTION_URLCONNECTIONS, 10);
|
||||
@@ -710,6 +718,7 @@ void Options::InitOptions()
|
||||
m_parRepair = (bool)ParseEnumValue(OPTION_PARREPAIR, BoolCount, BoolNames, BoolValues);
|
||||
m_parQuick = (bool)ParseEnumValue(OPTION_PARQUICK, BoolCount, BoolNames, BoolValues);
|
||||
m_parRename = (bool)ParseEnumValue(OPTION_PARRENAME, BoolCount, BoolNames, BoolValues);
|
||||
m_rarRename = (bool)ParseEnumValue(OPTION_RARRENAME, BoolCount, BoolNames, BoolValues);
|
||||
m_reloadQueue = (bool)ParseEnumValue(OPTION_RELOADQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
m_cursesNzbName = (bool)ParseEnumValue(OPTION_CURSESNZBNAME, BoolCount, BoolNames, BoolValues);
|
||||
m_cursesTime = (bool)ParseEnumValue(OPTION_CURSESTIME, BoolCount, BoolNames, BoolValues);
|
||||
@@ -743,6 +752,11 @@ void Options::InitOptions()
|
||||
const int ParScanCount = 4;
|
||||
m_parScan = (EParScan)ParseEnumValue(OPTION_PARSCAN, ParScanCount, ParScanNames, ParScanValues);
|
||||
|
||||
const char* PostStrategyNames[] = { "sequential", "balanced", "aggressive", "rocket" };
|
||||
const int PostStrategyValues[] = { ppSequential, ppBalanced, ppAggressive, ppRocket };
|
||||
const int PostStrategyCount = 4;
|
||||
m_postStrategy = (EPostStrategy)ParseEnumValue(OPTION_POSTSTRATEGY, PostStrategyCount, PostStrategyNames, PostStrategyValues);
|
||||
|
||||
const char* HealthCheckNames[] = { "pause", "delete", "park", "none" };
|
||||
const int HealthCheckValues[] = { hcPause, hcDelete, hcPark, hcNone };
|
||||
const int HealthCheckCount = 4;
|
||||
@@ -957,7 +971,8 @@ void Options::InitServers()
|
||||
#ifdef DISABLE_TLS
|
||||
if (tls)
|
||||
{
|
||||
ConfigError("Invalid value for option \"%s\": program was compiled without TLS/SSL-support", optname);
|
||||
ConfigError("Invalid value for option \"%s\": program was compiled without TLS/SSL-support",
|
||||
*BString<100>("Server%i.Encryption", n));
|
||||
tls = false;
|
||||
}
|
||||
#endif
|
||||
@@ -1017,10 +1032,10 @@ void Options::InitCategories()
|
||||
unpack = (bool)ParseEnumValue(BString<100>("Category%i.Unpack", n), BoolCount, BoolNames, BoolValues);
|
||||
}
|
||||
|
||||
const char* npostscript = GetOption(BString<100>("Category%i.PostScript", n));
|
||||
const char* nextensions = GetOption(BString<100>("Category%i.Extensions", n));
|
||||
const char* naliases = GetOption(BString<100>("Category%i.Aliases", n));
|
||||
|
||||
bool definition = nname || ndestdir || nunpack || npostscript || naliases;
|
||||
bool definition = nname || ndestdir || nunpack || nextensions || naliases;
|
||||
bool completed = nname && strlen(nname) > 0;
|
||||
|
||||
if (!definition)
|
||||
@@ -1036,7 +1051,7 @@ void Options::InitCategories()
|
||||
CheckDir(destDir, BString<100>("Category%i.DestDir", n), m_destDir, false, false);
|
||||
}
|
||||
|
||||
m_categories.emplace_back(nname, destDir, unpack, npostscript);
|
||||
m_categories.emplace_back(nname, destDir, unpack, nextensions);
|
||||
Category& category = m_categories.back();
|
||||
|
||||
// split Aliases into tokens and create items for each token
|
||||
@@ -1067,7 +1082,7 @@ void Options::InitFeeds()
|
||||
const char* nurl = GetOption(BString<100>("Feed%i.URL", n));
|
||||
const char* nfilter = GetOption(BString<100>("Feed%i.Filter", n));
|
||||
const char* ncategory = GetOption(BString<100>("Feed%i.Category", n));
|
||||
const char* nfeedscript = GetOption(BString<100>("Feed%i.FeedScript", n));
|
||||
const char* nextensions = GetOption(BString<100>("Feed%i.Extensions", n));
|
||||
|
||||
const char* nbacklog = GetOption(BString<100>("Feed%i.Backlog", n));
|
||||
bool backlog = true;
|
||||
@@ -1087,7 +1102,7 @@ void Options::InitFeeds()
|
||||
const char* npriority = GetOption(BString<100>("Feed%i.Priority", n));
|
||||
|
||||
bool definition = nname || nurl || nfilter || ncategory || nbacklog || npausenzb ||
|
||||
ninterval || npriority || nfeedscript;
|
||||
ninterval || npriority || nextensions;
|
||||
bool completed = nurl;
|
||||
|
||||
if (!definition)
|
||||
@@ -1100,7 +1115,7 @@ void Options::InitFeeds()
|
||||
if (m_extender)
|
||||
{
|
||||
m_extender->AddFeed(n, nname, nurl, ninterval ? atoi(ninterval) : 0, nfilter,
|
||||
backlog, pauseNzb, ncategory, npriority ? atoi(npriority) : 0, nfeedscript);
|
||||
backlog, pauseNzb, ncategory, npriority ? atoi(npriority) : 0, nextensions);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1169,13 +1184,6 @@ void Options::InitScheduler()
|
||||
continue;
|
||||
}
|
||||
|
||||
int weekDaysVal = 0;
|
||||
if (weekDays && !ParseWeekDays(weekDays, &weekDaysVal))
|
||||
{
|
||||
ConfigError("Invalid value for option \"Task%i.WeekDays\": \"%s\"", n, weekDays);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (taskCommand == scDownloadRate)
|
||||
{
|
||||
if (param)
|
||||
@@ -1206,36 +1214,60 @@ void Options::InitScheduler()
|
||||
continue;
|
||||
}
|
||||
|
||||
int hours, minutes;
|
||||
Tokenizer tok(time, ";,");
|
||||
while (const char* oneTime = tok.Next())
|
||||
{
|
||||
if (!ParseTime(oneTime, &hours, &minutes))
|
||||
{
|
||||
ConfigError("Invalid value for option \"Task%i.Time\": \"%s\"", n, oneTime);
|
||||
break;
|
||||
}
|
||||
CreateSchedulerTask(n, time, weekDays, taskCommand, param);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_extender)
|
||||
void Options::CreateSchedulerTask(int id, const char* time, const char* weekDays,
|
||||
ESchedulerCommand command, const char* param)
|
||||
{
|
||||
if (!id)
|
||||
{
|
||||
m_configLine = 0;
|
||||
}
|
||||
|
||||
int weekDaysVal = 0;
|
||||
if (weekDays && !ParseWeekDays(weekDays, &weekDaysVal))
|
||||
{
|
||||
ConfigError("Invalid value for option \"Task%i.WeekDays\": \"%s\"", id, weekDays);
|
||||
return;
|
||||
}
|
||||
|
||||
int hours, minutes;
|
||||
Tokenizer tok(time, ";,");
|
||||
while (const char* oneTime = tok.Next())
|
||||
{
|
||||
if (!ParseTime(oneTime, &hours, &minutes))
|
||||
{
|
||||
ConfigError("Invalid value for option \"Task%i.Time\": \"%s\"", id, oneTime);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_extender)
|
||||
{
|
||||
if (hours == -2)
|
||||
{
|
||||
if (hours == -1)
|
||||
for (int everyHour = 0; everyHour < 24; everyHour++)
|
||||
{
|
||||
for (int everyHour = 0; everyHour < 24; everyHour++)
|
||||
{
|
||||
m_extender->AddTask(n, everyHour, minutes, weekDaysVal, taskCommand, param);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_extender->AddTask(n, hours, minutes, weekDaysVal, taskCommand, param);
|
||||
m_extender->AddTask(id, everyHour, minutes, weekDaysVal, command, param);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_extender->AddTask(id, hours, minutes, weekDaysVal, command, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Options::ParseTime(const char* time, int* hours, int* minutes)
|
||||
{
|
||||
if (!strcmp(time, "*"))
|
||||
{
|
||||
*hours = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int colons = 0;
|
||||
const char* p = time;
|
||||
while (*p)
|
||||
@@ -1264,7 +1296,7 @@ bool Options::ParseTime(const char* time, int* hours, int* minutes)
|
||||
|
||||
if (time[0] == '*')
|
||||
{
|
||||
*hours = -1;
|
||||
*hours = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1485,7 +1517,7 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
|
||||
{
|
||||
char* p = (char*)optname + 8;
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".destdir") || !strcasecmp(p, ".postscript") ||
|
||||
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".destdir") || !strcasecmp(p, ".extensions") ||
|
||||
!strcasecmp(p, ".unpack") || !strcasecmp(p, ".aliases")))
|
||||
{
|
||||
return true;
|
||||
@@ -1498,7 +1530,7 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".url") || !strcasecmp(p, ".interval") ||
|
||||
!strcasecmp(p, ".filter") || !strcasecmp(p, ".backlog") || !strcasecmp(p, ".pausenzb") ||
|
||||
!strcasecmp(p, ".category") || !strcasecmp(p, ".priority") || !strcasecmp(p, ".feedscript")))
|
||||
!strcasecmp(p, ".category") || !strcasecmp(p, ".priority") || !strcasecmp(p, ".extensions")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1531,21 +1563,27 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
|
||||
ConfigWarn("Option \"%s\" is obsolete, ignored", optname);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcasecmp(optname, OPTION_POSTPROCESS) ||
|
||||
!strcasecmp(optname, OPTION_NZBPROCESS) ||
|
||||
!strcasecmp(optname, OPTION_NZBADDEDPROCESS))
|
||||
{
|
||||
if (optvalue && strlen(optvalue) > 0)
|
||||
{
|
||||
ConfigError("Option \"%s\" is obsolete, ignored, use \"%s\" and \"%s\" instead", optname, OPTION_SCRIPTDIR,
|
||||
!strcasecmp(optname, OPTION_POSTPROCESS) ? OPTION_POSTSCRIPT :
|
||||
!strcasecmp(optname, OPTION_NZBPROCESS) ? OPTION_SCANSCRIPT :
|
||||
!strcasecmp(optname, OPTION_NZBADDEDPROCESS) ? OPTION_QUEUESCRIPT :
|
||||
"ERROR");
|
||||
ConfigError("Option \"%s\" is obsolete, ignored, use \"%s\" and \"%s\" instead",
|
||||
optname, OPTION_SCRIPTDIR, OPTION_EXTENSIONS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcasecmp(optname, OPTION_SCANSCRIPT) ||
|
||||
!strcasecmp(optname, OPTION_QUEUESCRIPT) ||
|
||||
!strcasecmp(optname, OPTION_FEEDSCRIPT))
|
||||
{
|
||||
// will be automatically converted into "Extensions"
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcasecmp(optname, OPTION_CREATELOG) || !strcasecmp(optname, OPTION_RESETLOG))
|
||||
{
|
||||
ConfigWarn("Option \"%s\" is obsolete, ignored, use \"%s\" instead", optname, OPTION_WRITELOG);
|
||||
@@ -1599,16 +1637,22 @@ void Options::ConvertOldOption(CString& option, CString& value)
|
||||
value = "extended";
|
||||
}
|
||||
|
||||
if (!strcasecmp(option, "DefScript"))
|
||||
if (!strcasecmp(option, "DefScript") || !strcasecmp(option, "PostScript"))
|
||||
{
|
||||
option = "PostScript";
|
||||
option = "Extensions";
|
||||
}
|
||||
|
||||
int nameLen = strlen(option);
|
||||
if (!strncasecmp(option, "Category", 8) && nameLen > 10 &&
|
||||
!strcasecmp(option + nameLen - 10, ".DefScript"))
|
||||
if (!strncasecmp(option, "Category", 8) &&
|
||||
((nameLen > 10 && !strcasecmp(option + nameLen - 10, ".DefScript")) ||
|
||||
(nameLen > 11 && !strcasecmp(option + nameLen - 11, ".PostScript"))))
|
||||
{
|
||||
option.Replace(".DefScript", ".PostScript");
|
||||
option.Replace(".DefScript", ".Extensions");
|
||||
option.Replace(".PostScript", ".Extensions");
|
||||
}
|
||||
if (!strncasecmp(option, "Feed", 4) && nameLen > 11 && !strcasecmp(option + nameLen - 11, ".FeedScript"))
|
||||
{
|
||||
option.Replace(".FeedScript", ".Extensions");
|
||||
}
|
||||
|
||||
if (!strcasecmp(option, "WriteBufferSize"))
|
||||
@@ -1624,6 +1668,16 @@ void Options::ConvertOldOption(CString& option, CString& value)
|
||||
option = "ArticleTimeout";
|
||||
}
|
||||
|
||||
if (!strcasecmp(option, "Retries"))
|
||||
{
|
||||
option = "ArticleRetries";
|
||||
}
|
||||
|
||||
if (!strcasecmp(option, "RetryInterval"))
|
||||
{
|
||||
option = "ArticleInterval";
|
||||
}
|
||||
|
||||
if (!strcasecmp(option, "CreateBrokenLog"))
|
||||
{
|
||||
option = "BrokenLog";
|
||||
@@ -1695,7 +1749,7 @@ void Options::CheckOptions()
|
||||
if (sizeof(void*) == 4 && m_parBuffer + m_articleCache > 1900)
|
||||
{
|
||||
ConfigError("Options \"ArticleCache\" and \"ParBuffer\" in total cannot use more than 1900MB of memory in 32-Bit mode. Changed to 1500 and 400");
|
||||
m_articleCache = 1900;
|
||||
m_articleCache = 1500;
|
||||
m_parBuffer = 400;
|
||||
}
|
||||
|
||||
@@ -1704,3 +1758,77 @@ void Options::CheckOptions()
|
||||
ConfigError("Invalid value for option \"UnpackPassFile\": %s. File not found", *m_unpackPassFile);
|
||||
}
|
||||
}
|
||||
|
||||
void Options::ConvertOldOptions(OptEntries* optEntries)
|
||||
{
|
||||
MergeOldScriptOption(optEntries, OPTION_SCANSCRIPT, true);
|
||||
MergeOldScriptOption(optEntries, OPTION_QUEUESCRIPT, true);
|
||||
MergeOldScriptOption(optEntries, OPTION_FEEDSCRIPT, false);
|
||||
}
|
||||
|
||||
void Options::MergeOldScriptOption(OptEntries* optEntries, const char* optname, bool mergeCategories)
|
||||
{
|
||||
OptEntry* optEntry = optEntries->FindOption(optname);
|
||||
if (!optEntry || Util::EmptyStr(optEntry->GetValue()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OptEntry* extensionsOpt = optEntries->FindOption(OPTION_EXTENSIONS);
|
||||
if (!extensionsOpt)
|
||||
{
|
||||
optEntries->emplace_back(OPTION_EXTENSIONS, "");
|
||||
extensionsOpt = optEntries->FindOption(OPTION_EXTENSIONS);
|
||||
}
|
||||
|
||||
const char* scriptList = optEntry->GetValue();
|
||||
|
||||
Tokenizer tok(scriptList, ",;");
|
||||
while (const char* scriptName = tok.Next())
|
||||
{
|
||||
// merge into global "Extensions"
|
||||
if (!HasScript(extensionsOpt->m_value, scriptName))
|
||||
{
|
||||
if (!extensionsOpt->m_value.Empty())
|
||||
{
|
||||
extensionsOpt->m_value.Append(",");
|
||||
}
|
||||
extensionsOpt->m_value.Append(scriptName);
|
||||
}
|
||||
|
||||
// merge into categories' "Extensions" (if not empty)
|
||||
if (mergeCategories)
|
||||
{
|
||||
for (OptEntry& opt : optEntries)
|
||||
{
|
||||
const char* optname = opt.GetName();
|
||||
if (!strncasecmp(optname, "category", 8))
|
||||
{
|
||||
char* p = (char*)optname + 8;
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (p && (!strcasecmp(p, ".extensions")))
|
||||
{
|
||||
if (!opt.m_value.Empty() && !HasScript(opt.m_value, scriptName))
|
||||
{
|
||||
opt.m_value.Append(",");
|
||||
opt.m_value.Append(scriptName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Options::HasScript(const char* scriptList, const char* scriptName)
|
||||
{
|
||||
Tokenizer tok(scriptList, ",;");
|
||||
while (const char* scriptName2 = tok.Next())
|
||||
{
|
||||
if (!strcasecmp(scriptName2, scriptName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -85,6 +85,13 @@ public:
|
||||
scDeactivateServer,
|
||||
scFetchFeed
|
||||
};
|
||||
enum EPostStrategy
|
||||
{
|
||||
ppSequential,
|
||||
ppBalanced,
|
||||
ppAggressive,
|
||||
ppRocket
|
||||
};
|
||||
|
||||
class OptEntry
|
||||
{
|
||||
@@ -126,19 +133,19 @@ public:
|
||||
class Category
|
||||
{
|
||||
public:
|
||||
Category(const char* name, const char* destDir, bool unpack, const char* postScript) :
|
||||
m_name(name), m_destDir(destDir), m_unpack(unpack), m_postScript(postScript) {}
|
||||
Category(const char* name, const char* destDir, bool unpack, const char* extensions) :
|
||||
m_name(name), m_destDir(destDir), m_unpack(unpack), m_extensions(extensions) {}
|
||||
const char* GetName() { return m_name; }
|
||||
const char* GetDestDir() { return m_destDir; }
|
||||
bool GetUnpack() { return m_unpack; }
|
||||
const char* GetPostScript() { return m_postScript; }
|
||||
const char* GetExtensions() { return m_extensions; }
|
||||
NameList* GetAliases() { return &m_aliases; }
|
||||
|
||||
private:
|
||||
CString m_name;
|
||||
CString m_destDir;
|
||||
bool m_unpack;
|
||||
CString m_postScript;
|
||||
CString m_extensions;
|
||||
NameList m_aliases;
|
||||
};
|
||||
|
||||
@@ -159,7 +166,7 @@ public:
|
||||
int level, int group, bool optional) = 0;
|
||||
virtual void AddFeed(int id, const char* name, const char* url, int interval,
|
||||
const char* filter, bool backlog, bool pauseNzb, const char* category,
|
||||
int priority, const char* feedScript) {}
|
||||
int priority, const char* extensions) {}
|
||||
virtual void AddTask(int id, int hours, int minutes, int weekDaysBits, ESchedulerCommand command,
|
||||
const char* param) {}
|
||||
virtual void SetupFirstStart() {}
|
||||
@@ -170,9 +177,12 @@ public:
|
||||
Options(CmdOptList* commandLineOptions, Extender* extender);
|
||||
~Options();
|
||||
|
||||
bool SplitOptionString(const char* option, CString& optName, CString& optValue);
|
||||
static bool SplitOptionString(const char* option, CString& optName, CString& optValue);
|
||||
static void ConvertOldOptions(OptEntries* optEntries);
|
||||
bool GetFatalError() { return m_fatalError; }
|
||||
GuardedOptEntries GuardOptEntries() { return GuardedOptEntries(&m_optEntries, &m_optEntriesMutex); }
|
||||
void CreateSchedulerTask(int id, const char* time, const char* weekDays,
|
||||
ESchedulerCommand command, const char* param);
|
||||
|
||||
// Options
|
||||
const char* GetConfigFilename() { return m_configFilename; }
|
||||
@@ -200,8 +210,10 @@ public:
|
||||
bool GetDecode() { return m_decode; };
|
||||
bool GetAppendCategoryDir() { return m_appendCategoryDir; }
|
||||
bool GetContinuePartial() { return m_continuePartial; }
|
||||
int GetRetries() { return m_retries; }
|
||||
int GetRetryInterval() { return m_retryInterval; }
|
||||
int GetArticleRetries() { return m_articleRetries; }
|
||||
int GetArticleInterval() { return m_articleInterval; }
|
||||
int GetUrlRetries() { return m_urlRetries; }
|
||||
int GetUrlInterval() { return m_urlInterval; }
|
||||
bool GetSaveQueue() { return m_saveQueue; }
|
||||
bool GetFlushQueue() { return m_flushQueue; }
|
||||
bool GetDupeCheck() { return m_dupeCheck; }
|
||||
@@ -231,15 +243,14 @@ public:
|
||||
bool GetParRepair() { return m_parRepair; }
|
||||
EParScan GetParScan() { return m_parScan; }
|
||||
bool GetParQuick() { return m_parQuick; }
|
||||
EPostStrategy GetPostStrategy() { return m_postStrategy; }
|
||||
bool GetParRename() { return m_parRename; }
|
||||
int GetParBuffer() { return m_parBuffer; }
|
||||
int GetParThreads() { return m_parThreads; }
|
||||
bool GetRarRename() { return m_rarRename; }
|
||||
EHealthCheck GetHealthCheck() { return m_healthCheck; }
|
||||
const char* GetScriptOrder() { return m_scriptOrder; }
|
||||
const char* GetPostScript() { return m_postScript; }
|
||||
const char* GetScanScript() { return m_scanScript; }
|
||||
const char* GetQueueScript() { return m_queueScript; }
|
||||
const char* GetFeedScript() { return m_feedScript; }
|
||||
const char* GetExtensions() { return m_extensions; }
|
||||
int GetUMask() { return m_umask; }
|
||||
int GetUpdateInterval() {return m_updateInterval; }
|
||||
bool GetCursesNzbName() { return m_cursesNzbName; }
|
||||
@@ -267,6 +278,7 @@ public:
|
||||
bool GetUnpackPauseQueue() { return m_unpackPauseQueue; }
|
||||
const char* GetExtCleanupDisk() { return m_extCleanupDisk; }
|
||||
const char* GetParIgnoreExt() { return m_parIgnoreExt; }
|
||||
const char* GetUnpackIgnoreExt() { return m_unpackIgnoreExt; }
|
||||
int GetFeedHistory() { return m_feedHistory; }
|
||||
bool GetUrlForce() { return m_urlForce; }
|
||||
int GetTimeCorrection() { return m_timeCorrection; }
|
||||
@@ -343,8 +355,10 @@ private:
|
||||
int m_terminateTimeout = 0;
|
||||
bool m_appendCategoryDir = false;
|
||||
bool m_continuePartial = false;
|
||||
int m_retries = 0;
|
||||
int m_retryInterval = 0;
|
||||
int m_articleRetries = 0;
|
||||
int m_articleInterval = 0;
|
||||
int m_urlRetries = 0;
|
||||
int m_urlInterval = 0;
|
||||
bool m_saveQueue = false;
|
||||
bool m_flushQueue = false;
|
||||
bool m_dupeCheck = false;
|
||||
@@ -374,15 +388,14 @@ private:
|
||||
bool m_parRepair = false;
|
||||
EParScan m_parScan = psLimited;
|
||||
bool m_parQuick = true;
|
||||
EPostStrategy m_postStrategy = ppSequential;
|
||||
bool m_parRename = false;
|
||||
int m_parBuffer = 0;
|
||||
int m_parThreads = 0;
|
||||
bool m_rarRename = false;
|
||||
EHealthCheck m_healthCheck = hcNone;
|
||||
CString m_postScript;
|
||||
CString m_extensions;
|
||||
CString m_scriptOrder;
|
||||
CString m_scanScript;
|
||||
CString m_queueScript;
|
||||
CString m_feedScript;
|
||||
int m_umask = 0;
|
||||
int m_updateInterval = 0;
|
||||
bool m_cursesNzbName = false;
|
||||
@@ -410,6 +423,7 @@ private:
|
||||
bool m_unpackPauseQueue;
|
||||
CString m_extCleanupDisk;
|
||||
CString m_parIgnoreExt;
|
||||
CString m_unpackIgnoreExt;
|
||||
int m_feedHistory = 0;
|
||||
bool m_urlForce = false;
|
||||
int m_timeCorrection = 0;
|
||||
@@ -461,7 +475,9 @@ private:
|
||||
void ConfigError(const char* msg, ...);
|
||||
void ConfigWarn(const char* msg, ...);
|
||||
void LocateOptionSrcPos(const char *optionName);
|
||||
void ConvertOldOption(CString& option, CString& value);
|
||||
static void ConvertOldOption(CString& option, CString& value);
|
||||
static void MergeOldScriptOption(OptEntries* optEntries, const char* optname, bool mergeCategories);
|
||||
static bool HasScript(const char* scriptList, const char* scriptName);
|
||||
};
|
||||
|
||||
extern Options* g_Options;
|
||||
|
||||
@@ -40,7 +40,7 @@ void Scheduler::FirstCheck()
|
||||
Guard guard(m_taskListMutex);
|
||||
|
||||
std::sort(m_taskList.begin(), m_taskList.end(),
|
||||
[](std::unique_ptr<Task>& task1, std::unique_ptr<Task>& task2)
|
||||
[](const std::unique_ptr<Task>& task1, const std::unique_ptr<Task>& task2)
|
||||
{
|
||||
return (task1->m_hours < task2->m_hours) ||
|
||||
((task1->m_hours == task2->m_hours) && (task1->m_minutes < task2->m_minutes));
|
||||
@@ -133,9 +133,8 @@ void Scheduler::CheckTasks()
|
||||
}
|
||||
|
||||
bool weekDayOK = task->m_weekDaysBits == 0 || (task->m_weekDaysBits & (1 << (weekDay - 1)));
|
||||
bool doTask = weekDayOK && localLastCheck < appoint && appoint <= localCurrent;
|
||||
|
||||
//debug("TEMP: 1) m_tLastCheck=%i, tLocalCurrent=%i, tLoop=%i, tAppoint=%i, bWeekDayOK=%i, bDoTask=%i", m_tLastCheck, tLocalCurrent, tLoop, tAppoint, (int)bWeekDayOK, (int)bDoTask);
|
||||
bool doTask = (task->m_hours >= 0 && weekDayOK && localLastCheck < appoint && appoint <= localCurrent) ||
|
||||
(task->m_hours == Task::STARTUP_TASK && task->m_lastExecuted == 0);
|
||||
|
||||
if (doTask)
|
||||
{
|
||||
@@ -162,6 +161,8 @@ void Scheduler::ExecuteTask(Task* task)
|
||||
"Pause Scan", "Unpause Scan", "Enable Server", "Disable Server", "Fetch Feed" };
|
||||
debug("Executing scheduled command: %s", commandName[task->m_command]);
|
||||
|
||||
bool executeProcess = m_executeProcess || task->m_hours == Task::STARTUP_TASK;
|
||||
|
||||
switch (task->m_command)
|
||||
{
|
||||
case scDownloadRate:
|
||||
@@ -190,9 +191,9 @@ void Scheduler::ExecuteTask(Task* task)
|
||||
m_pauseScanChanged = true;
|
||||
break;
|
||||
|
||||
case scScript:
|
||||
case scExtensions:
|
||||
case scProcess:
|
||||
if (m_executeProcess)
|
||||
if (executeProcess)
|
||||
{
|
||||
SchedulerScriptController::StartScript(task->m_param, task->m_command == scProcess, task->m_id);
|
||||
}
|
||||
@@ -204,7 +205,7 @@ void Scheduler::ExecuteTask(Task* task)
|
||||
break;
|
||||
|
||||
case scFetchFeed:
|
||||
if (m_executeProcess)
|
||||
if (executeProcess)
|
||||
{
|
||||
FetchFeed(task->m_param);
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
scPausePostProcess,
|
||||
scUnpausePostProcess,
|
||||
scDownloadRate,
|
||||
scScript,
|
||||
scExtensions,
|
||||
scProcess,
|
||||
scPauseScan,
|
||||
scUnpauseScan,
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
m_id(id), m_hours(hours), m_minutes(minutes),
|
||||
m_weekDaysBits(weekDaysBits), m_command(command), m_param(param) {}
|
||||
friend class Scheduler;
|
||||
|
||||
static const int STARTUP_TASK = -1;
|
||||
private:
|
||||
int m_id;
|
||||
int m_hours;
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
#ifdef ENABLE_TESTS
|
||||
#include "TestMain.h"
|
||||
#endif
|
||||
#ifndef DISABLE_NSERV
|
||||
#include "NServMain.h"
|
||||
#endif
|
||||
|
||||
// Prototypes
|
||||
void RunMain();
|
||||
@@ -127,6 +130,16 @@ int main(int argc, char *argv[], char *argp[])
|
||||
TestCleanup();
|
||||
#endif
|
||||
|
||||
if (argc > 1 && (!strcmp(argv[1], "--nserv")))
|
||||
{
|
||||
#ifndef DISABLE_NSERV
|
||||
return NServMain(argc, argv);
|
||||
#else
|
||||
printf("ERROR: Could not start NServ, the program was compiled without NServ\n");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
InstallUninstallServiceCheck(argc, argv);
|
||||
#endif
|
||||
@@ -138,6 +151,7 @@ int main(int argc, char *argv[], char *argp[])
|
||||
{
|
||||
if (!strcmp(argv[i], "-D"))
|
||||
{
|
||||
AllocConsole(); // needed for sending CTRL+BREAK signal to child processes
|
||||
StartService(RunMain);
|
||||
return 0;
|
||||
}
|
||||
@@ -394,7 +408,7 @@ void NZBGet::BootConfig()
|
||||
}
|
||||
|
||||
m_serverPool->SetTimeout(m_options->GetArticleTimeout());
|
||||
m_serverPool->SetRetryInterval(m_options->GetRetryInterval());
|
||||
m_serverPool->SetRetryInterval(m_options->GetArticleInterval());
|
||||
|
||||
m_scriptConfig->InitOptions();
|
||||
}
|
||||
@@ -865,16 +879,12 @@ void NZBGet::Daemonize()
|
||||
// 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);
|
||||
dup2(d, 0);
|
||||
dup2(d, 1);
|
||||
dup2(d, 2);
|
||||
close(d);
|
||||
|
||||
// set up lock-file
|
||||
int lfp = -1;
|
||||
|
||||
@@ -196,6 +196,7 @@ using namespace MSXML;
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
#ifdef WIN32
|
||||
@@ -210,6 +211,9 @@ typedef int pid_t;
|
||||
#ifdef NEED_GCRYPT_LOCKING
|
||||
#include <gcrypt.h>
|
||||
#endif /* NEED_GCRYPT_LOCKING */
|
||||
#include <nettle/sha.h>
|
||||
#include <nettle/pbkdf2.h>
|
||||
#include <nettle/aes.h>
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
@@ -318,12 +322,16 @@ typedef int pid_t;
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
typedef uint8_t uint8;
|
||||
typedef int16_t int16;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
#else
|
||||
typedef unsigned char uint8;
|
||||
typedef signed short int16;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed long long int64;
|
||||
@@ -340,4 +348,19 @@ typedef unsigned char uchar;
|
||||
#define SCANF_SYNTAX(strindex)
|
||||
#endif
|
||||
|
||||
// providing "std::make_unique" for GCC 4.8.x (only 4.8.x)
|
||||
#if __GNUC__ && __cplusplus < 201402L && __cpp_generic_lambdas < 201304
|
||||
namespace std {
|
||||
template<class T> struct _Unique_if { typedef unique_ptr<T> _Single_object; };
|
||||
template<class T> struct _Unique_if<T[]> { typedef unique_ptr<T[]> _Unknown_bound; };
|
||||
template<class T, class... Args> typename _Unique_if<T>::_Single_object make_unique(Args&&... args) {
|
||||
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
template<class T> typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) {
|
||||
typedef typename remove_extent<T>::type U;
|
||||
return unique_ptr<T>(new U[n]());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NZBGET_H */
|
||||
|
||||
@@ -63,8 +63,8 @@ void ArticleDownloader::SetInfoName(const char* infoName)
|
||||
- if download fails with error "Not-Found" (article or group not found) or with CRC error,
|
||||
add the server to failed server list;
|
||||
- if download fails with general failure error (article incomplete, other unknown error
|
||||
codes), try the same server again as many times as defined by option <Retries>; if all attempts
|
||||
fail, add the server to failed server list;
|
||||
codes), try the same server again as many times as defined by option <ArticleRetries>;
|
||||
if all attempts fail, add the server to failed server list;
|
||||
- if all servers from current level were tried, increase level;
|
||||
- if all servers from all levels were tried, break the loop with failure status.
|
||||
<end-loop>
|
||||
@@ -80,7 +80,7 @@ void ArticleDownloader::Run()
|
||||
m_articleWriter.Prepare();
|
||||
|
||||
EStatus status = adFailed;
|
||||
int retries = g_Options->GetRetries() > 0 ? g_Options->GetRetries() : 1;
|
||||
int retries = g_Options->GetArticleRetries() > 0 ? g_Options->GetArticleRetries() : 1;
|
||||
int remainedRetries = retries;
|
||||
ServerPool::RawServerList failedServers;
|
||||
failedServers.reserve(g_ServerPool->GetServers()->size());
|
||||
|
||||
146
daemon/nserv/NServFrontend.cpp
Normal file
146
daemon/nserv/NServFrontend.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NServFrontend.h"
|
||||
#include "Util.h"
|
||||
|
||||
NServFrontend::NServFrontend()
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NServFrontend::Run()
|
||||
{
|
||||
while (!IsStopped())
|
||||
{
|
||||
Update();
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
// Printing the last messages
|
||||
Update();
|
||||
}
|
||||
|
||||
void NServFrontend::Update()
|
||||
{
|
||||
BeforePrint();
|
||||
|
||||
{
|
||||
GuardedMessageList messages = g_Log->GuardMessages();
|
||||
if (!messages->empty())
|
||||
{
|
||||
Message& firstMessage = messages->front();
|
||||
int start = m_neededLogFirstId - firstMessage.GetId() + 1;
|
||||
if (start < 0)
|
||||
{
|
||||
PrintSkip();
|
||||
start = 0;
|
||||
}
|
||||
for (uint32 i = (uint32)start; i < messages->size(); i++)
|
||||
{
|
||||
PrintMessage(messages->at(i));
|
||||
m_neededLogFirstId = messages->at(i).GetId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void NServFrontend::BeforePrint()
|
||||
{
|
||||
if (m_needGoBack)
|
||||
{
|
||||
// go back one line
|
||||
#ifdef WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO BufInfo;
|
||||
GetConsoleScreenBufferInfo(m_console, &BufInfo);
|
||||
BufInfo.dwCursorPosition.Y--;
|
||||
SetConsoleCursorPosition(m_console, BufInfo.dwCursorPosition);
|
||||
#else
|
||||
printf("\r\033[1A");
|
||||
#endif
|
||||
m_needGoBack = false;
|
||||
}
|
||||
}
|
||||
|
||||
void NServFrontend::PrintMessage(Message& message)
|
||||
{
|
||||
#ifdef WIN32
|
||||
switch (message.GetKind())
|
||||
{
|
||||
case Message::mkDebug:
|
||||
SetConsoleTextAttribute(m_console, 8);
|
||||
printf("[DEBUG] ");
|
||||
break;
|
||||
case Message::mkError:
|
||||
SetConsoleTextAttribute(m_console, 4);
|
||||
printf("[ERROR] ");
|
||||
break;
|
||||
case Message::mkWarning:
|
||||
SetConsoleTextAttribute(m_console, 5);
|
||||
printf("[WARNING]");
|
||||
break;
|
||||
case Message::mkInfo:
|
||||
SetConsoleTextAttribute(m_console, 2);
|
||||
printf("[INFO] ");
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
SetConsoleTextAttribute(m_console, 2);
|
||||
printf("[DETAIL]");
|
||||
break;
|
||||
}
|
||||
SetConsoleTextAttribute(m_console, 7);
|
||||
CString msg = message.GetText();
|
||||
CharToOem(msg, msg);
|
||||
printf(" %s\n", *msg);
|
||||
#else
|
||||
const char* msg = message.GetText();
|
||||
switch (message.GetKind())
|
||||
{
|
||||
case Message::mkDebug:
|
||||
printf("[DEBUG] %s\033[K\n", msg);
|
||||
break;
|
||||
case Message::mkError:
|
||||
printf("\033[31m[ERROR]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
case Message::mkWarning:
|
||||
printf("\033[35m[WARNING]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
case Message::mkInfo:
|
||||
printf("\033[32m[INFO]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
printf("\033[32m[DETAIL]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void NServFrontend::PrintSkip()
|
||||
{
|
||||
#ifdef WIN32
|
||||
printf(".....\n");
|
||||
#else
|
||||
printf(".....\033[K\n");
|
||||
#endif
|
||||
}
|
||||
48
daemon/nserv/NServFrontend.h
Normal file
48
daemon/nserv/NServFrontend.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NSERVFRONTEND_H
|
||||
#define NSERVFRONTEND_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Log.h"
|
||||
|
||||
class NServFrontend : public Thread
|
||||
{
|
||||
public:
|
||||
NServFrontend();
|
||||
|
||||
private:
|
||||
uint32 m_neededLogEntries = 0;
|
||||
uint32 m_neededLogFirstId = 0;
|
||||
bool m_needGoBack = false;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE m_console;
|
||||
#endif
|
||||
|
||||
void Run();
|
||||
void Update();
|
||||
void BeforePrint();
|
||||
void PrintMessage(Message& message);
|
||||
void PrintSkip();
|
||||
};
|
||||
|
||||
#endif
|
||||
246
daemon/nserv/NServMain.cpp
Normal file
246
daemon/nserv/NServMain.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Connection.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "FileSystem.h"
|
||||
#include "NServFrontend.h"
|
||||
#include "NntpServer.h"
|
||||
#include "NzbGenerator.h"
|
||||
#include "Options.h"
|
||||
|
||||
struct NServOpts
|
||||
{
|
||||
CString dataDir;
|
||||
CString cacheDir;
|
||||
CString bindAddress;
|
||||
int firstPort;
|
||||
int instances;
|
||||
CString logFile;
|
||||
CString secureCert;
|
||||
CString secureKey;
|
||||
BString<1024> logOpt;
|
||||
bool generateNzb;
|
||||
int segmentSize;
|
||||
bool quit;
|
||||
|
||||
NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts);
|
||||
};
|
||||
|
||||
void NServPrintUsage(const char* com);
|
||||
|
||||
int NServMain(int argc, char* argv[])
|
||||
{
|
||||
Log log;
|
||||
|
||||
info("NServ %s (Test NNTP server)", Util::VersionRevision());
|
||||
|
||||
Options::CmdOptList cmdOpts;
|
||||
NServOpts opts(argc, argv, cmdOpts);
|
||||
|
||||
if (opts.dataDir.Empty())
|
||||
{
|
||||
NServPrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!FileSystem::DirectoryExists(opts.dataDir))
|
||||
{
|
||||
// dataDir does not exist. Let's find out a bit more, and report:
|
||||
if (FileSystem::FileExists(opts.dataDir))
|
||||
{
|
||||
error("Specified data-dir %s is not a directory, but a file", *opts.dataDir );
|
||||
} else {
|
||||
error("Specified data-dir %s does not exist", *opts.dataDir );
|
||||
}
|
||||
}
|
||||
|
||||
Options options(&cmdOpts, nullptr);
|
||||
|
||||
log.InitOptions();
|
||||
Thread::Init();
|
||||
Connection::Init();
|
||||
#ifndef DISABLE_TLS
|
||||
TlsSocket::Init();
|
||||
#endif
|
||||
|
||||
NServFrontend frontend;
|
||||
frontend.Start();
|
||||
|
||||
if (opts.generateNzb)
|
||||
{
|
||||
NzbGenerator gen(opts.dataDir, opts.segmentSize);
|
||||
gen.Execute();
|
||||
if (opts.quit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
CString errmsg;
|
||||
if (opts.cacheDir && !FileSystem::ForceDirectories(opts.cacheDir, errmsg))
|
||||
{
|
||||
error("Could not create directory %s: %s", *opts.cacheDir, *errmsg);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<NntpServer>> instances;
|
||||
|
||||
for (int i = 0; i < opts.instances; i++)
|
||||
{
|
||||
instances.emplace_back(std::make_unique<NntpServer>(i + 1, opts.bindAddress,
|
||||
opts.firstPort + i, opts.secureCert, opts.secureKey, opts.dataDir, opts.cacheDir));
|
||||
instances.back()->Start();
|
||||
}
|
||||
|
||||
info("Press Ctrl+C to quit");
|
||||
while (getchar()) usleep(1000*200);
|
||||
|
||||
for (std::unique_ptr<NntpServer>& serv: instances)
|
||||
{
|
||||
serv->Stop();
|
||||
}
|
||||
frontend.Stop();
|
||||
|
||||
bool hasRunning = false;
|
||||
do
|
||||
{
|
||||
hasRunning = frontend.IsRunning();
|
||||
for (std::unique_ptr<NntpServer>& serv : instances)
|
||||
{
|
||||
hasRunning |= serv->IsRunning();
|
||||
}
|
||||
usleep(50 * 1000);
|
||||
} while (hasRunning);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NServPrintUsage(const char* com)
|
||||
{
|
||||
printf("Usage:\n"
|
||||
" %s --nserv -d <data-dir> [optional switches] \n"
|
||||
" -d <data-dir> - directory whose files will be served\n"
|
||||
" Optional switches:\n"
|
||||
" -c <cache-dir> - directory to store encoded articles\n"
|
||||
" -l <log-file> - write into log-file (disabled by default)\n"
|
||||
" -i <instances> - number of server instances (default is 1)\n"
|
||||
" -b <address> - ip address to bind to (default is 0.0.0.0)\n"
|
||||
" -p <port> - port number for the first instance (default is 6791)\n"
|
||||
" -s <cert> <key> - paths to SSL certificate and key files\n"
|
||||
" -v <verbose> - verbosity level 0..3 (default is 2)\n"
|
||||
" -z <seg-size> - generate nzbs for all files in data-dir (size in bytes)\n"
|
||||
" -q - quit after generating nzbs (in combination with -z)\n"
|
||||
, FileSystem::BaseFileName(com));
|
||||
}
|
||||
|
||||
NServOpts::NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts)
|
||||
{
|
||||
instances = 1;
|
||||
bindAddress = "0.0.0.0";
|
||||
firstPort = 6791;
|
||||
generateNzb = false;
|
||||
segmentSize = 500000;
|
||||
quit = false;
|
||||
int verbosity = 2;
|
||||
|
||||
char short_options[] = "b:c:d:l:p:i:s:v:z:q";
|
||||
|
||||
optind = 2;
|
||||
while (true)
|
||||
{
|
||||
int c = getopt(argc, argv, short_options);
|
||||
if (c == -1) break;
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
dataDir = optind > argc ? nullptr : argv[optind - 1];
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cacheDir = optind > argc ? nullptr : argv[optind - 1];
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
logFile = optind > argc ? nullptr : argv[optind - 1];
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bindAddress= optind > argc ? "0.0.0.0" : argv[optind - 1];
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
firstPort = atoi(optind > argc ? "6791" : argv[optind - 1]);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
secureCert = optind > argc ? nullptr : argv[optind - 1];
|
||||
optind++;
|
||||
secureKey = optind > argc ? nullptr : argv[optind - 1];
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
instances = atoi(optind > argc ? "1" : argv[optind - 1]);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbosity = atoi(optind > argc ? "1" : argv[optind - 1]);
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
generateNzb = true;
|
||||
segmentSize = atoi(optind > argc ? "500000" : argv[optind - 1]);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (logFile.Empty())
|
||||
{
|
||||
cmdOpts.push_back("WriteLog=none");
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdOpts.push_back("WriteLog=append");
|
||||
logOpt.Format("LogFile=%s", *logFile);
|
||||
cmdOpts.push_back(logOpt);
|
||||
}
|
||||
|
||||
if (verbosity < 1)
|
||||
{
|
||||
cmdOpts.push_back("InfoTarget=none");
|
||||
cmdOpts.push_back("WarningTarget=none");
|
||||
cmdOpts.push_back("ErrorTarget=none");
|
||||
}
|
||||
if (verbosity < 2)
|
||||
{
|
||||
cmdOpts.push_back("DetailTarget=none");
|
||||
}
|
||||
if (verbosity > 2)
|
||||
{
|
||||
cmdOpts.push_back("DebugTarget=both");
|
||||
}
|
||||
}
|
||||
26
daemon/nserv/NServMain.h
Normal file
26
daemon/nserv/NServMain.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NSERVMAIN_H
|
||||
#define NSERVMAIN_H
|
||||
|
||||
int NServMain(int argc, char * argv[]);
|
||||
|
||||
#endif
|
||||
321
daemon/nserv/NntpServer.cpp
Normal file
321
daemon/nserv/NntpServer.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NntpServer.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "YEncoder.h"
|
||||
|
||||
class NntpProcessor : public Thread
|
||||
{
|
||||
public:
|
||||
NntpProcessor(int id, int serverId, const char* dataDir, const char* cacheDir,
|
||||
const char* secureCert, const char* secureKey) :
|
||||
m_id(id), m_serverId(serverId), m_dataDir(dataDir), m_cacheDir(cacheDir),
|
||||
m_secureCert(secureCert), m_secureKey(secureKey) {}
|
||||
~NntpProcessor() { m_connection->Disconnect(); }
|
||||
virtual void Run();
|
||||
void SetConnection(std::unique_ptr<Connection>&& connection) { m_connection = std::move(connection); }
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
int m_serverId;
|
||||
std::unique_ptr<Connection> m_connection;
|
||||
const char* m_dataDir;
|
||||
const char* m_cacheDir;
|
||||
const char* m_secureCert;
|
||||
const char* m_secureKey;
|
||||
const char* m_messageid;
|
||||
CString m_filename;
|
||||
int m_part;
|
||||
int64 m_offset;
|
||||
int m_size;
|
||||
bool m_sendHeaders;
|
||||
|
||||
void ServArticle();
|
||||
void SendSegment();
|
||||
bool ServerInList(const char* servList);
|
||||
};
|
||||
|
||||
void NntpServer::Run()
|
||||
{
|
||||
debug("Entering NntpServer-loop");
|
||||
|
||||
info("Listening on port %i", m_port);
|
||||
|
||||
int num = 1;
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
bool bind = true;
|
||||
|
||||
if (!m_connection)
|
||||
{
|
||||
m_connection = std::make_unique<Connection>(m_host, m_port, m_secureCert);
|
||||
m_connection->SetTimeout(10);
|
||||
m_connection->SetSuppressErrors(false);
|
||||
bind = m_connection->Bind();
|
||||
}
|
||||
|
||||
// Accept connections and store the new Connection
|
||||
std::unique_ptr<Connection> acceptedConnection;
|
||||
if (bind)
|
||||
{
|
||||
acceptedConnection = m_connection->Accept();
|
||||
}
|
||||
if (!bind || !acceptedConnection)
|
||||
{
|
||||
// Server could not bind or accept connection, waiting 1/2 sec and try again
|
||||
if (IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_connection.reset();
|
||||
usleep(500 * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
NntpProcessor* commandThread = new NntpProcessor(num++, m_id,
|
||||
m_dataDir, m_cacheDir, m_secureCert, m_secureKey);
|
||||
commandThread->SetAutoDestroy(true);
|
||||
commandThread->SetConnection(std::move(acceptedConnection));
|
||||
commandThread->Start();
|
||||
}
|
||||
|
||||
if (m_connection)
|
||||
{
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
|
||||
debug("Exiting NntpServer-loop");
|
||||
}
|
||||
|
||||
void NntpServer::Stop()
|
||||
{
|
||||
Thread::Stop();
|
||||
if (m_connection)
|
||||
{
|
||||
m_connection->SetSuppressErrors(true);
|
||||
m_connection->Cancel();
|
||||
#ifdef WIN32
|
||||
m_connection->Disconnect();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NntpProcessor::Run()
|
||||
{
|
||||
m_connection->SetSuppressErrors(false);
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_secureCert && !m_connection->StartTls(false, m_secureCert, m_secureKey))
|
||||
{
|
||||
error("Could not establish secure connection to nntp-client: Start TLS failed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_connection->WriteLine("200 Welcome (NServ)\r\n");
|
||||
|
||||
CharBuffer buf(1024);
|
||||
int bytesRead = 0;
|
||||
while (CString line = m_connection->ReadLine(buf, 1024, &bytesRead))
|
||||
{
|
||||
line.TrimRight();
|
||||
detail("[%i] Received: %s", m_id, *line);
|
||||
|
||||
if (!strncasecmp(line, "ARTICLE ", 8))
|
||||
{
|
||||
m_messageid = line + 8;
|
||||
m_sendHeaders = true;
|
||||
ServArticle();
|
||||
}
|
||||
else if (!strncasecmp(line, "BODY ", 5))
|
||||
{
|
||||
m_messageid = line + 5;
|
||||
m_sendHeaders = false;
|
||||
ServArticle();
|
||||
}
|
||||
else if (!strncasecmp(line, "GROUP ", 6))
|
||||
{
|
||||
m_connection->WriteLine(CString::FormatStr("211 0 0 0 %s\r\n", line + 7));
|
||||
}
|
||||
else if (!strncasecmp(line, "AUTHINFO ", 9))
|
||||
{
|
||||
m_connection->WriteLine("281 Authentication accepted\r\n");
|
||||
}
|
||||
else if (!strcasecmp(line, "QUIT"))
|
||||
{
|
||||
detail("[%i] Closing connection", m_id);
|
||||
m_connection->WriteLine("205 Connection closing\r\n");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("[%i] Unknown command: %s", m_id, *line);
|
||||
m_connection->WriteLine("500 Unknown command\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
m_connection->SetGracefull(true);
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
|
||||
/*
|
||||
Message-id format:
|
||||
<file-path-relative-to-dataDir?xxx=yyy:zzz!1,2,3>
|
||||
where:
|
||||
xxx - part number (integer)
|
||||
xxx - offset from which to read the files (integer)
|
||||
yyy - size of file block to return (integer)
|
||||
1,2,3 - list of server ids, which have the article (optional),
|
||||
if the list is given and current server is not in the list
|
||||
the "article not found"-error is returned.
|
||||
Examples:
|
||||
<parchecker/testfile.dat?1=0:50000> - return first 50000 bytes starting from beginning
|
||||
<parchecker/testfile.dat?2=50000:50000> - return 50000 bytes starting from offset 50000
|
||||
<parchecker/testfile.dat?2=50000:50000!2> - article is missing on server 1
|
||||
*/
|
||||
void NntpProcessor::ServArticle()
|
||||
{
|
||||
detail("[%i] Serving: %s", m_id, m_messageid);
|
||||
|
||||
bool ok = false;
|
||||
|
||||
const char* from = strchr(m_messageid, '?');
|
||||
const char* off = strchr(m_messageid, '=');
|
||||
const char* to = strchr(m_messageid, ':');
|
||||
const char* end = strchr(m_messageid, '>');
|
||||
const char* serv = strchr(m_messageid, '!');
|
||||
|
||||
if (from && off && to && end)
|
||||
{
|
||||
m_filename.Set(m_messageid + 1, from - m_messageid - 1);
|
||||
m_part = atoi(from + 1);
|
||||
m_offset = atoll(off + 1);
|
||||
m_size = atoi(to + 1);
|
||||
|
||||
ok = !serv || ServerInList(serv + 1);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
SendSegment();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
m_connection->WriteLine("430 No Such Article Found\r\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_connection->WriteLine("430 No Such Article Found (invalid message id format)\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool NntpProcessor::ServerInList(const char* servList)
|
||||
{
|
||||
Tokenizer tok(servList, ",");
|
||||
while (const char* servid = tok.Next())
|
||||
{
|
||||
if (atoi(servid) == m_serverId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NntpProcessor::SendSegment()
|
||||
{
|
||||
detail("[%i] Sending segment %s (%i=%lli:%i)", m_id, *m_filename, m_part, (long long)m_offset, m_size);
|
||||
|
||||
BString<1024> fullFilename("%s/%s", m_dataDir, *m_filename);
|
||||
BString<1024> cacheFileDir("%s/%s", m_cacheDir, *m_filename);
|
||||
BString<1024> cacheFileName("%i=%lli-%i", m_part, (long long)m_offset, m_size);
|
||||
BString<1024> cacheFullFilename("%s/%s", *cacheFileDir, *cacheFileName);
|
||||
|
||||
DiskFile cacheFile;
|
||||
bool readCache = m_cacheDir && cacheFile.Open(cacheFullFilename, DiskFile::omRead);
|
||||
bool writeCache = m_cacheDir && !readCache;
|
||||
|
||||
CString errmsg;
|
||||
if (writeCache && !FileSystem::ForceDirectories(cacheFileDir, errmsg))
|
||||
{
|
||||
error("Could not create directory %s: %s", *cacheFileDir, *errmsg);
|
||||
}
|
||||
|
||||
if (writeCache && !cacheFile.Open(cacheFullFilename, DiskFile::omWrite))
|
||||
{
|
||||
error("Could not create file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage());
|
||||
}
|
||||
|
||||
if (!readCache && !FileSystem::FileExists(fullFilename))
|
||||
{
|
||||
m_connection->WriteLine(CString::FormatStr("430 Article not found\r\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
YEncoder encoder(fullFilename, m_part, m_offset, m_size,
|
||||
[con = m_connection.get(), writeCache, &cacheFile](const char* buf, int size)
|
||||
{
|
||||
if (writeCache)
|
||||
{
|
||||
cacheFile.Write(buf, size);
|
||||
}
|
||||
con->Send(buf, size);
|
||||
});
|
||||
|
||||
if (!readCache && !encoder.OpenFile(errmsg))
|
||||
{
|
||||
m_connection->WriteLine(CString::FormatStr("403 %s\r\n", *errmsg));
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection->WriteLine(CString::FormatStr("%i, 0 %s\r\n", m_sendHeaders ? 222 : 220, m_messageid));
|
||||
if (m_sendHeaders)
|
||||
{
|
||||
m_connection->WriteLine(CString::FormatStr("Message-ID: %s\r\n", m_messageid));
|
||||
m_connection->WriteLine(CString::FormatStr("Subject: \"%s\"\r\n", FileSystem::BaseFileName(m_filename)));
|
||||
m_connection->WriteLine("\r\n");
|
||||
}
|
||||
|
||||
if (readCache)
|
||||
{
|
||||
cacheFile.Seek(0, DiskFile::soEnd);
|
||||
int size = (int)cacheFile.Position();
|
||||
CharBuffer buf(size);
|
||||
cacheFile.Seek(0);
|
||||
if (cacheFile.Read((char*)buf, size) != size)
|
||||
{
|
||||
error("Could not read file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage());
|
||||
}
|
||||
m_connection->Send(buf, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.WriteSegment();
|
||||
}
|
||||
|
||||
m_connection->WriteLine(".\r\n");
|
||||
}
|
||||
48
daemon/nserv/NntpServer.h
Normal file
48
daemon/nserv/NntpServer.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NNTPSERVER_H
|
||||
#define NNTPSERVER_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Connection.h"
|
||||
|
||||
class NntpServer : public Thread
|
||||
{
|
||||
public:
|
||||
NntpServer(int id, const char* host, int port, const char* secureCert,
|
||||
const char* secureKey, const char* dataDir, const char* cacheDir) :
|
||||
m_id(id), m_host(host), m_port(port), m_secureCert(secureCert),
|
||||
m_secureKey(secureKey), m_dataDir(dataDir), m_cacheDir(cacheDir) {}
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
CString m_host;
|
||||
int m_port;
|
||||
CString m_dataDir;
|
||||
CString m_cacheDir;
|
||||
CString m_secureCert;
|
||||
CString m_secureKey;
|
||||
std::unique_ptr<Connection> m_connection;
|
||||
};
|
||||
|
||||
#endif
|
||||
131
daemon/nserv/NzbGenerator.cpp
Normal file
131
daemon/nserv/NzbGenerator.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NzbGenerator.h"
|
||||
#include "Util.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Log.h"
|
||||
|
||||
void NzbGenerator::Execute()
|
||||
{
|
||||
info("Generating nzbs for %s", *m_dataDir);
|
||||
|
||||
DirBrowser dir(m_dataDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", *m_dataDir, PATH_SEPARATOR, filename);
|
||||
|
||||
int len = strlen(filename);
|
||||
if (len > 4 && !strcasecmp(filename + len - 4, ".nzb"))
|
||||
{
|
||||
// skip nzb-files
|
||||
continue;
|
||||
}
|
||||
|
||||
GenerateNzb(fullFilename);
|
||||
}
|
||||
|
||||
info("Nzb generation finished");
|
||||
}
|
||||
|
||||
void NzbGenerator::GenerateNzb(const char* path)
|
||||
{
|
||||
BString<1024> nzbFilename("%s%c%s.nzb", *m_dataDir, PATH_SEPARATOR, FileSystem::BaseFileName(path));
|
||||
|
||||
if (FileSystem::FileExists(nzbFilename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
info("Generating nzb for %s", FileSystem::BaseFileName(path));
|
||||
|
||||
DiskFile outfile;
|
||||
if (!outfile.Open(nzbFilename, DiskFile::omWrite))
|
||||
{
|
||||
error("Could not create file %s", *nzbFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
outfile.Print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
outfile.Print("<!DOCTYPE nzb PUBLIC \"-//newzBin//DTD NZB 1.0//EN\" \"http://www.newzbin.com/DTD/nzb/nzb-1.0.dtd\">\n");
|
||||
outfile.Print("<nzb xmlns=\"http://www.newzbin.com/DTD/2003/nzb\">\n");
|
||||
|
||||
bool isDir = FileSystem::DirectoryExists(path);
|
||||
if (isDir)
|
||||
{
|
||||
AppendDir(outfile, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppendFile(outfile, path, nullptr);
|
||||
}
|
||||
|
||||
outfile.Print("</nzb>\n");
|
||||
|
||||
outfile.Close();
|
||||
}
|
||||
|
||||
void NzbGenerator::AppendDir(DiskFile& outfile, const char* path)
|
||||
{
|
||||
DirBrowser dir(path);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", path, PATH_SEPARATOR, filename);
|
||||
|
||||
bool isDir = FileSystem::DirectoryExists(fullFilename);
|
||||
if (!isDir)
|
||||
{
|
||||
AppendFile(outfile, fullFilename, FileSystem::BaseFileName(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NzbGenerator::AppendFile(DiskFile& outfile, const char* filename, const char* relativePath)
|
||||
{
|
||||
detail("Processing %s", FileSystem::BaseFileName(filename));
|
||||
|
||||
int64 fileSize = FileSystem::FileSize(filename);
|
||||
time_t timestamp = Util::CurrentTime();
|
||||
|
||||
int segmentCount = (int)((fileSize + m_segmentSize - 1) / m_segmentSize);
|
||||
|
||||
outfile.Print("<file poster=\"nserv\" date=\"%i\" subject=\""%s" yEnc (1/%i)\">\n",
|
||||
(int)timestamp, FileSystem::BaseFileName(filename), segmentCount);
|
||||
outfile.Print("<groups>\n");
|
||||
outfile.Print("<group>alt.binaries.test</group>\n");
|
||||
outfile.Print("</groups>\n");
|
||||
outfile.Print("<segments>\n");
|
||||
|
||||
int64 segOffset = 0;
|
||||
for (int segno = 1; segno <= segmentCount; segno++)
|
||||
{
|
||||
int segSize = (int)(segOffset + m_segmentSize < fileSize ? m_segmentSize : fileSize - segOffset);
|
||||
outfile.Print("<segment bytes=\"%i\" number=\"%i\">%s%s%s?%i=%lli:%i</segment>\n",
|
||||
m_segmentSize, segno,
|
||||
relativePath ? relativePath : "",
|
||||
relativePath ? "/" : "",
|
||||
FileSystem::BaseFileName(filename), segno, (long long)segOffset, (int)segSize);
|
||||
segOffset += segSize;
|
||||
}
|
||||
|
||||
outfile.Print("</segments>\n");
|
||||
outfile.Print("</file>\n");
|
||||
}
|
||||
43
daemon/nserv/NzbGenerator.h
Normal file
43
daemon/nserv/NzbGenerator.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NZBGENERATOR_H
|
||||
#define NZBGENERATOR_H
|
||||
|
||||
#include "NString.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
class NzbGenerator
|
||||
{
|
||||
public:
|
||||
NzbGenerator(const char* dataDir, int segmentSize) :
|
||||
m_dataDir(dataDir), m_segmentSize(segmentSize) {};
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
CString m_dataDir;
|
||||
int m_segmentSize;
|
||||
|
||||
void GenerateNzb(const char* path);
|
||||
void AppendFile(DiskFile& outfile, const char* filename, const char* relativePath);
|
||||
void AppendDir(DiskFile& outfile, const char* path);
|
||||
};
|
||||
|
||||
#endif
|
||||
131
daemon/nserv/YEncoder.cpp
Normal file
131
daemon/nserv/YEncoder.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "YEncoder.h"
|
||||
#include "Util.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Log.h"
|
||||
|
||||
bool YEncoder::OpenFile(CString& errmsg)
|
||||
{
|
||||
if (m_size < 0)
|
||||
{
|
||||
errmsg = "Invalid segment size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_diskfile.Open(m_filename, DiskFile::omRead) || !m_diskfile.Seek(0, DiskFile::soEnd))
|
||||
{
|
||||
errmsg = "File not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fileSize = m_diskfile.Position();
|
||||
if (m_size == 0)
|
||||
{
|
||||
m_size = (int)(m_fileSize - m_offset + 1);
|
||||
}
|
||||
|
||||
if (m_fileSize < m_offset + m_size)
|
||||
{
|
||||
errmsg = "Invalid segment size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_diskfile.Seek(m_offset))
|
||||
{
|
||||
errmsg = "Invalid segment offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void YEncoder::WriteSegment()
|
||||
{
|
||||
StringBuilder outbuf;
|
||||
outbuf.Reserve(std::max(2048, std::min((int)(m_size * 1.1), 16 * 1024 * 1024)));
|
||||
|
||||
outbuf.Append(CString::FormatStr("=ybegin part=%i line=128 size=%lli name=%s\r\n", m_part, (long long)m_fileSize, FileSystem::BaseFileName(m_filename)));
|
||||
outbuf.Append(CString::FormatStr("=ypart begin=%lli end=%lli\r\n", (long long)(m_offset + 1), (long long)(m_offset + m_size)));
|
||||
|
||||
uint32 crc = 0xFFFFFFFF;
|
||||
CharBuffer inbuf(std::min(m_size, 16 * 1024 * 1024));
|
||||
int lnsz = 0;
|
||||
char* out = (char*)outbuf + outbuf.Length();
|
||||
|
||||
while (m_diskfile.Position() < m_offset + m_size)
|
||||
{
|
||||
int64 needBytes = std::min((int64)inbuf.Size(), m_offset + m_size - m_diskfile.Position());
|
||||
int64 readBytes = m_diskfile.Read(inbuf, needBytes);
|
||||
bool lastblock = m_diskfile.Position() == m_offset + m_size;
|
||||
if (readBytes == 0)
|
||||
{
|
||||
return; // error;
|
||||
}
|
||||
|
||||
crc = Util::Crc32m(crc, (uchar*)(const char*)inbuf, (int)readBytes);
|
||||
|
||||
char* in = inbuf;
|
||||
while (readBytes > 0)
|
||||
{
|
||||
char ch = *in++;
|
||||
readBytes--;
|
||||
ch = (char)(((uchar)(ch) + 42) % 256);
|
||||
if (ch == '\0' || ch == '\n' || ch == '\r' || ch == '=' || ch == ' ' || ch == '\t')
|
||||
{
|
||||
*out++ = '=';
|
||||
lnsz++;
|
||||
ch = (char)(((uchar)ch + 64) % 256);
|
||||
}
|
||||
if (ch == '.' && lnsz == 0)
|
||||
{
|
||||
*out++ = '.';
|
||||
lnsz++;
|
||||
}
|
||||
*out++ = ch;
|
||||
lnsz++;
|
||||
|
||||
if (lnsz >= 128 || (readBytes == 0 && lastblock))
|
||||
{
|
||||
*out++ = '\r';
|
||||
*out++ = '\n';
|
||||
lnsz += 2;
|
||||
outbuf.SetLength(outbuf.Length() + lnsz);
|
||||
|
||||
if (outbuf.Length() > outbuf.Capacity() - 200)
|
||||
{
|
||||
m_writeFunc(outbuf, outbuf.Length());
|
||||
outbuf.SetLength(0);
|
||||
out = (char*)outbuf;
|
||||
}
|
||||
|
||||
lnsz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
crc ^= 0xFFFFFFFF;
|
||||
|
||||
m_diskfile.Close();
|
||||
|
||||
outbuf.Append(CString::FormatStr("=yend size=%i part=0 pcrc32=%08x\r\n", m_size, (unsigned int)crc));
|
||||
m_writeFunc(outbuf, outbuf.Length());
|
||||
}
|
||||
47
daemon/nserv/YEncoder.h
Normal file
47
daemon/nserv/YEncoder.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef YENCODER_H
|
||||
#define YENCODER_H
|
||||
|
||||
#include "NString.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
class YEncoder
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(const char* buf, int size)> WriteFunc;
|
||||
|
||||
YEncoder(const char* filename, int part, int64 offset, int size, WriteFunc writeFunc) :
|
||||
m_filename(filename), m_part(part), m_offset(offset), m_size(size), m_writeFunc(writeFunc) {};
|
||||
bool OpenFile(CString& errmsg);
|
||||
void WriteSegment();
|
||||
|
||||
private:
|
||||
DiskFile m_diskfile;
|
||||
CString m_filename;
|
||||
int m_part;
|
||||
int64 m_offset;
|
||||
int m_size;
|
||||
int64 m_fileSize;
|
||||
WriteFunc m_writeFunc;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -76,7 +76,6 @@ void MoveController::Run()
|
||||
m_postInfo->GetNzbInfo()->SetMoveStatus(NzbInfo::msFailure);
|
||||
}
|
||||
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
m_postInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
@@ -182,7 +181,6 @@ void CleanupController::Run()
|
||||
m_postInfo->GetNzbInfo()->SetCleanupStatus(NzbInfo::csFailure);
|
||||
}
|
||||
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
m_postInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@ class RepairThread;
|
||||
class Repairer : public Par2::Par2Repairer, public ParChecker::AbstractRepairer
|
||||
{
|
||||
public:
|
||||
Repairer(ParChecker* owner) { m_owner = owner; }
|
||||
Repairer(ParChecker* owner):
|
||||
Par2::Par2Repairer(owner->m_parCout, owner->m_parCerr),
|
||||
m_owner(owner), commandLine(owner->m_parCout, owner->m_parCerr) {}
|
||||
Par2::Result PreProcess(const char *parFilename);
|
||||
Par2::Result Process(bool dorepair);
|
||||
virtual Repairer* GetRepairer() { return this; }
|
||||
@@ -364,13 +366,6 @@ int ParChecker::StreamBuf::overflow(int ch)
|
||||
}
|
||||
|
||||
|
||||
ParChecker::~ParChecker()
|
||||
{
|
||||
debug("Destroying ParChecker");
|
||||
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void ParChecker::Cleanup()
|
||||
{
|
||||
m_repairer.reset();
|
||||
@@ -381,14 +376,11 @@ void ParChecker::Cleanup()
|
||||
m_errMsg = nullptr;
|
||||
}
|
||||
|
||||
void ParChecker::Run()
|
||||
void ParChecker::Execute()
|
||||
{
|
||||
Par2::cout.rdbuf(&m_parOutStream);
|
||||
Par2::cerr.rdbuf(&m_parErrStream);
|
||||
|
||||
m_status = RunParCheckAll();
|
||||
|
||||
if (m_status == psRepairNotNeeded && m_parQuick && m_forceRepair && !m_cancelled)
|
||||
if (m_status == psRepairNotNeeded && m_parQuick && m_forceRepair && !IsStopped())
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Performing full par-check for %s", *m_nzbName);
|
||||
m_parQuick = false;
|
||||
@@ -396,9 +388,6 @@ void ParChecker::Run()
|
||||
}
|
||||
|
||||
Completed();
|
||||
|
||||
Par2::cout.rdbuf(&Par2::nullStreamBuf);
|
||||
Par2::cerr.rdbuf(&Par2::nullStreamBuf);
|
||||
}
|
||||
|
||||
ParChecker::EStatus ParChecker::RunParCheckAll()
|
||||
@@ -411,19 +400,18 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
|
||||
}
|
||||
|
||||
EStatus allStatus = psRepairNotNeeded;
|
||||
m_cancelled = false;
|
||||
m_parFull = true;
|
||||
|
||||
for (CString& parFilename : fileList)
|
||||
{
|
||||
debug("Found par: %s", *parFilename);
|
||||
|
||||
if (!IsStopped() && !m_cancelled)
|
||||
if (!IsStopped())
|
||||
{
|
||||
BString<1024> fullParFilename( "%s%c%s", *m_destDir, (int)PATH_SEPARATOR, *parFilename);
|
||||
|
||||
int baseLen = 0;
|
||||
ParParser::ParseParFilename(parFilename, &baseLen, nullptr);
|
||||
ParParser::ParseParFilename(parFilename, true, &baseLen, nullptr);
|
||||
BString<1024> infoName;
|
||||
infoName.Set(parFilename, baseLen);
|
||||
|
||||
@@ -571,7 +559,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* parFilename)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cancelled)
|
||||
if (IsStopped())
|
||||
{
|
||||
if (m_stage >= ptRepairing)
|
||||
{
|
||||
@@ -688,7 +676,7 @@ bool ParChecker::LoadMainParBak()
|
||||
{
|
||||
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
|
||||
bool queuedParFilesChanged = false;
|
||||
while (!queuedParFilesChanged && !IsStopped() && !m_cancelled)
|
||||
while (!queuedParFilesChanged && !IsStopped())
|
||||
{
|
||||
{
|
||||
Guard guard(m_queuedParFilesMutex);
|
||||
@@ -754,7 +742,7 @@ int ParChecker::ProcessMorePars()
|
||||
{
|
||||
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
|
||||
bool queuedParFilesChanged = false;
|
||||
while (!queuedParFilesChanged && !IsStopped() && !m_cancelled)
|
||||
while (!queuedParFilesChanged && !IsStopped())
|
||||
{
|
||||
{
|
||||
Guard guard(m_queuedParFilesMutex);
|
||||
@@ -765,7 +753,7 @@ int ParChecker::ProcessMorePars()
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped() || m_cancelled)
|
||||
if (IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -973,7 +961,7 @@ bool ParChecker::AddExtraFiles(bool onlyMissing, bool externalDir, const char* d
|
||||
|
||||
// adding files one by one until all missing files are found
|
||||
|
||||
while (!IsStopped() && !m_cancelled && extrafiles.size() > 0)
|
||||
while (!IsStopped() && extrafiles.size() > 0)
|
||||
{
|
||||
std::list<Par2::CommandLine::ExtraFile> extrafiles1;
|
||||
extrafiles1.splice(extrafiles1.end(), extrafiles, extrafiles.begin());
|
||||
@@ -1199,7 +1187,6 @@ void ParChecker::CheckEmptyFiles()
|
||||
void ParChecker::Cancel()
|
||||
{
|
||||
GetRepairer()->cancelled = true;
|
||||
m_cancelled = true;
|
||||
QueueChanged();
|
||||
}
|
||||
|
||||
@@ -1214,7 +1201,7 @@ void ParChecker::WriteBrokenLog(EStatus status)
|
||||
{
|
||||
if (status == psFailed)
|
||||
{
|
||||
if (m_cancelled)
|
||||
if (IsStopped())
|
||||
{
|
||||
file.Print("Repair cancelled for %s\n", *m_infoName);
|
||||
}
|
||||
|
||||
@@ -25,13 +25,12 @@
|
||||
|
||||
#include "NString.h"
|
||||
#include "Container.h"
|
||||
#include "Thread.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Log.h"
|
||||
|
||||
class Repairer;
|
||||
|
||||
class ParChecker : public Thread
|
||||
class ParChecker
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
@@ -57,8 +56,7 @@ public:
|
||||
virtual Repairer* GetRepairer() = 0;
|
||||
};
|
||||
|
||||
virtual ~ParChecker();
|
||||
virtual void Run();
|
||||
void Execute();
|
||||
void SetDestDir(const char* destDir) { m_destDir = destDir; }
|
||||
const char* GetParFilename() { return m_parFilename; }
|
||||
const char* GetInfoName() { return m_infoName; }
|
||||
@@ -74,7 +72,6 @@ public:
|
||||
void AddParFile(const char* parFilename);
|
||||
void QueueChanged();
|
||||
void Cancel();
|
||||
bool GetCancelled() { return m_cancelled; }
|
||||
|
||||
protected:
|
||||
class Segment
|
||||
@@ -129,6 +126,7 @@ protected:
|
||||
*/
|
||||
virtual bool RequestMorePars(int blockNeeded, int* blockFound) = 0;
|
||||
virtual void UpdateProgress() {}
|
||||
virtual bool IsStopped() { return false; };
|
||||
virtual void Completed() {}
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3) {}
|
||||
virtual void RegisterParredFile(const char* filename) {}
|
||||
@@ -186,6 +184,8 @@ private:
|
||||
DupeSourceList m_dupeSources;
|
||||
StreamBuf m_parOutStream{this, Message::mkDetail};
|
||||
StreamBuf m_parErrStream{this, Message::mkError};
|
||||
std::ostream m_parCout{&m_parOutStream};
|
||||
std::ostream m_parCerr{&m_parErrStream};
|
||||
|
||||
// "m_repairer" should be of type "Par2::Par2Repairer", however to prevent the
|
||||
// including of libpar2-headers into this header-file we use an empty abstract class.
|
||||
|
||||
@@ -33,7 +33,7 @@ bool ParParser::FindMainPars(const char* path, ParFileList* fileList)
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
int baseLen = 0;
|
||||
if (ParseParFilename(filename, &baseLen, nullptr))
|
||||
if (ParseParFilename(filename, true, &baseLen, nullptr))
|
||||
{
|
||||
if (!fileList)
|
||||
{
|
||||
@@ -62,13 +62,13 @@ bool ParParser::FindMainPars(const char* path, ParFileList* fileList)
|
||||
bool ParParser::SameParCollection(const char* filename1, const char* filename2)
|
||||
{
|
||||
int baseLen1 = 0, baseLen2 = 0;
|
||||
return ParseParFilename(filename1, &baseLen1, nullptr) &&
|
||||
ParseParFilename(filename2, &baseLen2, nullptr) &&
|
||||
return ParseParFilename(filename1, false, &baseLen1, nullptr) &&
|
||||
ParseParFilename(filename2, false, &baseLen2, nullptr) &&
|
||||
baseLen1 == baseLen2 &&
|
||||
!strncasecmp(filename1, filename2, baseLen1);
|
||||
}
|
||||
|
||||
bool ParParser::ParseParFilename(const char* parFilename, int* baseNameLen, int* blocks)
|
||||
bool ParParser::ParseParFilename(const char* parFilename, bool confirmedFilename, int* baseNameLen, int* blocks)
|
||||
{
|
||||
BString<1024> filename = parFilename;
|
||||
for (char* p = filename; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
@@ -79,10 +79,13 @@ bool ParParser::ParseParFilename(const char* parFilename, int* baseNameLen, int*
|
||||
return false;
|
||||
}
|
||||
|
||||
// find last occurence of ".par2" and trim filename after it
|
||||
char* end = filename;
|
||||
while (char* p = strstr(end, ".par2")) end = p + 5;
|
||||
*end = '\0';
|
||||
if (!confirmedFilename)
|
||||
{
|
||||
// find last occurence of ".par2" and trim filename after it
|
||||
char* end = filename;
|
||||
while (char* p = strstr(end, ".par2")) end = p + 5;
|
||||
*end = '\0';
|
||||
}
|
||||
|
||||
len = strlen(filename);
|
||||
if (len < 6)
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
typedef std::vector<CString> ParFileList;
|
||||
|
||||
static bool FindMainPars(const char* path, ParFileList* fileList);
|
||||
static bool ParseParFilename(const char* parFilename, int* baseNameLen, int* blocks);
|
||||
static bool ParseParFilename(const char* parFilename, bool confirmedFilename, int* baseNameLen, int* blocks);
|
||||
static bool SameParCollection(const char* filename1, const char* filename2);
|
||||
};
|
||||
|
||||
|
||||
@@ -36,31 +36,17 @@
|
||||
class ParRenamerRepairer : public Par2::Par2Repairer
|
||||
{
|
||||
public:
|
||||
ParRenamerRepairer() : Par2::Par2Repairer(m_nout, m_nout) {};
|
||||
friend class ParRenamer;
|
||||
private:
|
||||
class NullStreamBuf : public std::streambuf {};
|
||||
NullStreamBuf m_nullbuf;
|
||||
std::ostream m_nout{&m_nullbuf};
|
||||
};
|
||||
|
||||
|
||||
void ParRenamer::Cleanup()
|
||||
void ParRenamer::Execute()
|
||||
{
|
||||
m_dirList.clear();
|
||||
m_fileHashList.clear();
|
||||
}
|
||||
|
||||
void ParRenamer::Cancel()
|
||||
{
|
||||
m_cancelled = true;
|
||||
}
|
||||
|
||||
void ParRenamer::Run()
|
||||
{
|
||||
Cleanup();
|
||||
m_cancelled = false;
|
||||
m_fileCount = 0;
|
||||
m_curFile = 0;
|
||||
m_renamedCount = 0;
|
||||
m_hasMissedFiles = false;
|
||||
m_status = psFailed;
|
||||
|
||||
m_progressLabel.Format("Checking renamed files for %s", *m_infoName);
|
||||
m_stageProgress = 0;
|
||||
UpdateProgress();
|
||||
@@ -71,14 +57,17 @@ void ParRenamer::Run()
|
||||
{
|
||||
debug("Checking %s", *destDir);
|
||||
m_fileHashList.clear();
|
||||
LoadParFiles(destDir);
|
||||
m_parInfoList.clear();
|
||||
m_badParList.clear();
|
||||
m_loadedParList.clear();
|
||||
|
||||
if (m_fileHashList.empty())
|
||||
CheckFiles(destDir, true);
|
||||
RenameParFiles(destDir);
|
||||
|
||||
LoadMainParFiles(destDir);
|
||||
if (m_hasDamagedParFiles)
|
||||
{
|
||||
int savedCurFile = m_curFile;
|
||||
CheckFiles(destDir, true);
|
||||
m_curFile = savedCurFile; // restore progress indicator
|
||||
LoadParFiles(destDir);
|
||||
LoadExtraParFiles(destDir);
|
||||
}
|
||||
|
||||
CheckFiles(destDir, false);
|
||||
@@ -87,24 +76,12 @@ void ParRenamer::Run()
|
||||
{
|
||||
CheckMissing();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cancelled)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Renaming cancelled for %s", *m_infoName);
|
||||
if (m_renamedCount > 0 && !m_badParList.empty())
|
||||
{
|
||||
RenameBadParFiles();
|
||||
}
|
||||
}
|
||||
else if (m_renamedCount > 0)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Successfully renamed %i file(s) for %s", m_renamedCount, *m_infoName);
|
||||
m_status = psSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "No renamed files found for %s", *m_infoName);
|
||||
}
|
||||
|
||||
Cleanup();
|
||||
Completed();
|
||||
}
|
||||
|
||||
void ParRenamer::BuildDirList(const char* destDir)
|
||||
@@ -115,7 +92,7 @@ void ParRenamer::BuildDirList(const char* destDir)
|
||||
|
||||
while (const char* filename = dirBrowser.Next())
|
||||
{
|
||||
if (!m_cancelled)
|
||||
if (!IsStopped())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", destDir, PATH_SEPARATOR, filename);
|
||||
if (FileSystem::DirectoryExists(fullFilename))
|
||||
@@ -130,7 +107,7 @@ void ParRenamer::BuildDirList(const char* destDir)
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::LoadParFiles(const char* destDir)
|
||||
void ParRenamer::LoadMainParFiles(const char* destDir)
|
||||
{
|
||||
ParParser::ParFileList parFileList;
|
||||
ParParser::FindMainPars(destDir, &parFileList);
|
||||
@@ -142,19 +119,52 @@ void ParRenamer::LoadParFiles(const char* destDir)
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::LoadExtraParFiles(const char* destDir)
|
||||
{
|
||||
DirBrowser dir(destDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
BString<1024> fullParFilename("%s%c%s", destDir, PATH_SEPARATOR, filename);
|
||||
if (ParParser::ParseParFilename(fullParFilename, true, nullptr, nullptr))
|
||||
{
|
||||
bool knownBadParFile = std::find_if(m_badParList.begin(), m_badParList.end(),
|
||||
[&fullParFilename](CString& filename)
|
||||
{
|
||||
return !strcmp(filename, fullParFilename);
|
||||
}) != m_badParList.end();
|
||||
|
||||
bool loadedParFile = std::find_if(m_loadedParList.begin(), m_loadedParList.end(),
|
||||
[&fullParFilename](CString& filename)
|
||||
{
|
||||
return !strcmp(filename, fullParFilename);
|
||||
}) != m_loadedParList.end();
|
||||
|
||||
if (!knownBadParFile && !loadedParFile)
|
||||
{
|
||||
LoadParFile(fullParFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::LoadParFile(const char* parFilename)
|
||||
{
|
||||
ParRenamerRepairer repairer;
|
||||
|
||||
if (!repairer.LoadPacketsFromFile(parFilename))
|
||||
if (!repairer.LoadPacketsFromFile(parFilename) || FileSystem::FileSize(parFilename) == 0)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Could not load par2-file %s", parFilename);
|
||||
m_hasDamagedParFiles = true;
|
||||
m_badParList.emplace_back(parFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
m_loadedParList.emplace_back(parFilename);
|
||||
PrintMessage(Message::mkInfo, "Loaded par2-file %s for par-rename", FileSystem::BaseFileName(parFilename));
|
||||
|
||||
for (std::pair<const Par2::MD5Hash, Par2::Par2RepairerSourceFile*>& entry : repairer.sourcefilemap)
|
||||
{
|
||||
if (m_cancelled)
|
||||
if (IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -162,32 +172,46 @@ void ParRenamer::LoadParFile(const char* parFilename)
|
||||
Par2::Par2RepairerSourceFile* sourceFile = entry.second;
|
||||
if (!sourceFile || !sourceFile->GetDescriptionPacket())
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Damaged par2-file detected: %s", parFilename);
|
||||
PrintMessage(Message::mkWarning, "Damaged par2-file detected: %s", FileSystem::BaseFileName(parFilename));
|
||||
m_badParList.emplace_back(parFilename);
|
||||
m_hasDamagedParFiles = true;
|
||||
continue;
|
||||
}
|
||||
std::string filename = Par2::DiskFile::TranslateFilename(sourceFile->GetDescriptionPacket()->FileName());
|
||||
m_fileHashList.emplace_back(filename.c_str(), sourceFile->GetDescriptionPacket()->Hash16k().print().c_str());
|
||||
RegisterParredFile(filename.c_str());
|
||||
std::string hash = sourceFile->GetDescriptionPacket()->Hash16k().print();
|
||||
|
||||
bool exists = std::find_if(m_fileHashList.begin(), m_fileHashList.end(),
|
||||
[&hash](FileHash& fileHash)
|
||||
{
|
||||
return !strcmp(fileHash.GetHash(), hash.c_str());
|
||||
})
|
||||
!= m_fileHashList.end();
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
m_fileHashList.emplace_back(filename.c_str(), hash.c_str());
|
||||
RegisterParredFile(filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::CheckFiles(const char* destDir, bool renamePars)
|
||||
void ParRenamer::CheckFiles(const char* destDir, bool checkPars)
|
||||
{
|
||||
DirBrowser dir(destDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (!m_cancelled)
|
||||
if (!IsStopped())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", destDir, PATH_SEPARATOR, filename);
|
||||
|
||||
if (!FileSystem::DirectoryExists(fullFilename))
|
||||
{
|
||||
m_progressLabel.Format("Checking file %s", filename);
|
||||
m_stageProgress = m_fileCount > 0 ? m_curFile * 1000 / m_fileCount : 1000;
|
||||
m_stageProgress = m_fileCount > 0 ? m_curFile * 1000 / m_fileCount / 2 : 1000;
|
||||
UpdateProgress();
|
||||
m_curFile++;
|
||||
|
||||
if (renamePars)
|
||||
if (checkPars)
|
||||
{
|
||||
CheckParFile(destDir, fullFilename);
|
||||
}
|
||||
@@ -289,22 +313,10 @@ void ParRenamer::CheckRegularFile(const char* destDir, const char* filename)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For files not having par2-extensions: checks if the file is a par2-file and renames
|
||||
* it according to its set-id.
|
||||
*/
|
||||
void ParRenamer::CheckParFile(const char* destDir, const char* filename)
|
||||
{
|
||||
debug("Checking par2-header for %s", filename);
|
||||
|
||||
const char* basename = FileSystem::BaseFileName(filename);
|
||||
const char* extension = strrchr(basename, '.');
|
||||
if (extension && !strcasecmp(extension, ".par2"))
|
||||
{
|
||||
// do not process files already having par2-extension
|
||||
return;
|
||||
}
|
||||
|
||||
DiskFile file;
|
||||
if (!file.Open(filename, DiskFile::omRead))
|
||||
{
|
||||
@@ -337,13 +349,70 @@ void ParRenamer::CheckParFile(const char* destDir, const char* filename)
|
||||
BString<100> setId = header.setid.print().c_str();
|
||||
for (char* p = setId; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
debug("Renaming: %s; setid: %s", FileSystem::BaseFileName(filename), *setId);
|
||||
debug("Storing: %s; setid: %s", FileSystem::BaseFileName(filename), *setId);
|
||||
|
||||
m_parInfoList.emplace_back(filename, setId);
|
||||
}
|
||||
|
||||
void ParRenamer::RenameParFiles(const char* destDir)
|
||||
{
|
||||
if (NeedRenameParFiles())
|
||||
{
|
||||
for (ParInfo& parInfo : m_parInfoList)
|
||||
{
|
||||
RenameParFile(destDir, parInfo.GetFilename(), parInfo.GetSetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ParRenamer::NeedRenameParFiles()
|
||||
{
|
||||
for (ParInfoList::iterator it1 = m_parInfoList.begin(); it1 != m_parInfoList.end(); it1++)
|
||||
{
|
||||
ParInfo& parInfo1 = *it1;
|
||||
|
||||
const char* baseName1 = FileSystem::BaseFileName(parInfo1.GetFilename());
|
||||
|
||||
const char* extension = strrchr(baseName1, '.');
|
||||
if (!extension || strcasecmp(extension, ".par2"))
|
||||
{
|
||||
// file doesn't have "par2" extension
|
||||
return true;
|
||||
}
|
||||
|
||||
int baseLen1;
|
||||
ParParser::ParseParFilename(baseName1, true, &baseLen1, nullptr);
|
||||
|
||||
for (ParInfoList::iterator it2 = it1 + 1; it2 != m_parInfoList.end(); it2++)
|
||||
{
|
||||
ParInfo& parInfo2 = *it2;
|
||||
|
||||
if (!strcmp(parInfo1.GetSetId(), parInfo2.GetSetId()))
|
||||
{
|
||||
const char* baseName2 = FileSystem::BaseFileName(parInfo2.GetFilename());
|
||||
int baseLen2;
|
||||
ParParser::ParseParFilename(baseName2, true, &baseLen2, nullptr);
|
||||
if (baseLen1 != baseLen2 || strncasecmp(baseName1, baseName2, baseLen1))
|
||||
{
|
||||
// same setid but different base file names
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ParRenamer::RenameParFile(const char* destDir, const char* filename, const char* setId)
|
||||
{
|
||||
debug("Renaming: %s; setid: %s", FileSystem::BaseFileName(filename), setId);
|
||||
|
||||
BString<1024> destFileName;
|
||||
int num = 1;
|
||||
while (num == 1 || FileSystem::FileExists(destFileName))
|
||||
{
|
||||
destFileName.Format("%s%c%s.vol%03i+01.PAR2", destDir, PATH_SEPARATOR, *setId, num);
|
||||
destFileName.Format("%s%c%s.vol%03i+01.PAR2", destDir, PATH_SEPARATOR, setId, num);
|
||||
num++;
|
||||
}
|
||||
|
||||
@@ -366,4 +435,13 @@ void ParRenamer::RenameFile(const char* srcFilename, const char* destFileName)
|
||||
RegisterRenamedFile(FileSystem::BaseFileName(srcFilename), FileSystem::BaseFileName(destFileName));
|
||||
}
|
||||
|
||||
void ParRenamer::RenameBadParFiles()
|
||||
{
|
||||
for (CString& parFilename : m_badParList)
|
||||
{
|
||||
BString<1024> destFileName("%s.bad", *parFilename);
|
||||
RenameFile(parFilename, destFileName);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,32 +24,23 @@
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
#include "NString.h"
|
||||
#include "Thread.h"
|
||||
#include "Log.h"
|
||||
|
||||
class ParRenamer : public Thread
|
||||
class ParRenamer
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
psFailed,
|
||||
psSuccess
|
||||
};
|
||||
|
||||
virtual void Run();
|
||||
void Execute();
|
||||
void SetDestDir(const char* destDir) { m_destDir = destDir; }
|
||||
const char* GetInfoName() { return m_infoName; }
|
||||
void SetInfoName(const char* infoName) { m_infoName = infoName; }
|
||||
void SetStatus(EStatus status);
|
||||
EStatus GetStatus() { return m_status; }
|
||||
void Cancel();
|
||||
bool GetCancelled() { return m_cancelled; }
|
||||
int GetRenamedCount() { return m_renamedCount; }
|
||||
bool HasMissedFiles() { return m_hasMissedFiles; }
|
||||
bool HasDamagedParFiles() { return m_hasDamagedParFiles; }
|
||||
void SetDetectMissing(bool detectMissing) { m_detectMissing = detectMissing; }
|
||||
|
||||
protected:
|
||||
virtual void UpdateProgress() {}
|
||||
virtual void Completed() {}
|
||||
virtual bool IsStopped() { return false; };
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3) {}
|
||||
virtual void RegisterParredFile(const char* filename) {}
|
||||
virtual void RegisterRenamedFile(const char* oldFilename, const char* newFileName) {}
|
||||
@@ -72,34 +63,52 @@ private:
|
||||
bool m_fileExists = false;
|
||||
};
|
||||
|
||||
class ParInfo
|
||||
{
|
||||
public:
|
||||
ParInfo(const char* filename, const char* setId) :
|
||||
m_filename(filename), m_setId(setId) {}
|
||||
const char* GetFilename() { return m_filename; }
|
||||
const char* GetSetId() { return m_setId; }
|
||||
private:
|
||||
CString m_filename;
|
||||
CString m_setId;
|
||||
};
|
||||
|
||||
typedef std::deque<FileHash> FileHashList;
|
||||
typedef std::deque<CString> DirList;
|
||||
typedef std::deque<ParInfo> ParInfoList;
|
||||
typedef std::deque<CString> NameList;
|
||||
|
||||
CString m_infoName;
|
||||
CString m_destDir;
|
||||
EStatus m_status;
|
||||
CString m_progressLabel;
|
||||
int m_stageProgress;
|
||||
bool m_cancelled;
|
||||
DirList m_dirList;
|
||||
int m_stageProgress = 0;
|
||||
NameList m_dirList;
|
||||
FileHashList m_fileHashList;
|
||||
int m_fileCount;
|
||||
int m_curFile;
|
||||
int m_renamedCount;
|
||||
bool m_hasMissedFiles;
|
||||
ParInfoList m_parInfoList;
|
||||
NameList m_badParList;
|
||||
NameList m_loadedParList;
|
||||
int m_fileCount = 0;
|
||||
int m_curFile = 0;
|
||||
int m_renamedCount = 0;
|
||||
bool m_hasMissedFiles = false;
|
||||
bool m_detectMissing = false;
|
||||
bool m_hasDamagedParFiles = false;
|
||||
|
||||
void BuildDirList(const char* destDir);
|
||||
void CheckDir(const char* destDir);
|
||||
void LoadParFiles(const char* destDir);
|
||||
void LoadMainParFiles(const char* destDir);
|
||||
void LoadExtraParFiles(const char* destDir);
|
||||
void LoadParFile(const char* parFilename);
|
||||
void CheckFiles(const char* destDir, bool renamePars);
|
||||
void CheckFiles(const char* destDir, bool checkPars);
|
||||
void CheckRegularFile(const char* destDir, const char* filename);
|
||||
void CheckParFile(const char* destDir, const char* filename);
|
||||
bool IsSplittedFragment(const char* filename, const char* correctName);
|
||||
void CheckMissing();
|
||||
void RenameParFiles(const char* destDir);
|
||||
void RenameParFile(const char* destDir, const char* filename, const char* setId);
|
||||
bool NeedRenameParFiles();
|
||||
void RenameFile(const char* srcFilename, const char* destFileName);
|
||||
void Cleanup();
|
||||
void RenameBadParFiles();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "FileSystem.h"
|
||||
#include "Unpack.h"
|
||||
#include "Cleanup.h"
|
||||
#include "Rename.h"
|
||||
#include "Repair.h"
|
||||
#include "NzbFile.h"
|
||||
#include "QueueScript.h"
|
||||
#include "ParParser.h"
|
||||
@@ -37,8 +39,7 @@ PrePostProcessor::PrePostProcessor()
|
||||
{
|
||||
debug("Creating PrePostProcessor");
|
||||
|
||||
m_downloadQueueObserver.m_owner = this;
|
||||
DownloadQueue::Guard()->Attach(&m_downloadQueueObserver);
|
||||
DownloadQueue::Guard()->Attach(this);
|
||||
}
|
||||
|
||||
void PrePostProcessor::Run()
|
||||
@@ -57,49 +58,108 @@ void PrePostProcessor::Run()
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
if (!g_Options->GetTempPausePostprocess())
|
||||
if (!g_Options->GetTempPausePostprocess() && m_queuedJobs)
|
||||
{
|
||||
// check post-queue every 200 msec
|
||||
CheckPostQueue();
|
||||
}
|
||||
|
||||
Util::SetStandByMode(!m_curJob);
|
||||
|
||||
usleep(200 * 1000);
|
||||
}
|
||||
|
||||
WaitJobs();
|
||||
|
||||
debug("Exiting PrePostProcessor-loop");
|
||||
}
|
||||
|
||||
void PrePostProcessor::WaitJobs()
|
||||
{
|
||||
debug("PrePostProcessor: waiting for jobs to complete");
|
||||
|
||||
// wait 5 seconds until all jobs gracefully finish
|
||||
time_t waitStart = Util::CurrentTime();
|
||||
while (Util::CurrentTime() < waitStart + 5)
|
||||
{
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
if (m_activeJobs.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
CheckPostQueue();
|
||||
usleep(200 * 1000);
|
||||
}
|
||||
|
||||
// kill remaining jobs; not safe but we can't wait any longer
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread())
|
||||
{
|
||||
Thread* thread = postJob->GetPostInfo()->GetPostThread();
|
||||
postJob->GetPostInfo()->SetPostThread(nullptr);
|
||||
warn("Terminating active post-process job for %s", postJob->GetName());
|
||||
thread->Kill();
|
||||
delete thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("PrePostProcessor: Jobs are completed");
|
||||
}
|
||||
|
||||
void PrePostProcessor::Stop()
|
||||
{
|
||||
Thread::Stop();
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_parCoordinator.Stop();
|
||||
#endif
|
||||
|
||||
if (m_curJob && m_curJob->GetPostInfo() &&
|
||||
(m_curJob->GetPostInfo()->GetStage() == PostInfo::ptUnpacking ||
|
||||
m_curJob->GetPostInfo()->GetStage() == PostInfo::ptExecutingScript) &&
|
||||
m_curJob->GetPostInfo()->GetPostThread())
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
Thread* postThread = m_curJob->GetPostInfo()->GetPostThread();
|
||||
m_curJob->GetPostInfo()->SetPostThread(nullptr);
|
||||
postThread->SetAutoDestroy(true);
|
||||
postThread->Stop();
|
||||
if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread())
|
||||
{
|
||||
postJob->GetPostInfo()->GetPostThread()->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
|
||||
/**
|
||||
* Reset the state of items after reloading from disk and
|
||||
* delete items which could not be resumed.
|
||||
* Also count the number of post-jobs.
|
||||
*/
|
||||
void PrePostProcessor::SanitisePostQueue()
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
|
||||
{
|
||||
PostInfo* postInfo = nzbInfo->GetPostInfo();
|
||||
if (postInfo)
|
||||
{
|
||||
m_queuedJobs++;
|
||||
if (postInfo->GetStage() == PostInfo::ptExecutingScript ||
|
||||
!FileSystem::DirectoryExists(nzbInfo->GetDestDir()))
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
postInfo->SetWorking(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::DownloadQueueUpdate(void* aspect)
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadQueue::Aspect* queueAspect = (DownloadQueue::Aspect*)Aspect;
|
||||
DownloadQueue::Aspect* queueAspect = (DownloadQueue::Aspect*)aspect;
|
||||
if (queueAspect->action == DownloadQueue::eaNzbFound)
|
||||
{
|
||||
NzbFound(queueAspect->downloadQueue, queueAspect->nzbInfo);
|
||||
@@ -128,9 +188,17 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (m_parCoordinator.AddPar(queueAspect->fileInfo, queueAspect->action == DownloadQueue::eaFileDeleted))
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
return;
|
||||
if (postJob && queueAspect->fileInfo->GetNzbInfo() == postJob &&
|
||||
postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread() &&
|
||||
postJob->GetPostInfo()->GetStage() >= PostInfo::ptLoadingPars &&
|
||||
postJob->GetPostInfo()->GetStage() <= PostInfo::ptVerifyingRepaired &&
|
||||
((RepairController*)postJob->GetPostInfo()->GetPostThread())->AddPar(
|
||||
queueAspect->fileInfo, queueAspect->action == DownloadQueue::eaFileDeleted))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -170,7 +238,8 @@ void PrePostProcessor::NzbAdded(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
||||
{
|
||||
if (g_Options->GetParCheck() != Options::pcForce)
|
||||
{
|
||||
m_parCoordinator.PausePars(downloadQueue, nzbInfo);
|
||||
downloadQueue->EditEntry(nzbInfo->GetId(),
|
||||
DownloadQueue::eaGroupPauseExtraPars, nullptr);
|
||||
}
|
||||
|
||||
if (nzbInfo->GetDeleteStatus() == NzbInfo::dsDupe ||
|
||||
@@ -199,7 +268,7 @@ void PrePostProcessor::NzbDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzbI
|
||||
nzbInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", nzbInfo->GetName());
|
||||
|
||||
nzbInfo->EnterPostProcess();
|
||||
m_jobCount++;
|
||||
m_queuedJobs++;
|
||||
|
||||
if (nzbInfo->GetParStatus() == NzbInfo::psNone &&
|
||||
g_Options->GetParCheck() != Options::pcAlways &&
|
||||
@@ -208,11 +277,6 @@ void PrePostProcessor::NzbDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzbI
|
||||
nzbInfo->SetParStatus(NzbInfo::psSkipped);
|
||||
}
|
||||
|
||||
if (nzbInfo->GetRenameStatus() == NzbInfo::rsNone && !g_Options->GetParRename())
|
||||
{
|
||||
nzbInfo->SetRenameStatus(NzbInfo::rsSkipped);
|
||||
}
|
||||
|
||||
downloadQueue->Save();
|
||||
}
|
||||
else
|
||||
@@ -320,90 +384,137 @@ void PrePostProcessor::DeleteCleanup(NzbInfo* nzbInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::CheckPostQueue()
|
||||
void PrePostProcessor::CheckRequestPar(DownloadQueue* downloadQueue)
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
if (!m_curJob && m_jobCount > 0)
|
||||
{
|
||||
m_curJob = GetNextJob(downloadQueue);
|
||||
}
|
||||
|
||||
if (m_curJob)
|
||||
{
|
||||
PostInfo* postInfo = m_curJob->GetPostInfo();
|
||||
if (!postInfo->GetWorking() && !IsNzbFileDownloading(m_curJob))
|
||||
{
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (postInfo->GetRequestParCheck() &&
|
||||
(postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped ||
|
||||
(postInfo->GetForceRepair() && !postInfo->GetNzbInfo()->GetParFull())) &&
|
||||
g_Options->GetParCheck() != Options::pcManual)
|
||||
{
|
||||
postInfo->SetForceParFull(postInfo->GetNzbInfo()->GetParStatus() > NzbInfo::psSkipped);
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psNone);
|
||||
postInfo->SetRequestParCheck(false);
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
postInfo->GetNzbInfo()->GetScriptStatuses()->clear();
|
||||
DeletePostThread(postInfo);
|
||||
}
|
||||
else if (postInfo->GetRequestParCheck() && postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped &&
|
||||
g_Options->GetParCheck() == Options::pcManual)
|
||||
{
|
||||
postInfo->SetRequestParCheck(false);
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psManual);
|
||||
DeletePostThread(postInfo);
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
PostInfo* postInfo = postJob->GetPostInfo();
|
||||
|
||||
if (!postInfo->GetNzbInfo()->GetFileList()->empty())
|
||||
if (postInfo->GetRequestParCheck() &&
|
||||
(postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped ||
|
||||
(postInfo->GetForceRepair() && !postInfo->GetNzbInfo()->GetParFull())) &&
|
||||
g_Options->GetParCheck() != Options::pcManual)
|
||||
{
|
||||
postInfo->SetForceParFull(postInfo->GetNzbInfo()->GetParStatus() > NzbInfo::psSkipped);
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psNone);
|
||||
postInfo->SetRequestParCheck(false);
|
||||
postInfo->GetNzbInfo()->GetScriptStatuses()->clear();
|
||||
postInfo->SetWorking(false);
|
||||
}
|
||||
else if (postInfo->GetRequestParCheck() &&
|
||||
postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped &&
|
||||
g_Options->GetParCheck() == Options::pcManual)
|
||||
{
|
||||
postInfo->SetRequestParCheck(false);
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psManual);
|
||||
|
||||
if (!postInfo->GetNzbInfo()->GetFileList()->empty())
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"Downloading all remaining files for manual par-check for %s", postInfo->GetNzbInfo()->GetName());
|
||||
downloadQueue->EditEntry(postInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupResume, nullptr);
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"There are no par-files remain for download for %s", postInfo->GetNzbInfo()->GetName());
|
||||
}
|
||||
postInfo->SetWorking(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrePostProcessor::CleanupJobs(DownloadQueue* downloadQueue)
|
||||
{
|
||||
m_activeJobs.erase(std::remove_if(m_activeJobs.begin(), m_activeJobs.end(),
|
||||
[processor = this, downloadQueue](NzbInfo* postJob)
|
||||
{
|
||||
PostInfo* postInfo = postJob->GetPostInfo();
|
||||
if (!postInfo->GetWorking())
|
||||
{
|
||||
delete postInfo->GetPostThread();
|
||||
postInfo->SetPostThread(nullptr);
|
||||
|
||||
postInfo->SetStageTime(0);
|
||||
postInfo->SetStageProgress(0);
|
||||
postInfo->SetFileProgress(0);
|
||||
postInfo->SetProgressLabel("");
|
||||
|
||||
if (postInfo->GetStartTime() > 0)
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"Downloading all remaining files for manual par-check for %s", postInfo->GetNzbInfo()->GetName());
|
||||
downloadQueue->EditEntry(postInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupResume, 0, nullptr);
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
postJob->SetPostTotalSec(postJob->GetPostTotalSec() +
|
||||
(int)(Util::CurrentTime() - postInfo->GetStartTime()));
|
||||
postInfo->SetStartTime(0);
|
||||
}
|
||||
|
||||
if (postInfo->GetStage() == PostInfo::ptFinished || postInfo->GetDeleted())
|
||||
{
|
||||
processor->JobCompleted(downloadQueue, postInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"There are no par-files remain for download for %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (postInfo->GetDeleted())
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
|
||||
if (postInfo->GetStage() == PostInfo::ptQueued &&
|
||||
(!g_Options->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority()))
|
||||
{
|
||||
DeletePostThread(postInfo);
|
||||
StartJob(downloadQueue, postInfo);
|
||||
}
|
||||
else if (postInfo->GetStage() == PostInfo::ptFinished)
|
||||
{
|
||||
UpdatePauseState(false, nullptr);
|
||||
JobCompleted(downloadQueue, postInfo);
|
||||
}
|
||||
else if (!g_Options->GetPausePostProcess())
|
||||
{
|
||||
error("Internal error: invalid state in post-processor");
|
||||
// TODO: cancel (delete) current job
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
m_activeJobs.end());
|
||||
}
|
||||
|
||||
NzbInfo* PrePostProcessor::GetNextJob(DownloadQueue* downloadQueue)
|
||||
bool PrePostProcessor::CanRunMoreJobs(bool* allowPar)
|
||||
{
|
||||
int totalJobs = (int)m_activeJobs.size();
|
||||
int parJobs = 0;
|
||||
int otherJobs = 0;
|
||||
bool repairJobs = false;
|
||||
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
bool parJob = postJob->GetPostInfo()->GetStage() >= PostInfo::ptLoadingPars &&
|
||||
postJob->GetPostInfo()->GetStage() <= PostInfo::ptVerifyingRepaired;
|
||||
repairJobs |= postJob->GetPostInfo()->GetStage() == PostInfo::ptRepairing;
|
||||
parJobs += parJob ? 1 : 0;
|
||||
otherJobs += parJob ? 0 : 1;
|
||||
}
|
||||
|
||||
switch (g_Options->GetPostStrategy())
|
||||
{
|
||||
case Options::ppSequential:
|
||||
*allowPar = true;
|
||||
return totalJobs == 0;
|
||||
|
||||
case Options::ppBalanced:
|
||||
*allowPar = parJobs == 0;
|
||||
return otherJobs == 0 && (parJobs == 0 || repairJobs);
|
||||
|
||||
case Options::ppAggressive:
|
||||
*allowPar = parJobs < 1;
|
||||
return totalJobs < 3;
|
||||
|
||||
case Options::ppRocket:
|
||||
*allowPar = parJobs < 2;
|
||||
return totalJobs < 6;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NzbInfo* PrePostProcessor::PickNextJob(DownloadQueue* downloadQueue, bool allowPar)
|
||||
{
|
||||
NzbInfo* nzbInfo = nullptr;
|
||||
|
||||
for (NzbInfo* nzbInfo1: downloadQueue->GetQueue())
|
||||
{
|
||||
if (nzbInfo1->GetPostInfo() && !g_QueueScriptCoordinator->HasJob(nzbInfo1->GetId(), nullptr) &&
|
||||
if (nzbInfo1->GetPostInfo() && !nzbInfo1->GetPostInfo()->GetWorking() &&
|
||||
!g_QueueScriptCoordinator->HasJob(nzbInfo1->GetId(), nullptr) &&
|
||||
(!nzbInfo || nzbInfo1->GetPriority() > nzbInfo->GetPriority()) &&
|
||||
(!g_Options->GetPausePostProcess() || nzbInfo1->GetForcePriority()))
|
||||
(!g_Options->GetPausePostProcess() || nzbInfo1->GetForcePriority()) &&
|
||||
(allowPar || !nzbInfo1->GetPostInfo()->GetNeedParCheck()) &&
|
||||
IsNzbFileCompleted(nzbInfo1, true))
|
||||
{
|
||||
nzbInfo = nzbInfo1;
|
||||
}
|
||||
@@ -412,73 +523,92 @@ NzbInfo* PrePostProcessor::GetNextJob(DownloadQueue* downloadQueue)
|
||||
return nzbInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of items after reloading from disk and
|
||||
* delete items which could not be resumed.
|
||||
* Also count the number of post-jobs.
|
||||
*/
|
||||
void PrePostProcessor::SanitisePostQueue()
|
||||
void PrePostProcessor::CheckPostQueue()
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
|
||||
|
||||
size_t countBefore = m_activeJobs.size();
|
||||
CheckRequestPar(downloadQueue);
|
||||
CleanupJobs(downloadQueue);
|
||||
bool changed = m_activeJobs.size() != countBefore;
|
||||
|
||||
bool allowPar;
|
||||
while (CanRunMoreJobs(&allowPar) && !IsStopped())
|
||||
{
|
||||
PostInfo* postInfo = nzbInfo->GetPostInfo();
|
||||
if (postInfo)
|
||||
NzbInfo* postJob = PickNextJob(downloadQueue, allowPar);
|
||||
if (!postJob)
|
||||
{
|
||||
m_jobCount++;
|
||||
if (postInfo->GetStage() == PostInfo::ptExecutingScript ||
|
||||
!FileSystem::DirectoryExists(nzbInfo->GetDestDir()))
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Util::SetStandByMode(false);
|
||||
|
||||
m_activeJobs.push_back(postJob);
|
||||
|
||||
PostInfo* postInfo = postJob->GetPostInfo();
|
||||
if (postInfo->GetStage() == PostInfo::ptQueued &&
|
||||
(!g_Options->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority()))
|
||||
{
|
||||
StartJob(downloadQueue, postInfo, allowPar);
|
||||
CheckRequestPar(downloadQueue);
|
||||
CleanupJobs(downloadQueue);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
downloadQueue->Save();
|
||||
UpdatePauseState();
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::DeletePostThread(PostInfo* postInfo)
|
||||
{
|
||||
delete postInfo->GetPostThread();
|
||||
postInfo->SetPostThread(nullptr);
|
||||
}
|
||||
|
||||
void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo)
|
||||
void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo, bool allowPar)
|
||||
{
|
||||
if (!postInfo->GetStartTime())
|
||||
{
|
||||
postInfo->SetStartTime(Util::CurrentTime());
|
||||
}
|
||||
postInfo->SetStageTime(Util::CurrentTime());
|
||||
postInfo->SetStageProgress(0);
|
||||
postInfo->SetFileProgress(0);
|
||||
postInfo->SetProgressLabel("");
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (postInfo->GetNzbInfo()->GetRenameStatus() == NzbInfo::rsNone &&
|
||||
postInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsNone)
|
||||
if (postInfo->GetNzbInfo()->GetParRenameStatus() == NzbInfo::rsNone &&
|
||||
postInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsNone &&
|
||||
g_Options->GetParRename())
|
||||
{
|
||||
UpdatePauseState(g_Options->GetParPauseQueue(), "par-rename");
|
||||
m_parCoordinator.StartParRenameJob(postInfo);
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptParRenaming);
|
||||
RenameController::StartJob(postInfo, RenameController::jkPar);
|
||||
return;
|
||||
}
|
||||
else if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psNone &&
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psNone &&
|
||||
postInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsNone)
|
||||
{
|
||||
if (ParParser::FindMainPars(postInfo->GetNzbInfo()->GetDestDir(), nullptr))
|
||||
{
|
||||
UpdatePauseState(g_Options->GetParPauseQueue(), "par-check");
|
||||
m_parCoordinator.StartParCheckJob(postInfo);
|
||||
if (!allowPar)
|
||||
{
|
||||
postInfo->SetNeedParCheck(true);
|
||||
return;
|
||||
}
|
||||
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptLoadingPars);
|
||||
postInfo->SetNeedParCheck(false);
|
||||
RepairController::StartJob(postInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"Nothing to par-check for %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psSkipped);
|
||||
postInfo->SetWorking(false);
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSkipped &&
|
||||
|
||||
if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSkipped &&
|
||||
((g_Options->GetParScan() != Options::psDupe &&
|
||||
postInfo->GetNzbInfo()->CalcHealth() < postInfo->GetNzbInfo()->CalcCriticalHealth(false) &&
|
||||
postInfo->GetNzbInfo()->CalcCriticalHealth(false) < 1000) ||
|
||||
@@ -500,7 +630,8 @@ void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo
|
||||
postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psFailure);
|
||||
return;
|
||||
}
|
||||
else if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSkipped &&
|
||||
|
||||
if (postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSkipped &&
|
||||
postInfo->GetNzbInfo()->GetFailedSize() - postInfo->GetNzbInfo()->GetParFailedSize() > 0 &&
|
||||
ParParser::FindMainPars(postInfo->GetNzbInfo()->GetDestDir(), nullptr))
|
||||
{
|
||||
@@ -513,15 +644,23 @@ void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo
|
||||
#endif
|
||||
|
||||
NzbParameter* unpackParameter = postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:", false);
|
||||
bool unpackParam = !(unpackParameter && !strcasecmp(unpackParameter->GetValue(), "no"));
|
||||
bool unpack = unpackParam && postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usNone &&
|
||||
bool wantUnpack = !(unpackParameter && !strcasecmp(unpackParameter->GetValue(), "no"));
|
||||
bool unpack = wantUnpack && postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usNone &&
|
||||
postInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsNone;
|
||||
|
||||
if (postInfo->GetNzbInfo()->GetRarRenameStatus() == NzbInfo::rsNone &&
|
||||
unpack && g_Options->GetRarRename())
|
||||
{
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptRarRenaming);
|
||||
RenameController::StartJob(postInfo, RenameController::jkRar);
|
||||
return;
|
||||
}
|
||||
|
||||
bool parFailed = postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psFailure ||
|
||||
postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psRepairPossible ||
|
||||
postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psManual;
|
||||
|
||||
bool cleanup = !unpack &&
|
||||
bool cleanup = !unpack && wantUnpack &&
|
||||
postInfo->GetNzbInfo()->GetCleanupStatus() == NzbInfo::csNone &&
|
||||
!Util::EmptyStr(g_Options->GetExtCleanupDisk()) &&
|
||||
((postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSuccess &&
|
||||
@@ -548,8 +687,6 @@ void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo
|
||||
!strncmp(postInfo->GetNzbInfo()->GetDestDir(), g_Options->GetInterDir(), strlen(g_Options->GetInterDir())) &&
|
||||
postInfo->GetNzbInfo()->GetDestDir()[strlen(g_Options->GetInterDir())] == PATH_SEPARATOR;
|
||||
|
||||
bool postScript = true;
|
||||
|
||||
if (unpack && parFailed)
|
||||
{
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkWarning,
|
||||
@@ -559,55 +696,38 @@ void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo
|
||||
unpack = false;
|
||||
}
|
||||
|
||||
if (!unpack && !moveInter && !postScript)
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptFinished);
|
||||
return;
|
||||
}
|
||||
|
||||
postInfo->SetProgressLabel(unpack ? "Unpacking" : moveInter ? "Moving" : "Executing post-process-script");
|
||||
postInfo->SetWorking(true);
|
||||
postInfo->SetStage(unpack ? PostInfo::ptUnpacking : moveInter ? PostInfo::ptMoving : PostInfo::ptExecutingScript);
|
||||
postInfo->SetFileProgress(0);
|
||||
postInfo->SetStageProgress(0);
|
||||
|
||||
downloadQueue->Save();
|
||||
|
||||
postInfo->SetStageTime(Util::CurrentTime());
|
||||
|
||||
if (unpack)
|
||||
{
|
||||
UpdatePauseState(g_Options->GetUnpackPauseQueue(), "unpack");
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptUnpacking);
|
||||
UnpackController::StartJob(postInfo);
|
||||
}
|
||||
else if (cleanup)
|
||||
{
|
||||
UpdatePauseState(g_Options->GetUnpackPauseQueue() || g_Options->GetScriptPauseQueue(), "cleanup");
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptCleaningUp);
|
||||
CleanupController::StartJob(postInfo);
|
||||
}
|
||||
else if (moveInter)
|
||||
{
|
||||
UpdatePauseState(g_Options->GetUnpackPauseQueue() || g_Options->GetScriptPauseQueue(), "move");
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptMoving);
|
||||
MoveController::StartJob(postInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePauseState(g_Options->GetScriptPauseQueue(), "post-process-script");
|
||||
EnterStage(downloadQueue, postInfo, PostInfo::ptExecutingScript);
|
||||
PostScriptController::StartJob(postInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::EnterStage(DownloadQueue* downloadQueue, PostInfo* postInfo, PostInfo::EStage stage)
|
||||
{
|
||||
postInfo->SetWorking(true);
|
||||
postInfo->SetStage(stage);
|
||||
}
|
||||
|
||||
void PrePostProcessor::JobCompleted(DownloadQueue* downloadQueue, PostInfo* postInfo)
|
||||
{
|
||||
NzbInfo* nzbInfo = postInfo->GetNzbInfo();
|
||||
|
||||
if (postInfo->GetStartTime() > 0)
|
||||
{
|
||||
nzbInfo->SetPostTotalSec((int)(Util::CurrentTime() - postInfo->GetStartTime()));
|
||||
postInfo->SetStartTime(0);
|
||||
}
|
||||
|
||||
DeletePostThread(postInfo);
|
||||
nzbInfo->LeavePostProcess();
|
||||
|
||||
if (IsNzbFileCompleted(nzbInfo, true))
|
||||
@@ -615,13 +735,7 @@ void PrePostProcessor::JobCompleted(DownloadQueue* downloadQueue, PostInfo* post
|
||||
NzbCompleted(downloadQueue, nzbInfo, false);
|
||||
}
|
||||
|
||||
if (nzbInfo == m_curJob)
|
||||
{
|
||||
m_curJob = nullptr;
|
||||
}
|
||||
m_jobCount--;
|
||||
|
||||
downloadQueue->Save();
|
||||
m_queuedJobs--;
|
||||
}
|
||||
|
||||
bool PrePostProcessor::IsNzbFileCompleted(NzbInfo* nzbInfo, bool ignorePausedPars)
|
||||
@@ -643,39 +757,52 @@ bool PrePostProcessor::IsNzbFileCompleted(NzbInfo* nzbInfo, bool ignorePausedPar
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrePostProcessor::IsNzbFileDownloading(NzbInfo* nzbInfo)
|
||||
void PrePostProcessor::UpdatePauseState()
|
||||
{
|
||||
if (nzbInfo->GetActiveDownloads())
|
||||
bool needPause = false;
|
||||
for (NzbInfo* postJob : m_activeJobs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (FileInfo* fileInfo : nzbInfo->GetFileList())
|
||||
{
|
||||
if (!fileInfo->GetPaused())
|
||||
switch (postJob->GetPostInfo()->GetStage())
|
||||
{
|
||||
return true;
|
||||
case PostInfo::ptLoadingPars:
|
||||
case PostInfo::ptVerifyingSources:
|
||||
case PostInfo::ptRepairing:
|
||||
case PostInfo::ptVerifyingRepaired:
|
||||
case PostInfo::ptParRenaming:
|
||||
needPause |= g_Options->GetParPauseQueue();
|
||||
break;
|
||||
|
||||
case PostInfo::ptRarRenaming:
|
||||
case PostInfo::ptUnpacking:
|
||||
case PostInfo::ptCleaningUp:
|
||||
case PostInfo::ptMoving:
|
||||
needPause |= g_Options->GetUnpackPauseQueue();
|
||||
break;
|
||||
|
||||
case PostInfo::ptExecutingScript:
|
||||
needPause |= g_Options->GetScriptPauseQueue();
|
||||
break;
|
||||
|
||||
case PostInfo::ptQueued:
|
||||
case PostInfo::ptFinished:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrePostProcessor::UpdatePauseState(bool needPause, const char* reason)
|
||||
{
|
||||
if (needPause && !g_Options->GetTempPauseDownload())
|
||||
{
|
||||
info("Pausing download before %s", reason);
|
||||
info("Pausing download before post-processing");
|
||||
}
|
||||
else if (!needPause && g_Options->GetTempPauseDownload())
|
||||
{
|
||||
info("Unpausing download after %s", m_pauseReason);
|
||||
info("Unpausing download after post-processing");
|
||||
}
|
||||
|
||||
g_Options->SetTempPauseDownload(needPause);
|
||||
m_pauseReason = reason;
|
||||
}
|
||||
|
||||
bool PrePostProcessor::EditList(DownloadQueue* downloadQueue, IdList* idList, DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
bool PrePostProcessor::EditList(DownloadQueue* downloadQueue, IdList* idList,
|
||||
DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
debug("Edit-command for post-processor received");
|
||||
switch (action)
|
||||
@@ -704,19 +831,9 @@ bool PrePostProcessor::PostQueueDelete(DownloadQueue* downloadQueue, IdList* idL
|
||||
postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo,
|
||||
"Deleting active post-job %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->SetDeleted(true);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (PostInfo::ptLoadingPars <= postInfo->GetStage() && postInfo->GetStage() <= PostInfo::ptRenaming)
|
||||
{
|
||||
if (m_parCoordinator.Cancel())
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (postInfo->GetPostThread())
|
||||
{
|
||||
debug("Terminating %s for %s", (postInfo->GetStage() == PostInfo::ptUnpacking ? "unpack" : "post-process-script"), postInfo->GetNzbInfo()->GetName());
|
||||
debug("Terminating post-process thread for %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->GetPostThread()->Stop();
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -24,50 +24,45 @@
|
||||
#include "Thread.h"
|
||||
#include "Observer.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "ParCoordinator.h"
|
||||
|
||||
class PrePostProcessor : public Thread
|
||||
class PrePostProcessor : public Thread, public Observer
|
||||
{
|
||||
public:
|
||||
PrePostProcessor();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
bool HasMoreJobs() { return m_jobCount > 0; }
|
||||
int GetJobCount() { return m_jobCount; }
|
||||
bool HasMoreJobs() { return m_queuedJobs > 0; }
|
||||
int GetJobCount() { return m_queuedJobs; }
|
||||
bool EditList(DownloadQueue* downloadQueue, IdList* idList, DownloadQueue::EEditAction action,
|
||||
int offset, const char* text);
|
||||
const char* args);
|
||||
void NzbAdded(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
void NzbDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
|
||||
protected:
|
||||
virtual void Update(Subject* caller, void* aspect) { DownloadQueueUpdate(aspect); }
|
||||
|
||||
private:
|
||||
class DownloadQueueObserver: public Observer
|
||||
{
|
||||
public:
|
||||
PrePostProcessor* m_owner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { m_owner->DownloadQueueUpdate(Caller, Aspect); }
|
||||
};
|
||||
int m_queuedJobs = 0;
|
||||
RawNzbList m_activeJobs;
|
||||
|
||||
ParCoordinator m_parCoordinator;
|
||||
DownloadQueueObserver m_downloadQueueObserver;
|
||||
int m_jobCount = 0;
|
||||
NzbInfo* m_curJob = nullptr;
|
||||
const char* m_pauseReason = nullptr;
|
||||
|
||||
bool IsNzbFileCompleted(NzbInfo* nzbInfo, bool ignorePausedPars);
|
||||
bool IsNzbFileDownloading(NzbInfo* nzbInfo);
|
||||
void CheckPostQueue();
|
||||
void JobCompleted(DownloadQueue* downloadQueue, PostInfo* postInfo);
|
||||
void StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo);
|
||||
void CheckRequestPar(DownloadQueue* downloadQueue);
|
||||
void CleanupJobs(DownloadQueue* downloadQueue);
|
||||
bool CanRunMoreJobs(bool* allowPar);
|
||||
NzbInfo* PickNextJob(DownloadQueue* downloadQueue, bool allowPar);
|
||||
void StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo, bool allowPar);
|
||||
void EnterStage(DownloadQueue* downloadQueue, PostInfo* postInfo, PostInfo::EStage stage);
|
||||
void SanitisePostQueue();
|
||||
void UpdatePauseState(bool needPause, const char* reason);
|
||||
void UpdatePauseState();
|
||||
void NzbFound(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
void NzbDeleted(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
void NzbCompleted(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, bool saveQueue);
|
||||
void JobCompleted(DownloadQueue* downloadQueue, PostInfo* postInfo);
|
||||
bool PostQueueDelete(DownloadQueue* downloadQueue, IdList* idList);
|
||||
void DeletePostThread(PostInfo* postInfo);
|
||||
NzbInfo* GetNextJob(DownloadQueue* downloadQueue);
|
||||
void DownloadQueueUpdate(Subject* Caller, void* Aspect);
|
||||
void DownloadQueueUpdate(void* aspect);
|
||||
void DeleteCleanup(NzbInfo* nzbInfo);
|
||||
bool IsNzbFileCompleted(NzbInfo* nzbInfo, bool ignorePausedPars);
|
||||
void WaitJobs();
|
||||
};
|
||||
|
||||
extern PrePostProcessor* g_PrePostProcessor;
|
||||
|
||||
730
daemon/postprocess/RarReader.cpp
Normal file
730
daemon/postprocess/RarReader.cpp
Normal file
@@ -0,0 +1,730 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
|
||||
#include "RarReader.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
// RAR3 constants
|
||||
|
||||
static const uint16 RAR3_MAIN_VOLUME = 0x0001;
|
||||
static const uint16 RAR3_MAIN_NEWNUMBERING = 0x0010;
|
||||
static const uint16 RAR3_MAIN_PASSWORD = 0x0080;
|
||||
|
||||
static const uint8 RAR3_BLOCK_MAIN = 0x73; // s
|
||||
static const uint8 RAR3_BLOCK_FILE = 0x74; // t
|
||||
static const uint8 RAR3_BLOCK_ENDARC = 0x7b; // {
|
||||
|
||||
static const uint16 RAR3_BLOCK_ADDSIZE = 0x8000;
|
||||
|
||||
static const uint16 RAR3_FILE_ADDSIZE = 0x0100;
|
||||
static const uint16 RAR3_FILE_SPLITBEFORE = 0x0001;
|
||||
static const uint16 RAR3_FILE_SPLITAFTER = 0x0002;
|
||||
|
||||
static const uint16 RAR3_ENDARC_NEXTVOL = 0x0001;
|
||||
static const uint16 RAR3_ENDARC_DATACRC = 0x0002;
|
||||
static const uint16 RAR3_ENDARC_VOLNUMBER = 0x0008;
|
||||
|
||||
// RAR5 constants
|
||||
|
||||
static const uint8 RAR5_BLOCK_MAIN = 1;
|
||||
static const uint8 RAR5_BLOCK_FILE = 2;
|
||||
static const uint8 RAR5_BLOCK_ENCRYPTION = 4;
|
||||
static const uint8 RAR5_BLOCK_ENDARC = 5;
|
||||
|
||||
static const uint8 RAR5_BLOCK_EXTRADATA = 0x01;
|
||||
static const uint8 RAR5_BLOCK_DATAAREA = 0x02;
|
||||
static const uint8 RAR5_BLOCK_SPLITBEFORE = 0x08;
|
||||
static const uint8 RAR5_BLOCK_SPLITAFTER = 0x10;
|
||||
|
||||
static const uint8 RAR5_MAIN_ISVOL = 0x01;
|
||||
static const uint8 RAR5_MAIN_VOLNR = 0x02;
|
||||
|
||||
static const uint8 RAR5_FILE_TIME = 0x02;
|
||||
static const uint8 RAR5_FILE_CRC = 0x04;
|
||||
static const uint8 RAR5_FILE_EXTRATIME = 0x03;
|
||||
static const uint8 RAR5_FILE_EXTRATIMEUNIXFORMAT = 0x01;
|
||||
|
||||
static const uint8 RAR5_ENDARC_NEXTVOL = 0x01;
|
||||
|
||||
|
||||
bool RarVolume::Read()
|
||||
{
|
||||
debug("Checking file %s", *m_filename);
|
||||
|
||||
DiskFile file;
|
||||
if (!file.Open(m_filename, DiskFile::omRead))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_version = DetectRarVersion(file);
|
||||
file.Seek(0);
|
||||
|
||||
bool ok = false;
|
||||
|
||||
switch (m_version)
|
||||
{
|
||||
case 3:
|
||||
ok = ReadRar3Volume(file);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
ok = ReadRar5Volume(file);
|
||||
break;
|
||||
}
|
||||
|
||||
file.Close();
|
||||
DecryptFree();
|
||||
|
||||
LogDebugInfo();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int RarVolume::DetectRarVersion(DiskFile& file)
|
||||
{
|
||||
static char RAR3_SIGNATURE[] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 };
|
||||
static char RAR5_SIGNATURE[] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00 };
|
||||
|
||||
char fileSignature[8];
|
||||
|
||||
int cnt = 0;
|
||||
cnt = (int)file.Read(fileSignature, sizeof(fileSignature));
|
||||
|
||||
bool rar5 = cnt == sizeof(fileSignature) && !strcmp(RAR5_SIGNATURE, fileSignature);
|
||||
bool rar3 = !rar5 && cnt == sizeof(fileSignature) && !strcmp(RAR3_SIGNATURE, fileSignature);
|
||||
|
||||
return rar3 ? 3 : rar5 ? 5 : 0;
|
||||
}
|
||||
|
||||
bool RarVolume::Read(DiskFile& file, RarBlock* block, void* buffer, int64 size)
|
||||
{
|
||||
if (m_encrypted)
|
||||
{
|
||||
if (!DecryptRead(file, buffer, size)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file.Read(buffer, size) != size) return false;
|
||||
}
|
||||
|
||||
if (block)
|
||||
{
|
||||
block->trailsize -= size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::Read16(DiskFile& file, RarBlock* block, uint16* result)
|
||||
{
|
||||
uint8 buf[2];
|
||||
if (!Read(file, block, buf, sizeof(buf))) return false;
|
||||
*result = ((uint16)buf[1] << 8) + buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::Read32(DiskFile& file, RarBlock* block, uint32* result)
|
||||
{
|
||||
uint8 buf[4];
|
||||
if (!Read(file, block, buf, sizeof(buf))) return false;
|
||||
*result = ((uint32)buf[3] << 24) + ((uint32)buf[2] << 16) + ((uint32)buf[1] << 8) + buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::ReadV(DiskFile& file, RarBlock* block, uint64* result)
|
||||
{
|
||||
*result = 0;
|
||||
uint8 val;
|
||||
uint8 bits = 0;
|
||||
do
|
||||
{
|
||||
if (Read(file, block, &val, sizeof(val)) != sizeof(val)) return false;
|
||||
*result += (uint64)(val & 0x7f) << bits;
|
||||
bits += 7;
|
||||
} while (val & 0x80);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::Skip(DiskFile& file, RarBlock* block, int64 size)
|
||||
{
|
||||
uint8 buf[256];
|
||||
while (size > 0)
|
||||
{
|
||||
int64 len = size <= sizeof(buf) ? size : sizeof(buf);
|
||||
if (!Read(file, block, buf, len)) return false;
|
||||
size -= len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::ReadRar3Volume(DiskFile& file)
|
||||
{
|
||||
debug("Reading rar3-file %s", *m_filename);
|
||||
|
||||
while (!file.Eof())
|
||||
{
|
||||
RarBlock block = ReadRar3Block(file);
|
||||
if (!block.type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block.type == RAR3_BLOCK_MAIN)
|
||||
{
|
||||
if (block.flags & RAR3_MAIN_PASSWORD)
|
||||
{
|
||||
m_encrypted = true;
|
||||
if (m_password.Empty()) return false;
|
||||
}
|
||||
m_newNaming = block.flags & RAR3_MAIN_NEWNUMBERING;
|
||||
m_multiVolume = block.flags & RAR3_MAIN_VOLUME;
|
||||
}
|
||||
|
||||
else if (block.type == RAR3_BLOCK_FILE)
|
||||
{
|
||||
RarFile innerFile;
|
||||
if (!ReadRar3File(file, block, innerFile)) return false;
|
||||
m_files.push_back(std::move(innerFile));
|
||||
}
|
||||
|
||||
else if (block.type == RAR3_BLOCK_ENDARC)
|
||||
{
|
||||
if (block.flags & RAR3_ENDARC_DATACRC)
|
||||
{
|
||||
if (!Skip(file, &block, 4)) return false;
|
||||
}
|
||||
if (block.flags & RAR3_ENDARC_VOLNUMBER)
|
||||
{
|
||||
if (!Read32(file, &block, &m_volumeNo)) return false;
|
||||
m_hasNextVolume = (block.flags & RAR3_ENDARC_NEXTVOL) != 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
else if (block.type < 0x72 || block.type > 0x7b)
|
||||
{
|
||||
// inlvaid block type
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64 skip = block.trailsize;
|
||||
if (m_encrypted)
|
||||
{
|
||||
skip -= 16 - m_decryptPos;
|
||||
m_decryptPos = 16;
|
||||
DecryptFree();
|
||||
}
|
||||
|
||||
if (!file.Seek(skip, DiskFile::soCur))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RarVolume::RarBlock RarVolume::ReadRar3Block(DiskFile& file)
|
||||
{
|
||||
RarBlock block {0};
|
||||
uint8 salt[8];
|
||||
|
||||
if (m_encrypted &&
|
||||
!(file.Read(salt, sizeof(salt)) == sizeof(salt) &&
|
||||
DecryptRar3Prepare(salt) && DecryptInit(128)))
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
|
||||
uint8 buf[7];
|
||||
|
||||
if (!Read(file, nullptr, &buf, sizeof(buf))) return {0};
|
||||
block.crc = ((uint16)buf[1] << 8) + buf[0];
|
||||
block.type = buf[2];
|
||||
block.flags = ((uint16)buf[4] << 8) + buf[3];
|
||||
uint16 size = ((uint16)buf[6] << 8) + buf[5];
|
||||
|
||||
uint32 blocksize = size;
|
||||
block.trailsize = blocksize - sizeof(buf);
|
||||
|
||||
uint8 addbuf[4];
|
||||
if ((block.flags & RAR3_BLOCK_ADDSIZE) && !Read(file, nullptr, &addbuf, sizeof(addbuf)))
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
block.addsize = ((uint32)addbuf[3] << 24) + ((uint32)addbuf[2] << 16) + ((uint32)addbuf[1] << 8) + addbuf[0];
|
||||
|
||||
if (block.flags & RAR3_BLOCK_ADDSIZE)
|
||||
{
|
||||
blocksize += (uint32)block.addsize;
|
||||
block.trailsize = blocksize - sizeof(buf) - 4;
|
||||
}
|
||||
|
||||
static int num = 0;
|
||||
debug("%i) %llu, %i, %i, %i, %u, %llu", ++num, (long long)block.crc, (int)block.type, (int)block.flags, (int)size, (int)block.addsize, (long long)block.trailsize);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
bool RarVolume::ReadRar3File(DiskFile& file, RarBlock& block, RarFile& innerFile)
|
||||
{
|
||||
innerFile.m_splitBefore = block.flags & RAR3_FILE_SPLITBEFORE;
|
||||
innerFile.m_splitAfter = block.flags & RAR3_FILE_SPLITAFTER;
|
||||
|
||||
uint16 namelen;
|
||||
|
||||
uint32 size;
|
||||
if (!Read32(file, &block, &size)) return false;
|
||||
innerFile.m_size = size;
|
||||
|
||||
if (!Skip(file, &block, 1)) return false;
|
||||
if (!Skip(file, &block, 4)) return false;
|
||||
if (!Read32(file, &block, &innerFile.m_time)) return false;
|
||||
if (!Skip(file, &block, 2)) return false;
|
||||
if (!Read16(file, &block, &namelen)) return false;
|
||||
if (!Read32(file, &block, &innerFile.m_attr)) return false;
|
||||
|
||||
if (block.flags & RAR3_FILE_ADDSIZE)
|
||||
{
|
||||
uint32 highsize;
|
||||
if (!Read32(file, &block, &highsize)) return false;
|
||||
block.trailsize += (uint64)highsize << 32;
|
||||
|
||||
if (!Read32(file, &block, &highsize)) return false;
|
||||
innerFile.m_size += (uint64)highsize << 32;
|
||||
}
|
||||
|
||||
if (namelen > 8192) return false; // an error
|
||||
CharBuffer name;
|
||||
name.Reserve(namelen + 1);
|
||||
if (!Read(file, &block, (char*)name, namelen)) return false;
|
||||
name[namelen] = '\0';
|
||||
innerFile.m_filename = name;
|
||||
debug("%i, %i, %s", (int)block.trailsize, (int)namelen, (const char*)name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::ReadRar5Volume(DiskFile& file)
|
||||
{
|
||||
debug("Reading rar5-file %s", *m_filename);
|
||||
|
||||
file.Seek(8);
|
||||
|
||||
while (!file.Eof())
|
||||
{
|
||||
RarBlock block = ReadRar5Block(file);
|
||||
if (!block.type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block.type == RAR5_BLOCK_MAIN)
|
||||
{
|
||||
uint64 arcflags;
|
||||
if (!ReadV(file, &block, &arcflags)) return false;
|
||||
if (arcflags & RAR5_MAIN_VOLNR)
|
||||
{
|
||||
uint64 volnr;
|
||||
if (!ReadV(file, &block, &volnr)) return false;
|
||||
m_volumeNo = (uint32)volnr;
|
||||
}
|
||||
m_newNaming = true;
|
||||
m_multiVolume = (arcflags & RAR5_MAIN_ISVOL) != 0;
|
||||
}
|
||||
|
||||
else if (block.type == RAR5_BLOCK_ENCRYPTION)
|
||||
{
|
||||
uint64 val;
|
||||
if (!ReadV(file, &block, &val)) return false;
|
||||
if (val != 0) return false; // supporting only AES
|
||||
if (!ReadV(file, &block, &val)) return false;
|
||||
uint8 kdfCount;
|
||||
uint8 salt[16];
|
||||
if (!Read(file, &block, &kdfCount, sizeof(kdfCount))) return false;
|
||||
if (!Read(file, &block, &salt, sizeof(salt))) return false;
|
||||
m_encrypted = true;
|
||||
if (m_password.Empty()) return false;
|
||||
if (!DecryptRar5Prepare(kdfCount, salt)) return false;
|
||||
}
|
||||
|
||||
else if (block.type == RAR5_BLOCK_FILE)
|
||||
{
|
||||
RarFile innerFile;
|
||||
if (!ReadRar5File(file, block, innerFile)) return false;
|
||||
m_files.push_back(std::move(innerFile));
|
||||
}
|
||||
|
||||
else if (block.type == RAR5_BLOCK_ENDARC)
|
||||
{
|
||||
uint64 endflags;
|
||||
if (!ReadV(file, &block, &endflags)) return false;
|
||||
m_hasNextVolume = (endflags & RAR5_ENDARC_NEXTVOL) != 0;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (block.type < 1 || block.type > 5)
|
||||
{
|
||||
// inlvaid block type
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64 skip = block.trailsize;
|
||||
if (m_encrypted)
|
||||
{
|
||||
skip -= 16 - m_decryptPos;
|
||||
if (m_decryptPos < 16)
|
||||
{
|
||||
skip += skip % 16 > 0 ? 16 - skip % 16 : 0;
|
||||
m_decryptPos = 16;
|
||||
}
|
||||
DecryptFree();
|
||||
}
|
||||
|
||||
if (!file.Seek(skip, DiskFile::soCur))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RarVolume::RarBlock RarVolume::ReadRar5Block(DiskFile& file)
|
||||
{
|
||||
RarBlock block {0};
|
||||
uint64 buf = 0;
|
||||
|
||||
if (m_encrypted &&
|
||||
!(file.Read(m_decryptIV, sizeof(m_decryptIV)) == sizeof(m_decryptIV) &&
|
||||
DecryptInit(256)))
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
|
||||
if (!Read32(file, nullptr, &block.crc)) return {0};
|
||||
|
||||
if (!ReadV(file, nullptr, &buf)) return {0};
|
||||
uint32 size = (uint32)buf;
|
||||
block.trailsize = size;
|
||||
|
||||
if (!ReadV(file, &block, &buf)) return {0};
|
||||
block.type = (uint8)buf;
|
||||
|
||||
if (!ReadV(file, &block, &buf)) return {0};
|
||||
block.flags = (uint16)buf;
|
||||
|
||||
block.addsize = 0;
|
||||
if ((block.flags & RAR5_BLOCK_EXTRADATA) && !ReadV(file, &block, &block.addsize)) return {0};
|
||||
|
||||
uint64 datasize = 0;
|
||||
if ((block.flags & RAR5_BLOCK_DATAAREA) && !ReadV(file, &block, &datasize)) return {0};
|
||||
block.trailsize += datasize;
|
||||
|
||||
static int num = 0;
|
||||
debug("%i) %llu, %i, %i, %i, %u, %llu", ++num, (long long)block.crc, (int)block.type, (int)block.flags, (int)size, (int)block.addsize, (long long)block.trailsize);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
bool RarVolume::ReadRar5File(DiskFile& file, RarBlock& block, RarFile& innerFile)
|
||||
{
|
||||
innerFile.m_splitBefore = block.flags & RAR5_BLOCK_SPLITBEFORE;
|
||||
innerFile.m_splitAfter = block.flags & RAR5_BLOCK_SPLITAFTER;
|
||||
|
||||
uint64 val;
|
||||
|
||||
uint64 fileflags;
|
||||
if (!ReadV(file, &block, &fileflags)) return false;
|
||||
|
||||
if (!ReadV(file, &block, &val)) return false; // skip
|
||||
innerFile.m_size = (int64)val;
|
||||
|
||||
if (!ReadV(file, &block, &val)) return false;
|
||||
innerFile.m_attr = (uint32)val;
|
||||
|
||||
if (fileflags & RAR5_FILE_TIME && !Read32(file, &block, &innerFile.m_time)) return false;
|
||||
if (fileflags & RAR5_FILE_CRC && !Skip(file, &block, 4)) return false;
|
||||
|
||||
if (!ReadV(file, &block, &val)) return false; // skip
|
||||
if (!ReadV(file, &block, &val)) return false; // skip
|
||||
|
||||
uint64 namelen;
|
||||
if (!ReadV(file, &block, &namelen)) return false;
|
||||
if (namelen > 8192) return false; // an error
|
||||
CharBuffer name;
|
||||
name.Reserve((uint32)namelen + 1);
|
||||
if (!Read(file, &block, (char*)name, namelen)) return false;
|
||||
name[namelen] = '\0';
|
||||
innerFile.m_filename = name;
|
||||
|
||||
// reading extra headers to find file time
|
||||
if (block.flags & RAR5_BLOCK_EXTRADATA)
|
||||
{
|
||||
uint64 remsize = block.addsize;
|
||||
while (remsize > 0)
|
||||
{
|
||||
uint64 trailsize = block.trailsize;
|
||||
|
||||
uint64 len;
|
||||
if (!ReadV(file, &block, &len)) return false;
|
||||
remsize -= trailsize - block.trailsize + len;
|
||||
trailsize = block.trailsize;
|
||||
|
||||
uint64 type;
|
||||
if (!ReadV(file, &block, &type)) return false;
|
||||
|
||||
if (type == RAR5_FILE_EXTRATIME)
|
||||
{
|
||||
uint64 flags;
|
||||
if (!ReadV(file, &block, &flags)) return false;
|
||||
if (flags & RAR5_FILE_EXTRATIMEUNIXFORMAT)
|
||||
{
|
||||
if (!Read32(file, &block, &innerFile.m_time)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 timelow, timehigh;
|
||||
if (!Read32(file, &block, &timelow)) return false;
|
||||
if (!Read32(file, &block, &timehigh)) return false;
|
||||
uint64 wintime = ((uint64)timehigh << 32) + timelow;
|
||||
innerFile.m_time = (uint32)(wintime / 10000000 - 11644473600LL);
|
||||
}
|
||||
}
|
||||
|
||||
len -= trailsize - block.trailsize;
|
||||
|
||||
if (!Skip(file, &block, len)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%llu, %i, %s", (long long)block.trailsize, (int)namelen, (const char*)name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RarVolume::LogDebugInfo()
|
||||
{
|
||||
debug("Volume: version:%i, multi:%i, vol-no:%i, new-naming:%i, has-next:%i, encrypted:%i, file-count:%i, [%s]",
|
||||
(int)m_version, (int)m_multiVolume, m_volumeNo, (int)m_newNaming, (int)m_hasNextVolume,
|
||||
(int)m_encrypted, (int)m_files.size(), FileSystem::BaseFileName(m_filename));
|
||||
|
||||
for (RarFile& file : m_files)
|
||||
{
|
||||
debug(" time:%i, size:%lli, attr:%i, split-before:%i, split-after:%i, [%s]",
|
||||
(int)file.m_time, (long long)file.m_size, (int)file.m_attr,
|
||||
(int)file.m_splitBefore, (int)file.m_splitAfter, *file.m_filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool RarVolume::DecryptRar3Prepare(const uint8 salt[8])
|
||||
{
|
||||
WString wstr(*m_password);
|
||||
int len = wstr.Length();
|
||||
if (len == 0) return false;
|
||||
|
||||
CharBuffer seed(len * 2 + 8);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
wchar_t ch = wstr[i];
|
||||
seed[i * 2] = ch & 0xFF;
|
||||
seed[i * 2 + 1] = (ch & 0xFF00) >> 8;
|
||||
}
|
||||
memcpy(seed + len * 2, salt, 8);
|
||||
|
||||
debug("seed: %s", *Util::FormatBuffer((const char*)seed, seed.Size()));
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_MD_CTX* context = EVP_MD_CTX_create();
|
||||
|
||||
if (!EVP_DigestInit(context, EVP_sha1()))
|
||||
{
|
||||
EVP_MD_CTX_destroy(context);
|
||||
return false;
|
||||
}
|
||||
#elif defined(HAVE_NETTLE)
|
||||
sha1_ctx context;
|
||||
sha1_init(&context);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
uint8 digest[20];
|
||||
const int rounds = 0x40000;
|
||||
|
||||
for (int i = 0; i < rounds; i++)
|
||||
{
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_DigestUpdate(context, *seed, seed.Size());
|
||||
#elif defined(HAVE_NETTLE)
|
||||
sha1_update(&context, seed.Size(), (const uint8_t*)*seed);
|
||||
#endif
|
||||
|
||||
uint8 buf[3];
|
||||
buf[0] = (uint8)i;
|
||||
buf[1] = (uint8)(i >> 8);
|
||||
buf[2] = (uint8)(i >> 16);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_DigestUpdate(context, buf, sizeof(buf));
|
||||
#elif defined(HAVE_NETTLE)
|
||||
sha1_update(&context, sizeof(buf), buf);
|
||||
#endif
|
||||
|
||||
if (i % (rounds / 16) == 0)
|
||||
{
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_MD_CTX* ivContext = EVP_MD_CTX_create();
|
||||
EVP_MD_CTX_copy(ivContext, context);
|
||||
EVP_DigestFinal(ivContext, digest, nullptr);
|
||||
EVP_MD_CTX_destroy(ivContext);
|
||||
#elif defined(HAVE_NETTLE)
|
||||
sha1_ctx ivContext = context;
|
||||
sha1_digest(&ivContext, sizeof(digest), digest);
|
||||
#endif
|
||||
m_decryptIV[i / (rounds / 16)] = digest[sizeof(digest) - 1];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_DigestFinal(context, digest, nullptr);
|
||||
EVP_MD_CTX_destroy(context);
|
||||
#elif defined(HAVE_NETTLE)
|
||||
sha1_digest(&context, sizeof(digest), digest);
|
||||
#endif
|
||||
|
||||
debug("digest: %s", *Util::FormatBuffer((const char*)digest, sizeof(digest)));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
m_decryptKey[i * 4 + j] = digest[i * 4 + 3 - j];
|
||||
}
|
||||
}
|
||||
|
||||
debug("key: %s", *Util::FormatBuffer((const char*)m_decryptKey, sizeof(m_decryptKey)));
|
||||
debug("iv: %s", *Util::FormatBuffer((const char*)m_decryptIV, sizeof(m_decryptIV)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RarVolume::DecryptRar5Prepare(uint8 kdfCount, const uint8 salt[16])
|
||||
{
|
||||
if (kdfCount > 24) return false;
|
||||
|
||||
int iterations = 1 << kdfCount;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (!PKCS5_PBKDF2_HMAC(m_password, m_password.Length(), salt, 16,
|
||||
iterations, EVP_sha256(), sizeof(m_decryptKey), m_decryptKey)) return false;
|
||||
return true;
|
||||
#elif defined(HAVE_NETTLE)
|
||||
pbkdf2_hmac_sha256(m_password.Length(), (const uint8_t*)*m_password,
|
||||
iterations, 16, salt, sizeof(m_decryptKey), m_decryptKey);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RarVolume::DecryptInit(int keyLength)
|
||||
{
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (!(m_context = EVP_CIPHER_CTX_new())) return false;
|
||||
if (!EVP_DecryptInit((EVP_CIPHER_CTX*)m_context,
|
||||
keyLength == 128 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(),
|
||||
m_decryptKey, m_decryptIV))
|
||||
return false;
|
||||
return true;
|
||||
#elif defined(HAVE_NETTLE)
|
||||
m_context = new aes_ctx;
|
||||
aes_set_decrypt_key((aes_ctx*)m_context, keyLength == 128 ? 16 : 32, m_decryptKey);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RarVolume::DecryptBuf(const uint8 in[16], uint8 out[16])
|
||||
{
|
||||
#ifdef HAVE_OPENSSL
|
||||
uint8 outbuf[32];
|
||||
int outlen = 0;
|
||||
if (!EVP_DecryptUpdate((EVP_CIPHER_CTX*)m_context, outbuf, &outlen, in, 16)) return false;
|
||||
memcpy(out, outbuf + outlen, 16);
|
||||
debug("decrypted: %s", *Util::FormatBuffer((const char*)out, 16));
|
||||
return true;
|
||||
#elif defined(HAVE_NETTLE)
|
||||
aes_decrypt((aes_ctx*)m_context, 16, out, in);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
out[i] ^= m_decryptIV[i];
|
||||
}
|
||||
memcpy(m_decryptIV, in, 16);
|
||||
debug("decrypted: %s", *Util::FormatBuffer((const char*)out, 16));
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RarVolume::DecryptFree()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
#ifdef HAVE_OPENSSL
|
||||
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)m_context);
|
||||
#elif defined(HAVE_NETTLE)
|
||||
delete (aes_ctx*)m_context;
|
||||
#endif
|
||||
m_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool RarVolume::DecryptRead(DiskFile& file, void* buffer, int64 size)
|
||||
{
|
||||
while (size > 0)
|
||||
{
|
||||
if (m_decryptPos >= 16)
|
||||
{
|
||||
uint8 buf[16];
|
||||
if (file.Read(&buf, sizeof(buf)) != sizeof(buf)) return false;
|
||||
m_decryptPos = 0;
|
||||
if (!DecryptBuf(buf, m_decryptBuf)) return false;
|
||||
}
|
||||
|
||||
uint8 remainingBuf = 16 - m_decryptPos;
|
||||
uint8 len = size <= remainingBuf ? (uint8)size : remainingBuf;
|
||||
memcpy(buffer, m_decryptBuf + m_decryptPos, len);
|
||||
m_decryptPos += len;
|
||||
size -= len;
|
||||
buffer = (char*)buffer + len;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
114
daemon/postprocess/RarReader.h
Normal file
114
daemon/postprocess/RarReader.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RARREADER_H
|
||||
#define RARREADER_H
|
||||
|
||||
#include "NString.h"
|
||||
#include "Log.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
class RarFile
|
||||
{
|
||||
public:
|
||||
const char* GetFilename() { return m_filename; }
|
||||
uint32 GetTime() { return m_time; }
|
||||
uint32 GetAttr() { return m_attr; }
|
||||
int64 GetSize() { return m_size; }
|
||||
bool GetSplitBefore() { return m_splitBefore; }
|
||||
bool GetSplitAfter() { return m_splitAfter; }
|
||||
private:
|
||||
CString m_filename;
|
||||
uint32 m_time = 0;
|
||||
uint32 m_attr = 0;
|
||||
int64 m_size = 0;
|
||||
bool m_splitBefore = false;
|
||||
bool m_splitAfter = false;
|
||||
friend class RarVolume;
|
||||
};
|
||||
|
||||
class RarVolume
|
||||
{
|
||||
public:
|
||||
typedef std::deque<RarFile> FileList;
|
||||
|
||||
RarVolume(const char* filename) : m_filename(filename) {}
|
||||
bool Read();
|
||||
|
||||
const char* GetFilename() { return m_filename; }
|
||||
int GetVersion() { return m_version; }
|
||||
uint32 GetVolumeNo() { return m_volumeNo; }
|
||||
bool GetNewNaming() { return m_newNaming; }
|
||||
bool GetHasNextVolume() { return m_hasNextVolume; }
|
||||
bool GetMultiVolume() { return m_multiVolume; }
|
||||
bool GetEncrypted() { return m_encrypted; }
|
||||
void SetPassword(const char* password) { m_password = password; }
|
||||
FileList* GetFiles() { return &m_files; }
|
||||
|
||||
private:
|
||||
struct RarBlock
|
||||
{
|
||||
uint32 crc;
|
||||
uint8 type;
|
||||
uint16 flags;
|
||||
uint64 addsize;
|
||||
uint64 trailsize;
|
||||
};
|
||||
|
||||
CString m_filename;
|
||||
int m_version = 0;
|
||||
uint32 m_volumeNo = 0;
|
||||
bool m_newNaming = false;
|
||||
bool m_hasNextVolume = false;
|
||||
bool m_multiVolume = false;
|
||||
FileList m_files;
|
||||
bool m_encrypted = false;
|
||||
CString m_password;
|
||||
uint8 m_decryptKey[32];
|
||||
uint8 m_decryptIV[16];
|
||||
uint8 m_decryptBuf[16];
|
||||
uint8 m_decryptPos = 16;
|
||||
|
||||
// using "void*" to prevent the including of GnuTLS/OpenSSL header files into TlsSocket.h
|
||||
void* m_context = nullptr;
|
||||
void* m_session = nullptr;
|
||||
|
||||
int DetectRarVersion(DiskFile& file);
|
||||
void LogDebugInfo();
|
||||
bool Skip(DiskFile& file, RarBlock* block, int64 size);
|
||||
bool Read(DiskFile& file, RarBlock* block, void* buffer, int64 size);
|
||||
bool Read16(DiskFile& file, RarBlock* block, uint16* result);
|
||||
bool Read32(DiskFile& file, RarBlock* block, uint32* result);
|
||||
bool ReadV(DiskFile& file, RarBlock* block, uint64* result);
|
||||
bool ReadRar3Volume(DiskFile& file);
|
||||
bool ReadRar5Volume(DiskFile& file);
|
||||
RarBlock ReadRar3Block(DiskFile& file);
|
||||
RarBlock ReadRar5Block(DiskFile& file);
|
||||
bool ReadRar3File(DiskFile& file, RarBlock& block, RarFile& innerFile);
|
||||
bool ReadRar5File(DiskFile& file, RarBlock& block, RarFile& innerFile);
|
||||
bool DecryptRar3Prepare(const uint8 salt[8]);
|
||||
bool DecryptRar5Prepare(uint8 kdfCount, const uint8 salt[16]);
|
||||
bool DecryptInit(int keyLength);
|
||||
bool DecryptBuf(const uint8 in[16], uint8 out[16]);
|
||||
void DecryptFree();
|
||||
bool DecryptRead(DiskFile& file, void* buffer, int64 size);
|
||||
};
|
||||
|
||||
#endif
|
||||
325
daemon/postprocess/RarRenamer.cpp
Normal file
325
daemon/postprocess/RarRenamer.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
|
||||
#include "RarRenamer.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
void RarRenamer::Execute()
|
||||
{
|
||||
m_progressLabel.Format("Checking renamed rar-files for %s", *m_infoName);
|
||||
m_stageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
BuildDirList(m_destDir);
|
||||
|
||||
for (CString& destDir : m_dirList)
|
||||
{
|
||||
debug("Checking %s", *destDir);
|
||||
CheckFiles(destDir);
|
||||
}
|
||||
}
|
||||
|
||||
void RarRenamer::BuildDirList(const char* destDir)
|
||||
{
|
||||
m_dirList.push_back(destDir);
|
||||
|
||||
DirBrowser dirBrowser(destDir);
|
||||
|
||||
while (const char* filename = dirBrowser.Next())
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", destDir, PATH_SEPARATOR, filename);
|
||||
if (FileSystem::DirectoryExists(fullFilename))
|
||||
{
|
||||
BuildDirList(fullFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fileCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RarRenamer::CheckFiles(const char* destDir)
|
||||
{
|
||||
DirBrowser dir(destDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", destDir, PATH_SEPARATOR, filename);
|
||||
|
||||
if (!FileSystem::DirectoryExists(fullFilename))
|
||||
{
|
||||
m_progressLabel.Format("Checking file %s", filename);
|
||||
m_stageProgress = m_fileCount > 0 ? m_curFile * 1000 / m_fileCount : 1000;
|
||||
UpdateProgress();
|
||||
m_curFile++;
|
||||
|
||||
CheckOneFile(fullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_volumes.empty())
|
||||
{
|
||||
RenameFiles(destDir);
|
||||
}
|
||||
}
|
||||
|
||||
void RarRenamer::CheckOneFile(const char* filename)
|
||||
{
|
||||
if (m_ignoreExt && Util::MatchFileExt(FileSystem::BaseFileName(filename), m_ignoreExt, ",;"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RarVolume volume(filename);
|
||||
volume.SetPassword(m_password);
|
||||
if (volume.Read())
|
||||
{
|
||||
m_volumes.push_back(std::move(volume));
|
||||
}
|
||||
}
|
||||
|
||||
void RarRenamer::RenameFile(const char* srcFilename, const char* destFileName)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Renaming %s to %s", FileSystem::BaseFileName(srcFilename), FileSystem::BaseFileName(destFileName));
|
||||
if (!FileSystem::MoveFile(srcFilename, destFileName))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", srcFilename, destFileName,
|
||||
*FileSystem::GetLastErrorMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
m_renamedCount++;
|
||||
|
||||
// notify about new file name
|
||||
RegisterRenamedFile(FileSystem::BaseFileName(srcFilename), FileSystem::BaseFileName(destFileName));
|
||||
}
|
||||
|
||||
void RarRenamer::RenameFiles(const char* destDir)
|
||||
{
|
||||
MakeSets();
|
||||
|
||||
for (RarVolumeSet& set : m_sets)
|
||||
{
|
||||
if (!IsSetProperlyNamed(set))
|
||||
{
|
||||
RarFile* mainFile = FindMainFile(set);
|
||||
BString<1024> mainBasename = FileSystem::BaseFileName(mainFile->GetFilename());
|
||||
char* ext = strrchr(mainBasename, '.');
|
||||
// strip extension if its length is 3 chars
|
||||
if (ext && strlen(ext) == 4)
|
||||
{
|
||||
*ext = '\0';
|
||||
}
|
||||
|
||||
BString<1024> newBasename = *mainBasename;
|
||||
int num = 0;
|
||||
bool willOverwrite = true;
|
||||
while (willOverwrite)
|
||||
{
|
||||
if (num++)
|
||||
{
|
||||
newBasename.Format("%s-%i", *mainBasename, num);
|
||||
}
|
||||
|
||||
for (RarVolume* volume : set)
|
||||
{
|
||||
CString destfilename = GenNewVolumeFilename(destDir, newBasename, volume);
|
||||
willOverwrite = strcmp(volume->GetFilename(), destfilename) && FileSystem::FileExists(destfilename);
|
||||
if (willOverwrite)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (RarVolume* volume : set)
|
||||
{
|
||||
CString destfilename = GenNewVolumeFilename(destDir, newBasename, volume);
|
||||
if (strcmp(volume->GetFilename(), destfilename))
|
||||
{
|
||||
RenameFile(volume->GetFilename(), destfilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CString RarRenamer::GenNewVolumeFilename(const char* destDir, const char* newBasename, RarVolume* volume)
|
||||
{
|
||||
CString extension = volume->GetNewNaming() ? GenNewExtension(volume->GetVolumeNo()) : GenOldExtension(volume->GetVolumeNo());
|
||||
return CString::FormatStr("%s%c%s.%s", destDir, PATH_SEPARATOR, newBasename, *extension);
|
||||
}
|
||||
|
||||
CString RarRenamer::GenNewExtension(int volumeNo)
|
||||
{
|
||||
return CString::FormatStr("part%04i.rar", volumeNo + 1);
|
||||
}
|
||||
|
||||
CString RarRenamer::GenOldExtension(int volumeNo)
|
||||
{
|
||||
if (volumeNo == 0)
|
||||
{
|
||||
return "rar";
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char ch = 'r' + (volumeNo - 1) / 100;
|
||||
return CString::FormatStr("%c%02d", ch, (volumeNo - 1) % 100);
|
||||
}
|
||||
}
|
||||
|
||||
void RarRenamer::MakeSets()
|
||||
{
|
||||
m_sets.clear();
|
||||
|
||||
// find first volumes and create initial incomplete sets
|
||||
for (RarVolume& volume : m_volumes)
|
||||
{
|
||||
if (!volume.GetFiles()->empty() && volume.GetVolumeNo() == 0)
|
||||
{
|
||||
m_sets.push_back({&volume});
|
||||
}
|
||||
}
|
||||
|
||||
// complete sets, discard sets which cannot be completed
|
||||
m_sets.erase(std::remove_if(m_sets.begin(), m_sets.end(),
|
||||
[volumes = &m_volumes](RarVolumeSet& set)
|
||||
{
|
||||
debug("*** Building set %s", FileSystem::BaseFileName(set[0]->GetFilename()));
|
||||
bool found = true;
|
||||
while (found)
|
||||
{
|
||||
found = false;
|
||||
RarVolume* lastVolume = set.back();
|
||||
for (RarVolume& volume : *volumes)
|
||||
{
|
||||
if (!volume.GetFiles()->empty() && volume.GetMultiVolume() &&
|
||||
volume.GetVolumeNo() == lastVolume->GetVolumeNo() + 1 &&
|
||||
volume.GetVersion() == lastVolume->GetVersion() &&
|
||||
lastVolume->GetHasNextVolume() &&
|
||||
((volume.GetFiles()->at(0).GetSplitBefore() &&
|
||||
lastVolume->GetFiles()->at(0).GetSplitAfter() &&
|
||||
!strcmp(volume.GetFiles()->at(0).GetFilename(), lastVolume->GetFiles()->at(0).GetFilename())) ||
|
||||
(!volume.GetFiles()->at(0).GetSplitBefore() && !lastVolume->GetFiles()->at(0).GetSplitAfter())))
|
||||
{
|
||||
debug(" adding %s", FileSystem::BaseFileName(volume.GetFilename()));
|
||||
set.push_back(&volume);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool completed = !set.back()->GetHasNextVolume();
|
||||
|
||||
return !completed;
|
||||
}),
|
||||
m_sets.end());
|
||||
|
||||
// debug log
|
||||
for (RarVolumeSet& set : m_sets)
|
||||
{
|
||||
debug("*** Set ***");
|
||||
for (RarVolume* volume : set)
|
||||
{
|
||||
debug(" %s", FileSystem::BaseFileName(volume->GetFilename()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RarRenamer::IsSetProperlyNamed(RarVolumeSet& set)
|
||||
{
|
||||
RegEx regExPart(".*.part([0-9]+)\\.rar$");
|
||||
|
||||
const char* setBasename = FileSystem::BaseFileName(set[0]->GetFilename());
|
||||
int setPartLen = 0;
|
||||
for (RarVolume* volume : set)
|
||||
{
|
||||
const char* filename = FileSystem::BaseFileName(volume->GetFilename());
|
||||
|
||||
if (strlen(setBasename) != strlen(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (volume->GetNewNaming())
|
||||
{
|
||||
if (!regExPart.Match(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BString<1024> partNo(filename + regExPart.GetMatchStart(1), regExPart.GetMatchLen(1));
|
||||
if (setPartLen == 0)
|
||||
{
|
||||
setPartLen = partNo.Length();
|
||||
}
|
||||
bool ok = atoi(partNo) == volume->GetVolumeNo() + 1 &&
|
||||
partNo.Length() == setPartLen &&
|
||||
!strncmp(setBasename, filename, regExPart.GetMatchStart(1));
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* ext = strrchr(filename, '.');
|
||||
if (!ext || strcmp(ext + 1, GenOldExtension(volume->GetVolumeNo())) ||
|
||||
strncmp(setBasename, filename, ext - filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RarFile* RarRenamer::FindMainFile(RarVolumeSet& set)
|
||||
{
|
||||
std::deque<RarFile*> allFiles;
|
||||
|
||||
for (RarVolume* volume : set)
|
||||
{
|
||||
for (RarFile& file : *volume->GetFiles())
|
||||
{
|
||||
allFiles.push_back(&file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::deque<RarFile*>::iterator it = std::max_element(allFiles.begin(), allFiles.end(),
|
||||
[](RarFile* file1, RarFile* file2)
|
||||
{
|
||||
return file1->GetSize() < file2->GetSize();
|
||||
});
|
||||
|
||||
return *it;
|
||||
}
|
||||
81
daemon/postprocess/RarRenamer.h
Normal file
81
daemon/postprocess/RarRenamer.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RARRENAMER_H
|
||||
#define RARRENAMER_H
|
||||
|
||||
#include "NString.h"
|
||||
#include "Log.h"
|
||||
#include "FileSystem.h"
|
||||
#include "RarReader.h"
|
||||
|
||||
class RarRenamer
|
||||
{
|
||||
public:
|
||||
void Execute();
|
||||
void SetDestDir(const char* destDir) { m_destDir = destDir; }
|
||||
const char* GetInfoName() { return m_infoName; }
|
||||
void SetInfoName(const char* infoName) { m_infoName = infoName; }
|
||||
void SetPassword(const char* password) { m_password = password; }
|
||||
void SetIgnoreExt(const char* ignoreExt) { m_ignoreExt = ignoreExt; }
|
||||
int GetRenamedCount() { return m_renamedCount; }
|
||||
|
||||
protected:
|
||||
virtual void UpdateProgress() {}
|
||||
virtual bool IsStopped() { return false; };
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3) {}
|
||||
virtual void RegisterRenamedFile(const char* oldFilename, const char* newFileName) {}
|
||||
const char* GetProgressLabel() { return m_progressLabel; }
|
||||
int GetStageProgress() { return m_stageProgress; }
|
||||
|
||||
private:
|
||||
typedef std::deque<CString> DirList;
|
||||
typedef std::deque<RarVolume> RarVolumeList;
|
||||
typedef std::deque<RarVolume*> RarVolumeSet;
|
||||
typedef std::deque<RarVolumeSet> RarSets;
|
||||
|
||||
CString m_infoName;
|
||||
CString m_destDir;
|
||||
CString m_progressLabel;
|
||||
int m_stageProgress = 0;
|
||||
bool m_cancelled = false;
|
||||
DirList m_dirList;
|
||||
int m_fileCount = 0;
|
||||
int m_curFile = 0;
|
||||
int m_renamedCount = 0;
|
||||
RarVolumeList m_volumes;
|
||||
RarSets m_sets;
|
||||
CString m_password;
|
||||
CString m_ignoreExt;
|
||||
|
||||
void BuildDirList(const char* destDir);
|
||||
void CheckFiles(const char* destDir);
|
||||
void CheckOneFile(const char* filename);
|
||||
void RenameFile(const char* srcFilename, const char* destFileName);
|
||||
void RenameFiles(const char* destDir);
|
||||
CString GenNewVolumeFilename(const char* destDir, const char* newBasename, RarVolume* volume);
|
||||
CString GenNewExtension(int volumeNo);
|
||||
CString GenOldExtension(int volumeNo);
|
||||
void MakeSets();
|
||||
bool IsSetProperlyNamed(RarVolumeSet& set);
|
||||
RarFile* FindMainFile(RarVolumeSet& set);
|
||||
};
|
||||
|
||||
#endif
|
||||
221
daemon/postprocess/Rename.cpp
Normal file
221
daemon/postprocess/Rename.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Options.h"
|
||||
#include "DiskState.h"
|
||||
#include "Log.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Rename.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RenameController::PostParRenamer::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(text, 1024, format, args);
|
||||
va_end(args);
|
||||
text[1024-1] = '\0';
|
||||
|
||||
m_owner->m_postInfo->GetNzbInfo()->AddMessage(kind, text);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void RenameController::PostRarRenamer::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(text, 1024, format, args);
|
||||
va_end(args);
|
||||
text[1024 - 1] = '\0';
|
||||
|
||||
m_owner->m_postInfo->GetNzbInfo()->AddMessage(kind, text);
|
||||
}
|
||||
|
||||
|
||||
RenameController::RenameController()
|
||||
{
|
||||
debug("Creating RenameController");
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_parRenamer.m_owner = this;
|
||||
#endif
|
||||
|
||||
m_rarRenamer.m_owner = this;
|
||||
}
|
||||
|
||||
void RenameController::StartJob(PostInfo* postInfo, EJobKind kind)
|
||||
{
|
||||
RenameController* renameController = new RenameController();
|
||||
renameController->m_postInfo = postInfo;
|
||||
renameController->m_kind = kind;
|
||||
renameController->SetAutoDestroy(false);
|
||||
|
||||
postInfo->SetPostThread(renameController);
|
||||
|
||||
renameController->Start();
|
||||
}
|
||||
|
||||
void RenameController::Run()
|
||||
{
|
||||
BString<1024> nzbName;
|
||||
CString destDir;
|
||||
CString finalDir;
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
nzbName = m_postInfo->GetNzbInfo()->GetName();
|
||||
destDir = m_postInfo->GetNzbInfo()->GetDestDir();
|
||||
finalDir = m_postInfo->GetNzbInfo()->GetFinalDir();
|
||||
}
|
||||
|
||||
BString<1024> infoName("rename for %s", *nzbName);
|
||||
SetInfoName(infoName);
|
||||
|
||||
PrintMessage(Message::mkInfo, "Checking renamed %sfiles for %s",
|
||||
m_kind == jkRar ? "archive " : "", *nzbName);
|
||||
|
||||
ExecRename(destDir, finalDir, nzbName);
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Renaming cancelled for %s", *nzbName);
|
||||
}
|
||||
else if (m_renamedCount > 0)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Successfully renamed %i %sfile(s) for %s",
|
||||
m_renamedCount, m_kind == jkRar ? "archive " : "", *nzbName);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "No renamed %sfiles found for %s",
|
||||
m_kind == jkRar ? "archive " : "", *nzbName);
|
||||
}
|
||||
|
||||
RenameCompleted();
|
||||
}
|
||||
|
||||
void RenameController::AddMessage(Message::EKind kind, const char* text)
|
||||
{
|
||||
m_postInfo->GetNzbInfo()->AddMessage(kind, text);
|
||||
}
|
||||
|
||||
void RenameController::ExecRename(const char* destDir, const char* finalDir, const char* nzbName)
|
||||
{
|
||||
if (m_kind == jkPar)
|
||||
{
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_parRenamer.SetDestDir(m_postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usSuccess &&
|
||||
!Util::EmptyStr(finalDir) ? finalDir : destDir);
|
||||
m_parRenamer.SetInfoName(nzbName);
|
||||
m_parRenamer.SetDetectMissing(m_postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usNone);
|
||||
m_parRenamer.Execute();
|
||||
#endif
|
||||
}
|
||||
else if (m_kind == jkRar)
|
||||
{
|
||||
m_rarRenamer.SetDestDir(destDir);
|
||||
m_rarRenamer.SetInfoName(nzbName);
|
||||
m_rarRenamer.SetIgnoreExt(g_Options->GetUnpackIgnoreExt());
|
||||
|
||||
NzbParameter* parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:Password", false);
|
||||
if (parameter)
|
||||
{
|
||||
m_rarRenamer.SetPassword(parameter->GetValue());
|
||||
}
|
||||
|
||||
m_rarRenamer.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
void RenameController::RenameCompleted()
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
if (m_kind == jkPar)
|
||||
{
|
||||
m_postInfo->GetNzbInfo()->SetParRenameStatus(m_renamedCount > 0 ? NzbInfo::rsSuccess : NzbInfo::rsNothing);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
// request another par2-file if the renaming has failed due to damaged par2-files
|
||||
if (m_renamedCount == 0 && m_parRenamer.HasDamagedParFiles() &&
|
||||
m_postInfo->GetNzbInfo()->GetRemainingParCount() > 0)
|
||||
{
|
||||
m_parRenamer.PrintMessage(Message::mkInfo, "Requesting extra par2-files for %s to perform par-rename", m_parRenamer.GetInfoName());
|
||||
downloadQueue->EditEntry(m_postInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupResume, nullptr);
|
||||
downloadQueue->EditEntry(m_postInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupPauseExtraPars, nullptr);
|
||||
if (m_postInfo->GetNzbInfo()->GetRemainingSize() > 0)
|
||||
{
|
||||
// reset rename status to execute renamer again, after the new par2-file is downloaded
|
||||
m_postInfo->GetNzbInfo()->SetParRenameStatus(NzbInfo::rsNone);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (m_kind == jkRar)
|
||||
{
|
||||
m_postInfo->GetNzbInfo()->SetRarRenameStatus(m_renamedCount > 0 ? NzbInfo::rsSuccess : NzbInfo::rsNothing);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (m_parRenamer.HasMissedFiles() && m_postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped)
|
||||
{
|
||||
m_parRenamer.PrintMessage(Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_parRenamer.GetInfoName());
|
||||
m_postInfo->SetRequestParCheck(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_postInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RenameController::UpdateParRenameProgress()
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
|
||||
m_postInfo->SetProgressLabel(m_parRenamer.GetProgressLabel());
|
||||
m_postInfo->SetStageProgress(m_parRenamer.GetStageProgress());
|
||||
}
|
||||
#endif
|
||||
|
||||
void RenameController::UpdateRarRenameProgress()
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
|
||||
m_postInfo->SetProgressLabel(m_rarRenamer.GetProgressLabel());
|
||||
m_postInfo->SetStageProgress(m_rarRenamer.GetStageProgress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update file name in the CompletedFiles-list of NZBInfo
|
||||
*/
|
||||
void RenameController::RegisterRenamedFile(const char* oldFilename, const char* newFileName)
|
||||
{
|
||||
for (CompletedFile& completedFile : m_postInfo->GetNzbInfo()->GetCompletedFiles())
|
||||
{
|
||||
if (!strcasecmp(completedFile.GetFileName(), oldFilename))
|
||||
{
|
||||
completedFile.SetFileName(newFileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_renamedCount++;
|
||||
}
|
||||
98
daemon/postprocess/Rename.h
Normal file
98
daemon/postprocess/Rename.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is part of nzbget. See <http://nzbget.net>.
|
||||
*
|
||||
* Copyright (C) 2016 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RENAME_H
|
||||
#define RENAME_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Script.h"
|
||||
#include "RarRenamer.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParRenamer.h"
|
||||
#endif
|
||||
|
||||
class RenameController : public Thread, public ScriptController
|
||||
{
|
||||
public:
|
||||
enum EJobKind
|
||||
{
|
||||
jkPar,
|
||||
jkRar
|
||||
};
|
||||
|
||||
RenameController();
|
||||
virtual void Run();
|
||||
static void StartJob(PostInfo* postInfo, EJobKind kind);
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind kind, const char* text);
|
||||
|
||||
private:
|
||||
PostInfo* m_postInfo;
|
||||
CString m_destDir;
|
||||
int m_renamedCount = 0;
|
||||
EJobKind m_kind;
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
class PostParRenamer : public ParRenamer
|
||||
{
|
||||
protected:
|
||||
virtual void UpdateProgress() { m_owner->UpdateParRenameProgress(); }
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3);
|
||||
virtual void RegisterParredFile(const char* filename)
|
||||
{ m_owner->m_postInfo->GetParredFiles()->push_back(filename); }
|
||||
virtual void RegisterRenamedFile(const char* oldFilename, const char* newFileName)
|
||||
{ m_owner->RegisterRenamedFile(oldFilename, newFileName); }
|
||||
virtual bool IsStopped() { return m_owner->IsStopped(); };
|
||||
private:
|
||||
RenameController* m_owner;
|
||||
friend class RenameController;
|
||||
};
|
||||
|
||||
PostParRenamer m_parRenamer;
|
||||
|
||||
void UpdateParRenameProgress();
|
||||
#endif
|
||||
|
||||
class PostRarRenamer : public RarRenamer
|
||||
{
|
||||
protected:
|
||||
virtual void UpdateProgress() { m_owner->UpdateRarRenameProgress(); }
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3);
|
||||
virtual void RegisterRenamedFile(const char* oldFilename, const char* newFileName)
|
||||
{ m_owner->RegisterRenamedFile(oldFilename, newFileName); }
|
||||
virtual bool IsStopped() { return m_owner->IsStopped(); };
|
||||
private:
|
||||
RenameController* m_owner;
|
||||
friend class RenameController;
|
||||
};
|
||||
|
||||
PostRarRenamer m_rarRenamer;
|
||||
|
||||
void UpdateRarRenameProgress();
|
||||
|
||||
void ExecRename(const char* destDir, const char* finalDir, const char* nzbName);
|
||||
void RenameCompleted();
|
||||
void RegisterRenamedFile(const char* oldFilename, const char* newFileName);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ParCoordinator.h"
|
||||
#include "Repair.h"
|
||||
#include "DupeCoordinator.h"
|
||||
#include "ParParser.h"
|
||||
#include "Options.h"
|
||||
@@ -28,17 +28,17 @@
|
||||
#include "FileSystem.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
bool ParCoordinator::PostParChecker::RequestMorePars(int blockNeeded, int* blockFound)
|
||||
bool RepairController::PostParChecker::RequestMorePars(int blockNeeded, int* blockFound)
|
||||
{
|
||||
return m_owner->RequestMorePars(m_postInfo->GetNzbInfo(), GetParFilename(), blockNeeded, blockFound);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::UpdateProgress()
|
||||
void RepairController::PostParChecker::UpdateProgress()
|
||||
{
|
||||
m_owner->UpdateParCheckProgress();
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
void RepairController::PostParChecker::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list args;
|
||||
@@ -50,12 +50,12 @@ void ParCoordinator::PostParChecker::PrintMessage(Message::EKind kind, const cha
|
||||
m_postInfo->GetNzbInfo()->AddMessage(kind, text);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::RegisterParredFile(const char* filename)
|
||||
void RepairController::PostParChecker::RegisterParredFile(const char* filename)
|
||||
{
|
||||
m_postInfo->GetParredFiles()->push_back(filename);
|
||||
}
|
||||
|
||||
bool ParCoordinator::PostParChecker::IsParredFile(const char* filename)
|
||||
bool RepairController::PostParChecker::IsParredFile(const char* filename)
|
||||
{
|
||||
for (CString& parredFile : m_postInfo->GetParredFiles())
|
||||
{
|
||||
@@ -67,7 +67,7 @@ bool ParCoordinator::PostParChecker::IsParredFile(const char* filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
ParChecker::EFileStatus ParCoordinator::PostParChecker::FindFileCrc(const char* filename,
|
||||
ParChecker::EFileStatus RepairController::PostParChecker::FindFileCrc(const char* filename,
|
||||
uint32* crc, SegmentList* segments)
|
||||
{
|
||||
CompletedFile* completedFile = nullptr;
|
||||
@@ -114,7 +114,7 @@ ParChecker::EFileStatus ParCoordinator::PostParChecker::FindFileCrc(const char*
|
||||
ParChecker::fsUnknown;
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::RequestDupeSources(DupeSourceList* dupeSourceList)
|
||||
void RepairController::PostParChecker::RequestDupeSources(DupeSourceList* dupeSourceList)
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
@@ -145,7 +145,7 @@ void ParCoordinator::PostParChecker::RequestDupeSources(DupeSourceList* dupeSour
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::StatDupeSources(DupeSourceList* dupeSourceList)
|
||||
void RepairController::PostParChecker::StatDupeSources(DupeSourceList* dupeSourceList)
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
@@ -169,44 +169,8 @@ void ParCoordinator::PostParChecker::StatDupeSources(DupeSourceList* dupeSourceL
|
||||
m_postInfo->GetNzbInfo()->SetExtraParBlocks(m_postInfo->GetNzbInfo()->GetExtraParBlocks() + totalExtraParBlocks);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::UpdateProgress()
|
||||
{
|
||||
m_owner->UpdateParRenameProgress();
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(text, 1024, format, args);
|
||||
va_end(args);
|
||||
text[1024-1] = '\0';
|
||||
|
||||
m_postInfo->GetNzbInfo()->AddMessage(kind, text);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::RegisterParredFile(const char* filename)
|
||||
{
|
||||
m_postInfo->GetParredFiles()->push_back(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update file name in the CompletedFiles-list of NZBInfo
|
||||
*/
|
||||
void ParCoordinator::PostParRenamer::RegisterRenamedFile(const char* oldFilename, const char* newFileName)
|
||||
{
|
||||
for (CompletedFile& completedFile : m_postInfo->GetNzbInfo()->GetCompletedFiles())
|
||||
{
|
||||
if (!strcasecmp(completedFile.GetFileName(), oldFilename))
|
||||
{
|
||||
completedFile.SetFileName(newFileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::PostDupeMatcher::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
void RepairController::PostDupeMatcher::PrintMessage(Message::EKind kind, const char* format, ...)
|
||||
{
|
||||
char text[1024];
|
||||
va_list args;
|
||||
@@ -220,127 +184,66 @@ void ParCoordinator::PostDupeMatcher::PrintMessage(Message::EKind kind, const ch
|
||||
|
||||
#endif
|
||||
|
||||
ParCoordinator::ParCoordinator()
|
||||
RepairController::RepairController()
|
||||
{
|
||||
debug("Creating ParCoordinator");
|
||||
debug("Creating RepairController");
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_parChecker.m_owner = this;
|
||||
m_parRenamer.m_owner = this;
|
||||
#endif
|
||||
}
|
||||
|
||||
ParCoordinator::~ParCoordinator()
|
||||
void RepairController::Stop()
|
||||
{
|
||||
debug("Destroying ParCoordinator");
|
||||
debug("Stopping RepairController");
|
||||
Thread::Stop();
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_parChecker.Cancel();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void ParCoordinator::Stop()
|
||||
|
||||
void RepairController::StartJob(PostInfo* postInfo)
|
||||
{
|
||||
debug("Stopping ParCoordinator");
|
||||
RepairController* repairController = new RepairController();
|
||||
repairController->m_postInfo = postInfo;
|
||||
repairController->SetAutoDestroy(false);
|
||||
|
||||
m_stopped = true;
|
||||
postInfo->SetPostThread(repairController);
|
||||
|
||||
if (m_parChecker.IsRunning())
|
||||
repairController->Start();
|
||||
}
|
||||
|
||||
void RepairController::Run()
|
||||
{
|
||||
BString<1024> nzbName;
|
||||
CString destDir;
|
||||
{
|
||||
m_parChecker.Stop();
|
||||
int mSecWait = 5000;
|
||||
while (m_parChecker.IsRunning() && mSecWait > 0)
|
||||
{
|
||||
usleep(50 * 1000);
|
||||
mSecWait -= 50;
|
||||
}
|
||||
if (m_parChecker.IsRunning())
|
||||
{
|
||||
warn("Terminating par-check for %s", m_parChecker.GetInfoName());
|
||||
m_parChecker.Kill();
|
||||
}
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
nzbName = m_postInfo->GetNzbInfo()->GetName();
|
||||
destDir = m_postInfo->GetNzbInfo()->GetDestDir();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ParCoordinator::PausePars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
||||
{
|
||||
debug("ParCoordinator: Pausing pars");
|
||||
|
||||
downloadQueue->EditEntry(nzbInfo->GetId(),
|
||||
DownloadQueue::eaGroupPauseExtraPars, 0, nullptr);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void ParCoordinator::StartParCheckJob(PostInfo* postInfo)
|
||||
{
|
||||
m_currentJob = jkParCheck;
|
||||
m_parChecker.SetPostInfo(postInfo);
|
||||
m_parChecker.SetDestDir(postInfo->GetNzbInfo()->GetDestDir());
|
||||
m_parChecker.SetNzbName(postInfo->GetNzbInfo()->GetName());
|
||||
m_parChecker.SetPostInfo(m_postInfo);
|
||||
m_parChecker.SetDestDir(destDir);
|
||||
m_parChecker.SetNzbName(nzbName);
|
||||
m_parChecker.SetParTime(Util::CurrentTime());
|
||||
m_parChecker.SetDownloadSec(postInfo->GetNzbInfo()->GetDownloadSec());
|
||||
m_parChecker.SetParQuick(g_Options->GetParQuick() && !postInfo->GetForceParFull());
|
||||
m_parChecker.SetForceRepair(postInfo->GetForceRepair());
|
||||
m_parChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->SetWorking(true);
|
||||
m_parChecker.Start();
|
||||
m_parChecker.SetDownloadSec(m_postInfo->GetNzbInfo()->GetDownloadSec());
|
||||
m_parChecker.SetParQuick(g_Options->GetParQuick() && !m_postInfo->GetForceParFull());
|
||||
m_parChecker.SetForceRepair(m_postInfo->GetForceRepair());
|
||||
|
||||
m_parChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", *nzbName);
|
||||
|
||||
m_parChecker.Execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void ParCoordinator::StartParRenameJob(PostInfo* postInfo)
|
||||
bool RepairController::AddPar(FileInfo* fileInfo, bool deleted)
|
||||
{
|
||||
const char* destDir = postInfo->GetNzbInfo()->GetDestDir();
|
||||
|
||||
if (postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usSuccess &&
|
||||
!Util::EmptyStr(postInfo->GetNzbInfo()->GetFinalDir()))
|
||||
{
|
||||
destDir = postInfo->GetNzbInfo()->GetFinalDir();
|
||||
}
|
||||
|
||||
m_currentJob = jkParRename;
|
||||
m_parRenamer.SetPostInfo(postInfo);
|
||||
m_parRenamer.SetDestDir(destDir);
|
||||
m_parRenamer.SetInfoName(postInfo->GetNzbInfo()->GetName());
|
||||
m_parRenamer.SetDetectMissing(postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usNone);
|
||||
m_parRenamer.PrintMessage(Message::mkInfo, "Checking renamed files for %s", postInfo->GetNzbInfo()->GetName());
|
||||
postInfo->SetWorking(true);
|
||||
m_parRenamer.Start();
|
||||
}
|
||||
|
||||
bool ParCoordinator::Cancel()
|
||||
{
|
||||
if (m_currentJob == jkParCheck)
|
||||
{
|
||||
if (!m_parChecker.GetCancelled())
|
||||
{
|
||||
debug("Cancelling par-repair for %s", m_parChecker.GetInfoName());
|
||||
m_parChecker.Cancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (m_currentJob == jkParRename)
|
||||
{
|
||||
if (!m_parRenamer.GetCancelled())
|
||||
{
|
||||
debug("Cancelling par-rename for %s", m_parRenamer.GetInfoName());
|
||||
m_parRenamer.Cancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
bool ParCoordinator::AddPar(FileInfo* fileInfo, bool deleted)
|
||||
{
|
||||
bool sameCollection = m_parChecker.IsRunning() &&
|
||||
fileInfo->GetNzbInfo() == m_parChecker.GetPostInfo()->GetNzbInfo();
|
||||
bool sameCollection = fileInfo->GetNzbInfo() == m_parChecker.GetPostInfo()->GetNzbInfo();
|
||||
if (sameCollection && !deleted)
|
||||
{
|
||||
BString<1024> fullFilename("%s%c%s", fileInfo->GetNzbInfo()->GetDestDir(), (int)PATH_SEPARATOR, fileInfo->GetFilename());
|
||||
@@ -353,7 +256,7 @@ bool ParCoordinator::AddPar(FileInfo* fileInfo, bool deleted)
|
||||
return sameCollection;
|
||||
}
|
||||
|
||||
void ParCoordinator::ParCheckCompleted()
|
||||
void RepairController::ParCheckCompleted()
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
@@ -385,9 +288,6 @@ void ParCoordinator::ParCheckCompleted()
|
||||
postInfo->GetNzbInfo()->SetParFull(m_parChecker.GetParFull());
|
||||
|
||||
postInfo->SetWorking(false);
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
|
||||
downloadQueue->Save();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,80 +297,68 @@ void ParCoordinator::ParCheckCompleted()
|
||||
* special case: returns true if there are any unpaused par2-files in the queue regardless
|
||||
* of the amount of blocks; this is to keep par-checker wait for download completion.
|
||||
*/
|
||||
bool ParCoordinator::RequestMorePars(NzbInfo* nzbInfo, const char* parFilename, int blockNeeded, int* blockFoundOut)
|
||||
bool RepairController::RequestMorePars(NzbInfo* nzbInfo, const char* parFilename, int blockNeeded, int* blockFoundOut)
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
Blocks blocks;
|
||||
blocks.clear();
|
||||
Blocks availableBlocks;
|
||||
Blocks selectedBlocks;
|
||||
int blockFound = 0;
|
||||
int curBlockFound = 0;
|
||||
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, blocks, true, true, &curBlockFound);
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, availableBlocks, true, true, &curBlockFound);
|
||||
blockFound += curBlockFound;
|
||||
if (blockFound < blockNeeded)
|
||||
{
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, blocks, true, false, &curBlockFound);
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, availableBlocks, true, false, &curBlockFound);
|
||||
blockFound += curBlockFound;
|
||||
}
|
||||
if (blockFound < blockNeeded)
|
||||
{
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, blocks, false, false, &curBlockFound);
|
||||
FindPars(downloadQueue, nzbInfo, parFilename, availableBlocks, false, false, &curBlockFound);
|
||||
blockFound += curBlockFound;
|
||||
}
|
||||
|
||||
std::sort(availableBlocks.begin(), availableBlocks.end(),
|
||||
[](BlockInfo& block1, BlockInfo& block2)
|
||||
{
|
||||
return block1.m_blockCount < block2.m_blockCount;
|
||||
});
|
||||
|
||||
if (blockFound >= blockNeeded)
|
||||
{
|
||||
// 1. first unpause all files with par-blocks less or equal iBlockNeeded
|
||||
// starting from the file with max block count.
|
||||
// if par-collection was built exponentially and all par-files present,
|
||||
// this step selects par-files with exact number of blocks we need.
|
||||
while (blockNeeded > 0)
|
||||
// collect as much blocks as needed
|
||||
for (Blocks::iterator it = availableBlocks.begin(); blockNeeded > 0 && it != availableBlocks.end(); it++)
|
||||
{
|
||||
BlockInfo* bestBlockInfo = nullptr;
|
||||
Blocks::iterator bestBlockIter;
|
||||
for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
|
||||
BlockInfo& blockInfo = *it;
|
||||
selectedBlocks.push_front(blockInfo);
|
||||
blockNeeded -= blockInfo.m_blockCount;
|
||||
}
|
||||
|
||||
// discarding superfluous blocks
|
||||
for (Blocks::iterator it = selectedBlocks.begin(); it != selectedBlocks.end(); )
|
||||
{
|
||||
BlockInfo& blockInfo = *it;
|
||||
if (blockNeeded + blockInfo.m_blockCount <= 0)
|
||||
{
|
||||
BlockInfo& blockInfo = *it;
|
||||
if (blockInfo.m_blockCount <= blockNeeded &&
|
||||
(!bestBlockInfo || bestBlockInfo->m_blockCount < blockInfo.m_blockCount))
|
||||
{
|
||||
bestBlockInfo = &blockInfo;
|
||||
bestBlockIter = it;
|
||||
}
|
||||
}
|
||||
if (bestBlockInfo)
|
||||
{
|
||||
if (bestBlockInfo->m_fileInfo->GetPaused())
|
||||
{
|
||||
m_parChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", nzbInfo->GetName(), (int)PATH_SEPARATOR, bestBlockInfo->m_fileInfo->GetFilename());
|
||||
bestBlockInfo->m_fileInfo->SetPaused(false);
|
||||
bestBlockInfo->m_fileInfo->SetExtraPriority(true);
|
||||
}
|
||||
blockNeeded -= bestBlockInfo->m_blockCount;
|
||||
blocks.erase(bestBlockIter);
|
||||
blockNeeded += blockInfo.m_blockCount;
|
||||
it = selectedBlocks.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. then unpause other files
|
||||
// this step only needed if the par-collection was built not exponentially
|
||||
// or not all par-files present (or some of them were corrupted)
|
||||
// this step is not optimal, but we hope, that the first step will work good
|
||||
// in most cases and we will not need the second step often
|
||||
while (blockNeeded > 0)
|
||||
// unpause files with blocks
|
||||
for (BlockInfo& blockInfo : selectedBlocks)
|
||||
{
|
||||
BlockInfo& blockInfo = blocks.front();
|
||||
if (blockInfo.m_fileInfo->GetPaused())
|
||||
{
|
||||
m_parChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", nzbInfo->GetName(), (int)PATH_SEPARATOR, blockInfo.m_fileInfo->GetFilename());
|
||||
blockInfo.m_fileInfo->SetPaused(false);
|
||||
blockInfo.m_fileInfo->SetExtraPriority(true);
|
||||
}
|
||||
blockNeeded -= blockInfo.m_blockCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +382,7 @@ bool ParCoordinator::RequestMorePars(NzbInfo* nzbInfo, const char* parFilename,
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ParCoordinator::FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, const char* parFilename,
|
||||
void RepairController::FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, const char* parFilename,
|
||||
Blocks& blocks, bool strictParName, bool exactParName, int* blockFound)
|
||||
{
|
||||
*blockFound = 0;
|
||||
@@ -502,7 +390,7 @@ void ParCoordinator::FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, co
|
||||
// extract base name from m_szParFilename (trim .par2-extension and possible .vol-part)
|
||||
char* baseParFilename = FileSystem::BaseFileName(parFilename);
|
||||
int mainBaseLen = 0;
|
||||
if (!ParParser::ParseParFilename(baseParFilename, &mainBaseLen, nullptr))
|
||||
if (!ParParser::ParseParFilename(baseParFilename, true, &mainBaseLen, nullptr))
|
||||
{
|
||||
// should not happen
|
||||
nzbInfo->PrintMessage(Message::mkError, "Internal error: could not parse filename %s", baseParFilename);
|
||||
@@ -515,7 +403,7 @@ void ParCoordinator::FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, co
|
||||
for (FileInfo* fileInfo : nzbInfo->GetFileList())
|
||||
{
|
||||
int blockCount = 0;
|
||||
if (ParParser::ParseParFilename(fileInfo->GetFilename(), nullptr, &blockCount) &&
|
||||
if (ParParser::ParseParFilename(fileInfo->GetFilename(), fileInfo->GetFilenameConfirmed(), nullptr, &blockCount) &&
|
||||
blockCount > 0)
|
||||
{
|
||||
bool useFile = true;
|
||||
@@ -566,7 +454,7 @@ void ParCoordinator::FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, co
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::UpdateParCheckProgress()
|
||||
void RepairController::UpdateParCheckProgress()
|
||||
{
|
||||
PostInfo* postInfo;
|
||||
|
||||
@@ -600,7 +488,7 @@ void ParCoordinator::UpdateParCheckProgress()
|
||||
}
|
||||
|
||||
bool parCancel = false;
|
||||
if (!m_parChecker.GetCancelled())
|
||||
if (!IsStopped())
|
||||
{
|
||||
if ((g_Options->GetParTimeLimit() > 0) &&
|
||||
m_parChecker.GetStage() == PostParChecker::ptRepairing &&
|
||||
@@ -621,14 +509,14 @@ void ParCoordinator::UpdateParCheckProgress()
|
||||
|
||||
if (parCancel)
|
||||
{
|
||||
m_parChecker.Cancel();
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
CheckPauseState(postInfo);
|
||||
}
|
||||
|
||||
void ParCoordinator::CheckPauseState(PostInfo* postInfo)
|
||||
void RepairController::CheckPauseState(PostInfo* postInfo)
|
||||
{
|
||||
if (g_Options->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority())
|
||||
{
|
||||
@@ -639,7 +527,7 @@ void ParCoordinator::CheckPauseState(PostInfo* postInfo)
|
||||
time_t waitTime = Util::CurrentTime();
|
||||
|
||||
// wait until Post-processor is unpaused
|
||||
while (g_Options->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority() && !m_stopped)
|
||||
while (g_Options->GetPausePostProcess() && !postInfo->GetNzbInfo()->GetForcePriority() && !IsStopped())
|
||||
{
|
||||
usleep(50 * 1000);
|
||||
|
||||
@@ -667,44 +555,4 @@ void ParCoordinator::CheckPauseState(PostInfo* postInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::ParRenameCompleted()
|
||||
{
|
||||
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
|
||||
|
||||
PostInfo* postInfo = m_parRenamer.GetPostInfo();
|
||||
postInfo->GetNzbInfo()->SetRenameStatus(m_parRenamer.GetStatus() == ParRenamer::psSuccess ? NzbInfo::rsSuccess : NzbInfo::rsFailure);
|
||||
|
||||
if (m_parRenamer.HasMissedFiles() && postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped)
|
||||
{
|
||||
m_parRenamer.PrintMessage(Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_parRenamer.GetInfoName());
|
||||
postInfo->SetRequestParCheck(true);
|
||||
}
|
||||
|
||||
postInfo->SetWorking(false);
|
||||
postInfo->SetStage(PostInfo::ptQueued);
|
||||
|
||||
downloadQueue->Save();
|
||||
}
|
||||
|
||||
void ParCoordinator::UpdateParRenameProgress()
|
||||
{
|
||||
PostInfo* postInfo;
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
|
||||
postInfo = m_parRenamer.GetPostInfo();
|
||||
postInfo->SetProgressLabel(m_parRenamer.GetProgressLabel());
|
||||
postInfo->SetStageProgress(m_parRenamer.GetStageProgress());
|
||||
time_t current = Util::CurrentTime();
|
||||
|
||||
if (postInfo->GetStage() != PostInfo::ptRenaming)
|
||||
{
|
||||
postInfo->SetStage(PostInfo::ptRenaming);
|
||||
postInfo->SetStageTime(current);
|
||||
}
|
||||
}
|
||||
|
||||
CheckPauseState(postInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -18,36 +18,32 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PARCOORDINATOR_H
|
||||
#define PARCOORDINATOR_H
|
||||
#ifndef REPAIR_H
|
||||
#define REPAIR_H
|
||||
|
||||
#include "DownloadInfo.h"
|
||||
#include "Thread.h"
|
||||
#include "Script.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
#include "ParRenamer.h"
|
||||
#include "DupeMatcher.h"
|
||||
#endif
|
||||
|
||||
class ParCoordinator
|
||||
class RepairController : public Thread, public ScriptController
|
||||
{
|
||||
public:
|
||||
ParCoordinator();
|
||||
virtual ~ParCoordinator();
|
||||
void PausePars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
RepairController();
|
||||
virtual void Stop();
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
virtual void Run();
|
||||
static void StartJob(PostInfo* postInfo);
|
||||
bool AddPar(FileInfo* fileInfo, bool deleted);
|
||||
void StartParCheckJob(PostInfo* postInfo);
|
||||
void StartParRenameJob(PostInfo* postInfo);
|
||||
void Stop();
|
||||
bool Cancel();
|
||||
|
||||
protected:
|
||||
void UpdateParCheckProgress();
|
||||
void UpdateParRenameProgress();
|
||||
void ParCheckCompleted();
|
||||
void ParRenameCompleted();
|
||||
void CheckPauseState(PostInfo* postInfo);
|
||||
bool RequestMorePars(NzbInfo* nzbInfo, const char* parFilename, int blockNeeded, int* blockFound);
|
||||
|
||||
@@ -66,6 +62,7 @@ private:
|
||||
protected:
|
||||
virtual bool RequestMorePars(int blockNeeded, int* blockFound);
|
||||
virtual void UpdateProgress();
|
||||
virtual bool IsStopped() { return m_owner->IsStopped(); };
|
||||
virtual void Completed() { m_owner->ParCheckCompleted(); }
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3);
|
||||
virtual void RegisterParredFile(const char* filename);
|
||||
@@ -74,31 +71,13 @@ private:
|
||||
virtual void RequestDupeSources(DupeSourceList* dupeSourceList);
|
||||
virtual void StatDupeSources(DupeSourceList* dupeSourceList);
|
||||
private:
|
||||
ParCoordinator* m_owner;
|
||||
RepairController* m_owner;
|
||||
PostInfo* m_postInfo;
|
||||
time_t m_parTime;
|
||||
time_t m_repairTime;
|
||||
int m_downloadSec;
|
||||
|
||||
friend class ParCoordinator;
|
||||
};
|
||||
|
||||
class PostParRenamer: public ParRenamer
|
||||
{
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_postInfo; }
|
||||
void SetPostInfo(PostInfo* postInfo) { m_postInfo = postInfo; }
|
||||
protected:
|
||||
virtual void UpdateProgress();
|
||||
virtual void Completed() { m_owner->ParRenameCompleted(); }
|
||||
virtual void PrintMessage(Message::EKind kind, const char* format, ...) PRINTF_SYNTAX(3);
|
||||
virtual void RegisterParredFile(const char* filename);
|
||||
virtual void RegisterRenamedFile(const char* oldFilename, const char* newFileName);
|
||||
private:
|
||||
ParCoordinator* m_owner;
|
||||
PostInfo* m_postInfo;
|
||||
|
||||
friend class ParCoordinator;
|
||||
friend class RepairController;
|
||||
};
|
||||
|
||||
class PostDupeMatcher: public DupeMatcher
|
||||
@@ -124,16 +103,8 @@ private:
|
||||
|
||||
typedef std::deque<BlockInfo> Blocks;
|
||||
|
||||
enum EJobKind
|
||||
{
|
||||
jkParCheck,
|
||||
jkParRename
|
||||
};
|
||||
|
||||
PostInfo* m_postInfo;
|
||||
PostParChecker m_parChecker;
|
||||
bool m_stopped = false;
|
||||
PostParRenamer m_parRenamer;
|
||||
EJobKind m_currentJob;
|
||||
|
||||
void FindPars(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, const char* parFilename,
|
||||
Blocks& blocks, bool strictParName, bool exactParName, int* blockFound);
|
||||
@@ -87,16 +87,13 @@ void UnpackController::Run()
|
||||
|
||||
if (unpack)
|
||||
{
|
||||
bool scanNonStdFiles = m_postInfo->GetNzbInfo()->GetRenameStatus() > NzbInfo::rsSkipped ||
|
||||
m_postInfo->GetNzbInfo()->GetParStatus() == NzbInfo::psSuccess ||
|
||||
!m_hasParFiles;
|
||||
CheckArchiveFiles(scanNonStdFiles);
|
||||
CheckArchiveFiles();
|
||||
}
|
||||
|
||||
SetInfoName(m_infoName);
|
||||
SetWorkingDir(m_destDir);
|
||||
|
||||
bool hasFiles = m_hasRarFiles || m_hasNonStdRarFiles || m_hasSevenZipFiles || m_hasSevenZipMultiFiles || m_hasSplittedFiles;
|
||||
bool hasFiles = m_hasRarFiles || m_hasSevenZipFiles || m_hasSevenZipMultiFiles || m_hasSplittedFiles;
|
||||
|
||||
if (m_postInfo->GetUnpackTried() && !m_postInfo->GetParRepaired() &&
|
||||
(!m_password.Empty() || Util::EmptyStr(g_Options->GetUnpackPassFile()) || m_postInfo->GetPassListTried()))
|
||||
@@ -107,7 +104,6 @@ void UnpackController::Run()
|
||||
"%s failed: checksum error in the encrypted file. Corrupt file or wrong password." : "%s failed.",
|
||||
*m_infoNameUp);
|
||||
m_postInfo->GetNzbInfo()->SetUnpackStatus((NzbInfo::EUnpackStatus)m_postInfo->GetLastUnpackStatus());
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else if (unpack && hasFiles)
|
||||
{
|
||||
@@ -115,7 +111,7 @@ void UnpackController::Run()
|
||||
|
||||
CreateUnpackDir();
|
||||
|
||||
if (m_hasRarFiles || m_hasNonStdRarFiles)
|
||||
if (m_hasRarFiles)
|
||||
{
|
||||
UnpackArchives(upUnrar, false);
|
||||
}
|
||||
@@ -139,23 +135,35 @@ void UnpackController::Run()
|
||||
|
||||
m_joinedFiles.clear();
|
||||
}
|
||||
else
|
||||
else if (unpack)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, (unpack ? "Nothing to unpack for %s" : "Unpack for %s skipped"), *m_name);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (unpack && m_postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped &&
|
||||
m_postInfo->GetNzbInfo()->GetRenameStatus() <= NzbInfo::rsSkipped && m_hasParFiles)
|
||||
if (m_postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped &&
|
||||
m_postInfo->GetNzbInfo()->GetParRenameStatus() <= NzbInfo::rsSkipped &&
|
||||
m_hasParFiles)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Nothing to unpack for %s", *m_name);
|
||||
RequestParCheck(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (m_hasRenamedArchiveFiles)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not unpack %s due to renamed archive files", *m_name);
|
||||
m_postInfo->GetNzbInfo()->SetUnpackStatus(NzbInfo::usFailure);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Nothing to unpack for %s", *m_name);
|
||||
m_postInfo->GetNzbInfo()->SetUnpackStatus(NzbInfo::usSkipped);
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Unpack for %s skipped", *m_name);
|
||||
m_postInfo->GetNzbInfo()->SetUnpackStatus(NzbInfo::usSkipped);
|
||||
}
|
||||
|
||||
|
||||
int unpackSec = (int)(Util::CurrentTime() - start);
|
||||
m_postInfo->GetNzbInfo()->SetUnpackSec(m_postInfo->GetNzbInfo()->GetUnpackSec() + unpackSec);
|
||||
@@ -268,7 +276,7 @@ void UnpackController::ExecuteUnrar(const char* password)
|
||||
params.emplace_back("-o+");
|
||||
}
|
||||
|
||||
params.emplace_back(m_hasNonStdRarFiles ? "*.*" : "*.rar");
|
||||
params.emplace_back("*.rar");
|
||||
params.push_back(FileSystem::MakeExtendedPath(BString<1024>("%s%c", *m_unpackDir, PATH_SEPARATOR), true));
|
||||
SetArgs(std::move(params));
|
||||
SetLogPrefix("Unrar");
|
||||
@@ -532,9 +540,8 @@ void UnpackController::Completed()
|
||||
if (g_Options->GetParRename())
|
||||
{
|
||||
//request par-rename check for extracted files
|
||||
m_postInfo->GetNzbInfo()->SetRenameStatus(NzbInfo::rsNone);
|
||||
m_postInfo->GetNzbInfo()->SetParRenameStatus(NzbInfo::rsNone);
|
||||
}
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -558,7 +565,6 @@ void UnpackController::Completed()
|
||||
m_unpackSpaceError ? NzbInfo::usSpace :
|
||||
m_unpackPasswordError || m_unpackDecryptError ? NzbInfo::usPassword :
|
||||
NzbInfo::usFailure);
|
||||
m_postInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -569,7 +575,6 @@ void UnpackController::RequestParCheck(bool forceRepair)
|
||||
PrintMessage(Message::mkInfo, "%s requested %s", *m_infoNameUp, forceRepair ? "par-check with forced repair" : "par-check/repair");
|
||||
m_postInfo->SetRequestParCheck(true);
|
||||
m_postInfo->SetForceRepair(forceRepair);
|
||||
m_postInfo->SetStage(PostInfo::ptFinished);
|
||||
m_postInfo->SetUnpackTried(true);
|
||||
m_postInfo->SetPassListTried(m_passListTried);
|
||||
m_postInfo->SetLastUnpackStatus((int)(m_unpackSpaceError ? NzbInfo::usSpace :
|
||||
@@ -609,19 +614,18 @@ void UnpackController::CreateUnpackDir()
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::CheckArchiveFiles(bool scanNonStdFiles)
|
||||
void UnpackController::CheckArchiveFiles()
|
||||
{
|
||||
m_hasRarFiles = false;
|
||||
m_hasNonStdRarFiles = false;
|
||||
m_hasRenamedArchiveFiles = false;
|
||||
m_hasSevenZipFiles = false;
|
||||
m_hasSevenZipMultiFiles = false;
|
||||
m_hasSplittedFiles = false;
|
||||
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExRarMultiSeq(".*\\.(r|s)[0-9][0-9]$");
|
||||
RegEx regExRarMultiSeq(".*\\.[r-z][0-9][0-9]$");
|
||||
RegEx regExSevenZip(".*\\.7z$");
|
||||
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]+$");
|
||||
RegEx regExNumExt(".*\\.[0-9]+$");
|
||||
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.[0-9]{3}$");
|
||||
|
||||
DirBrowser dir(m_destDir);
|
||||
@@ -646,16 +650,16 @@ void UnpackController::CheckArchiveFiles(bool scanNonStdFiles)
|
||||
{
|
||||
m_hasSevenZipMultiFiles = true;
|
||||
}
|
||||
else if (scanNonStdFiles && !m_hasNonStdRarFiles && extNum > 1 &&
|
||||
!regExRarMultiSeq.Match(filename) && regExNumExt.Match(filename) &&
|
||||
FileHasRarSignature(fullFilename))
|
||||
{
|
||||
m_hasNonStdRarFiles = true;
|
||||
}
|
||||
else if (regExSplitExt.Match(filename) && (extNum == 0 || extNum == 1))
|
||||
{
|
||||
m_hasSplittedFiles = true;
|
||||
}
|
||||
else if (!m_hasRenamedArchiveFiles && !regExRarMultiSeq.Match(filename) &&
|
||||
!Util::MatchFileExt(filename, g_Options->GetUnpackIgnoreExt(), ",;") &&
|
||||
FileHasRarSignature(fullFilename))
|
||||
{
|
||||
m_hasRenamedArchiveFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -737,7 +741,6 @@ bool UnpackController::Cleanup()
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExRarMultiSeq(".*\\.[r-z][0-9][0-9]$");
|
||||
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]+$");
|
||||
RegEx regExNumExt(".*\\.[0-9]+$");
|
||||
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.[0-9]{3}$");
|
||||
|
||||
DirBrowser dir(m_destDir);
|
||||
@@ -749,7 +752,6 @@ bool UnpackController::Cleanup()
|
||||
(m_interDir || !extractedFiles.Exists(filename)) &&
|
||||
(regExRar.Match(filename) || regExSevenZip.Match(filename) ||
|
||||
(regExRarMultiSeq.Match(filename) && FileHasRarSignature(fullFilename)) ||
|
||||
(m_hasNonStdRarFiles && regExNumExt.Match(filename) && FileHasRarSignature(fullFilename)) ||
|
||||
(m_hasSplittedFiles && regExSplitExt.Match(filename) && m_joinedFiles.Exists(filename))))
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
|
||||
@@ -871,7 +873,7 @@ void UnpackController::AddMessage(Message::EKind kind, const char* text)
|
||||
m_unpackDecryptError = true;
|
||||
}
|
||||
|
||||
if (m_unpacker == upUnrar && !strncmp(text, "Unrar: The specified password is incorrect.'", 43))
|
||||
if (m_unpacker == upUnrar && !strncmp(text, "Unrar: The specified password is incorrect.", 43))
|
||||
{
|
||||
m_unpackPasswordError = true;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
bool m_noFilesMessageReceived;
|
||||
bool m_hasParFiles;
|
||||
bool m_hasRarFiles;
|
||||
bool m_hasNonStdRarFiles;
|
||||
bool m_hasRenamedArchiveFiles;
|
||||
bool m_hasSevenZipFiles;
|
||||
bool m_hasSevenZipMultiFiles;
|
||||
bool m_hasSplittedFiles;
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
void Completed();
|
||||
void CreateUnpackDir();
|
||||
bool Cleanup();
|
||||
void CheckArchiveFiles(bool scanNonStdFiles);
|
||||
void CheckArchiveFiles();
|
||||
void SetProgressLabel(const char* progressLabel);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RequestParCheck(bool forceRepair);
|
||||
|
||||
@@ -265,7 +265,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* downloadQueue, bool saveHistory
|
||||
bool ok = true;
|
||||
|
||||
{
|
||||
StateFile stateFile("queue", 57, true);
|
||||
StateFile stateFile("queue", 59, true);
|
||||
if (!downloadQueue->GetQueue()->empty())
|
||||
{
|
||||
StateDiskFile* outfile = stateFile.BeginWrite();
|
||||
@@ -288,7 +288,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* downloadQueue, bool saveHistory
|
||||
|
||||
if (saveHistory)
|
||||
{
|
||||
StateFile stateFile("history", 57, true);
|
||||
StateFile stateFile("history", 59, true);
|
||||
if (!downloadQueue->GetHistory()->empty())
|
||||
{
|
||||
StateDiskFile* outfile = stateFile.BeginWrite();
|
||||
@@ -320,7 +320,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers
|
||||
int formatVersion = 0;
|
||||
|
||||
{
|
||||
StateFile stateFile("queue", 57, true);
|
||||
StateFile stateFile("queue", 59, true);
|
||||
if (stateFile.FileExists())
|
||||
{
|
||||
StateDiskFile* infile = stateFile.BeginRead();
|
||||
@@ -349,7 +349,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers
|
||||
|
||||
if (formatVersion == 0 || formatVersion >= 57)
|
||||
{
|
||||
StateFile stateFile("history", 57, true);
|
||||
StateFile stateFile("history", 59, true);
|
||||
if (stateFile.FileExists())
|
||||
{
|
||||
StateDiskFile* infile = stateFile.BeginRead();
|
||||
@@ -428,9 +428,9 @@ void DiskState::SaveNzbInfo(NzbInfo* nzbInfo, StateDiskFile& outfile)
|
||||
outfile.PrintLine("%i,%i,%i,%i,%i", (int)nzbInfo->GetPriority(),
|
||||
nzbInfo->GetPostInfo() ? (int)nzbInfo->GetPostInfo()->GetStage() + 1 : 0,
|
||||
(int)nzbInfo->GetDeletePaused(), (int)nzbInfo->GetManyDupeFiles(), nzbInfo->GetFeedId());
|
||||
outfile.PrintLine("%i,%i,%i,%i,%i,%i,%i", (int)nzbInfo->GetParStatus(), (int)nzbInfo->GetUnpackStatus(),
|
||||
(int)nzbInfo->GetMoveStatus(), (int)nzbInfo->GetRenameStatus(), (int)nzbInfo->GetDeleteStatus(),
|
||||
(int)nzbInfo->GetMarkStatus(), (int)nzbInfo->GetUrlStatus());
|
||||
outfile.PrintLine("%i,%i,%i,%i,%i,%i,%i,%i", (int)nzbInfo->GetParStatus(), (int)nzbInfo->GetUnpackStatus(),
|
||||
(int)nzbInfo->GetMoveStatus(), (int)nzbInfo->GetParRenameStatus(), (int)nzbInfo->GetRarRenameStatus(),
|
||||
(int)nzbInfo->GetDeleteStatus(), (int)nzbInfo->GetMarkStatus(), (int)nzbInfo->GetUrlStatus());
|
||||
outfile.PrintLine("%i,%i,%i", (int)nzbInfo->GetUnpackCleanedUpDisk(), (int)nzbInfo->GetHealthPaused(),
|
||||
(int)nzbInfo->GetAddUrlPaused());
|
||||
outfile.PrintLine("%i,%i,%i", nzbInfo->GetFileCount(), nzbInfo->GetParkedFileCount(),
|
||||
@@ -556,17 +556,29 @@ bool DiskState::LoadNzbInfo(NzbInfo* nzbInfo, Servers* servers, StateDiskFile& i
|
||||
if (postStage > 0)
|
||||
{
|
||||
nzbInfo->EnterPostProcess();
|
||||
if (formatVersion < 59 && postStage == 6)
|
||||
{
|
||||
postStage++;
|
||||
}
|
||||
else if (formatVersion < 59 && postStage > 6)
|
||||
{
|
||||
postStage += 2;
|
||||
}
|
||||
nzbInfo->GetPostInfo()->SetStage((PostInfo::EStage)postStage);
|
||||
}
|
||||
nzbInfo->SetFeedId(feedId);
|
||||
|
||||
int parStatus, unpackStatus, moveStatus, renameStatus, deleteStatus, markStatus, urlStatus;
|
||||
if (infile.ScanLine("%i,%i,%i,%i,%i,%i,%i", &parStatus, &unpackStatus, &moveStatus,
|
||||
&renameStatus, &deleteStatus, &markStatus, &urlStatus) != 7) goto error;
|
||||
int parStatus, unpackStatus, moveStatus, parRenameStatus, rarRenameStatus, deleteStatus, markStatus, urlStatus;
|
||||
if (formatVersion < 58 && infile.ScanLine("%i,%i,%i,%i,%i,%i,%i", &parStatus, &unpackStatus, &moveStatus,
|
||||
&parRenameStatus, &deleteStatus, &markStatus, &urlStatus) != 7) goto error;
|
||||
rarRenameStatus = 0;
|
||||
if (formatVersion >= 58 && infile.ScanLine("%i,%i,%i,%i,%i,%i,%i,%i", &parStatus, &unpackStatus, &moveStatus,
|
||||
&parRenameStatus, &rarRenameStatus, &deleteStatus, &markStatus, &urlStatus) != 8) goto error;
|
||||
nzbInfo->SetParStatus((NzbInfo::EParStatus)parStatus);
|
||||
nzbInfo->SetUnpackStatus((NzbInfo::EUnpackStatus)unpackStatus);
|
||||
nzbInfo->SetMoveStatus((NzbInfo::EMoveStatus)moveStatus);
|
||||
nzbInfo->SetRenameStatus((NzbInfo::ERenameStatus)renameStatus);
|
||||
nzbInfo->SetParRenameStatus((NzbInfo::ERenameStatus)parRenameStatus);
|
||||
nzbInfo->SetRarRenameStatus((NzbInfo::ERenameStatus)rarRenameStatus);
|
||||
nzbInfo->SetDeleteStatus((NzbInfo::EDeleteStatus)deleteStatus);
|
||||
nzbInfo->SetMarkStatus((NzbInfo::EMarkStatus)markStatus);
|
||||
if (nzbInfo->GetKind() == NzbInfo::nkNzb ||
|
||||
|
||||
@@ -336,7 +336,7 @@ public:
|
||||
{
|
||||
rsNone,
|
||||
rsSkipped,
|
||||
rsFailure,
|
||||
rsNothing,
|
||||
rsSuccess
|
||||
};
|
||||
|
||||
@@ -485,8 +485,10 @@ public:
|
||||
void BuildDestDirName();
|
||||
CString BuildFinalDirName();
|
||||
CompletedFileList* GetCompletedFiles() { return &m_completedFiles; }
|
||||
ERenameStatus GetRenameStatus() { return m_renameStatus; }
|
||||
void SetRenameStatus(ERenameStatus renameStatus) { m_renameStatus = renameStatus; }
|
||||
ERenameStatus GetParRenameStatus() { return m_parRenameStatus; }
|
||||
void SetParRenameStatus(ERenameStatus renameStatus) { m_parRenameStatus = renameStatus; }
|
||||
ERenameStatus GetRarRenameStatus() { return m_rarRenameStatus; }
|
||||
void SetRarRenameStatus(ERenameStatus renameStatus) { m_rarRenameStatus = renameStatus; }
|
||||
EParStatus GetParStatus() { return m_parStatus; }
|
||||
void SetParStatus(EParStatus parStatus) { m_parStatus = parStatus; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_unpackStatus; }
|
||||
@@ -616,7 +618,8 @@ private:
|
||||
time_t m_maxTime = 0;
|
||||
int m_priority = 0;
|
||||
CompletedFileList m_completedFiles;
|
||||
ERenameStatus m_renameStatus = rsNone;
|
||||
ERenameStatus m_parRenameStatus = rsNone;
|
||||
ERenameStatus m_rarRenameStatus = rsNone;
|
||||
EParStatus m_parStatus = psNone;
|
||||
EUnpackStatus m_unpackStatus = usNone;
|
||||
ECleanupStatus m_cleanupStatus = csNone;
|
||||
@@ -685,8 +688,10 @@ public:
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
ptRenaming,
|
||||
ptParRenaming,
|
||||
ptRarRenaming,
|
||||
ptUnpacking,
|
||||
ptCleaningUp,
|
||||
ptMoving,
|
||||
ptExecutingScript,
|
||||
ptFinished
|
||||
@@ -726,6 +731,8 @@ public:
|
||||
void SetPassListTried(bool passListTried) { m_passListTried = passListTried; }
|
||||
int GetLastUnpackStatus() { return m_lastUnpackStatus; }
|
||||
void SetLastUnpackStatus(int unpackStatus) { m_lastUnpackStatus = unpackStatus; }
|
||||
bool GetNeedParCheck() { return m_needParCheck; }
|
||||
void SetNeedParCheck(bool needParCheck) { m_needParCheck = needParCheck; }
|
||||
Thread* GetPostThread() { return m_postThread; }
|
||||
void SetPostThread(Thread* postThread) { m_postThread = postThread; }
|
||||
ParredFiles* GetParredFiles() { return &m_parredFiles; }
|
||||
@@ -741,6 +748,7 @@ private:
|
||||
bool m_unpackTried = false;
|
||||
bool m_passListTried = false;
|
||||
int m_lastUnpackStatus = 0;
|
||||
bool m_needParCheck = false;
|
||||
EStage m_stage = ptQueued;
|
||||
CString m_progressLabel = "";
|
||||
int m_fileProgress = 0;
|
||||
@@ -867,9 +875,11 @@ public:
|
||||
eaFilePauseExtraPars, // pause only (almost all) pars, except main par-file (does not affect other files)
|
||||
eaFileReorder, // set file order
|
||||
eaFileSplit, // split - create new group from selected files
|
||||
eaGroupMoveOffset, // move group to m_iOffset relative to the current position in download-queue
|
||||
eaGroupMoveOffset, // move group to offset relative to the current position in download-queue
|
||||
eaGroupMoveTop, // move group to the top of download-queue
|
||||
eaGroupMoveBottom, // move group to the bottom of download-queue
|
||||
eaGroupMoveBefore, // move group to a certain position
|
||||
eaGroupMoveAfter, // move group to a certain position
|
||||
eaGroupPause, // pause group
|
||||
eaGroupResume, // resume (unpause) group
|
||||
eaGroupDelete, // delete group and put to history, delete already downloaded files
|
||||
@@ -918,8 +928,8 @@ public:
|
||||
static GuardedDownloadQueue Guard() { return GuardedDownloadQueue(g_DownloadQueue, &g_DownloadQueue->m_lockMutex); }
|
||||
NzbList* GetQueue() { return &m_queue; }
|
||||
HistoryList* GetHistory() { return &m_history; }
|
||||
virtual bool EditEntry(int ID, EEditAction action, int offset, const char* text) = 0;
|
||||
virtual bool EditList(IdList* idList, NameList* nameList, EMatchMode matchMode, EEditAction action, int offset, const char* text) = 0;
|
||||
virtual bool EditEntry(int ID, EEditAction action, const char* args) = 0;
|
||||
virtual bool EditList(IdList* idList, NameList* nameList, EMatchMode matchMode, EEditAction action, const char* args) = 0;
|
||||
virtual void HistoryChanged() = 0;
|
||||
virtual void Save() = 0;
|
||||
void CalcRemainingSize(int64* remaining, int64* remainingForced);
|
||||
|
||||
@@ -287,7 +287,7 @@ void DupeCoordinator::NzbFound(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
||||
info("Moving collection %s with lower duplicate score to history", queuedNzbInfo->GetName());
|
||||
queuedNzbInfo->SetDeleteStatus(NzbInfo::dsDupe);
|
||||
downloadQueue->EditEntry(queuedNzbInfo->GetId(),
|
||||
DownloadQueue::eaGroupDelete, 0, nullptr);
|
||||
DownloadQueue::eaGroupDelete, nullptr);
|
||||
it = downloadQueue->GetQueue()->begin() + index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,13 +129,13 @@ void HistoryCoordinator::AddToHistory(DownloadQueue* downloadQueue, NzbInfo* nzb
|
||||
// park remaining files
|
||||
for (FileInfo* fileInfo : nzbInfo->GetFileList())
|
||||
{
|
||||
fileInfo->GetNzbInfo()->UpdateCompletedStats(fileInfo);
|
||||
fileInfo->GetNzbInfo()->GetCompletedFiles()->emplace_back(fileInfo->GetId(),
|
||||
nzbInfo->UpdateCompletedStats(fileInfo);
|
||||
nzbInfo->GetCompletedFiles()->emplace_back(fileInfo->GetId(),
|
||||
fileInfo->GetFilename(), CompletedFile::cfNone, 0);
|
||||
}
|
||||
|
||||
// Cleaning up parked files if par-check was successful or unpack was successful or
|
||||
// health is 100% (if unpack and par-check were not performed)
|
||||
// health is 100% (if unpack and par-check were not performed) or if deleted
|
||||
bool cleanupParkedFiles =
|
||||
((nzbInfo->GetParStatus() == NzbInfo::psSuccess ||
|
||||
nzbInfo->GetParStatus() == NzbInfo::psRepairPossible) &&
|
||||
@@ -147,7 +147,13 @@ void HistoryCoordinator::AddToHistory(DownloadQueue* downloadQueue, NzbInfo* nzb
|
||||
(nzbInfo->GetUnpackStatus() <= NzbInfo::usSkipped &&
|
||||
nzbInfo->GetParStatus() != NzbInfo::psFailure &&
|
||||
nzbInfo->GetFailedSize() - nzbInfo->GetParFailedSize() == 0) ||
|
||||
nzbInfo->GetUnpackCleanedUpDisk();
|
||||
(nzbInfo->GetDeleteStatus() != NzbInfo::dsNone);
|
||||
|
||||
// Do not cleanup when parking
|
||||
cleanupParkedFiles &= !nzbInfo->GetParking();
|
||||
|
||||
// Parking not possible if files were already deleted
|
||||
cleanupParkedFiles |= nzbInfo->GetUnpackCleanedUpDisk();
|
||||
|
||||
if (cleanupParkedFiles)
|
||||
{
|
||||
@@ -158,7 +164,10 @@ void HistoryCoordinator::AddToHistory(DownloadQueue* downloadQueue, NzbInfo* nzb
|
||||
nzbInfo->SetParkedFileCount(0);
|
||||
for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles())
|
||||
{
|
||||
if (completedFile.GetStatus() == CompletedFile::cfNone)
|
||||
if (completedFile.GetStatus() == CompletedFile::cfNone ||
|
||||
// consider last completed file with partial status not completely tried
|
||||
(completedFile.GetStatus() == CompletedFile::cfPartial &&
|
||||
&completedFile == &*nzbInfo->GetCompletedFiles()->rbegin()))
|
||||
{
|
||||
nzbInfo->PrintMessage(Message::mkDetail, "Parking file %s", completedFile.GetFileName());
|
||||
nzbInfo->SetParkedFileCount(nzbInfo->GetParkedFileCount() + 1);
|
||||
@@ -223,7 +232,8 @@ void HistoryCoordinator::PrepareEdit(DownloadQueue* downloadQueue, IdList* idLis
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryCoordinator::EditList(DownloadQueue* downloadQueue, IdList* idList, DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
bool HistoryCoordinator::EditList(DownloadQueue* downloadQueue, IdList* idList,
|
||||
DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
bool ok = false;
|
||||
PrepareEdit(downloadQueue, idList, action);
|
||||
@@ -261,22 +271,22 @@ bool HistoryCoordinator::EditList(DownloadQueue* downloadQueue, IdList* idList,
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetParameter:
|
||||
ok = HistorySetParameter(historyInfo, text);
|
||||
ok = HistorySetParameter(historyInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetCategory:
|
||||
ok = HistorySetCategory(historyInfo, text);
|
||||
ok = HistorySetCategory(historyInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetName:
|
||||
ok = HistorySetName(historyInfo, text);
|
||||
ok = HistorySetName(historyInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistorySetDupeKey:
|
||||
case DownloadQueue::eaHistorySetDupeScore:
|
||||
case DownloadQueue::eaHistorySetDupeMode:
|
||||
case DownloadQueue::eaHistorySetDupeBackup:
|
||||
HistorySetDupeParam(historyInfo, action, text);
|
||||
HistorySetDupeParam(historyInfo, action, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaHistoryMarkBad:
|
||||
@@ -370,7 +380,8 @@ void HistoryCoordinator::MoveToQueue(DownloadQueue* downloadQueue, HistoryList::
|
||||
{
|
||||
nzbInfo->SetUnpackStatus(NzbInfo::usNone);
|
||||
nzbInfo->SetCleanupStatus(NzbInfo::csNone);
|
||||
nzbInfo->SetRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetParRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetRarRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetPostTotalSec(nzbInfo->GetPostTotalSec() - nzbInfo->GetUnpackSec());
|
||||
nzbInfo->SetUnpackSec(0);
|
||||
|
||||
@@ -480,7 +491,8 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* downloadQueue, History
|
||||
nzbInfo->SetMoveStatus(NzbInfo::msNone);
|
||||
nzbInfo->SetUnpackCleanedUpDisk(false);
|
||||
nzbInfo->SetParStatus(NzbInfo::psNone);
|
||||
nzbInfo->SetRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetParRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetRarRenameStatus(NzbInfo::rsNone);
|
||||
nzbInfo->SetDownloadedSize(0);
|
||||
nzbInfo->SetDownloadSec(0);
|
||||
nzbInfo->SetPostTotalSec(0);
|
||||
@@ -576,7 +588,6 @@ void HistoryCoordinator::HistoryRetry(DownloadQueue* downloadQueue, HistoryList:
|
||||
(resetFailed || fileInfo->GetRemainingSize() > 0))))
|
||||
{
|
||||
fileInfo->SetFilename(completedFile.GetFileName());
|
||||
fileInfo->SetPaused(fileInfo->GetParFile());
|
||||
fileInfo->SetNzbInfo(nzbInfo);
|
||||
|
||||
BString<1024> outputFilename("%s%c%s", nzbInfo->GetDestDir(), PATH_SEPARATOR, fileInfo->GetFilename());
|
||||
@@ -595,6 +606,7 @@ void HistoryCoordinator::HistoryRetry(DownloadQueue* downloadQueue, HistoryList:
|
||||
else if (!reprocess)
|
||||
{
|
||||
nzbInfo->PrintMessage(Message::mkWarning, "File %s could not be found on disk, downloading again", fileInfo->GetFilename());
|
||||
fileInfo->SetPartialState(FileInfo::psNone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,6 +631,11 @@ void HistoryCoordinator::HistoryRetry(DownloadQueue* downloadQueue, HistoryList:
|
||||
nzbInfo->UpdateCurrentStats();
|
||||
|
||||
MoveToQueue(downloadQueue, itHistory, historyInfo, reprocess);
|
||||
|
||||
if (g_Options->GetParCheck() != Options::pcForce)
|
||||
{
|
||||
downloadQueue->EditEntry(nzbInfo->GetId(), DownloadQueue::eaGroupPauseExtraPars, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryCoordinator::ResetArticles(FileInfo* fileInfo, bool allFailed, bool resetFailed)
|
||||
|
||||
@@ -28,7 +28,7 @@ class HistoryCoordinator : public Service
|
||||
{
|
||||
public:
|
||||
void AddToHistory(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
|
||||
bool EditList(DownloadQueue* downloadQueue, IdList* idList, DownloadQueue::EEditAction action, int offset, const char* text);
|
||||
bool EditList(DownloadQueue* downloadQueue, IdList* idList, DownloadQueue::EEditAction action, const char* args);
|
||||
void DeleteDiskFiles(NzbInfo* nzbInfo);
|
||||
void HistoryHide(DownloadQueue* downloadQueue, HistoryInfo* historyInfo, int rindex);
|
||||
void Redownload(DownloadQueue* downloadQueue, HistoryInfo* historyInfo);
|
||||
|
||||
@@ -32,16 +32,16 @@
|
||||
#include "StatMeter.h"
|
||||
|
||||
bool QueueCoordinator::CoordinatorDownloadQueue::EditEntry(
|
||||
int ID, EEditAction action, int offset, const char* text)
|
||||
int ID, EEditAction action, const char* args)
|
||||
{
|
||||
return m_owner->m_queueEditor.EditEntry(&m_owner->m_downloadQueue, ID, action, offset, text);
|
||||
return m_owner->m_queueEditor.EditEntry(&m_owner->m_downloadQueue, ID, action, args);
|
||||
}
|
||||
|
||||
bool QueueCoordinator::CoordinatorDownloadQueue::EditList(
|
||||
IdList* idList, NameList* nameList, EMatchMode matchMode, EEditAction action, int offset, const char* text)
|
||||
IdList* idList, NameList* nameList, EMatchMode matchMode, EEditAction action, const char* args)
|
||||
{
|
||||
m_massEdit = true;
|
||||
bool ret = m_owner->m_queueEditor.EditList(&m_owner->m_downloadQueue, idList, nameList, matchMode, action, offset, text);
|
||||
bool ret = m_owner->m_queueEditor.EditList(&m_owner->m_downloadQueue, idList, nameList, matchMode, action, args);
|
||||
m_massEdit = false;
|
||||
if (m_wantSave)
|
||||
{
|
||||
@@ -256,23 +256,31 @@ void QueueCoordinator::Run()
|
||||
}
|
||||
}
|
||||
|
||||
WaitJobs();
|
||||
SavePartialState();
|
||||
|
||||
debug("Exiting QueueCoordinator-loop");
|
||||
}
|
||||
|
||||
void QueueCoordinator::WaitJobs()
|
||||
{
|
||||
// waiting for downloads
|
||||
debug("QueueCoordinator: waiting for Downloads to complete");
|
||||
bool completed = false;
|
||||
while (!completed)
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
completed = m_activeDownloads.size() == 0;
|
||||
if (m_activeDownloads.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep(100 * 1000);
|
||||
ResetHangingDownloads();
|
||||
}
|
||||
|
||||
debug("QueueCoordinator: Downloads are completed");
|
||||
|
||||
SavePartialState();
|
||||
|
||||
debug("Exiting QueueCoordinator-loop");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -371,7 +379,10 @@ NzbInfo* QueueCoordinator::AddNzbFileToQueue(std::unique_ptr<NzbInfo> nzbInfo, N
|
||||
{
|
||||
// in a case if none of listeners did already delete the temporary object - we do it ourselves
|
||||
downloadQueue->GetQueue()->Remove(addedNzb);
|
||||
addedNzb = nullptr;
|
||||
if (!downloadQueue->GetHistory()->Find(addedNzb->GetId()))
|
||||
{
|
||||
addedNzb = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
downloadQueue->Save();
|
||||
@@ -709,7 +720,8 @@ void QueueCoordinator::DeleteFileInfo(DownloadQueue* downloadQueue, FileInfo* fi
|
||||
{
|
||||
fileInfo->GetNzbInfo()->GetCompletedFiles()->emplace_back(
|
||||
fileInfo->GetId(),
|
||||
completed ? FileSystem::BaseFileName(fileInfo->GetOutputFilename()) : fileInfo->GetFilename(),
|
||||
completed && fileInfo->GetOutputFilename() ?
|
||||
FileSystem::BaseFileName(fileInfo->GetOutputFilename()) : fileInfo->GetFilename(),
|
||||
fileStatus,
|
||||
fileStatus == CompletedFile::cfSuccess ? fileInfo->GetCrc() : 0);
|
||||
}
|
||||
@@ -807,7 +819,7 @@ void QueueCoordinator::CheckHealth(DownloadQueue* downloadQueue, FileInfo* fileI
|
||||
warn("Pausing %s due to health %.1f%% below critical %.1f%%", fileInfo->GetNzbInfo()->GetName(),
|
||||
fileInfo->GetNzbInfo()->CalcHealth() / 10.0, fileInfo->GetNzbInfo()->CalcCriticalHealth(true) / 10.0);
|
||||
fileInfo->GetNzbInfo()->SetHealthPaused(true);
|
||||
downloadQueue->EditEntry(fileInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupPause, 0, nullptr);
|
||||
downloadQueue->EditEntry(fileInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupPause, nullptr);
|
||||
}
|
||||
else if (g_Options->GetHealthCheck() == Options::hcDelete ||
|
||||
g_Options->GetHealthCheck() == Options::hcPark)
|
||||
@@ -819,7 +831,7 @@ void QueueCoordinator::CheckHealth(DownloadQueue* downloadQueue, FileInfo* fileI
|
||||
fileInfo->GetNzbInfo()->SetDeleteStatus(NzbInfo::dsHealth);
|
||||
downloadQueue->EditEntry(fileInfo->GetNzbInfo()->GetId(),
|
||||
g_Options->GetHealthCheck() == Options::hcPark ? DownloadQueue::eaGroupParkDelete : DownloadQueue::eaGroupDelete,
|
||||
0, nullptr);
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,9 @@ private:
|
||||
class CoordinatorDownloadQueue : public DownloadQueue
|
||||
{
|
||||
public:
|
||||
virtual bool EditEntry(int ID, EEditAction action, int offset, const char* text);
|
||||
virtual bool EditEntry(int ID, EEditAction action, const char* args);
|
||||
virtual bool EditList(IdList* idList, NameList* nameList, EMatchMode matchMode,
|
||||
EEditAction action, int offset, const char* text);
|
||||
EEditAction action, const char* args);
|
||||
virtual void HistoryChanged() { m_historyChanged = true; }
|
||||
virtual void Save();
|
||||
private:
|
||||
@@ -90,6 +90,7 @@ private:
|
||||
void Load();
|
||||
void SavePartialState();
|
||||
void LoadPartialState(FileInfo* fileInfo);
|
||||
void WaitJobs();
|
||||
};
|
||||
|
||||
extern QueueCoordinator* g_QueueCoordinator;
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
GroupSorter(NzbList* nzbList, QueueEditor::ItemList* sortItemList) :
|
||||
m_nzbList(nzbList), m_sortItemList(sortItemList) {}
|
||||
bool Execute(const char* sort);
|
||||
bool operator()(std::unique_ptr<NzbInfo>& refNzbInfo1, std::unique_ptr<NzbInfo>& refNzbInfo2) const;
|
||||
bool operator()(const std::unique_ptr<NzbInfo>& refNzbInfo1, const std::unique_ptr<NzbInfo>& refNzbInfo2) const;
|
||||
|
||||
private:
|
||||
enum ESortCriteria
|
||||
@@ -62,8 +62,6 @@ private:
|
||||
QueueEditor::ItemList* m_sortItemList;
|
||||
ESortCriteria m_sortCriteria;
|
||||
ESortOrder m_sortOrder;
|
||||
|
||||
void AlignSelectedGroups();
|
||||
};
|
||||
|
||||
bool GroupSorter::Execute(const char* sort)
|
||||
@@ -112,8 +110,6 @@ bool GroupSorter::Execute(const char* sort)
|
||||
m_sortOrder = soAuto;
|
||||
}
|
||||
|
||||
AlignSelectedGroups();
|
||||
|
||||
RawNzbList tempList;
|
||||
for (NzbInfo* nzbInfo : m_nzbList)
|
||||
{
|
||||
@@ -126,23 +122,23 @@ bool GroupSorter::Execute(const char* sort)
|
||||
m_sortOrder = soDescending;
|
||||
}
|
||||
|
||||
std::sort(m_nzbList->begin(), m_nzbList->end(), *this);
|
||||
std::stable_sort(m_nzbList->begin(), m_nzbList->end(), *this);
|
||||
|
||||
if (origSortOrder == soAuto &&
|
||||
std::equal(tempList.begin(), tempList.end(), m_nzbList->begin(), m_nzbList->end(),
|
||||
std::equal(tempList.begin(), tempList.end(), m_nzbList->begin(),
|
||||
[](NzbInfo* nzbInfo1, std::unique_ptr<NzbInfo>& nzbInfo2)
|
||||
{
|
||||
return nzbInfo1 == nzbInfo2.get();
|
||||
}))
|
||||
{
|
||||
m_sortOrder = m_sortOrder == soDescending ? soAscending : soDescending;
|
||||
std::sort(m_nzbList->begin(), m_nzbList->end(), *this);
|
||||
std::stable_sort(m_nzbList->begin(), m_nzbList->end(), *this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GroupSorter::operator()(std::unique_ptr<NzbInfo>& refNzbInfo1, std::unique_ptr<NzbInfo>& refNzbInfo2) const
|
||||
bool GroupSorter::operator()(const std::unique_ptr<NzbInfo>& refNzbInfo1, const std::unique_ptr<NzbInfo>& refNzbInfo2) const
|
||||
{
|
||||
NzbInfo* nzbInfo1 = refNzbInfo1.get();
|
||||
NzbInfo* nzbInfo2 = refNzbInfo2.get();
|
||||
@@ -200,44 +196,6 @@ bool GroupSorter::operator()(std::unique_ptr<NzbInfo>& refNzbInfo1, std::unique_
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GroupSorter::AlignSelectedGroups()
|
||||
{
|
||||
NzbInfo* lastNzbInfo = nullptr;
|
||||
uint32 lastNum = 0;
|
||||
uint32 num = 0;
|
||||
while (num < m_nzbList->size())
|
||||
{
|
||||
std::unique_ptr<NzbInfo>& nzbInfo = m_nzbList->at(num);
|
||||
|
||||
bool selected = false;
|
||||
for (QueueEditor::EditItem& item : m_sortItemList)
|
||||
{
|
||||
if (item.m_nzbInfo == nzbInfo.get())
|
||||
{
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
if (lastNzbInfo && num - lastNum > 1)
|
||||
{
|
||||
std::unique_ptr<NzbInfo> movedNzbInfo = std::move(*(m_nzbList->begin() + num));
|
||||
m_nzbList->erase(m_nzbList->begin() + num);
|
||||
m_nzbList->insert(m_nzbList->begin() + lastNum + 1, std::move(movedNzbInfo));
|
||||
lastNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastNum = num;
|
||||
}
|
||||
lastNzbInfo = nzbInfo.get();
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FileInfo* QueueEditor::FindFileInfo(int id)
|
||||
{
|
||||
@@ -252,17 +210,11 @@ FileInfo* QueueEditor::FindFileInfo(int id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pause flag of the specific entry in the queue
|
||||
*/
|
||||
void QueueEditor::PauseUnpauseEntry(FileInfo* fileInfo, bool pause)
|
||||
{
|
||||
fileInfo->SetPaused(pause);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes entry
|
||||
*/
|
||||
void QueueEditor::DeleteEntry(FileInfo* fileInfo)
|
||||
{
|
||||
if (!fileInfo->GetDeleted())
|
||||
@@ -274,9 +226,6 @@ void QueueEditor::DeleteEntry(FileInfo* fileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves entry in the queue
|
||||
*/
|
||||
void QueueEditor::MoveEntry(FileInfo* fileInfo, int offset)
|
||||
{
|
||||
int entry = 0;
|
||||
@@ -309,9 +258,6 @@ void QueueEditor::MoveEntry(FileInfo* fileInfo, int offset)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves group in the queue
|
||||
*/
|
||||
void QueueEditor::MoveGroup(NzbInfo* nzbInfo, int offset)
|
||||
{
|
||||
int entry = 0;
|
||||
@@ -344,24 +290,24 @@ void QueueEditor::MoveGroup(NzbInfo* nzbInfo, int offset)
|
||||
}
|
||||
}
|
||||
|
||||
bool QueueEditor::EditEntry(DownloadQueue* downloadQueue, int ID, DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
bool QueueEditor::EditEntry(DownloadQueue* downloadQueue, int ID, DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
m_downloadQueue = downloadQueue;
|
||||
IdList cIdList;
|
||||
cIdList.push_back(ID);
|
||||
return InternEditList(nullptr, &cIdList, action, offset, text);
|
||||
return InternEditList(nullptr, &cIdList, action, args);
|
||||
}
|
||||
|
||||
bool QueueEditor::EditList(DownloadQueue* downloadQueue, IdList* idList, NameList* nameList, DownloadQueue::EMatchMode matchMode,
|
||||
DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
if (action == DownloadQueue::eaPostDelete)
|
||||
{
|
||||
return g_PrePostProcessor->EditList(downloadQueue, idList, action, offset, text);
|
||||
return g_PrePostProcessor->EditList(downloadQueue, idList, action, args);
|
||||
}
|
||||
else if (DownloadQueue::eaHistoryDelete <= action && action <= DownloadQueue::eaHistorySetName)
|
||||
{
|
||||
return g_HistoryCoordinator->EditList(downloadQueue, idList, action, offset, text);
|
||||
return g_HistoryCoordinator->EditList(downloadQueue, idList, action, args);
|
||||
}
|
||||
|
||||
m_downloadQueue = downloadQueue;
|
||||
@@ -376,7 +322,7 @@ bool QueueEditor::EditList(DownloadQueue* downloadQueue, IdList* idList, NameLis
|
||||
ok = BuildIdListFromNameList(idList, nameList, matchMode, action);
|
||||
}
|
||||
|
||||
ok = ok && (InternEditList(nullptr, idList, action, offset, text) || matchMode == DownloadQueue::mmRegEx);
|
||||
ok = ok && (InternEditList(nullptr, idList, action, args) || matchMode == DownloadQueue::mmRegEx);
|
||||
|
||||
m_downloadQueue->Save();
|
||||
|
||||
@@ -384,12 +330,14 @@ bool QueueEditor::EditList(DownloadQueue* downloadQueue, IdList* idList, NameLis
|
||||
}
|
||||
|
||||
bool QueueEditor::InternEditList(ItemList* itemList,
|
||||
IdList* idList, DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
IdList* idList, DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
ItemList workItems;
|
||||
if (!itemList)
|
||||
{
|
||||
itemList = &workItems;
|
||||
int offset = args && (action == DownloadQueue::eaFileMoveOffset ||
|
||||
action == DownloadQueue::eaGroupMoveOffset) ? atoi(args) : 0;
|
||||
PrepareList(itemList, idList, action, offset);
|
||||
}
|
||||
|
||||
@@ -404,10 +352,14 @@ bool QueueEditor::InternEditList(ItemList* itemList,
|
||||
return MergeGroups(itemList);
|
||||
|
||||
case DownloadQueue::eaGroupSort:
|
||||
return SortGroups(itemList, text);
|
||||
return SortGroups(itemList, args);
|
||||
|
||||
case DownloadQueue::eaGroupMoveAfter:
|
||||
case DownloadQueue::eaGroupMoveBefore:
|
||||
return MoveGroupsTo(itemList, idList, action == DownloadQueue::eaGroupMoveBefore, args);
|
||||
|
||||
case DownloadQueue::eaFileSplit:
|
||||
return SplitGroup(itemList, text);
|
||||
return SplitGroup(itemList, args);
|
||||
|
||||
case DownloadQueue::eaFileReorder:
|
||||
ReorderFiles(itemList);
|
||||
@@ -437,26 +389,26 @@ bool QueueEditor::InternEditList(ItemList* itemList,
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupSetPriority:
|
||||
SetNzbPriority(item.m_nzbInfo, text);
|
||||
SetNzbPriority(item.m_nzbInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupSetCategory:
|
||||
case DownloadQueue::eaGroupApplyCategory:
|
||||
SetNzbCategory(item.m_nzbInfo, text, action == DownloadQueue::eaGroupApplyCategory);
|
||||
SetNzbCategory(item.m_nzbInfo, args, action == DownloadQueue::eaGroupApplyCategory);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupSetName:
|
||||
SetNzbName(item.m_nzbInfo, text);
|
||||
SetNzbName(item.m_nzbInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupSetDupeKey:
|
||||
case DownloadQueue::eaGroupSetDupeScore:
|
||||
case DownloadQueue::eaGroupSetDupeMode:
|
||||
SetNzbDupeParam(item.m_nzbInfo, action, text);
|
||||
SetNzbDupeParam(item.m_nzbInfo, action, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupSetParameter:
|
||||
SetNzbParameter(item.m_nzbInfo, text);
|
||||
SetNzbParameter(item.m_nzbInfo, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupMoveTop:
|
||||
@@ -469,7 +421,7 @@ bool QueueEditor::InternEditList(ItemList* itemList,
|
||||
case DownloadQueue::eaGroupResume:
|
||||
case DownloadQueue::eaGroupPauseAllPars:
|
||||
case DownloadQueue::eaGroupPauseExtraPars:
|
||||
EditGroup(item.m_nzbInfo, action, offset, text);
|
||||
EditGroup(item.m_nzbInfo, action, args);
|
||||
break;
|
||||
|
||||
case DownloadQueue::eaGroupDelete:
|
||||
@@ -482,7 +434,7 @@ bool QueueEditor::InternEditList(ItemList* itemList,
|
||||
}
|
||||
else
|
||||
{
|
||||
EditGroup(item.m_nzbInfo, action, offset, text);
|
||||
EditGroup(item.m_nzbInfo, action, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -566,15 +518,15 @@ void QueueEditor::PrepareList(ItemList* itemList, IdList* idList,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((offset != 0) &&
|
||||
(action == DownloadQueue::eaGroupMoveOffset || action == DownloadQueue::eaGroupMoveTop || action == DownloadQueue::eaGroupMoveBottom))
|
||||
else if (((offset != 0) &&
|
||||
(action == DownloadQueue::eaGroupMoveOffset || action == DownloadQueue::eaGroupMoveTop || action == DownloadQueue::eaGroupMoveBottom)) ||
|
||||
action == DownloadQueue::eaGroupMoveBefore || action == DownloadQueue::eaGroupMoveAfter)
|
||||
{
|
||||
// add IDs to list in order they currently have in download queue
|
||||
// per group only one FileInfo is added to the list
|
||||
int nrEntries = (int)m_downloadQueue->GetQueue()->size();
|
||||
int lastDestPos = -1;
|
||||
int start, end, step;
|
||||
if (offset < 0)
|
||||
if (offset <= 0)
|
||||
{
|
||||
start = 0;
|
||||
end = nrEntries;
|
||||
@@ -756,7 +708,7 @@ bool QueueEditor::BuildIdListFromNameList(IdList* idList, NameList* nameList, Do
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QueueEditor::EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, int offset, const char* text)
|
||||
bool QueueEditor::EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, const char* args)
|
||||
{
|
||||
ItemList itemList;
|
||||
bool allPaused = true;
|
||||
@@ -778,7 +730,7 @@ bool QueueEditor::EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action,
|
||||
nzbInfo->SetParking(action == DownloadQueue::eaGroupParkDelete &&
|
||||
g_Options->GetKeepHistory() > 0 &&
|
||||
!nzbInfo->GetUnpackCleanedUpDisk() &&
|
||||
(nzbInfo->GetSuccessArticles() > 0 || nzbInfo->GetFailedArticles() > 0));
|
||||
nzbInfo->GetCurrentSuccessArticles() > 0);
|
||||
nzbInfo->SetAvoidHistory(action == DownloadQueue::eaGroupFinalDelete);
|
||||
nzbInfo->SetDeletePaused(allPaused);
|
||||
if (action == DownloadQueue::eaGroupDupeDelete)
|
||||
@@ -803,6 +755,8 @@ bool QueueEditor::EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action,
|
||||
DownloadQueue::eaFileMoveOffset,
|
||||
DownloadQueue::eaFileMoveTop,
|
||||
DownloadQueue::eaFileMoveBottom,
|
||||
(DownloadQueue::EEditAction)0,
|
||||
(DownloadQueue::EEditAction)0,
|
||||
DownloadQueue::eaFilePause,
|
||||
DownloadQueue::eaFileResume,
|
||||
DownloadQueue::eaFileDelete,
|
||||
@@ -816,7 +770,7 @@ bool QueueEditor::EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action,
|
||||
(DownloadQueue::EEditAction)0,
|
||||
(DownloadQueue::EEditAction)0 };
|
||||
|
||||
bool ok = InternEditList(&itemList, nullptr, GroupToFileMap[action], offset, text);
|
||||
bool ok = InternEditList(&itemList, nullptr, GroupToFileMap[action], args);
|
||||
|
||||
if ((action == DownloadQueue::eaGroupDelete || action == DownloadQueue::eaGroupDupeDelete || action == DownloadQueue::eaGroupFinalDelete) &&
|
||||
// NZBInfo could have been destroyed already
|
||||
@@ -950,16 +904,16 @@ void QueueEditor::SetNzbCategory(NzbInfo* nzbInfo, const char* category, bool ap
|
||||
debug("QueueEditor: setting category '%s' for '%s'", category, nzbInfo->GetName());
|
||||
|
||||
bool oldUnpack = g_Options->GetUnpack();
|
||||
const char* oldPostScript = g_Options->GetPostScript();
|
||||
const char* oldExtensions = g_Options->GetExtensions();
|
||||
if (applyParams && !Util::EmptyStr(nzbInfo->GetCategory()))
|
||||
{
|
||||
Options::Category* categoryObj = g_Options->FindCategory(nzbInfo->GetCategory(), false);
|
||||
if (categoryObj)
|
||||
{
|
||||
oldUnpack = categoryObj->GetUnpack();
|
||||
if (!Util::EmptyStr(categoryObj->GetPostScript()))
|
||||
if (!Util::EmptyStr(categoryObj->GetExtensions()))
|
||||
{
|
||||
oldPostScript = categoryObj->GetPostScript();
|
||||
oldExtensions = categoryObj->GetExtensions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,16 +926,16 @@ void QueueEditor::SetNzbCategory(NzbInfo* nzbInfo, const char* category, bool ap
|
||||
}
|
||||
|
||||
bool newUnpack = g_Options->GetUnpack();
|
||||
const char* newPostScript = g_Options->GetPostScript();
|
||||
const char* newExtensions = g_Options->GetExtensions();
|
||||
if (!Util::EmptyStr(nzbInfo->GetCategory()))
|
||||
{
|
||||
Options::Category* categoryObj = g_Options->FindCategory(nzbInfo->GetCategory(), false);
|
||||
if (categoryObj)
|
||||
{
|
||||
newUnpack = categoryObj->GetUnpack();
|
||||
if (!Util::EmptyStr(categoryObj->GetPostScript()))
|
||||
if (!Util::EmptyStr(categoryObj->GetExtensions()))
|
||||
{
|
||||
newPostScript = categoryObj->GetPostScript();
|
||||
newExtensions = categoryObj->GetExtensions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -991,15 +945,15 @@ void QueueEditor::SetNzbCategory(NzbInfo* nzbInfo, const char* category, bool ap
|
||||
nzbInfo->GetParameters()->SetParameter("*Unpack:", newUnpack ? "yes" : "no");
|
||||
}
|
||||
|
||||
if (strcasecmp(oldPostScript, newPostScript))
|
||||
if (strcasecmp(oldExtensions, newExtensions))
|
||||
{
|
||||
// add new params not existed in old category
|
||||
Tokenizer tokNew(newPostScript, ",;");
|
||||
Tokenizer tokNew(newExtensions, ",;");
|
||||
while (const char* newScriptName = tokNew.Next())
|
||||
{
|
||||
bool found = false;
|
||||
const char* oldScriptName;
|
||||
Tokenizer tokOld(oldPostScript, ",;");
|
||||
Tokenizer tokOld(oldExtensions, ",;");
|
||||
while ((oldScriptName = tokOld.Next()) && !found)
|
||||
{
|
||||
found = !strcasecmp(newScriptName, oldScriptName);
|
||||
@@ -1011,12 +965,12 @@ void QueueEditor::SetNzbCategory(NzbInfo* nzbInfo, const char* category, bool ap
|
||||
}
|
||||
|
||||
// remove old params not existed in new category
|
||||
Tokenizer tokOld(oldPostScript, ",;");
|
||||
Tokenizer tokOld(oldExtensions, ",;");
|
||||
while (const char* oldScriptName = tokOld.Next())
|
||||
{
|
||||
bool found = false;
|
||||
const char* newScriptName;
|
||||
Tokenizer tokNew(newPostScript, ",;");
|
||||
Tokenizer tokNew(newExtensions, ",;");
|
||||
while ((newScriptName = tokNew.Next()) && !found)
|
||||
{
|
||||
found = !strcasecmp(newScriptName, oldScriptName);
|
||||
@@ -1084,10 +1038,137 @@ bool QueueEditor::SplitGroup(ItemList* itemList, const char* name)
|
||||
|
||||
bool QueueEditor::SortGroups(ItemList* itemList, const char* sort)
|
||||
{
|
||||
AlignGroups(itemList);
|
||||
GroupSorter sorter(m_downloadQueue->GetQueue(), itemList);
|
||||
return sorter.Execute(sort);
|
||||
}
|
||||
|
||||
void QueueEditor::AlignGroups(ItemList* itemList)
|
||||
{
|
||||
NzbList* nzbList = m_downloadQueue->GetQueue();
|
||||
NzbInfo* lastNzbInfo = nullptr;
|
||||
uint32 lastNum = 0;
|
||||
uint32 num = 0;
|
||||
while (num < nzbList->size())
|
||||
{
|
||||
std::unique_ptr<NzbInfo>& nzbInfo = nzbList->at(num);
|
||||
|
||||
bool selected = false;
|
||||
for (QueueEditor::EditItem& item : itemList)
|
||||
{
|
||||
if (item.m_nzbInfo == nzbInfo.get())
|
||||
{
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
if (lastNzbInfo && num - lastNum > 1)
|
||||
{
|
||||
std::unique_ptr<NzbInfo> movedNzbInfo = std::move(*(nzbList->begin() + num));
|
||||
nzbList->erase(nzbList->begin() + num);
|
||||
nzbList->insert(nzbList->begin() + lastNum + 1, std::move(movedNzbInfo));
|
||||
lastNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastNum = num;
|
||||
}
|
||||
lastNzbInfo = nzbInfo.get();
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
bool QueueEditor::ItemListContainsItem(ItemList* itemList, int id)
|
||||
{
|
||||
return std::find_if(itemList->begin(), itemList->end(),
|
||||
[id](const EditItem& item)
|
||||
{
|
||||
return item.m_nzbInfo->GetId() == id;
|
||||
}) != itemList->end();
|
||||
};
|
||||
|
||||
bool QueueEditor::MoveGroupsTo(ItemList* itemList, IdList* idList, bool before, const char* args)
|
||||
{
|
||||
if (itemList->size() == 0 || Util::EmptyStr(args))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int targetId = atoi(args);
|
||||
int offset = 0;
|
||||
|
||||
// check if target is in list of moved items
|
||||
if (ItemListContainsItem(itemList, targetId))
|
||||
{
|
||||
// find the next item to use as target-before
|
||||
bool found = false;
|
||||
bool targetSet = false;
|
||||
|
||||
for (NzbInfo* nzbInfo : m_downloadQueue->GetQueue())
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
if (!ItemListContainsItem(itemList, nzbInfo->GetId()))
|
||||
{
|
||||
targetId = nzbInfo->GetId();
|
||||
before = true;
|
||||
targetSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (targetId == nzbInfo->GetId())
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetSet)
|
||||
{
|
||||
// there are no next item; move to the bottom then
|
||||
offset = MAX_ID;
|
||||
}
|
||||
}
|
||||
|
||||
AlignGroups(itemList);
|
||||
|
||||
if (offset == 0)
|
||||
{
|
||||
// calculate offset between first moving item and target
|
||||
int moveId = itemList->at(0).m_nzbInfo->GetId();
|
||||
bool progress = false;
|
||||
int step = 0;
|
||||
for (NzbInfo* nzbInfo : m_downloadQueue->GetQueue())
|
||||
{
|
||||
int id = nzbInfo->GetId();
|
||||
if (id == targetId || id == moveId)
|
||||
{
|
||||
if (!progress)
|
||||
{
|
||||
step = id == targetId ? -1 : 1;
|
||||
offset = (before ? 0 : 1) - (step > 0 ? itemList->size() : 0);
|
||||
progress = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
offset += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return InternEditList(nullptr, idList, DownloadQueue::eaGroupMoveOffset,
|
||||
CString::FormatStr("%i", offset));
|
||||
}
|
||||
|
||||
void QueueEditor::ReorderFiles(ItemList* itemList)
|
||||
{
|
||||
if (itemList->size() == 0)
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
class QueueEditor
|
||||
{
|
||||
public:
|
||||
bool EditEntry(DownloadQueue* downloadQueue, int ID, DownloadQueue::EEditAction action, int offset, const char* text);
|
||||
bool EditList(DownloadQueue* downloadQueue, IdList* idList, NameList* nameList, DownloadQueue::EMatchMode matchMode, DownloadQueue::EEditAction action, int offset, const char* text);
|
||||
bool EditEntry(DownloadQueue* downloadQueue, int ID, DownloadQueue::EEditAction action, const char* args);
|
||||
bool EditList(DownloadQueue* downloadQueue, IdList* idList, NameList* nameList, DownloadQueue::EMatchMode matchMode, DownloadQueue::EEditAction action, const char* args);
|
||||
|
||||
private:
|
||||
class EditItem
|
||||
@@ -46,10 +46,10 @@ private:
|
||||
DownloadQueue* m_downloadQueue;
|
||||
|
||||
FileInfo* FindFileInfo(int id);
|
||||
bool InternEditList(ItemList* itemList, IdList* idList, DownloadQueue::EEditAction action, int offset, const char* text);
|
||||
bool InternEditList(ItemList* itemList, IdList* idList, DownloadQueue::EEditAction action, const char* args);
|
||||
void PrepareList(ItemList* itemList, IdList* idList, DownloadQueue::EEditAction action, int offset);
|
||||
bool BuildIdListFromNameList(IdList* idList, NameList* nameList, DownloadQueue::EMatchMode matchMode, DownloadQueue::EEditAction action);
|
||||
bool EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, int offset, const char* text);
|
||||
bool EditGroup(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, const char* args);
|
||||
void PauseParsInGroups(ItemList* itemList, bool extraParsOnly);
|
||||
void PausePars(RawFileList* fileList, bool extraParsOnly);
|
||||
void SetNzbPriority(NzbInfo* nzbInfo, const char* priority);
|
||||
@@ -57,15 +57,18 @@ private:
|
||||
void SetNzbName(NzbInfo* nzbInfo, const char* name);
|
||||
bool MergeGroups(ItemList* itemList);
|
||||
bool SortGroups(ItemList* itemList, const char* sort);
|
||||
void AlignGroups(ItemList* itemList);
|
||||
bool MoveGroupsTo(ItemList* itemList, IdList* idList, bool before, const char* args);
|
||||
bool SplitGroup(ItemList* itemList, const char* name);
|
||||
bool DeleteUrl(NzbInfo* nzbInfo, DownloadQueue::EEditAction action);
|
||||
void ReorderFiles(ItemList* itemList);
|
||||
void SetNzbParameter(NzbInfo* nzbInfo, const char* paramString);
|
||||
void SetNzbDupeParam(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, const char* text);
|
||||
void SetNzbDupeParam(NzbInfo* nzbInfo, DownloadQueue::EEditAction action, const char* args);
|
||||
void PauseUnpauseEntry(FileInfo* fileInfo, bool pause);
|
||||
void DeleteEntry(FileInfo* fileInfo);
|
||||
void MoveEntry(FileInfo* fileInfo, int offset);
|
||||
void MoveGroup(NzbInfo* nzbInfo, int offset);
|
||||
bool ItemListContainsItem(ItemList* itemList, int id);
|
||||
|
||||
friend class GroupSorter;
|
||||
};
|
||||
|
||||
@@ -72,8 +72,7 @@ void Scanner::QueueData::SetNzbId(int nzbId)
|
||||
void Scanner::InitOptions()
|
||||
{
|
||||
m_nzbDirInterval = g_Options->GetNzbDirInterval() * 1000;
|
||||
const char* scanScript = g_Options->GetScanScript();
|
||||
m_scanScript = scanScript && strlen(scanScript) > 0;
|
||||
m_scanScript = ScanScriptController::HasScripts();
|
||||
}
|
||||
|
||||
void Scanner::ServiceWork()
|
||||
@@ -96,7 +95,7 @@ void Scanner::ServiceWork()
|
||||
CheckIncomingNzbs(g_Options->GetNzbDir(), "", checkStat);
|
||||
if (!checkStat && m_scanScript)
|
||||
{
|
||||
// if immediate scan requested, we need second scan to process files extracted by NzbProcess-script
|
||||
// if immediate scan requested, we need second scan to process files extracted by scan-scripts
|
||||
CheckIncomingNzbs(g_Options->GetNzbDir(), "", checkStat);
|
||||
}
|
||||
m_scanning = false;
|
||||
@@ -105,7 +104,7 @@ void Scanner::ServiceWork()
|
||||
// if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval
|
||||
// is set for rare scans like once per hour) we make 4 scans:
|
||||
// - one additional scan is neccessary to check sizes of detected files;
|
||||
// - another scan is required to check files which were extracted by NzbProcess-script;
|
||||
// - another scan is required to check files which were extracted by scan-scripts;
|
||||
// - third scan is needed to check sizes of extracted files.
|
||||
if (g_Options->GetNzbDirInterval() > 0 && g_Options->GetNzbDirFileAge() < g_Options->GetNzbDirInterval())
|
||||
{
|
||||
@@ -347,7 +346,7 @@ void Scanner::ProcessIncomingFile(const char* directory, const char* baseFilenam
|
||||
void Scanner::InitPPParameters(const char* category, NzbParameterList* parameters, bool reset)
|
||||
{
|
||||
bool unpack = g_Options->GetUnpack();
|
||||
const char* postScript = g_Options->GetPostScript();
|
||||
const char* extensions = g_Options->GetExtensions();
|
||||
|
||||
if (!Util::EmptyStr(category))
|
||||
{
|
||||
@@ -355,9 +354,9 @@ void Scanner::InitPPParameters(const char* category, NzbParameterList* parameter
|
||||
if (categoryObj)
|
||||
{
|
||||
unpack = categoryObj->GetUnpack();
|
||||
if (!Util::EmptyStr(categoryObj->GetPostScript()))
|
||||
if (!Util::EmptyStr(categoryObj->GetExtensions()))
|
||||
{
|
||||
postScript = categoryObj->GetPostScript();
|
||||
extensions = categoryObj->GetExtensions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,13 +371,20 @@ void Scanner::InitPPParameters(const char* category, NzbParameterList* parameter
|
||||
|
||||
parameters->SetParameter("*Unpack:", unpack ? "yes" : "no");
|
||||
|
||||
if (!Util::EmptyStr(postScript))
|
||||
if (!Util::EmptyStr(extensions))
|
||||
{
|
||||
// split szPostScript into tokens and create pp-parameter for each token
|
||||
Tokenizer tok(postScript, ",;");
|
||||
// create pp-parameter for each post-processing or queue- script
|
||||
Tokenizer tok(extensions, ",;");
|
||||
while (const char* scriptName = tok.Next())
|
||||
{
|
||||
parameters->SetParameter(BString<1024>("%s:", scriptName), "yes");
|
||||
for (ScriptConfig::Script& script : g_ScriptConfig->GetScripts())
|
||||
{
|
||||
if ((script.GetPostScript() || script.GetQueueScript()) &&
|
||||
FileSystem::SameFilename(scriptName, script.GetName()))
|
||||
{
|
||||
parameters->SetParameter(BString<1024>("%s:", scriptName), "yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,21 +117,30 @@ void UrlCoordinator::Run()
|
||||
}
|
||||
}
|
||||
|
||||
WaitJobs();
|
||||
|
||||
debug("Exiting UrlCoordinator-loop");
|
||||
}
|
||||
|
||||
void UrlCoordinator::WaitJobs()
|
||||
{
|
||||
// waiting for downloads
|
||||
debug("UrlCoordinator: waiting for Downloads to complete");
|
||||
bool completed = false;
|
||||
while (!completed)
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
GuardedDownloadQueue guard = DownloadQueue::Guard();
|
||||
completed = m_activeDownloads.size() == 0;
|
||||
if (m_activeDownloads.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep(100 * 1000);
|
||||
ResetHangingDownloads();
|
||||
}
|
||||
debug("UrlCoordinator: Downloads are completed");
|
||||
|
||||
debug("Exiting UrlCoordinator-loop");
|
||||
debug("UrlCoordinator: Downloads are completed");
|
||||
}
|
||||
|
||||
void UrlCoordinator::Stop()
|
||||
|
||||
@@ -56,6 +56,7 @@ private:
|
||||
void StartUrlDownload(NzbInfo* nzbInfo);
|
||||
void UrlCompleted(UrlDownloader* urlDownloader);
|
||||
void ResetHangingDownloads();
|
||||
void WaitJobs();
|
||||
};
|
||||
|
||||
extern UrlCoordinator* g_UrlCoordinator;
|
||||
|
||||
@@ -860,7 +860,9 @@ void EditQueueBinCommand::Execute()
|
||||
bool ok = DownloadQueue::Guard()->EditList(
|
||||
nrIdEntries > 0 ? &cIdList : nullptr,
|
||||
nrNameEntries > 0 ? &cNameList : nullptr,
|
||||
(DownloadQueue::EMatchMode)matchMode, (DownloadQueue::EEditAction)action, offset, text);
|
||||
(DownloadQueue::EMatchMode)matchMode, (DownloadQueue::EEditAction)action,
|
||||
action == DownloadQueue::eaFileMoveOffset || action == DownloadQueue::eaGroupMoveOffset ?
|
||||
*CString::FormatStr("%i", offset) : text);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifndef MESSAGEBASE_H
|
||||
#define MESSAGEBASE_H
|
||||
|
||||
static const int32 NZBMESSAGE_SIGNATURE = 0x6E7A6228; // = "nzb-XX" (protocol version)
|
||||
static const int32 NZBMESSAGE_SIGNATURE = 0x6E7A6230; // = "nzb-XX" (protocol version)
|
||||
static const int NZBREQUESTFILENAMESIZE = 512;
|
||||
static const int NZBREQUESTPASSWORDSIZE = 32;
|
||||
|
||||
|
||||
@@ -957,7 +957,9 @@ bool RemoteClient::RequestPostQueue()
|
||||
completed.Format(", %i%s", (int)(stageProgress / 10), "%");
|
||||
}
|
||||
|
||||
const char* postStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Unpacking", ", Executing postprocess-script", "" };
|
||||
const char* postStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing",
|
||||
", Verifying repaired files", ", Par-Renaming", ", Rar-Renaming", ", Unpacking", ", Cleaning up",
|
||||
", Moving", ", Executing postprocess-script", "" };
|
||||
char* infoName = bufPtr + sizeof(SNzbPostQueueResponseEntry) + ntohl(postQueueAnswer->m_nzbFilenameLen);
|
||||
|
||||
printf("[%i] %s%s%s\n", ntohl(postQueueAnswer->m_id), infoName, postStageName[ntohl(postQueueAnswer->m_stage)], *completed);
|
||||
|
||||
@@ -1746,8 +1746,8 @@ void NzbInfoXmlCommand::AppendNzbInfoFields(NzbInfo* nzbInfo)
|
||||
*EncodeStr(nzbInfo->GetDupeKey()), nzbInfo->GetDupeScore(), dupeModeName[nzbInfo->GetDupeMode()],
|
||||
BoolToStr(nzbInfo->GetDeleteStatus() != NzbInfo::dsNone),
|
||||
downloadedSizeLo, downloadedSizeHi, downloadedSizeMB, nzbInfo->GetDownloadSec(),
|
||||
nzbInfo->GetPostInfo() && nzbInfo->GetPostInfo()->GetStartTime() ?
|
||||
Util::CurrentTime() - nzbInfo->GetPostInfo()->GetStartTime() : nzbInfo->GetPostTotalSec(),
|
||||
nzbInfo->GetPostTotalSec() + (nzbInfo->GetPostInfo() && nzbInfo->GetPostInfo()->GetStartTime() ?
|
||||
Util::CurrentTime() - nzbInfo->GetPostInfo()->GetStartTime() : 0),
|
||||
nzbInfo->GetParSec(), nzbInfo->GetRepairSec(), nzbInfo->GetUnpackSec(), messageCount, nzbInfo->GetExtraParBlocks());
|
||||
|
||||
// Post-processing parameters
|
||||
@@ -1966,7 +1966,7 @@ void ListGroupsXmlCommand::Execute()
|
||||
const char* ListGroupsXmlCommand::DetectStatus(NzbInfo* nzbInfo)
|
||||
{
|
||||
const char* postStageName[] = { "PP_QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING",
|
||||
"VERIFYING_REPAIRED", "RENAMING", "UNPACKING", "MOVING", "EXECUTING_SCRIPT", "PP_FINISHED" };
|
||||
"VERIFYING_REPAIRED", "RENAMING", "RENAMING", "UNPACKING", "MOVING", "MOVING", "EXECUTING_SCRIPT", "PP_FINISHED" };
|
||||
|
||||
const char* status = nullptr;
|
||||
|
||||
@@ -2019,6 +2019,8 @@ EditCommandEntry EditCommandNameMap[] = {
|
||||
{ DownloadQueue::eaGroupMoveOffset, "GroupMoveOffset" },
|
||||
{ DownloadQueue::eaGroupMoveTop, "GroupMoveTop" },
|
||||
{ DownloadQueue::eaGroupMoveBottom, "GroupMoveBottom" },
|
||||
{ DownloadQueue::eaGroupMoveBefore, "GroupMoveBefore" },
|
||||
{ DownloadQueue::eaGroupMoveAfter, "GroupMoveAfter" },
|
||||
{ DownloadQueue::eaGroupPause, "GroupPause" },
|
||||
{ DownloadQueue::eaGroupResume, "GroupResume" },
|
||||
{ DownloadQueue::eaGroupDelete, "GroupDelete" },
|
||||
@@ -2057,6 +2059,10 @@ EditCommandEntry EditCommandNameMap[] = {
|
||||
{ 0, nullptr }
|
||||
};
|
||||
|
||||
// v18:
|
||||
// bool editqueue(string Command, string Args, int[] IDs)
|
||||
// v17:
|
||||
// bool editqueue(string Command, int Offset, string Args, int[] IDs)
|
||||
void EditQueueXmlCommand::Execute()
|
||||
{
|
||||
if (!CheckSafeMethod())
|
||||
@@ -2089,30 +2095,34 @@ void EditQueueXmlCommand::Execute()
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
if (!NextParamAsInt(&offset))
|
||||
bool hasOffset = NextParamAsInt(&offset);
|
||||
|
||||
char* args;
|
||||
if (!NextParamAsStr(&args))
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
}
|
||||
debug("Args=%s", args);
|
||||
|
||||
char* editText;
|
||||
if (!NextParamAsStr(&editText))
|
||||
DecodeStr(args);
|
||||
|
||||
BString<100> offsetStr("%i", offset);
|
||||
if (hasOffset && (action == DownloadQueue::eaFileMoveOffset ||
|
||||
action == DownloadQueue::eaGroupMoveOffset))
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
args = *offsetStr;
|
||||
}
|
||||
debug("EditText=%s", editText);
|
||||
|
||||
DecodeStr(editText);
|
||||
|
||||
IdList cIdList;
|
||||
IdList idList;
|
||||
int id = 0;
|
||||
while (NextParamAsInt(&id))
|
||||
{
|
||||
cIdList.push_back(id);
|
||||
idList.push_back(id);
|
||||
}
|
||||
|
||||
bool ok = DownloadQueue::Guard()->EditList(&cIdList, nullptr, DownloadQueue::mmId, (DownloadQueue::EEditAction)action, offset, editText);
|
||||
bool ok = DownloadQueue::Guard()->EditList(&idList, nullptr, DownloadQueue::mmId,
|
||||
(DownloadQueue::EEditAction)action, args);
|
||||
|
||||
BuildBoolResponse(ok);
|
||||
}
|
||||
@@ -2312,7 +2322,7 @@ void PostQueueXmlCommand::Execute()
|
||||
"}";
|
||||
|
||||
const char* postStageName[] = { "QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING",
|
||||
"VERIFYING_REPAIRED", "RENAMING", "UNPACKING", "MOVING", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
"VERIFYING_REPAIRED", "RENAMING", "RENAMING", "UNPACKING", "MOVING", "MOVING", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -2426,6 +2436,7 @@ void HistoryXmlCommand::Execute()
|
||||
"<member><name>ID</name><value><i4>%i</i4></value></member>\n" // Deprecated, use "NZBID" instead
|
||||
"<member><name>Name</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>RemainingFileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RetryData</name><value><boolean>%s</boolean></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"
|
||||
"<member><name>Log</name><value><array><data></data></array></value></member>\n"; // Deprected, always empty
|
||||
@@ -2435,6 +2446,7 @@ void HistoryXmlCommand::Execute()
|
||||
"\"ID\" : %i,\n" // Deprecated, use "NZBID" instead
|
||||
"\"Name\" : \"%s\",\n"
|
||||
"\"RemainingFileCount\" : %i,\n"
|
||||
"\"RetryData\" : %s,\n"
|
||||
"\"HistoryTime\" : %i,\n"
|
||||
"\"Status\" : \"%s\",\n"
|
||||
"\"Log\" : [],\n"; // Deprected, always empty
|
||||
@@ -2506,7 +2518,7 @@ void HistoryXmlCommand::Execute()
|
||||
|
||||
AppendFmtResponse(IsJson() ? JSON_HISTORY_ITEM_START : XML_HISTORY_ITEM_START,
|
||||
historyInfo->GetId(), *EncodeStr(historyInfo->GetName()), nzbInfo->GetParkedFileCount(),
|
||||
historyInfo->GetTime(), status);
|
||||
BoolToStr(nzbInfo->GetCompletedFiles()->size()), historyInfo->GetTime(), status);
|
||||
}
|
||||
else if (historyInfo->GetKind() == HistoryInfo::hkDup)
|
||||
{
|
||||
@@ -2704,6 +2716,8 @@ void ConfigTemplatesXmlCommand::Execute()
|
||||
"<member><name>QueueScript</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>SchedulerScript</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>FeedScript</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>QueueEvents</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>TaskTime</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Template</name><value><string>%s</string></value></member>\n"
|
||||
"</struct></value>\n";
|
||||
|
||||
@@ -2716,6 +2730,8 @@ void ConfigTemplatesXmlCommand::Execute()
|
||||
"\"QueueScript\" : %s,\n"
|
||||
"\"SchedulerScript\" : %s,\n"
|
||||
"\"FeedScript\" : %s,\n"
|
||||
"\"QueueEvents\" : \"%s\",\n"
|
||||
"\"TaskTime\" : \"%s\",\n"
|
||||
"\"Template\" : \"%s\"\n"
|
||||
"}";
|
||||
|
||||
@@ -2750,6 +2766,8 @@ void ConfigTemplatesXmlCommand::Execute()
|
||||
BoolToStr(configTemplate.GetScript()->GetQueueScript()),
|
||||
BoolToStr(configTemplate.GetScript()->GetSchedulerScript()),
|
||||
BoolToStr(configTemplate.GetScript()->GetFeedScript()),
|
||||
*EncodeStr(configTemplate.GetScript()->GetQueueEvents()),
|
||||
*EncodeStr(configTemplate.GetScript()->GetTaskTime()),
|
||||
*EncodeStr(configTemplate.GetTemplate()));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,16 @@ CString FileSystem::GetLastErrorMessage()
|
||||
{
|
||||
BString<1024> msg;
|
||||
strerror_r(errno, msg, msg.Capacity());
|
||||
|
||||
#ifdef WIN32
|
||||
if (!errno)
|
||||
{
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
msg, 1024, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return *msg;
|
||||
}
|
||||
|
||||
@@ -105,6 +115,7 @@ bool FileSystem::ForceDirectories(const char* path, CString& errmsg)
|
||||
}
|
||||
}
|
||||
|
||||
errmsg.Format("path %s does not exist and could not be created", *normPath);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
@@ -249,6 +260,7 @@ bool FileSystem::AllocateFile(const char* filename, int64 size, bool sparse, CSt
|
||||
HANDLE hFile = CreateFileW(UtfPathToWidePath(filename), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_NEW, 0, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = 0; // wanting error message from WinAPI instead of C-lib
|
||||
errmsg = GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
@@ -526,17 +538,21 @@ bool FileSystem::DirectoryExists(const char* dirFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WIN32_FIND_DATAW findData;
|
||||
// extra "\*" needed for network shares
|
||||
HANDLE handle = FindFirstFileW(UtfPathToWidePath(
|
||||
BString<1024>(dirFilename && dirFilename[strlen(dirFilename) - 1] == PATH_SEPARATOR ? "%s*" : "%s\\*", dirFilename)),
|
||||
&findData);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bool exists = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ||
|
||||
(strlen(dirFilename) == 3 && dirFilename[1] == ':');
|
||||
(dirFilename[0] != '\0' && dirFilename[1] == ':' && (dirFilename[2] == '\0' || dirFilename[3] == '\0'));
|
||||
FindClose(handle);
|
||||
return exists;
|
||||
}
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
// path exists but doesn't have any file/directory entries - possible only for root paths (e. g. "C:\")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
struct stat buffer;
|
||||
@@ -841,10 +857,8 @@ bool FileSystem::FlushFileBuffers(int fileDescriptor, CString& errmsg)
|
||||
BOOL ok = ::FlushFileBuffers((HANDLE)_get_osfhandle(fileDescriptor));
|
||||
if (!ok)
|
||||
{
|
||||
errmsg.Reserve(1024 - 1);
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
errmsg, 1024, nullptr);
|
||||
errno = 0; // wanting error message from WinAPI instead of C-lib
|
||||
errmsg = GetLastErrorMessage();
|
||||
}
|
||||
return ok;
|
||||
#else
|
||||
@@ -1154,7 +1168,7 @@ int64 DiskFile::Position()
|
||||
return ftell(m_file);
|
||||
}
|
||||
|
||||
int64 DiskFile::Seek(int64 position, ESeekOrigin origin)
|
||||
bool DiskFile::Seek(int64 position, ESeekOrigin origin)
|
||||
{
|
||||
return fseek(m_file, position,
|
||||
origin == soCur ? SEEK_CUR :
|
||||
|
||||
@@ -23,10 +23,6 @@
|
||||
|
||||
#include "NString.h"
|
||||
|
||||
#ifdef WIN32
|
||||
class WString;
|
||||
#endif
|
||||
|
||||
class FileSystem
|
||||
{
|
||||
public:
|
||||
@@ -139,7 +135,7 @@ public:
|
||||
int64 Read(void* buffer, int64 size);
|
||||
int64 Write(const void* buffer, int64 size);
|
||||
int64 Position();
|
||||
int64 Seek(int64 position, ESeekOrigin origin = soSet);
|
||||
bool Seek(int64 position, ESeekOrigin origin = soSet);
|
||||
bool Eof();
|
||||
bool Error();
|
||||
int64 Print(const char* format, ...) PRINTF_SYNTAX(2);
|
||||
|
||||
@@ -244,6 +244,7 @@ void CString::Reserve(int capacity)
|
||||
if (capacity > curLen || curLen == 0)
|
||||
{
|
||||
m_data = (char*)realloc(m_data, capacity + 1);
|
||||
m_data[curLen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,14 +276,39 @@ void CString::TrimRight()
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
WString::WString(const char* utfstr)
|
||||
{
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, utfstr, -1, nullptr, 0);
|
||||
m_data = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, utfstr, -1, m_data, len);
|
||||
m_data = (wchar_t*)malloc((strlen(utfstr) * 2 + 1) * sizeof(wchar_t));
|
||||
|
||||
wchar_t* out = m_data;
|
||||
unsigned int codepoint;
|
||||
while (*utfstr != 0)
|
||||
{
|
||||
unsigned char ch = (unsigned char)*utfstr;
|
||||
if (ch <= 0x7f)
|
||||
codepoint = ch;
|
||||
else if (ch <= 0xbf)
|
||||
codepoint = (codepoint << 6) | (ch & 0x3f);
|
||||
else if (ch <= 0xdf)
|
||||
codepoint = ch & 0x1f;
|
||||
else if (ch <= 0xef)
|
||||
codepoint = ch & 0x0f;
|
||||
else
|
||||
codepoint = ch & 0x07;
|
||||
++utfstr;
|
||||
if (((*utfstr & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
|
||||
{
|
||||
if (codepoint > 0xffff)
|
||||
{
|
||||
*out++ = (wchar_t)(0xd800 + (codepoint >> 10));
|
||||
*out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff));
|
||||
}
|
||||
else if (codepoint < 0xd800 || codepoint >= 0xe000)
|
||||
*out++ = (wchar_t)(codepoint);
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void StringBuilder::Clear()
|
||||
|
||||
@@ -94,14 +94,13 @@ protected:
|
||||
char* m_data = nullptr;
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
/*
|
||||
Wide-character string, Windows specific.
|
||||
Wide-character string.
|
||||
*/
|
||||
class WString
|
||||
{
|
||||
public:
|
||||
WString(wchar_t* wstr) : m_data(_wcsdup(wstr)) {}
|
||||
WString(wchar_t* wstr) : m_data(wcsdup(wstr)) {}
|
||||
WString(const char* utfstr);
|
||||
~WString() { free(m_data); }
|
||||
WString(WString&& other) noexcept { m_data = other.m_data; other.m_data = nullptr; }
|
||||
@@ -113,7 +112,6 @@ public:
|
||||
protected:
|
||||
wchar_t* m_data = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
StringBuilder preallocates storage space and is best suitable for often "Append"s.
|
||||
@@ -126,6 +124,7 @@ public:
|
||||
explicit operator char*() { return m_data; }
|
||||
const char* operator*() const { return m_data; }
|
||||
int Length() const { return m_length; }
|
||||
void SetLength(int length) { m_length = length; }
|
||||
int Capacity() const { return m_capacity; }
|
||||
void Reserve(int capacity, bool exact = false);
|
||||
bool Empty() const { return m_length == 0; }
|
||||
|
||||
@@ -304,6 +304,7 @@ int ScriptController::Execute()
|
||||
PrepareEnvOptions(nullptr);
|
||||
PrepareArgs();
|
||||
|
||||
m_completed = false;
|
||||
int exitCode = 0;
|
||||
|
||||
#ifdef CHILD_WATCHDOG
|
||||
@@ -315,6 +316,7 @@ int ScriptController::Execute()
|
||||
int pipein = StartProcess();
|
||||
if (pipein == -1)
|
||||
{
|
||||
m_completed = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -322,8 +324,9 @@ int ScriptController::Execute()
|
||||
m_readpipe = fdopen(pipein, "r");
|
||||
if (!m_readpipe)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open pipe to %s", m_infoName);
|
||||
PrintMessage(Message::mkError, "Could not open pipe to %s", *m_infoName);
|
||||
close(pipein);
|
||||
m_completed = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -383,7 +386,7 @@ int ScriptController::Execute()
|
||||
|
||||
if (m_terminated && m_infoName)
|
||||
{
|
||||
warn("Interrupted %s", m_infoName);
|
||||
warn("Interrupted %s", *m_infoName);
|
||||
}
|
||||
|
||||
exitCode = 0;
|
||||
@@ -404,7 +407,7 @@ int ScriptController::Execute()
|
||||
#endif
|
||||
|
||||
debug("Exit code %i", exitCode);
|
||||
|
||||
m_completed = true;
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
@@ -474,7 +477,7 @@ int ScriptController::StartProcess()
|
||||
std::unique_ptr<wchar_t[]> environmentStrings = m_environmentStrings.GetStrings();
|
||||
|
||||
BOOL ok = CreateProcessW(nullptr, WString(cmdLine), nullptr, nullptr, TRUE,
|
||||
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||
NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT,
|
||||
environmentStrings.get(), wideWorkingDir, &startupInfo, &processInfo);
|
||||
if (!ok)
|
||||
{
|
||||
@@ -483,11 +486,11 @@ int ScriptController::StartProcess()
|
||||
errMsg[255 - 1] = '\0';
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errCode, 0, errMsg, 255, nullptr))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start %s: %s", m_infoName, errMsg);
|
||||
PrintMessage(Message::mkError, "Could not start %s: %s", *m_infoName, errMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start %s: error %i", m_infoName, errCode);
|
||||
PrintMessage(Message::mkError, "Could not start %s: error %i", *m_infoName, errCode);
|
||||
}
|
||||
if (!FileSystem::FileExists(script))
|
||||
{
|
||||
@@ -505,6 +508,7 @@ int ScriptController::StartProcess()
|
||||
debug("Child Process-ID: %i", (int)processInfo.dwProcessId);
|
||||
|
||||
m_processId = processInfo.hProcess;
|
||||
m_dwProcessId = processInfo.dwProcessId;
|
||||
|
||||
// close unused "write" end
|
||||
CloseHandle(writePipe);
|
||||
@@ -541,7 +545,7 @@ int ScriptController::StartProcess()
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start %s: errno %i", m_infoName, errno);
|
||||
PrintMessage(Message::mkError, "Could not start %s: errno %i", *m_infoName, errno);
|
||||
close(pipein);
|
||||
close(pipeout);
|
||||
return -1;
|
||||
@@ -632,11 +636,11 @@ int ScriptController::WaitProcess()
|
||||
|
||||
void ScriptController::Terminate()
|
||||
{
|
||||
debug("Stopping %s", m_infoName);
|
||||
debug("Stopping %s", *m_infoName);
|
||||
m_terminated = true;
|
||||
|
||||
#ifdef WIN32
|
||||
BOOL ok = TerminateProcess(m_processId, -1);
|
||||
BOOL ok = TerminateProcess(m_processId, -1) || m_completed;
|
||||
if (ok)
|
||||
{
|
||||
// wait 60 seconds for process to terminate
|
||||
@@ -655,19 +659,19 @@ void ScriptController::Terminate()
|
||||
// if the child process has its own group (setsid() was successful), kill the whole group
|
||||
killId = -killId;
|
||||
}
|
||||
bool ok = killId && kill(killId, SIGKILL) == 0;
|
||||
bool ok = (killId && kill(killId, SIGKILL) == 0) || m_completed;
|
||||
#endif
|
||||
|
||||
if (ok)
|
||||
{
|
||||
debug("Terminated %s", m_infoName);
|
||||
debug("Terminated %s", *m_infoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not terminate %s", m_infoName);
|
||||
error("Could not terminate %s", *m_infoName);
|
||||
}
|
||||
|
||||
debug("Stopped %s", m_infoName);
|
||||
debug("Stopped %s", *m_infoName);
|
||||
}
|
||||
|
||||
void ScriptController::TerminateAll()
|
||||
@@ -677,14 +681,45 @@ void ScriptController::TerminateAll()
|
||||
{
|
||||
if (script->m_processId && !script->m_detached)
|
||||
{
|
||||
// send break signal and wait up to 5 seconds for graceful termination
|
||||
if (script->Break())
|
||||
{
|
||||
time_t curtime = Util::CurrentTime();
|
||||
while (!script->m_completed && std::abs(curtime - Util::CurrentTime()) <= 10)
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
script->Terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptController::Break()
|
||||
{
|
||||
debug("Sending break signal to %s", *m_infoName);
|
||||
|
||||
#ifdef WIN32
|
||||
BOOL ok = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_dwProcessId);
|
||||
#else
|
||||
bool ok = kill(m_processId, SIGINT) == 0;
|
||||
#endif
|
||||
|
||||
if (ok)
|
||||
{
|
||||
debug("Sent break signal to %s", *m_infoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Could not send break signal to %s", *m_infoName);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ScriptController::Detach()
|
||||
{
|
||||
debug("Detaching %s", m_infoName);
|
||||
debug("Detaching %s", *m_infoName);
|
||||
m_detached = true;
|
||||
FILE* readpipe = m_readpipe;
|
||||
m_readpipe = nullptr;
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
virtual ~ScriptController();
|
||||
int Execute();
|
||||
void Terminate();
|
||||
bool Break();
|
||||
void Resume();
|
||||
void Detach();
|
||||
static void TerminateAll();
|
||||
@@ -87,14 +88,16 @@ protected:
|
||||
private:
|
||||
ArgList m_args;
|
||||
const char* m_workingDir = nullptr;
|
||||
const char* m_infoName = nullptr;
|
||||
CString m_infoName;
|
||||
const char* m_logPrefix = nullptr;
|
||||
EnvironmentStrings m_environmentStrings;
|
||||
bool m_terminated = false;
|
||||
bool m_completed = false;
|
||||
bool m_detached = false;
|
||||
FILE* m_readpipe;
|
||||
#ifdef WIN32
|
||||
HANDLE m_processId = 0;
|
||||
DWORD m_dwProcessId = 0;
|
||||
char m_cmdLine[2048];
|
||||
#else
|
||||
pid_t m_processId = 0;
|
||||
|
||||
@@ -276,6 +276,17 @@ CString Util::FormatTime(time_t timeSec)
|
||||
return result;
|
||||
}
|
||||
|
||||
CString Util::FormatBuffer(const char* buf, int len)
|
||||
{
|
||||
CString result;
|
||||
result.Reserve(len * 3 + 1);
|
||||
while (len--)
|
||||
{
|
||||
result.AppendFmt("%02x ", (int)(uchar)*buf++);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Util::MatchFileExt(const char* filename, const char* extensionList, const char* listSeparator)
|
||||
{
|
||||
int filenameLen = strlen(filename);
|
||||
@@ -506,7 +517,23 @@ bool Util::RegReadStr(HKEY keyRoot, const char* keyName, const char* valueName,
|
||||
|
||||
time_t Util::CurrentTime()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// C-library function "time()" works on Windows too but is very CPU intensive
|
||||
// since it uses high performance timer which we don't need anyway.
|
||||
// A combination of GetSystemTime() + Timegm() works much faster.
|
||||
SYSTEMTIME systm;
|
||||
GetSystemTime(&systm);
|
||||
struct tm tm;
|
||||
tm.tm_year = systm.wYear - 1900;
|
||||
tm.tm_mon = systm.wMonth - 1;
|
||||
tm.tm_mday = systm.wDay;
|
||||
tm.tm_hour = systm.wHour;
|
||||
tm.tm_min = systm.wMinute;
|
||||
tm.tm_sec = systm.wSecond;
|
||||
return Timegm(&tm);
|
||||
#else
|
||||
return ::time(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* From boost */
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
|
||||
static CString FormatSpeed(int bytesPerSecond);
|
||||
static CString FormatSize(int64 fileSize);
|
||||
static CString FormatBuffer(const char* buf, int len);
|
||||
|
||||
/*
|
||||
* Returns program version and revision number as string formatted like "0.7.0-r295".
|
||||
|
||||
@@ -31,10 +31,6 @@ static char THIS_FILE[]=__FILE__;
|
||||
namespace Par2
|
||||
{
|
||||
|
||||
NullStreamBuf nullStreamBuf;
|
||||
std::ostream cout(&nullStreamBuf);
|
||||
std::ostream cerr(&nullStreamBuf);
|
||||
|
||||
CommandLine::ExtraFile::ExtraFile(void)
|
||||
: filename()
|
||||
, filesize(0)
|
||||
@@ -62,7 +58,7 @@ CommandLine::ExtraFile::ExtraFile(const string &name, u64 size)
|
||||
}
|
||||
|
||||
|
||||
CommandLine::CommandLine(void)
|
||||
CommandLine::CommandLine(std::ostream& cout, std::ostream& cerr)
|
||||
: operation(opNone)
|
||||
, version(verUnknown)
|
||||
, noiselevel(nlUnknown)
|
||||
@@ -80,12 +76,14 @@ CommandLine::CommandLine(void)
|
||||
, totalsourcesize(0)
|
||||
, largestsourcesize(0)
|
||||
, memorylimit(0)
|
||||
, cout(cout)
|
||||
, cerr(cerr)
|
||||
{
|
||||
}
|
||||
|
||||
void CommandLine::usage(void)
|
||||
{
|
||||
cout <<
|
||||
std::cout <<
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Par2
|
||||
class CommandLine
|
||||
{
|
||||
public:
|
||||
CommandLine(void);
|
||||
CommandLine(std::ostream& cout, std::ostream& cerr);
|
||||
|
||||
// Parse the supplied command line arguments.
|
||||
bool Parse(int argc, char *argv[]);
|
||||
@@ -153,6 +153,9 @@ protected:
|
||||
size_t memorylimit; // How much memory is permitted to be used
|
||||
// for the output buffer when creating
|
||||
// or repairing.
|
||||
|
||||
std::ostream& cout;
|
||||
std::ostream& cerr;
|
||||
};
|
||||
|
||||
typedef list<CommandLine::ExtraFile>::const_iterator ExtraFileIterator;
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace Par2
|
||||
#define LengthType unsigned int
|
||||
#define MaxLength 0xffffffffUL
|
||||
|
||||
DiskFile::DiskFile(void)
|
||||
DiskFile::DiskFile(std::ostream& cerr) :
|
||||
cerr(cerr)
|
||||
{
|
||||
filename;
|
||||
filesize = 0;
|
||||
@@ -365,7 +366,8 @@ list<string>* DiskFile::FindFiles(string path, string wildcard)
|
||||
#define LengthType unsigned int
|
||||
#define MaxLength 0xffffffffUL
|
||||
|
||||
DiskFile::DiskFile(void)
|
||||
DiskFile::DiskFile(std::ostream& cerr) :
|
||||
cerr(cerr)
|
||||
{
|
||||
//filename;
|
||||
filesize = 0;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Par2
|
||||
class DiskFile
|
||||
{
|
||||
public:
|
||||
DiskFile(void);
|
||||
DiskFile(std::ostream& cerr);
|
||||
~DiskFile(void);
|
||||
|
||||
// Create a file and set its length
|
||||
@@ -106,6 +106,8 @@ protected:
|
||||
#ifdef WIN32
|
||||
static string ErrorMessage(DWORD error);
|
||||
#endif
|
||||
|
||||
std::ostream& cerr;
|
||||
};
|
||||
|
||||
// This class keeps track of which DiskFile objects exist
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Par2
|
||||
{
|
||||
|
||||
// Construct the main packet from the source files and the block size
|
||||
|
||||
/*
|
||||
bool MainPacket::Create(vector<Par2CreatorSourceFile*> &sourcefiles, u64 _blocksize)
|
||||
{
|
||||
recoverablefilecount = totalfilecount =(u32)sourcefiles.size();
|
||||
@@ -80,6 +80,7 @@ bool MainPacket::Create(vector<Par2CreatorSourceFile*> &sourcefiles, u64 _blocks
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
// Load a main packet from a specified file
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ public:
|
||||
public:
|
||||
// Construct the main packet from the source file list and block size.
|
||||
// "sourcefiles" will be sorted base on their FileId value.
|
||||
bool Create(vector<Par2CreatorSourceFile*> &sourcefiles,
|
||||
u64 _blocksize);
|
||||
/*bool Create(vector<Par2CreatorSourceFile*> &sourcefiles,
|
||||
u64 _blocksize);*/
|
||||
|
||||
// Load a main packet from a specified file
|
||||
bool Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header);
|
||||
|
||||
@@ -141,11 +141,6 @@ typedef enum Result
|
||||
|
||||
} Result;
|
||||
|
||||
class NullStreamBuf : public std::streambuf {};
|
||||
extern NullStreamBuf nullStreamBuf;
|
||||
extern std::ostream cout;
|
||||
extern std::ostream cerr;
|
||||
|
||||
} // end namespace Par2
|
||||
|
||||
#define LONGMULTIPLY
|
||||
@@ -171,7 +166,7 @@ using namespace std;
|
||||
#include "datablock.h"
|
||||
|
||||
#include "criticalpacket.h"
|
||||
#include "par2creatorsourcefile.h"
|
||||
//#include "par2creatorsourcefile.h"
|
||||
|
||||
#include "mainpacket.h"
|
||||
#include "creatorpacket.h"
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
|
||||
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
|
||||
//
|
||||
// Copyright (c) 2003 Peter Brian Clements
|
||||
//
|
||||
// par2cmdline is free software; you can 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.
|
||||
//
|
||||
// par2cmdline is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU 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
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "par2cmdline.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _DEBUG
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[]=__FILE__;
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Par2
|
||||
{
|
||||
|
||||
Par2CreatorSourceFile::Par2CreatorSourceFile(void)
|
||||
{
|
||||
descriptionpacket = 0;
|
||||
verificationpacket = 0;
|
||||
diskfile = 0;
|
||||
blockcount = 0;
|
||||
//diskfilename;
|
||||
//parfilename;
|
||||
contextfull = 0;
|
||||
}
|
||||
|
||||
Par2CreatorSourceFile::~Par2CreatorSourceFile(void)
|
||||
{
|
||||
delete descriptionpacket;
|
||||
delete verificationpacket;
|
||||
delete diskfile;
|
||||
delete contextfull;
|
||||
}
|
||||
|
||||
// Open the source file, compute the MD5 Hash of the whole file and the first
|
||||
// 16k of the file, and then compute the FileId and store the results
|
||||
// in a file description packet and a file verification packet.
|
||||
|
||||
bool Par2CreatorSourceFile::Open(CommandLine::NoiseLevel noiselevel, const CommandLine::ExtraFile &extrafile, u64 blocksize, bool deferhashcomputation)
|
||||
{
|
||||
// Get the filename and filesize
|
||||
diskfilename = extrafile.FileName();
|
||||
filesize = extrafile.FileSize();
|
||||
|
||||
// Work out how many blocks the file will be sliced into
|
||||
blockcount = (u32)((filesize + blocksize-1) / blocksize);
|
||||
|
||||
// Determine what filename to record in the PAR2 files
|
||||
string::size_type where;
|
||||
if (string::npos != (where = diskfilename.find_last_of('\\')) ||
|
||||
string::npos != (where = diskfilename.find_last_of('/')))
|
||||
{
|
||||
parfilename = diskfilename.substr(where+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
parfilename = diskfilename;
|
||||
}
|
||||
|
||||
// Create the Description and Verification packets
|
||||
descriptionpacket = new DescriptionPacket;
|
||||
descriptionpacket->Create(parfilename, filesize);
|
||||
|
||||
verificationpacket = new VerificationPacket;
|
||||
verificationpacket->Create(blockcount);
|
||||
|
||||
// Create the diskfile object
|
||||
diskfile = new DiskFile;
|
||||
|
||||
// Open the source file
|
||||
if (!diskfile->Open(diskfilename, filesize))
|
||||
return false;
|
||||
|
||||
// Do we want to defer the computation of the full file hash, and
|
||||
// the block crc and hashes. This is only permitted if there
|
||||
// is sufficient memory available to create all recovery blocks
|
||||
// in one pass of the source files (i.e. chunksize == blocksize)
|
||||
if (deferhashcomputation)
|
||||
{
|
||||
// Initialise a buffer to read the first 16k of the source file
|
||||
size_t buffersize = 16 * 1024;
|
||||
if (buffersize > filesize)
|
||||
buffersize = (size_t)filesize;
|
||||
char *buffer = new char[buffersize];
|
||||
|
||||
// Read the data from the file
|
||||
if (!diskfile->Read(0, buffer, buffersize))
|
||||
{
|
||||
diskfile->Close();
|
||||
delete [] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the hash of the data read from the file
|
||||
MD5Context context;
|
||||
context.Update(buffer, buffersize);
|
||||
delete [] buffer;
|
||||
MD5Hash hash;
|
||||
context.Final(hash);
|
||||
|
||||
// Store the hash in the descriptionpacket and compute the file id
|
||||
descriptionpacket->Hash16k(hash);
|
||||
|
||||
// Compute the fileid and store it in the verification packet.
|
||||
descriptionpacket->ComputeFileId();
|
||||
verificationpacket->FileId(descriptionpacket->FileId());
|
||||
|
||||
// Allocate an MD5 context for computing the file hash
|
||||
// during the recovery data generation phase
|
||||
contextfull = new MD5Context;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialise a buffer to read the source file
|
||||
size_t buffersize = 1024*1024;
|
||||
if (buffersize > min(blocksize,filesize))
|
||||
buffersize = (size_t)min(blocksize,filesize);
|
||||
char *buffer = new char[buffersize];
|
||||
|
||||
// Get ready to start reading source file to compute the hashes and crcs
|
||||
u64 offset = 0;
|
||||
u32 blocknumber = 0;
|
||||
u64 need = blocksize;
|
||||
|
||||
MD5Context filecontext;
|
||||
MD5Context blockcontext;
|
||||
u32 blockcrc = 0;
|
||||
|
||||
// Whilst we have not reached the end of the file
|
||||
while (offset < filesize)
|
||||
{
|
||||
// Work out how much we can read
|
||||
size_t want = (size_t)min(filesize-offset, (u64)buffersize);
|
||||
|
||||
// Read some data from the file into the buffer
|
||||
if (!diskfile->Read(offset, buffer, want))
|
||||
{
|
||||
diskfile->Close();
|
||||
delete [] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the new data passes the 16k boundary, compute the 16k hash for the file
|
||||
if (offset < 16384 && offset + want >= 16384)
|
||||
{
|
||||
filecontext.Update(buffer, (size_t)(16384-offset));
|
||||
|
||||
MD5Context temp = filecontext;
|
||||
MD5Hash hash;
|
||||
temp.Final(hash);
|
||||
|
||||
// Store the 16k hash in the file description packet
|
||||
descriptionpacket->Hash16k(hash);
|
||||
|
||||
if (offset + want > 16384)
|
||||
{
|
||||
filecontext.Update(&buffer[16384-offset], (size_t)(offset+want)-16384);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filecontext.Update(buffer, want);
|
||||
}
|
||||
|
||||
// Get ready to update block hashes and crcs
|
||||
u32 used = 0;
|
||||
|
||||
// Whilst we have not used all of the data we just read
|
||||
while (used < want)
|
||||
{
|
||||
// How much of it can we use for the current block
|
||||
u32 use = (u32)min(need, (u64)(want-used));
|
||||
|
||||
blockcrc = ~0 ^ CRCUpdateBlock(~0 ^ blockcrc, use, &buffer[used]);
|
||||
blockcontext.Update(&buffer[used], use);
|
||||
|
||||
used += use;
|
||||
need -= use;
|
||||
|
||||
// Have we finished the current block
|
||||
if (need == 0)
|
||||
{
|
||||
MD5Hash blockhash;
|
||||
blockcontext.Final(blockhash);
|
||||
|
||||
// Store the block hash and block crc in the file verification packet.
|
||||
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
|
||||
|
||||
blocknumber++;
|
||||
|
||||
// More blocks
|
||||
if (blocknumber < blockcount)
|
||||
{
|
||||
need = blocksize;
|
||||
|
||||
blockcontext.Reset();
|
||||
blockcrc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noiselevel > CommandLine::nlQuiet)
|
||||
{
|
||||
// Display progress
|
||||
u32 oldfraction = (u32)(1000 * offset / filesize);
|
||||
offset += want;
|
||||
u32 newfraction = (u32)(1000 * offset / filesize);
|
||||
if (oldfraction != newfraction)
|
||||
{
|
||||
cout << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did we finish the last block
|
||||
if (need > 0)
|
||||
{
|
||||
blockcrc = ~0 ^ CRCUpdateBlock(~0 ^ blockcrc, (size_t)need);
|
||||
blockcontext.Update((size_t)need);
|
||||
|
||||
MD5Hash blockhash;
|
||||
blockcontext.Final(blockhash);
|
||||
|
||||
// Store the block hash and block crc in the file verification packet.
|
||||
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
|
||||
|
||||
blocknumber++;
|
||||
|
||||
need = 0;
|
||||
}
|
||||
|
||||
// Finish computing the file hash.
|
||||
MD5Hash filehash;
|
||||
filecontext.Final(filehash);
|
||||
|
||||
// Store the file hash in the file description packet.
|
||||
descriptionpacket->HashFull(filehash);
|
||||
|
||||
// Did we compute the 16k hash.
|
||||
if (offset < 16384)
|
||||
{
|
||||
// Store the 16k hash in the file description packet.
|
||||
descriptionpacket->Hash16k(filehash);
|
||||
}
|
||||
|
||||
delete [] buffer;
|
||||
|
||||
// Compute the fileid and store it in the verification packet.
|
||||
descriptionpacket->ComputeFileId();
|
||||
verificationpacket->FileId(descriptionpacket->FileId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Par2CreatorSourceFile::Close(void)
|
||||
{
|
||||
diskfile->Close();
|
||||
}
|
||||
|
||||
|
||||
void Par2CreatorSourceFile::RecordCriticalPackets(list<CriticalPacket*> &criticalpackets)
|
||||
{
|
||||
// Add the file description packet and file verification packet to
|
||||
// the critical packet list.
|
||||
criticalpackets.push_back(descriptionpacket);
|
||||
criticalpackets.push_back(verificationpacket);
|
||||
}
|
||||
|
||||
bool Par2CreatorSourceFile::CompareLess(const Par2CreatorSourceFile* const &left, const Par2CreatorSourceFile* const &right)
|
||||
{
|
||||
// Sort source files based on fileid
|
||||
return left->descriptionpacket->FileId() < right->descriptionpacket->FileId();
|
||||
}
|
||||
|
||||
const MD5Hash& Par2CreatorSourceFile::FileId(void) const
|
||||
{
|
||||
// Get the file id hash
|
||||
return descriptionpacket->FileId();
|
||||
}
|
||||
|
||||
void Par2CreatorSourceFile::InitialiseSourceBlocks(vector<DataBlock>::iterator &sourceblock, u64 blocksize)
|
||||
{
|
||||
for (u32 blocknum=0; blocknum<blockcount; blocknum++)
|
||||
{
|
||||
// Configure each source block to an appropriate offset and length within the source file.
|
||||
sourceblock->SetLocation(diskfile, // file
|
||||
blocknum * blocksize); // offset
|
||||
sourceblock->SetLength(min(blocksize, filesize - (u64)blocknum * blocksize)); // length
|
||||
sourceblock++;
|
||||
}
|
||||
}
|
||||
|
||||
void Par2CreatorSourceFile::UpdateHashes(u32 blocknumber, const void *buffer, size_t length)
|
||||
{
|
||||
// Compute the crc and hash of the data
|
||||
u32 blockcrc = ~0 ^ CRCUpdateBlock(~0, length, buffer);
|
||||
MD5Context blockcontext;
|
||||
blockcontext.Update(buffer, length);
|
||||
MD5Hash blockhash;
|
||||
blockcontext.Final(blockhash);
|
||||
|
||||
// Store the results in the verification packet
|
||||
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
|
||||
|
||||
|
||||
// Update the full file hash, but don't go beyond the end of the file
|
||||
if (length > filesize - blocknumber * length)
|
||||
{
|
||||
length = (size_t)(filesize - blocknumber * (u64)length);
|
||||
}
|
||||
|
||||
assert(contextfull != 0);
|
||||
|
||||
contextfull->Update(buffer, length);
|
||||
}
|
||||
|
||||
void Par2CreatorSourceFile::FinishHashes(void)
|
||||
{
|
||||
assert(contextfull != 0);
|
||||
|
||||
// Finish computation of the full file hash
|
||||
MD5Hash hash;
|
||||
contextfull->Final(hash);
|
||||
|
||||
// Store it in the description packet
|
||||
descriptionpacket->HashFull(hash);
|
||||
}
|
||||
|
||||
} // end namespace Par2
|
||||
@@ -1,86 +0,0 @@
|
||||
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
|
||||
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
|
||||
//
|
||||
// Copyright (c) 2003 Peter Brian Clements
|
||||
//
|
||||
// par2cmdline is free software; you can 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.
|
||||
//
|
||||
// par2cmdline is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU 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
|
||||
|
||||
#ifndef __PAR2CREATORSOURCEFILE_H__
|
||||
#define __PAR2CREATORSOURCEFILE_H__
|
||||
|
||||
namespace Par2
|
||||
{
|
||||
|
||||
class DescriptionPacket;
|
||||
class VerificationPacket;
|
||||
class DiskFile;
|
||||
|
||||
// The Par2CreatorSourceFile contains the file verification and file description
|
||||
// packet for one source file.
|
||||
|
||||
class Par2CreatorSourceFile
|
||||
{
|
||||
private:
|
||||
// Don't permit copying or assignment
|
||||
Par2CreatorSourceFile(const Par2CreatorSourceFile &other);
|
||||
Par2CreatorSourceFile& operator=(const Par2CreatorSourceFile &other);
|
||||
|
||||
public:
|
||||
Par2CreatorSourceFile(void);
|
||||
~Par2CreatorSourceFile(void);
|
||||
|
||||
// Open the source file and compute the Hashes and CRCs.
|
||||
bool Open(CommandLine::NoiseLevel noiselevel, const CommandLine::ExtraFile &extrafile, u64 blocksize, bool deferhashcomputation);
|
||||
void Close(void);
|
||||
|
||||
// Recover the file description and file verification packets
|
||||
// in the critical packet list.
|
||||
void RecordCriticalPackets(list<CriticalPacket*> &criticalpackets);
|
||||
|
||||
// Get the file id
|
||||
const MD5Hash& FileId(void) const;
|
||||
|
||||
// Sort source files based on the file id hash
|
||||
static bool CompareLess(const Par2CreatorSourceFile* const &left, const Par2CreatorSourceFile* const &right);
|
||||
|
||||
// Allocate the appropriate number of source blocks to the source file
|
||||
void InitialiseSourceBlocks(vector<DataBlock>::iterator &sourceblock, u64 blocksize);
|
||||
|
||||
// Update the file hash and the block crc and hashes
|
||||
void UpdateHashes(u32 blocknumber, const void *buffer, size_t length);
|
||||
|
||||
// Finish computation of the file hash
|
||||
void FinishHashes(void);
|
||||
|
||||
// How many blocks does this source file use
|
||||
u32 BlockCount(void) const {return blockcount;}
|
||||
|
||||
protected:
|
||||
DescriptionPacket *descriptionpacket; // The file description packet.
|
||||
VerificationPacket *verificationpacket; // The file verification packet.
|
||||
DiskFile *diskfile; // The source file
|
||||
|
||||
u64 filesize; // The size of the source file.
|
||||
string diskfilename; // The filename of the source file on disk.
|
||||
string parfilename; // The filename that will be recorded in the file description packet.
|
||||
|
||||
u32 blockcount; // How many blocks the file will be divided into.
|
||||
|
||||
MD5Context *contextfull; // MD5 context used to calculate the hash of the whole file
|
||||
};
|
||||
|
||||
} // end namespace Par2
|
||||
|
||||
#endif // __PAR2CREATORSOURCEFILE_H__
|
||||
@@ -31,7 +31,8 @@ static char THIS_FILE[]=__FILE__;
|
||||
namespace Par2
|
||||
{
|
||||
|
||||
Par2Repairer::Par2Repairer(void)
|
||||
Par2Repairer::Par2Repairer(std::ostream& cout, std::ostream& cerr):
|
||||
cout(cout), cerr(cerr), rs(cout, cerr)
|
||||
{
|
||||
firstpacket = true;
|
||||
mainpacket = 0;
|
||||
@@ -360,7 +361,7 @@ bool Par2Repairer::LoadPacketsFromFile(string filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
DiskFile *diskfile = new DiskFile;
|
||||
DiskFile *diskfile = new DiskFile(cerr);
|
||||
|
||||
// Open the file
|
||||
if (!diskfile->Open(filename))
|
||||
@@ -1276,7 +1277,7 @@ bool Par2Repairer::VerifySourceFiles(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
DiskFile *diskfile = new DiskFile;
|
||||
DiskFile *diskfile = new DiskFile(cerr);
|
||||
|
||||
// Does the target file exist
|
||||
if (diskfile->Open(filename))
|
||||
@@ -1340,7 +1341,7 @@ bool Par2Repairer::VerifyExtraFiles(const list<CommandLine::ExtraFile> &extrafil
|
||||
// Has this file already been dealt with
|
||||
if (diskFileMap.Find(filename) == 0)
|
||||
{
|
||||
DiskFile *diskfile = new DiskFile;
|
||||
DiskFile *diskfile = new DiskFile(cerr);
|
||||
|
||||
// Does the file exist
|
||||
if (!diskfile->Open(filename))
|
||||
@@ -2099,7 +2100,7 @@ bool Par2Repairer::CreateTargetFiles(void)
|
||||
// If the file does not exist
|
||||
if (!sourcefile->GetTargetExists())
|
||||
{
|
||||
DiskFile *targetfile = new DiskFile;
|
||||
DiskFile *targetfile = new DiskFile(cerr);
|
||||
string filename = sourcefile->TargetFileName();
|
||||
u64 filesize = sourcefile->GetDescriptionPacket()->FileSize();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Par2 {
|
||||
class Par2Repairer
|
||||
{
|
||||
public:
|
||||
Par2Repairer(void);
|
||||
Par2Repairer(std::ostream& cout, std::ostream& cerr);
|
||||
~Par2Repairer(void);
|
||||
|
||||
Result PreProcess(const CommandLine &commandline);
|
||||
@@ -196,6 +196,9 @@ protected:
|
||||
u64 totalsize; // Total data size
|
||||
|
||||
bool cancelled; // repair cancelled
|
||||
|
||||
std::ostream& cout;
|
||||
std::ostream& cerr;
|
||||
};
|
||||
|
||||
} // end namespace Par2
|
||||
|
||||
@@ -47,7 +47,7 @@ class ReedSolomon
|
||||
public:
|
||||
typedef g G;
|
||||
|
||||
ReedSolomon(void);
|
||||
ReedSolomon(std::ostream& cout, std::ostream& cerr);
|
||||
~ReedSolomon(void);
|
||||
|
||||
// Set which input blocks are present or missing
|
||||
@@ -105,10 +105,14 @@ protected:
|
||||
#ifdef LONGMULTIPLY
|
||||
GaloisLongMultiplyTable<g> *glmt; // A multiplication table used by Process()
|
||||
#endif
|
||||
|
||||
std::ostream& cout;
|
||||
std::ostream& cerr;
|
||||
};
|
||||
|
||||
template<class g>
|
||||
inline ReedSolomon<g>::ReedSolomon(void)
|
||||
inline ReedSolomon<g>::ReedSolomon(std::ostream& cout, std::ostream& cerr) :
|
||||
cout(cout), cerr(cerr)
|
||||
{
|
||||
inputcount = 0;
|
||||
|
||||
|
||||
760
nzbget.conf
760
nzbget.conf
@@ -14,11 +14,6 @@ MainDir=~/downloads
|
||||
#
|
||||
# If you want to distinguish between partially downloaded files and
|
||||
# completed downloads, use also option <InterDir>.
|
||||
#
|
||||
# It is allowed to enter multiple directories here by separating them with comma
|
||||
# or semicolon. NZBGet checks how much free disk space is available in each
|
||||
# directory (assuming all directories are located on different drives) and
|
||||
# chooses the directory with the most free space.
|
||||
DestDir=${MainDir}/dst
|
||||
|
||||
# Directory to store intermediate files.
|
||||
@@ -41,8 +36,8 @@ InterDir=${MainDir}/inter
|
||||
# Directory for incoming nzb-files.
|
||||
#
|
||||
# If a new nzb-file is added to queue via web-interface or RPC-API, it
|
||||
# is saved into this directory and then processed by preprocessing
|
||||
# script (option <ScanScript>).
|
||||
# is saved into this directory and then processed by extension
|
||||
# scripts (option <Extensions>).
|
||||
#
|
||||
# This directory is also monitored for new nzb-files. If a new file
|
||||
# is found it is added to download queue. The directory can have
|
||||
@@ -349,7 +344,7 @@ AddPassword=
|
||||
|
||||
# Secure control of NZBGet server (yes, no).
|
||||
#
|
||||
# Activate the option if you want to access NZBGet built-in web-server
|
||||
# Activate the option if you want to access NZBGet built-in web-server
|
||||
# via HTTPS (web-interface and RPC). You should also provide certificate
|
||||
# and key files, see option <SecureCert> and option <SecureKey>.
|
||||
SecureControl=no
|
||||
@@ -423,10 +418,10 @@ Category1.DestDir=
|
||||
# For more information see global option <Unpack>.
|
||||
Category1.Unpack=yes
|
||||
|
||||
# Default list of post-processing scripts.
|
||||
# List of extension scripts for this category.
|
||||
#
|
||||
# For more information see global option <PostScript>.
|
||||
Category1.PostScript=
|
||||
# For more information see global option <Extensions>.
|
||||
Category1.Extensions=
|
||||
|
||||
# List of aliases.
|
||||
#
|
||||
@@ -627,10 +622,14 @@ Category4.Name=Software
|
||||
# post-processed even if the program is in paused state (force mode).
|
||||
#Feed1.Priority=0
|
||||
|
||||
# List of rss feed scripts to execute before rss feed content is processed.
|
||||
# List of rss feed extension scripts to execute for rss content.
|
||||
#
|
||||
# For more information see global option <FeedScript>.
|
||||
#Feed1.FeedScript=
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
# paths relative to <ScriptDir> must be entered here.
|
||||
#
|
||||
# NOTE: For developer documentation visit http://nzbget.net/Extension_scripts.
|
||||
#Feed1.Extensions=
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -644,8 +643,7 @@ AppendCategoryDir=yes
|
||||
#
|
||||
# Value "0" disables the check.
|
||||
#
|
||||
# NOTE: nzb-files are processed by scan and queue scripts. See
|
||||
# options <ScanScript> and <QueueScript>.
|
||||
# NOTE: nzb-files are processed by extension scripts. See option <Extensions>.
|
||||
NzbDirInterval=5
|
||||
|
||||
# How old nzb-file should at least be for it to be loaded to queue (seconds).
|
||||
@@ -719,7 +717,7 @@ ContinuePartial=yes
|
||||
# Propagation delay to your news servers (minutes).
|
||||
#
|
||||
# The option sets minimum post age for nzb-files. Very recent files
|
||||
# are not downloaded to avoid download failures. The files remain
|
||||
# are not downloaded to avoid download failures. The files remain
|
||||
# on hold in the download queue until the propagation delay expires,
|
||||
# after that they are downloaded.
|
||||
PropagationDelay=0
|
||||
@@ -773,7 +771,7 @@ ArticleCache=0
|
||||
# all articles of the file are downloaded or when the cache becomes
|
||||
# full to 90%.
|
||||
#
|
||||
# The direct write relies on the ability of file system to create
|
||||
# The direct write relies on the ability of file system to create
|
||||
# empty files without allocating the space on the drive (sparse files),
|
||||
# which most modern file systems support including EXT3, EXT4
|
||||
# and NTFS. The notable exception is HFS+ (default file system on OSX).
|
||||
@@ -817,65 +815,25 @@ WriteBuffer=0
|
||||
# slow CPU disabling of CRC-Check may improve performance.
|
||||
CrcCheck=yes
|
||||
|
||||
# How many retries should be attempted if a download error occurs (0-99).
|
||||
# Post-processing strategy (sequential, balanced, aggressive, rocket).
|
||||
#
|
||||
# If download fails because of incomplete or damaged article or due to
|
||||
# CRC-error the program tries to re-download 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.
|
||||
# Sequential - downloaded items are post processed from a queue, one item at a
|
||||
# time, to dedicate the most computer resources to each
|
||||
# item. Therefore, a post process par repair will prevent another
|
||||
# task from running even if the item does not require a par repair;
|
||||
# Balanced - items that do not need par repair are post processed one at a
|
||||
# time while par repair tasks may also run simultaneously one after
|
||||
# another at the same time. This means that a post process par
|
||||
# repair will not prevent another task from running, but at a cost
|
||||
# of using more computer resource;
|
||||
# Aggressive - will simultaneously post process up to three items including
|
||||
# one par repair task;
|
||||
# Rocket - will simultaneously post process up to six items including one
|
||||
# or two par repair tasks.
|
||||
#
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# Connection timeout for article downloading (seconds).
|
||||
ArticleTimeout=60
|
||||
|
||||
# Connection timeout for URL fetching (seconds).
|
||||
#
|
||||
# This includes fetching of nzb-files via URLs and fetching of RSS feeds.
|
||||
UrlTimeout=60
|
||||
|
||||
# Timeout until a download-thread should be killed (seconds).
|
||||
#
|
||||
# This can help on hanging downloads, but is dangerous.
|
||||
# Do not use small values!
|
||||
TerminateTimeout=600
|
||||
|
||||
# Set the maximum download rate on program start (kilobytes/sec).
|
||||
#
|
||||
# The download rate can be changed later via remote calls.
|
||||
#
|
||||
# Value "0" means no speed control.
|
||||
DownloadRate=0
|
||||
|
||||
# Accurate speed rate calculation (yes, no).
|
||||
#
|
||||
# During downloading using several connections the download threads may
|
||||
# interfere with each other when updating statistical data for speed
|
||||
# meter. This may cause small errors in current download speed reported
|
||||
# by the program. The speed meter recovers automatically from such errors
|
||||
# after max. 30 seconds (time window used for speed calculation).
|
||||
#
|
||||
# Enable the option to use thread synchronisation mechanisms in order to
|
||||
# provide absolutely accurate speed calculations.
|
||||
#
|
||||
# NOTE: Thread synchronisation increases CPU load and therefore can
|
||||
# decrease download speed. Do not activate this option on computers with
|
||||
# limited CPU power. Before activating the option it is recommended to
|
||||
# run tests to determine how the option affects the CPU usage and the
|
||||
# download speed on a particular system.
|
||||
AccurateRate=no
|
||||
# NOTE: Computer resources are in heavy demand when post-processing with
|
||||
# simultaneous tasks - make sure the hardware is capable.
|
||||
PostStrategy=balanced
|
||||
|
||||
# Pause if disk space gets below this value (megabytes).
|
||||
#
|
||||
@@ -907,13 +865,16 @@ NzbCleanupDisk=yes
|
||||
#
|
||||
# If option <DupeCheck> is NOT active the items are removed from history.
|
||||
#
|
||||
# When a failed item is removed from history or become hidden all downloaded
|
||||
# files of that item are deleted from disk.
|
||||
#
|
||||
# Value "0" disables history. Duplicate check will not work.
|
||||
KeepHistory=30
|
||||
|
||||
# Keep the history of outdated feed items (days).
|
||||
#
|
||||
# After fetching of an RSS feed the information about included items (nzb-files)
|
||||
# is saved to disk. This allows to detect new items on next fetch. Feed
|
||||
# is saved to disk. This allows to detect new items on next fetch. Feed
|
||||
# providers update RSS feeds constantly. Since the feed length is limited
|
||||
# (usually 100 items or less) the old items get pushed away by new
|
||||
# ones. When an item is not present in the feed anymore it's not necessary
|
||||
@@ -927,9 +888,80 @@ KeepHistory=30
|
||||
# has technical issues and may response with empty feeds (or with missing
|
||||
# items). When the technical issue is fixed the items may reappear in the
|
||||
# feed causing the program to re-download items if they were not found in
|
||||
# the feed history.
|
||||
# the feed history.
|
||||
FeedHistory=7
|
||||
|
||||
##############################################################################
|
||||
### CONNECTION ###
|
||||
|
||||
# How many retries should be attempted if a download error occurs (0-99).
|
||||
#
|
||||
# If download fails because of incomplete or damaged article or due to
|
||||
# CRC-error the program tries to re-download the article from the same
|
||||
# news server as many times as defined in this option. 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.
|
||||
ArticleRetries=3
|
||||
|
||||
# Article retry interval (seconds).
|
||||
#
|
||||
# If download of article fails because of interrupted connection
|
||||
# the server is temporary blocked until the retry interval expires.
|
||||
ArticleInterval=10
|
||||
|
||||
# Connection timeout for article downloading (seconds).
|
||||
ArticleTimeout=60
|
||||
|
||||
# Number of download attempts for URL fetching (0-99).
|
||||
#
|
||||
# If fetching of nzb-file via URL or fetching of RSS feed fails another
|
||||
# attempt is made after the retry interval (option <UrlInterval>).
|
||||
UrlRetries=3
|
||||
|
||||
# URL fetching retry interval (seconds).
|
||||
#
|
||||
# If fetching of nzb-file via URL or fetching of RSS feed fails another
|
||||
# attempt is made after the retry interval.
|
||||
UrlInterval=10
|
||||
|
||||
# Connection timeout for URL fetching (seconds).
|
||||
#
|
||||
# Connection timeout when fetching nzb-files via URLs and fetching RSS feeds.
|
||||
UrlTimeout=60
|
||||
|
||||
# Timeout until a download-thread should be killed (seconds).
|
||||
#
|
||||
# This can help on hanging downloads, but is dangerous.
|
||||
# Do not use small values!
|
||||
TerminateTimeout=600
|
||||
|
||||
# Set the maximum download rate on program start (kilobytes/sec).
|
||||
#
|
||||
# The download rate can be changed later in web-interface or via remote calls.
|
||||
#
|
||||
# Value "0" means no speed control.
|
||||
DownloadRate=0
|
||||
|
||||
# Accurate speed rate calculation (yes, no).
|
||||
#
|
||||
# During downloading using several connections the download threads may
|
||||
# interfere with each other when updating statistical data for speed
|
||||
# meter. This may cause small errors in current download speed reported
|
||||
# by the program. The speed meter recovers automatically from such errors
|
||||
# after max. 30 seconds (time window used for speed calculation).
|
||||
#
|
||||
# Enable the option to use thread synchronisation mechanisms in order to
|
||||
# provide absolutely accurate speed calculations.
|
||||
#
|
||||
# NOTE: Thread synchronisation increases CPU load and therefore can
|
||||
# decrease download speed. Do not activate this option on computers with
|
||||
# limited CPU power. Before activating the option it is recommended to
|
||||
# run tests to determine how the option affects the CPU usage and the
|
||||
# download speed on a particular system.
|
||||
AccurateRate=no
|
||||
|
||||
# Maximum number of simultaneous connections for nzb URL downloads (0-999).
|
||||
#
|
||||
# When NZB-files are added to queue via URL, the program downloads them
|
||||
@@ -1088,9 +1120,10 @@ UpdateInterval=200
|
||||
# Time to execute the command (HH:MM).
|
||||
#
|
||||
# Multiple comma-separated values are accepted.
|
||||
# An asterisk placed in the hours location will run every hour.
|
||||
# An asterisk placed in the hours location will run task every hour (e. g. "*:00").
|
||||
# An asterisk without minutes will run task at program startup (e. g. "*").
|
||||
#
|
||||
# Examples: "08:00", "00:00,06:00,12:00,18:00", "*:00", "*:00,*:30".
|
||||
# Examples: "08:00", "00:00,06:00,12:00,18:00", "*:00", "*,*:00,*:30".
|
||||
#
|
||||
# NOTE: Also see option <TimeCorrection>.
|
||||
#Task1.Time=08:00
|
||||
@@ -1136,14 +1169,15 @@ UpdateInterval=200
|
||||
# list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option
|
||||
# <ScriptDir> and paths relative to <ScriptDir> must be
|
||||
# entered here. For more info see below;
|
||||
# entered here. For developer documentation visit
|
||||
# http://nzbget.net/Extension_scripts;
|
||||
# Process - path to the program to execute and its parameters.
|
||||
# Example: /home/user/fetch.sh.
|
||||
# If filename or any parameter contains spaces it
|
||||
# must be surrounded with single quotation
|
||||
# marks. If filename/parameter contains single quotation marks,
|
||||
# each of them must be replaced (escaped) with two single quotation
|
||||
# marks and the resulting filename/parameter must be
|
||||
# each of them must be replaced (escaped) with two single quotation
|
||||
# marks and the resulting filename/parameter must be
|
||||
# surrounded with single quotation marks.
|
||||
# Example: '/home/user/download/my scripts/task process.sh' 'world''s fun'.
|
||||
# In this example one parameter (world's fun) is passed
|
||||
@@ -1158,27 +1192,6 @@ UpdateInterval=200
|
||||
# Example: bookmarks feed, another feed.
|
||||
# NOTE: feed names should not have commas.
|
||||
# NOTE: use feed id "0" to fetch all feeds.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# The rest of the description is for command "Script".
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#
|
||||
# NZBGet passes following arguments to scheduler script as environment
|
||||
# variables:
|
||||
# NZBSP_TASKID - id number of scheduler Task.
|
||||
#
|
||||
# In addition to these arguments NZBGet passes all nzbget.conf-options
|
||||
# as environment variables. These variables have prefix "NZBOP_" and
|
||||
# are written in UPPER CASE. For Example option "ParRepair" is passed as
|
||||
# environment variable "NZBOP_PARREPAIR". The dots in option names are
|
||||
# replaced with underscores, for example "SERVER1_HOST". For options
|
||||
# with predefined possible values (yes/no, etc.) the values are passed
|
||||
# always in lower case.
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#Task1.Param=
|
||||
|
||||
#Task2.Time=20:00
|
||||
@@ -1188,7 +1201,7 @@ UpdateInterval=200
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PAR CHECK/REPAIR ###
|
||||
### CHECK AND REPAIR ###
|
||||
|
||||
# Whether and how par-verification must be performed (auto, always, force, manual).
|
||||
#
|
||||
@@ -1198,7 +1211,7 @@ UpdateInterval=200
|
||||
# is enabled;
|
||||
# Always - check every download (even undamaged). One par2-file is
|
||||
# always downloaded. Additional par2-files are downloaded
|
||||
# if needed for repair. Repair is performed if the option
|
||||
# if needed for repair. Repair is performed if the option
|
||||
# <ParRepair> is enabled;
|
||||
# Force - force par-check for every download (even undamaged). All
|
||||
# par2-files are always downloaded. Repair is performed if
|
||||
@@ -1210,17 +1223,6 @@ UpdateInterval=200
|
||||
# eventually on another faster computer.
|
||||
ParCheck=auto
|
||||
|
||||
# Check for renamed and missing files (yes, no).
|
||||
#
|
||||
# Par-rename restores original file names using information stored
|
||||
# in par2-files. It also detects missing files (files listed in
|
||||
# par2-files but not present on disk). When enabled the par-rename is
|
||||
# performed as the first step of post-processing for every nzb-file.
|
||||
#
|
||||
# Par-rename is very fast and is highly recommended, especially if
|
||||
# unpack is disabled.
|
||||
ParRename=yes
|
||||
|
||||
# Automatic par-repair after par-verification (yes, no).
|
||||
#
|
||||
# If option <ParCheck> is set to "Auto" or "Force" this option defines
|
||||
@@ -1245,9 +1247,9 @@ ParScan=extended
|
||||
# Quick file verification during par-check (yes, no).
|
||||
#
|
||||
# If the option is active the files are quickly verified using
|
||||
# checksums calculated during download; quick verification is very fast
|
||||
# because it doesn't require the reading of files from disk, NZBGet
|
||||
# knows checksums of downloaded files and quickly compares them with
|
||||
# checksums calculated during download; quick verification is very fast
|
||||
# because it doesn't require the reading of files from disk, NZBGet
|
||||
# knows checksums of downloaded files and quickly compares them with
|
||||
# checksums stored in the par-file.
|
||||
#
|
||||
# If the option is disabled the files are verified as usual. That's
|
||||
@@ -1295,6 +1297,30 @@ ParThreads=0
|
||||
# Example: .sfv, .nzb, .nfo
|
||||
ParIgnoreExt=.sfv, .nzb, .nfo
|
||||
|
||||
# Check for renamed and missing files using par-files (yes, no).
|
||||
#
|
||||
# Par-rename restores original file names using information stored
|
||||
# in par2-files. It also detects missing files (files listed in
|
||||
# par2-files but not present on disk). When enabled the par-rename is
|
||||
# performed as the first step of post-processing for every nzb-file.
|
||||
#
|
||||
# Par-rename is very fast and is highly recommended, especially if
|
||||
# unpack is disabled.
|
||||
ParRename=yes
|
||||
|
||||
# Check for renamed rar-files (yes, no).
|
||||
#
|
||||
# Rar-rename restores original file names using information stored
|
||||
# in rar-files. When enabled the rar-rename is performed as one of the
|
||||
# first steps of post-processing for every nzb-file.
|
||||
#
|
||||
# Rar-rename is useful for downloads not having par2-files or for
|
||||
# downloads those files were renamed before creating par2-files. In
|
||||
# both cases par-rename (option <ParRename>) can't rename files
|
||||
# and the rar-rename makes it possible to unpack downloads which
|
||||
# would fail otherwise.
|
||||
RarRename=yes
|
||||
|
||||
# What to do if download health drops below critical health (delete, park,
|
||||
# pause, none).
|
||||
#
|
||||
@@ -1382,7 +1408,7 @@ UnpackCleanupDisk=yes
|
||||
#
|
||||
# Example: /usr/bin/unrar.
|
||||
#
|
||||
# The option can also contain extra switches to pass to unrar. To the
|
||||
# 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/
|
||||
#
|
||||
@@ -1418,9 +1444,9 @@ SevenZipCmd=7z
|
||||
#
|
||||
# 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%.
|
||||
# not performed. If download doesn't contain archives nor par-files
|
||||
# the cleanup is performed if the health is 100%. If parameter "unpack"
|
||||
# is disabled for that nzb-file the cleanup isn't performed.
|
||||
#
|
||||
# The entries must be separated with commas. The entries can be file
|
||||
# extensions, file names or file masks containing wildcard
|
||||
@@ -1429,6 +1455,29 @@ SevenZipCmd=7z
|
||||
# Example: .par2, .sfv
|
||||
ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
|
||||
|
||||
# Files to ignore during unpack.
|
||||
#
|
||||
# List of file extensions to ignore when unpacking archives or renaming
|
||||
# obfuscated archive files. The entries must be separated with commas.
|
||||
#
|
||||
# Archive files with non standard extensions belong to one of two categories: they
|
||||
# are either obfuscated files or files with special purposes which should not be
|
||||
# unpacked. List the files of second type here to avoid attempts to unpack them.
|
||||
#
|
||||
# This option has effect on two post-processing stages.
|
||||
#
|
||||
# First, during rar-rename (option <RarRename>) rar-files with non-standard
|
||||
# extensions are renamed back to rar-extension, which is required for successful
|
||||
# unpacking. Files with extensions listed here will not be renamed.
|
||||
#
|
||||
# Second, if during unpack no rar-files are found but instead rar-archives
|
||||
# with non-rar extensions are found the unpack fails. For files listed here
|
||||
# no unpack failure occurs and download is considered not having archive
|
||||
# files and be successful.
|
||||
#
|
||||
# Example: .cbr
|
||||
UnpackIgnoreExt=.cbr
|
||||
|
||||
# Path to file containing unpack passwords.
|
||||
#
|
||||
# If the option is set the program will try all passwords from the file
|
||||
@@ -1439,15 +1488,31 @@ ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
|
||||
# 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.
|
||||
# passwords should be set per nzb-file in their post-processing settings.
|
||||
UnpackPassFile=
|
||||
|
||||
|
||||
##############################################################################
|
||||
### EXTENSION SCRIPTS ###
|
||||
|
||||
# Default list of post-processing scripts to execute after the download
|
||||
# of nzb-file is completed and possibly par-checked/repaired and unpacked.
|
||||
# List of active extension scripts for new downloads.
|
||||
#
|
||||
# Extension scripts associated with nzb-files are executed before, during
|
||||
# or after download as defined by script developer.
|
||||
#
|
||||
# Each download (nzb-file) has its own list of extension scripts; the list
|
||||
# can be viewed and changed in web-interface in download details dialog or
|
||||
# via API. Option <Extensions> sets defaults for new downloads; changes
|
||||
# to option <Extensions> do not affect downloads which are already in queue.
|
||||
#
|
||||
# When nzb-file is added to queue it can have a category assigned to it. In this
|
||||
# case option <CategoryX.Extensions> (if not empty) have precedence and
|
||||
# defines the scripts for that nzb-file; consequently global option <Extensions>
|
||||
# has no effect for that nzb-file.
|
||||
#
|
||||
# Certain extensions work globally for the whole program instead of
|
||||
# per-nzb basis. Such extensions are activated once and cannot be overriden
|
||||
# per category or per nzb.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
@@ -1455,421 +1520,19 @@ UnpackPassFile=
|
||||
#
|
||||
# Example: Cleanup.sh, Move.sh, EMail.py.
|
||||
#
|
||||
# Each download (nzb-file) has its own list of post-processing scripts. The option
|
||||
# <PostScript> is the default value assigned to download when it is added to
|
||||
# queue. The list of post-processing scripts for a particular download can be
|
||||
# changed in the edit dialog in web-interface or using remote command "--edit/-E".
|
||||
#
|
||||
# When nzb-file is added to queue it can have a category assigned to it. In this
|
||||
# case the option <CategoryX.PostScript> (if not empty) overrides the
|
||||
# global option <PostScript>.
|
||||
#
|
||||
# NOTE: The script execution order is controlled by option <ScriptOrder>, not
|
||||
# by their order in option <PostScript>.
|
||||
# by their order in option <Extensions>.
|
||||
#
|
||||
# NOTE: Changing options <PostScript> and <CategoryX.PostScript> doesn't affect
|
||||
# already queued downloads.
|
||||
#
|
||||
# NOTE: For the list of interesting post-processing scripts see
|
||||
# NOTE: For the list of interesting extension scripts see
|
||||
# http://nzbget.net/Catalog_of_post-processing_scripts.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#
|
||||
# NZBGet passes following arguments to post-processing script as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination directory for downloaded files;
|
||||
# NZBPP_NZBNAME - user-friendly name of processed nzb-file as it is displayed
|
||||
# by the program. The file path and extension are removed.
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - original name of processed nzb-file. It includes file extension
|
||||
# and may include full path;
|
||||
# NZBPP_QUEUEDFILE - full filename of the queued (renamed) nzb-file;
|
||||
# NZBPP_FINALDIR - final destination path if set by one of previous pp-scripts;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# NZBPP_DUPEKEY - duplicate key of nzb-file;
|
||||
# NZBPP_DUPESCORE - duplicate score of nzb-file;
|
||||
# NZBPP_DUPEMODE - duplicate mode of nzb-file: SCORE, ALL, FORCE;
|
||||
# NZBPP_TOTALSTATUS - total status of nzb-file:
|
||||
# SUCCESS - everything OK;
|
||||
# WARNING - download is damaged but probably can
|
||||
# be repaired; user intervention is
|
||||
# required;
|
||||
# FAILURE - download has failed or a serious error
|
||||
# occurred during post-processing (unpack, par);
|
||||
# DELETED - download was deleted; post-processing
|
||||
# scripts are usually not called in this case;
|
||||
# however it's possible to force calling
|
||||
# scripts with command "post-process again";
|
||||
# NZBPP_STATUS - complete status info for nzb-file: it consists
|
||||
# of total status and status detail separated with
|
||||
# slash, for example: "FAILURE/UNPACK"; for possible
|
||||
# status details see documentation on web site;
|
||||
# NZBPP_SCRIPTSTATUS - summary status of the scripts executed before the
|
||||
# current one:
|
||||
# NONE - no other scripts were executed yet or all
|
||||
# of them have ended with exit code "NONE";
|
||||
# SUCCESS - all other scripts have ended with exit
|
||||
# code "SUCCESS" ;
|
||||
# FAILURE - at least one of the script has failed;
|
||||
# NZBPP_HEALTH - download health: an integer value in the range
|
||||
# from 0 (all articles failed) to 1000 (all articles
|
||||
# successfully downloaded);
|
||||
# NZBPP_CRITICALHEALTH - critical health for this nzb-file: an integer
|
||||
# value in the range 0-1000. The critical health
|
||||
# is calculated based on number and size of
|
||||
# par-files. If nzb-file doesn't have any par-files
|
||||
# the critical health is 1000 (100.0%). If a half
|
||||
# of nzb-file were par-files its critical health
|
||||
# would be 0. If NZBPP_HEALTH goes down below
|
||||
# NZBPP_CRITICALHEALTH the download becomes unrepairable;
|
||||
# NZBPP_TOTALARTICLES - number of articles in nzb-file;
|
||||
# NZBPP_SUCCESSARTICLES - number of successfully downloaded articles;
|
||||
# NZBPP_FAILEDARTICLES - number of failed articles;
|
||||
# NZBPP_SERVERX_SUCCESSARTICLES - number of successfully downloaded
|
||||
# articles from ServerX (X is replaced with server
|
||||
# number, for example NZBPP_SERVER1_SUCCESSARTICLES);
|
||||
# NZBPP_SERVERX_FAILEDARTICLES - number of failed articles from ServerX.
|
||||
#
|
||||
# If the script defines own options they are also passed as environment
|
||||
# variables. These variables have prefix "NZBPO_" in their names. For
|
||||
# example, option "myoption" will be passed as environment variable
|
||||
# "NZBPO_myoption" and in addition in uppercase as "NZBPO_MYOPTION".
|
||||
#
|
||||
# If the script defines own post-processing parameters, they are also passed as
|
||||
# environment variables. These variables have prefix "NZBPR_" in their
|
||||
# names. For example, pp-parameter "myparam" will be passed as environment
|
||||
# variable "NZBPR_myparam" and in addition in uppercase as "NZBPR_MYPARAM".
|
||||
#
|
||||
# In addition to arguments, pp-options and pp-parameters NZBGet passes all
|
||||
# nzbget.conf-options to pp-script as environment variables. These
|
||||
# variables have prefix "NZBOP_" and are written in UPPER CASE. For Example
|
||||
# option "ParRepair" is passed as environment variable "NZBOP_PARREPAIR". The
|
||||
# dots in option names are replaced with underscores, for example
|
||||
# "SERVER1_HOST". For options with predefined possible values (yes/no, etc.)
|
||||
# the values are passed always in lower case.
|
||||
#
|
||||
# If the script moves files it can inform the program about new location
|
||||
# by printing special message into standard output (which is processed
|
||||
# by NZBGet):
|
||||
# echo "[NZB] DIRECTORY=/path/to/moved/files";
|
||||
# or:
|
||||
# echo "[NZB] FINALDIR=/path/to/moved/files";
|
||||
#
|
||||
# Command "DIRECTORY" changes the destination path of the download and
|
||||
# affects the scripts executed after the current script as well as the
|
||||
# program code itself, for example the command "Post-process again"
|
||||
# will work on new location. Command "FINALDIR" just sets a separate
|
||||
# property of the download and should be used when the files are moved
|
||||
# into an existing directory containing other files to avoid the processing
|
||||
# of those files by other scripts.
|
||||
#
|
||||
# To assign post-processing parameters:
|
||||
# echo "[NZB] NZBPR_myvar=my value";
|
||||
#
|
||||
# The prefix "NZBPR_" will be removed. In this example a post-processing
|
||||
# parameter with name "myvar" and value "my value" will be associated
|
||||
# with nzb-file.
|
||||
#
|
||||
# To inform NZBGet about bad download:
|
||||
# echo "[NZB] MARK=BAD";
|
||||
#
|
||||
# Return value: NZBGet processes the exit code returned by the script:
|
||||
# 93 - post-process successful (status = SUCCESS);
|
||||
# 94 - post-process failed (status = FAILURE);
|
||||
# 95 - post-process skipped (status = NONE). Use this code when you script
|
||||
# terminates immediately without doing any job and when this is not
|
||||
# a failure termination;
|
||||
# 92 - request NZBGet to do par-check/repair for current nzb-file.
|
||||
#
|
||||
# All other return codes are interpreted as failure (status = FAILURE).
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
PostScript=
|
||||
# NOTE: For developer documentation visit http://nzbget.net/Extension_scripts.
|
||||
Extensions=
|
||||
|
||||
# List of scan scripts to execute before a nzb-file is added to queue.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
# paths relative to <ScriptDir> must be entered here.
|
||||
#
|
||||
# The scripts are executed each time a new file is found in incoming
|
||||
# directory (option <NzbDir>) or a file is received via RPC (web-interface,
|
||||
# command "nzbget --append", etc.).
|
||||
#
|
||||
# Example: UnzipNzb.sh, ScanNotify.py.
|
||||
#
|
||||
# The scripts can unpack archives which were put in incoming directory, make
|
||||
# filename cleanup, change nzb-name, category, priority and post-processing
|
||||
# parameters of the nzb-file or do other things.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#
|
||||
# NZBGet passes following arguments to the script as environment
|
||||
# variables:
|
||||
# NZBNP_DIRECTORY - path to directory, where file is located. It is a directory
|
||||
# specified by the option <NzbDir> or a subdirectory;
|
||||
# NZBNP_FILENAME - name of file to be processed;
|
||||
# NZBNP_NZBNAME - nzb-name (without path but with extension);
|
||||
# NZBNP_CATEGORY - category of nzb-file;
|
||||
# NZBNP_PRIORITY - priority of nzb-file;
|
||||
# NZBNP_TOP - flag indicating that the file will be added to the top
|
||||
# of queue: 0 or 1;
|
||||
# NZBNP_PAUSED - flag indicating that the file will be added as
|
||||
# paused: 0 or 1;
|
||||
# NZBNP_DUPEKEY - duplicate key of nzb-file;
|
||||
# NZBNP_DUPESCORE - duplicate score of nzb-file;
|
||||
# NZBNP_DUPEMODE - duplicate mode of nzb-file: SCORE, ALL, FORCE.
|
||||
#
|
||||
# In addition to these arguments NZBGet passes all nzbget.conf-options
|
||||
# as environment variables. These variables have prefix "NZBOP_" and
|
||||
# are written in UPPER CASE. For , the option "ParRepair" is passed as
|
||||
# environment variable "NZBOP_PARREPAIR". The dots in option names are
|
||||
# replaced with underscores, for example "SERVER1_HOST". For options
|
||||
# with predefined possible values (yes/no, etc.) the values are passed
|
||||
# always in lower case.
|
||||
#
|
||||
# The script can change nzb-name, category, priority,
|
||||
# post-processing parameters and top-/paused-flags of the nzb-file
|
||||
# by printing special messages into standard output (which is processed
|
||||
# by NZBGet).
|
||||
#
|
||||
# To change nzb-name use following syntax:
|
||||
# echo "[NZB] NZBNAME=my download";
|
||||
#
|
||||
# To change category:
|
||||
# echo "[NZB] CATEGORY=my category";
|
||||
#
|
||||
# To change priority:
|
||||
# echo "[NZB] PRIORITY=signed_integer_value";
|
||||
#
|
||||
# for example: to set priority higher than normal:
|
||||
# echo "[NZB] PRIORITY=50";
|
||||
#
|
||||
# another example: use a negative value for "lower than normal" priority:
|
||||
# echo "[NZB] PRIORITY=-100";
|
||||
#
|
||||
# Although priority can be any integer value, the web-interface operates
|
||||
# with six predefined priorities:
|
||||
# -100 - very low priority;
|
||||
# -50 - low priority;
|
||||
# 0 - normal priority (default);
|
||||
# 50 - high priority;
|
||||
# 100 - very high priority;
|
||||
# 900 - force priority.
|
||||
#
|
||||
# Downloads with priorities equal to or greater than 900 are downloaded and
|
||||
# post-processed even if the program is in paused state (force mode).
|
||||
#
|
||||
# To assign post-processing parameters:
|
||||
# echo "[NZB] NZBPR_myvar=my value";
|
||||
#
|
||||
# The prefix "NZBPR_" will be removed. In this example a post-processing
|
||||
# parameter with name "myvar" and value "my value" will be associated
|
||||
# with nzb-file.
|
||||
#
|
||||
# To change top-flag (nzb-file will be added to the top of queue):
|
||||
# echo "[NZB] TOP=1";
|
||||
#
|
||||
# To change paused-flag (nzb-file will be added in paused state):
|
||||
# echo "[NZB] PAUSED=1";
|
||||
#
|
||||
# To change duplicate key:
|
||||
# echo "[NZB] DUPEKEY=tv show s01e02";
|
||||
#
|
||||
# To change duplicate score:
|
||||
# echo "[NZB] DUPESCORE=integer_value";
|
||||
#
|
||||
# To change duplicate mode:
|
||||
# echo "[NZB] DUPEMODE=(SCORE|ALL|FORCE)";
|
||||
#
|
||||
# The script can delete processed file, rename it or move somewhere.
|
||||
# After the calling of the script the file will be either added to queue
|
||||
# (if it was an nzb-file) or renamed by adding the extension ".processed".
|
||||
#
|
||||
# NOTE: Files with extensions ".processed", ".queued" and ".error" are skipped
|
||||
# during the directory scanning.
|
||||
#
|
||||
# NOTE: Files with extension ".nzb_processed" are not passed to
|
||||
# scan-script before adding to queue. This feature allows scan-script
|
||||
# to prevent the scanning of nzb-files extracted from archives, if
|
||||
# they were already processed by the script.
|
||||
#
|
||||
# NOTE: Files added via RPC calls in particular from web-interface are
|
||||
# saved into incoming nzb-directory and then processed by the script.
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
ScanScript=
|
||||
|
||||
# List of queue scripts to execute on queue events.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
# paths relative to <ScriptDir> must be entered here.
|
||||
#
|
||||
# The scripts are executed on certain queue events such as adding
|
||||
# a new nzb-file to queue, etc.
|
||||
#
|
||||
# Example: DeleteQueueSamples.sh, NzbAddedNotify.py.
|
||||
#
|
||||
# The script can modify the files in download queue (for example
|
||||
# delete or pause all .nfo, .sfv, sample files) or do something else.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#
|
||||
# NZBGet passes following arguments to the queue script as environment
|
||||
# variables:
|
||||
# NZBNA_NZBNAME - name of nzb-group. This name can be used in calls
|
||||
# to nzbget edit-command using the subswitch "-GN name";
|
||||
# NZBNA_FILENAME - filename of the nzb-file. If the file was added
|
||||
# from nzb-directory this is the full name with path.
|
||||
# If the file was added via web-interface it contains
|
||||
# only filename without path;
|
||||
# NZBNA_EVENT - describes why the script was called:
|
||||
# NZB_ADDED - after adding of nzb-file to queue;
|
||||
# FILE_DOWNLOADED - after a file included in nzb is
|
||||
# downloaded;
|
||||
# NZB_DOWNLOADED - after all files in nzb are downloaded
|
||||
# (before post-processing);
|
||||
# NZB_DELETED - when nzb is deleted from queue (moved
|
||||
# to history). See NZBNA_DELETESTATUS for details;
|
||||
# NZB_MARKED - when a history item is marked as good, bad or
|
||||
# success. See NZBNA_MARKSTATUS for details;
|
||||
# URL_COMPLETED - after an URL download is completed
|
||||
# and the downloaded file was not added to queue
|
||||
# (not nzb-extension, download error, parse
|
||||
# error). See NZBNA_URLSTATUS for details;
|
||||
# In the future the list of supported events may be
|
||||
# extended. To avoid conflicts with future NZBGet
|
||||
# versions the script must exit if the parameter
|
||||
# has a value unknown to the script;
|
||||
# NZBNA_QUEUEDFILE - full filename of the queued (renamed) nzb-file;
|
||||
# NZBNA_DELETESTATUS - delete status info, NZBNA_EVENT=NZB_DELETED:
|
||||
# MANUAL - deleted by user or via API call;
|
||||
# HEALTH - deleted by health check;
|
||||
# DUPE - moved to history by duplicate check, can be
|
||||
# reused later if necessary;
|
||||
# GOOD - moved to history by duplicate check because
|
||||
# there is already a duplicate marked as good;
|
||||
# BAD - marked as bad by user or by queue-script;
|
||||
# COPY - already in queue or in history;
|
||||
# SCAN - malformed nzb-file, cannot be parsed;
|
||||
# NZBNA_URLSTATUS - URL status info, when NZBNA_EVENT=URL_COMPLETED:
|
||||
# FAILURE - fetch error (could not be downloaded);
|
||||
# SCAN_SKIPPED - downloaded file doesn't have
|
||||
# nzb-extension and was skipped;
|
||||
# SCAN_FAILED - file format error;
|
||||
# NZBNA_MARKSTATUS - mark status info, NZBNA_EVENT=NZB_MARKED:
|
||||
# GOOD - marked as good by user or by a script;
|
||||
# BAD - marked as bad;
|
||||
# SUCCESS - marked as success;
|
||||
# NZBNA_CATEGORY - category of nzb-file (if assigned);
|
||||
# NZBNA_NZBID - id of the nzb-file. This ID can be used with
|
||||
# calls to nzbget edit-command;
|
||||
# NZBNA_PRIORITY - priority (default is 0);
|
||||
# NZBNA_DUPEKEY - duplicate key of nzb-file;
|
||||
# NZBNA_DUPESCORE - duplicate score of nzb-file;
|
||||
# NZBNA_DUPEMODE - duplicate mode of nzb-file: SCORE, ALL, FORCE.
|
||||
#
|
||||
# In addition to these arguments NZBGet passes all nzbget.conf-options
|
||||
# to the script as environment variables. These variables have prefix
|
||||
# "NZBOP_" and are written in UPPER CASE. For Example, the option "ParRepair"
|
||||
# is passed as environment variable "NZBOP_PARREPAIR". The dots in option
|
||||
# names are replaced with underscores, for example "SERVER1_HOST". For
|
||||
# options with predefined possible values (yes/no, etc.) the values are
|
||||
# passed always in lower case.
|
||||
#
|
||||
# The script can printing special messages into standard output (which
|
||||
# is processed by NZBGet).
|
||||
#
|
||||
# To assign post-processing parameters:
|
||||
# echo "[NZB] NZBPR_myvar=my value";
|
||||
#
|
||||
# The prefix "NZBPR_" will be removed. In this example a post-processing
|
||||
# parameter with name "myvar" and value "my value" will be associated
|
||||
# with nzb-file.
|
||||
#
|
||||
# To inform NZBGet about bad download:
|
||||
# echo "[NZB] MARK=BAD";
|
||||
#
|
||||
# To set destination directory (only from event "NZB_DOWNLOADED"):
|
||||
# echo "[NZB] DIRECTORY=/destination/path/for/this/nzb";
|
||||
#
|
||||
# Examples of what the script can do:
|
||||
# 1) pausing nzb-file using file-id:
|
||||
# "$NZBOP_APPBIN" -c "$NZBOP_CONFIGFILE" -E G P $NZBNA_NZBID;
|
||||
# 2) setting category using nzb-name:
|
||||
# "$NZBOP_APPBIN" -c "$NZBOP_CONFIGFILE" -E GN K "my cat" "$NZBNA_NZBNAME";
|
||||
# 3) pausing files with extension "nzb":
|
||||
# "$NZBOP_APPBIN" -c "$NZBOP_CONFIGFILE" -E FR P "$NZBNA_NZBNAME/.*\.nzb";
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
QueueScript=
|
||||
|
||||
# List of rss feed scripts to execute before a rss feed content is processed.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
# paths relative to <ScriptDir> must be entered here.
|
||||
#
|
||||
# If rss feed has option <FeedX.FeedScript> defined (if not empty)
|
||||
# the scripts defined there override the global option <FeedScript>.
|
||||
#
|
||||
# The scripts are executed after rss feed is read from server and before it
|
||||
# is processed by the feed parser. Once the feed is fetched it is saved
|
||||
# to a temporary file and the feed scripts are executed. The scripts
|
||||
# can modify the content of the temporary feed file. Then the file is
|
||||
# read by the feed parser and processed.
|
||||
#
|
||||
# Example: Rss.sh, Filter.py.
|
||||
#
|
||||
# The feed content is usually filtered using option <FeedX.Filter>. If a
|
||||
# required filtering cannot be achieved via built-in filter commands the
|
||||
# more advanced processing of the feed can be made using feed scripts.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
#
|
||||
# NZBGet passes following arguments to the script as environment
|
||||
# variables:
|
||||
# NZBFP_FILENAME - name of feed file to be processed;
|
||||
# NZBFP_FEEDID - ID of the feed.
|
||||
#
|
||||
# In addition to these arguments NZBGet passes all nzbget.conf-options
|
||||
# as environment variables. These variables have prefix "NZBOP_" and
|
||||
# are written in UPPER CASE. For Example option "ParRepair" is passed as
|
||||
# environment variable "NZBOP_PARREPAIR". The dots in option names are
|
||||
# replaced with underscores, for example "SERVER1_HOST". For options
|
||||
# with predefined possible values (yes/no, etc.) the values are passed
|
||||
# always in lower case.
|
||||
#
|
||||
# Return value: NZBGet processes the exit code returned by the script:
|
||||
# 93 - script successful (status = SUCCESS).
|
||||
# All other return codes are interpreted as failure (status = FAILURE).
|
||||
#
|
||||
# If the script doesn't end with SUCCESS-status the whole content of RSS
|
||||
# feed is ignored. This is to prevent accidental enqueuing of many
|
||||
# nzb-files if a feed script unexpectedly terminates before processing
|
||||
# of the feed.
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.net/Extension_scripts.
|
||||
FeedScript=
|
||||
|
||||
# Execution order for scripts.
|
||||
# Execution order for extension scripts.
|
||||
#
|
||||
# If you assign multiple scripts to one nzb-file, they are executed in the
|
||||
# order defined by this option. Scripts not listed here are executed at
|
||||
# the end in their alphabetical order.
|
||||
# order defined by this option.
|
||||
#
|
||||
# The scripts in the list must be separated with commas or semicolons. All
|
||||
# scripts must be stored in directory set by option <ScriptDir> and
|
||||
@@ -1899,25 +1562,18 @@ ScriptPauseQueue=no
|
||||
# Example: .py=/usr/bin/python2;.py3=/usr/bin/python3;.sh=/usr/bin/bash.
|
||||
ShellOverride=
|
||||
|
||||
# Minimum interval between calls of queue-scripts (seconds).
|
||||
# Minimum interval between queue events (seconds).
|
||||
#
|
||||
# Queue-scripts are executed during download, after every file included in
|
||||
# nzb-file is downloaded. If the files are small they may be downloaded
|
||||
# very fast causing queue-scripts to be working all the time. Sometimes
|
||||
# this may lead to a performance decrease on systems with slow CPUs.
|
||||
# Extension scripts can opt-in for progress notifcations during
|
||||
# download. For downloads containing many small files the events can
|
||||
# be fired way too often increasing load on the system due to script
|
||||
# execution.
|
||||
#
|
||||
# This option allows to reduce the number of calls of queue-scripts by
|
||||
# skipping "file-downloaded"-events if the previous call of queue-scripts
|
||||
# for the same download (nzb-file) were performed a short time ago
|
||||
# (as defined by the option).
|
||||
# This option allows to reduce the number of calls of scripts by
|
||||
# skipping "file-downloaded"-events if the previous call for the same
|
||||
# download (nzb-file) were performed a short time ago (as defined by
|
||||
# the option).
|
||||
#
|
||||
# Value "-1" disables executing of queue-scripts on
|
||||
# "file-downloaded"-events. Scripts are still executed on events
|
||||
# "nzb-added" and "nzb-downloaded".
|
||||
#
|
||||
# NOTE: This options affects only queue-scripts and only
|
||||
# "file-downloaded"-events. Queue-scripts can be activated using
|
||||
# option <QueueScript> (for pure queue-scripts) or option <PostScript>
|
||||
# (for dual-mode scripts which act as queue- and post-processing-scripts
|
||||
# at the same time).
|
||||
# Value "-1" disables "file-downloaded"-events. Scripts are still
|
||||
# notified on other events (such as "nzb-added" or "nzb-downloaded").
|
||||
EventInterval=0
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="17.0";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="18.0";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@@ -71,8 +71,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="17.0";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="18.0";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
@@ -124,13 +124,21 @@
|
||||
<ClCompile Include="daemon\nntp\NntpConnection.cpp" />
|
||||
<ClCompile Include="daemon\nntp\ServerPool.cpp" />
|
||||
<ClCompile Include="daemon\nntp\StatMeter.cpp" />
|
||||
<ClCompile Include="daemon\nserv\NntpServer.cpp" />
|
||||
<ClCompile Include="daemon\nserv\NServFrontend.cpp" />
|
||||
<ClCompile Include="daemon\nserv\NServMain.cpp" />
|
||||
<ClCompile Include="daemon\nserv\NzbGenerator.cpp" />
|
||||
<ClCompile Include="daemon\nserv\YEncoder.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\Cleanup.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\DupeMatcher.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\ParChecker.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\ParCoordinator.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\Repair.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\ParParser.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\ParRenamer.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\PrePostProcessor.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\RarReader.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\RarRenamer.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\Rename.cpp" />
|
||||
<ClCompile Include="daemon\postprocess\Unpack.cpp" />
|
||||
<ClCompile Include="daemon\queue\DiskState.cpp" />
|
||||
<ClCompile Include="daemon\queue\DownloadInfo.cpp" />
|
||||
@@ -171,7 +179,6 @@
|
||||
<ClCompile Include="lib\par2\galois.cpp" />
|
||||
<ClCompile Include="lib\par2\mainpacket.cpp" />
|
||||
<ClCompile Include="lib\par2\md5.cpp" />
|
||||
<ClCompile Include="lib\par2\par2creatorsourcefile.cpp" />
|
||||
<ClCompile Include="lib\par2\par2fileformat.cpp" />
|
||||
<ClCompile Include="lib\par2\par2repairer.cpp" />
|
||||
<ClCompile Include="lib\par2\par2repairersourcefile.cpp" />
|
||||
@@ -214,13 +221,21 @@
|
||||
<ClInclude Include="daemon\nntp\NntpConnection.h" />
|
||||
<ClInclude Include="daemon\nntp\ServerPool.h" />
|
||||
<ClInclude Include="daemon\nntp\StatMeter.h" />
|
||||
<ClInclude Include="daemon\nserv\NntpServer.h" />
|
||||
<ClInclude Include="daemon\nserv\NServFrontend.h" />
|
||||
<ClInclude Include="daemon\nserv\NServMain.h" />
|
||||
<ClInclude Include="daemon\nserv\NzbGenerator.h" />
|
||||
<ClInclude Include="daemon\nserv\YEncoder.h" />
|
||||
<ClInclude Include="daemon\postprocess\Cleanup.h" />
|
||||
<ClInclude Include="daemon\postprocess\DupeMatcher.h" />
|
||||
<ClInclude Include="daemon\postprocess\ParChecker.h" />
|
||||
<ClInclude Include="daemon\postprocess\ParCoordinator.h" />
|
||||
<ClInclude Include="daemon\postprocess\Repair.h" />
|
||||
<ClInclude Include="daemon\postprocess\ParParser.h" />
|
||||
<ClInclude Include="daemon\postprocess\ParRenamer.h" />
|
||||
<ClInclude Include="daemon\postprocess\PrePostProcessor.h" />
|
||||
<ClInclude Include="daemon\postprocess\RarReader.h" />
|
||||
<ClInclude Include="daemon\postprocess\RarRenamer.h" />
|
||||
<ClInclude Include="daemon\postprocess\Rename.h" />
|
||||
<ClInclude Include="daemon\postprocess\Unpack.h" />
|
||||
<ClInclude Include="daemon\queue\DiskState.h" />
|
||||
<ClInclude Include="daemon\queue\DownloadInfo.h" />
|
||||
@@ -261,7 +276,6 @@
|
||||
<ClInclude Include="lib\par2\mainpacket.h" />
|
||||
<ClInclude Include="lib\par2\md5.h" />
|
||||
<ClInclude Include="lib\par2\par2cmdline.h" />
|
||||
<ClInclude Include="lib\par2\par2creatorsourcefile.h" />
|
||||
<ClInclude Include="lib\par2\par2fileformat.h" />
|
||||
<ClInclude Include="lib\par2\par2repairer.h" />
|
||||
<ClInclude Include="lib\par2\par2repairersourcefile.h" />
|
||||
@@ -284,4 +298,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -25,9 +25,14 @@
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2007-2016 Andrey Prygunkov</string>
|
||||
<string>Copyright © 2007-2017 Andrey Prygunkov</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainApp</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user