Compare commits

...

221 Commits
v15.0 ... v16.4

Author SHA1 Message Date
Andrey Prygunkov
1d77852bea updated version string to "16.4" 2015-12-05 12:24:20 +01:00
Andrey Prygunkov
15a5d056ed #118: merge 80653a8dad: fixed resource (socket) leak
, which may cause “too many open files” errors with a possible crash.
2015-12-05 11:51:30 +01:00
Andrey Prygunkov
050dc8d55f updated version string to "16.3" 2015-10-29 20:59:27 +01:00
Andrey Prygunkov
4a5063c14e #100: fixed: downloads may sometimes fail due to incorrect decoding of articles 2015-10-28 18:09:29 +01:00
Andrey Prygunkov
665645b510 updated version string to "16.2" 2015-10-24 15:26:50 +02:00
Andrey Prygunkov
eb87111204 fixed #100: workaround to deal with malformed responses
…which still may contain useful data.
2015-10-24 15:13:04 +02:00
Andrey Prygunkov
94aa547a85 updated version string to "16.1" 2015-10-19 22:17:18 +02:00
Andrey Prygunkov
dfa18b50a4 corrected file permissions 2015-10-19 22:01:52 +02:00
Andrey Prygunkov
2820ee4bc5 fixed #95: starting nzbget from setup (Windows)
When launching NZBGet at the end of setup the program is now started
with regular user permissions.
2015-10-19 21:55:21 +02:00
Andrey Prygunkov
c9ff56cc7e #89: fixed unpack failure on certain CPUs
unrar shipped with nzbget was compiled in optimization mode O3. In that
mode GCC activates loop vectorization. On x86_64 architecture that
caused the usage of CPU commands from extended set SSSE3. Some older
AMD processors doesn’t support SSSE3, which lead to abortion with
“illegal instruction”-message. Now using O2-mode; that solves the
issues.
2015-10-19 21:53:06 +02:00
Andrey Prygunkov
9ea9da8d33 #77: fixed issues with reverse proxies (3)
merging into 16.x-branch: when very long headers were sent from the
proxy, in particular if htdigest authorization were used.
2015-10-19 21:52:33 +02:00
Andrey Prygunkov
297a966da3 #77: fixed issues with reverse proxies
merging into 16.x-branch: removing of authorization-header wasn’t such
a good idea.
2015-10-19 21:51:23 +02:00
Andrey Prygunkov
dafb956e6e updated version string to "16.0" 2015-10-10 20:52:12 +02:00
Andrey Prygunkov
263f669873 Merge branch 'develop' 2015-10-10 19:54:45 +02:00
Andrey Prygunkov
ceec19c6fd updated ChangeLog 2015-10-10 19:54:24 +02:00
Andrey Prygunkov
a513dc0c01 fixed compilation error on Linux
…when compiled with “--enable-test”
2015-10-10 19:52:05 +02:00
Andrey Prygunkov
1948dd2420 closed #87: added hint about RC4 cipher considered insecure 2015-10-07 23:28:58 +02:00
Andrey Prygunkov
87f9cc68a0 compatibility with Visual Studio 2015 2015-09-28 21:35:41 +02:00
Andrey Prygunkov
d0897c2e09 #72: fixed: filter was not reset when reopening dialogs 2015-09-23 22:01:40 +02:00
Andrey Prygunkov
5e392e98b6 #18: fixed one failed test 2015-09-17 20:56:36 +02:00
Andrey Prygunkov
caf2d919b4 closes #16: renamed "svn_version.cpp" to "code_revision.cpp" 2015-09-17 20:44:38 +02:00
Andrey Prygunkov
111630b6b7 improved performance in web ui with large queue or history
Improved performance in web-interface when working with very large
queue or history (thousands of items).
2015-09-14 22:54:19 +02:00
Andrey Prygunkov
5418865a1b improved performance on mass delete
Better performance when deleting many items from queue at once
(hundreds or thousands).
2015-09-14 22:42:11 +02:00
Andrey Prygunkov
752d27ee08 speed optimizations in built-in web-server
- big speed improvement in built-in web-server on Windows when serving
API requests (web-interface) for very large queue or history (with
thousands items);
- refactoring in API server: clearer code yet faster.
2015-09-11 21:32:02 +02:00
Andrey Prygunkov
afa32676ac fixed #20: option Encryption=Force in EMail.py
PP-Script EMail.py now supports new TLS/SSL mode “Force”. When active
the secure communication with SMTP server is built using secure socket
on connection level instead of plain connection and following switch
into secure mode using SMTP-command “STARTLS”. This new mode is in
particular required when using GMail on port 465.
2015-09-08 19:16:14 +02:00
Andrey Prygunkov
e4d3773c22 Merge branch '77-comm-errors' into develop 2015-09-07 23:14:46 +02:00
Andrey Prygunkov
04558bc25e #77: authorization via X-Auth-Token
Implemented authorization via X-Auth-Token to overcome Safari’s bug,
where it may stop sending HTTP Basic Auth header when executing ajax
requests leading to communication errors in web-interface. With
X-Auth-Token only the first request must include HTTP Basic Auth, for
sub-sequential requests the web-interface sends X-Auth-Token, received
from server on first request. The web-interface even tries to remove
the HTTP Basic Auth header from request to improve security; this
however works only in Chrome, other tested browsers still send the Auth
data anyway (IE, Safari, Firefox).
2015-09-07 18:46:45 +02:00
Andrey Prygunkov
12b6a2602a #77: graceful disconnect in web-server
Implemented graceful disconnect strategy in web-server. This may help
with communication errors in web-interface in certain web-browsers.
2015-09-05 22:01:10 +02:00
Andrey Prygunkov
9e493c6c4d #64: fixed: par-checker may not look for missing files
When option ParScan was set to “Dupe” the extra-files were not scanned
in current directory.
2015-09-04 23:36:40 +02:00
hugbug
fdebae5cc2 d48a16598f: fixed line endings 2015-09-04 21:22:01 +02:00
Andrey Prygunkov
ff8f2472a0 #64: fixed: option ParScan=Extended didn't work
When option ParScan was set to “Extended” the extra-files were not
found. Bug introduced v16.
2015-09-04 20:55:49 +02:00
Andrey Prygunkov
f732a0edc1 #18: fixed: feed id wasn't passed to script from preview 2015-09-04 20:36:08 +02:00
Andrey Prygunkov
d48a16598f closed #59: new preference for tray icon behavior on Windows 2015-09-04 19:51:48 +02:00
Andrey Prygunkov
fb5a254b83 #18: new option "FeedX.FeedScript"
…to define per rss feed scripts; in addition to existing global option
“FeedScript”.
2015-09-03 21:45:36 +02:00
Andrey Prygunkov
e01f1a37e5 fixed #78: updating on Windows may fail
Updating the Windows version fails if NZBGet is not installed on the
system drive.
2015-09-03 21:32:04 +02:00
Andrey Prygunkov
4887941170 Merge branch '76-add-with-rename' into develop 2015-08-30 20:36:44 +02:00
Andrey Prygunkov
d57c895127 #76: setting password when adding nzbs 2015-08-30 18:01:42 +02:00
Andrey Prygunkov
7385a1744b #76: change name when adding nzbs
- when nzbs are selected for adding via web-interface they are shown in
the upload-list in the add files dialog;
- the list items are now clickable;
- a click opens a properties dialog where the name, password, duplicate
key and duplicate score can be changed;
- the password-field is currently not implemented yet.
2015-08-30 17:28:33 +02:00
Andrey Prygunkov
dc678b37f5 showing tooltips on article completion tab
The completion tab of download details dialog (and history details
dialog) shows per servers article completion in percents. Now there are
also tooltips to show article counts.
2015-08-26 22:06:10 +02:00
Andrey Prygunkov
cdcbd783cd increased limit for log-entries in history dialog
from 1000 to 10000.
2015-08-26 21:59:37 +02:00
Andrey Prygunkov
20b43ec736 fixed #74: added support for UNC-paths to par2-module
(affects Windows only)
2015-08-26 21:56:40 +02:00
Andrey Prygunkov
cb41e3314c closed #73: new option FeedX.Backlog
- option to reset RSS backlog protection;
- useful for bookmark feeds but also for feeds where filter is often
changed;
- API-method “previewfeed” has new parameter “bool backlog”.
2015-08-21 21:40:31 +02:00
Andrey Prygunkov
a9edcdf4fd Merge branch '72-advanced-search' into develop 2015-08-20 21:31:13 +02:00
Andrey Prygunkov
f5daf39bb8 fixed #67: mark as bad may return items to queue
… if multiple duplicate-items were marked at once
2015-08-20 21:23:37 +02:00
Andrey Prygunkov
aeab407dc0 #72: saved filters in filter menu
- filters can be saved, deleted and renamed.
2015-08-19 22:47:36 +02:00
Andrey Prygunkov
d2770d7a33 #72: popup menu for filter input
- currently with only one menu item “quick help”;
- will be expanded in the future with recent searches.
2015-08-18 22:12:09 +02:00
Andrey Prygunkov
ab86d0efe2 #72: reset filter input on page refresh 2015-08-18 21:08:31 +02:00
Andrey Prygunkov
5b4d3d8038 Merge branch '72-advanced-search' into develop 2015-08-17 23:48:24 +02:00
Andrey Prygunkov
95fffe619d #72: advanced search in settings
- searchable fields: name, description, value.
2015-08-17 22:59:11 +02:00
Andrey Prygunkov
ea95a819c1 #72: comparison operators for integer fields
- search box now supports operators : = <> > < >= <=
- new search fields in downloads list: sizemb, sizegb, leftmb, leftgb,
agem, ageh, aged - download size in MB, GB, left size in MB, GB, age in
minutes, hours, days;
- the same fields except leftmb, leftgb are also available in history.
2015-08-17 18:18:34 +02:00
Andrey Prygunkov
44197148d0 #72: search field names using any letter case
- field names can be typed in any letter case, for example “parstatus”
instead of “ParStatus”;
- there is a potential ambiguity when searching through field “status”:
this field exists in both as column in table and as field in the API;
although it has the same meaning the content is slightly different, the
field in API is more technical and includes extra text, the field in
column is more user friendly;
- to avoid ambiguity use the correct letter case (“Status”) to search
in API field, use low letter case (“status”) to search in table; any
other letter case form (like “sTatus” or “STATUS”) will search in table
too since it has precedence;
2015-08-16 21:37:05 +02:00
Andrey Prygunkov
434ded22e2 Merge branch 'develop' into 72-advanced-search 2015-08-16 19:29:43 +02:00
Andrey Prygunkov
46c8398942 #64: renamed status "Repair" to "ExPar"
- new field “ExParStatus” returned by API-method “history” with values:
“NONE”, “RECIPIENT”, “DONOR”;
- history dialog shows dupe repair status as “EXPAR” instead of
“REPAIR”.
2015-08-16 19:24:27 +02:00
Andrey Prygunkov
1369b23974 #72: search in hidden fields
- in addition to fields shown in tables all other fields coming from
API are now searchable;
- for list of available fields on downloads-tab see API-method
“listgroups”;
- for history-tab see API-method “history”;
- for messages-tab see API-method “log”;
- field names must be typed with correct letter-case;
- visible fields (shown in tables) must be typed in lower case.
2015-08-15 22:11:17 +02:00
Andrey Prygunkov
d21badb6d5 #72: search in specified fields
- column name and a colon should be used as prefix;
- example: “status:downloading|status:processing”
- if no field is specified the search is performed through all fields.
2015-08-15 17:29:29 +02:00
Andrey Prygunkov
4c51d2dc28 #72: better error recovery 2015-08-15 15:25:09 +02:00
Andrey Prygunkov
c0b3058f7c #72: fixed parser errors and better error recovery 2015-08-14 19:42:15 +02:00
Andrey Prygunkov
e5eb29be05 #72: integrated advanced search into module "tasttable"
- removed old word-search default search engine;
- the new advanced search is always used now;
2015-08-14 19:28:12 +02:00
Andrey Prygunkov
3d3fa4980e #72: replaced jison-generated parser with own
- rewritten the parser manually;
- greatly reduced file size;
- better handling of errors;
- supports non-ascii characters.
2015-08-14 18:44:37 +02:00
Andrey Prygunkov
405ed766f4 #72: fixed: clear-button in search box overlapped with text 2015-08-14 18:38:51 +02:00
Andrey Prygunkov
cc62387292 #72: implemented advanced search 2015-08-13 23:16:06 +02:00
Andrey Prygunkov
1594345775 #72: removed search option "CaseSensitive"
it was always set to false anyway.
2015-08-13 22:59:39 +02:00
Andrey Prygunkov
2d3d5af25e #72: made search engine pluggable
the default search engine is words-searcher (the old one).
2015-08-13 22:58:02 +02:00
Andrey Prygunkov
c6656cffbf #64: indication of par-repair using dupe sources
in history details dialog:
- status “REPAIR: RECIPIENT” or “STATUS:DONOR” with hint details;
- in statistics details (via click on “Total downloaded ->”);
- new field “ExtraParBlocks” returned by API-method “history”: positive
numbers for recipient, negative numbers for donor.
2015-08-13 19:38:28 +02:00
Andrey Prygunkov
e4d62ebbc8 par-checker: do not report bad blocks for missing files
- do not report bad blocks for missing files (which are already
reported as missing);
- reporting of bad blocks for empty files could print garbage file
names.
2015-08-12 21:16:44 +02:00
Andrey Prygunkov
af422050b6 #60: don't allow editing of items queued for queue-scripts 2015-08-12 21:14:16 +02:00
Andrey Prygunkov
5f52512a5f fixed #71: crash on reload if a queue-script is running 2015-08-12 21:10:49 +02:00
Andrey Prygunkov
ca0af70d53 #60: active queue-scripts indicated in webui
- the number of active (and queued) scripts are shown in the status
dialog in web-interface; this new row is hidden if no scripts are
queued;
- active queue scripts accounts for activity indicator in web-interface
(rotating button);
- new field “QueueScriptCount” in API-method “status” indicates number
of queue-scripts queued for execution including the currently running.
2015-08-11 22:43:25 +02:00
Andrey Prygunkov
6e0a3e0ceb fixed #69: total articles wasn't reset when downloading again 2015-08-11 22:34:22 +02:00
Andrey Prygunkov
24fd4e8c15 #26, #60, #64, #70: corrected file permissions 2015-08-11 22:31:59 +02:00
Andrey Prygunkov
1e64a7d453 #60: new download status to indicate queue script activity
- new values for field “Status” in method “listgroups”: QS_QUEUED,
QS_EXECUTING;
- QS_QUEUED means that nzb is queued for processing by a queue-script;
- QS_EXECUTING means for that nzb a queue script is currently running;
- indication in web UI: status “QS-QUEUED” (gray) or “QUEUE-SCRIPT”
(green).
2015-08-11 22:27:41 +02:00
Andrey Prygunkov
8a03c64021 #26: executing queue scripts for URLs
- queue-scripts are now also called for failed URLs;
- new queue event “URL_COMPLETED” with possible values: FAILURE,
SCAN_SKIPPED, SCAN_FAILURE;
- queue scripts are not called when URL was successfully fetched and
added queue; event “NZB_ADDED” is fired in this case;
2015-08-11 18:46:43 +02:00
Andrey Prygunkov
f8c1df1856 fixed #70: incorrect reading of UrlStatus from diskstate 2015-08-11 18:43:15 +02:00
Andrey Prygunkov
5b460b7512 #64: improved progress calculation during extra par-scan 2015-08-10 19:52:27 +02:00
Andrey Prygunkov
45277c85e0 fixed: relative redirects did not work
- Absolute redirects to other sites (like “http://host.com/page.html”
did work;
- Absolute redirects to other resource on the same site (like
“/page.html” did work;
- Relative redirects (like “page.html”) did NOT work. Fixed.
2015-08-09 22:56:54 +02:00
Andrey Prygunkov
c38069443d closes #68: better description for option "ServerX.Active" 2015-08-09 01:05:24 +02:00
Andrey Prygunkov
6da5730356 Merge branch '64-dupe-repair' into develop 2015-08-08 21:56:37 +02:00
Andrey Prygunkov
2a9f9f8e98 #64: implemented dupe matcher
Before scanning of dupe directories the directories are quickly checked
by dupe matcher. It determines if they contain or may contain the same
content. If the dupe checker detects a dupe containing different
content as the download being currently processed by par-checker, such
extra dupe is skipped to save time during dupe par scan.
2015-08-07 18:38:51 +02:00
Andrey Prygunkov
a334a32b35 ec47da608f: fixed: crash if an nzb contains only par2-files 2015-08-06 17:52:37 +02:00
Andrey Prygunkov
1583e84927 #64: adjusted health check in dupe par scan mode
When option “ParScan” is set to "Dupe" the delete-action is performed
only if article completion is below 10% (empirical threshold). This is
to improve efficiency of dupe par scan mode.
2015-08-04 22:37:23 +02:00
Andrey Prygunkov
8a2fef7c46 Merge branch 'develop' into 64-dupe-repair 2015-08-03 23:35:04 +02:00
Andrey Prygunkov
6c3f2a9871 #21: refactor: new modules Service and DiskService
Extracted secondary functions from module PrePostProcessor into new
modules Service and DiskService.
2015-08-03 23:27:02 +02:00
Andrey Prygunkov
3ac2ccbc80 #64: do not skip par-check in dupe scan mode
Do not skip par-check when health is below critical health and
ParScan=dupe. The download may be still repairable if the data from
other duplicates can be used.
2015-08-03 00:50:11 +02:00
Andrey Prygunkov
a11d22d3e0 #64: small adjustments in debug logging 2015-08-02 16:59:49 +02:00
Andrey Prygunkov
d07b9af366 #64: process more pars again, after dupe par-check 2015-08-02 16:59:25 +02:00
Andrey Prygunkov
1a65409d0e #64: par-checker should wait for download completion
If par-checker requests extra par2-files, it should wait until all of
them are completely downloaded, even if it becomes clear that repair
isn’t possible. This may happen if par2-files were damaged or not from
the par-set. The waiting is required for correct further processing.
2015-08-02 16:56:51 +02:00
Andrey Prygunkov
941c2efb52 #64: first use par2-files, then scan dupes 2015-08-02 01:32:59 +02:00
Andrey Prygunkov
e99a0c5975 #61: 860f05eb70: fixed: crash in debug mode when reloading 2015-08-02 00:59:48 +02:00
Andrey Prygunkov
6b8c27fdcc #61: 860f05eb70: fixed: crash in debug mode when reloading 2015-08-02 00:57:39 +02:00
Andrey Prygunkov
820260cb6c #64: in option "ParScan" renamed mode "auto" to "extended"
Now having four modes: limited, extended, full and dupe.
2015-08-02 00:38:39 +02:00
Andrey Prygunkov
96c73f05af #64: c674405b44: corrected missing renaming in config file 2015-08-01 21:36:59 +02:00
Andrey Prygunkov
c674405b44 #64: renamed value "Beyond" to "Dupe"
in option ParScan. The new value name suits better.
2015-08-01 01:23:34 +02:00
Andrey Prygunkov
6ac82f03d8 #64: refactor: extracted classes from module "Unpack" into new module "Cleanup" 2015-08-01 00:20:31 +02:00
Andrey Prygunkov
1a206457a2 #64: new par-scan mode "beyond"
- new value for option “ParScan” - “Beyond”;
- in this mode the files from other downloads (duplicates) are scanned
as well;
- this helps if both downloads contain the same file inside archive,
even if the archives were created with different split-settings and
different par-sets.
2015-07-31 21:26:14 +02:00
Andrey Prygunkov
6fd407b200 Merge remote-tracking branch 'origin/develop' into develop 2015-07-31 12:00:29 +02:00
Andrey Prygunkov
d8c6be9f52 Merge branch '26-history' into develop 2015-07-31 12:00:07 +02:00
Andrey Prygunkov
46039698ca #48: added .sln to ignore list
.sln is a Visual Studio Solution file which is generated when opening project file (.vcproj) and therefore can be omitted from repository.
2015-07-28 12:20:09 +02:00
Andrey Prygunkov
002547fde5 #26: passing DupeKey, DupeMode and DupeScore to queue- and pp-scripts
- new env. parameters passed to queue-scripts: NZBNA_DUPEKEY,
NZBNA_DUPEMODE, NZBNA_DUPESCORE;
- new env. parameters passed to pp-scripts: NZBPP_DUPEKEY,
NZBPP_DUPEMODE, NZBPP_DUPESCORE.
2015-07-27 19:12:38 +02:00
Andrey Prygunkov
547b430c91 closed #46 (again): devel version-revision in "Check for Updates"
Showing correct development version-revision in "Check for
Updates"-dialog.
2015-07-25 14:55:21 +02:00
Andrey Prygunkov
860f05eb70 fixed #61: config error messages were not printed to log or screen
but only to stdout, where users typically don’t see them.
2015-07-25 14:45:44 +02:00
Andrey Prygunkov
4cc2beaaca #26: new queue-script event "NZB_DELETED"
- when an nzb is deleted from queue and moved to history the
queue-scripts are called with event “NZB_DELETED”.
- no scripts are called if items are deleted permanently without
putting to history or if the history is completely disabled. This is
because queue-scripts are executed asynchronously and at the time the
script is executed the item must exist (either in queue or in history)
in order to pass item info to the script.
2015-07-24 19:45:44 +02:00
Andrey Prygunkov
d49ab2a087 #26: removed unneeded extra check 2015-07-24 19:34:51 +02:00
Andrey Prygunkov
c208eec5c3 #26: removed code "SUCCESS" from DeleteStatus
A more general code “GOOD” is used instead.
2015-07-24 19:29:41 +02:00
Andrey Prygunkov
c7047b1e33 #26: RPC-method "append" return ID on parsing failure
… instead of error code “-1” as in previous version. Since now a
history item is created on parsing failure its ID is returned. The
caller can check the status from history.
2015-07-24 19:26:31 +02:00
Andrey Prygunkov
659ed48652 #26: ignored nzbs are now added to history
When an nzb-file isn’t added to queue for some reason, the file is now
also added to history (in addition to messages printed to log):
- for malformed nzb-files which cannot be parsed the status in history
“DELETE: SCAN”;
- for duplicate files with exactly same content status “DELETE: COPY”;
- for duplicate files having history items with status “GOOD” - status
“DELETE: GOOD”;
- for duplicate files having history items with status “SUCCESS” -
status “DELETE: SUCCESS”;
- history items have log-entries with explanation;
- new values for field “DeleteStatus” of RPC-Method “history”: GOOD,
SUCCESS, COPY, SCAN;
- new values for field “Status” of RPC-Method “history”:
"FAILURE/SCAN”, ”DELETED/COPY”, "DELETED/GOOD”, "DELETED/SUCCESS”;
- one exception: for files added from RSS-feeds no history items are
created, the files are ignored as if they were filtered.
2015-07-23 23:47:59 +02:00
Andrey Prygunkov
a9a73b635c #21: new option "RequiredDir" 2015-07-23 23:07:47 +02:00
Andrey Prygunkov
fc484ba0dd #28: fixed: files were deleted during flush (Windows only) 2015-07-21 18:22:34 +02:00
Andrey Prygunkov
c6ad5523c7 #56: also supporting ctrl+click in addition to meta+click
Meta+Click doesn’t work on Windows. Ctrl+Click doesn’t work on Mac.
Therefore supporting both.
2015-07-20 20:24:12 +02:00
hugbug
0a8edc2388 fixed #57: activated optimizations in unpack build script 2015-07-19 23:49:14 +02:00
hugbug
3e5bb54ca4 #35: auto-selecting "armhf"-architecture on ARM 64 bit systems (aarch64) 2015-07-19 15:04:05 +02:00
Andrey Prygunkov
7fc8238b23 #56: quick toggle of speed limit
Meta+click-on-speed-icon toggles between "all servers active and
speed-limit=none" and "servers and speed limit as in the config file".
Meta-key: “Command” on Mac; “Win” on Windows.
2015-07-19 14:56:02 +02:00
Andrey Prygunkov
06454eddcc #41: removed workaround which disabled spinlocks for Linux builds 2015-07-17 23:44:56 +02:00
Andrey Prygunkov
c93c0e9dce #41: removed spinlocks support 2015-07-17 23:43:53 +02:00
Andrey Prygunkov
4ec9f947c6 #41: removed spin lock support detection
from configure script (POSIX).
2015-07-17 23:39:07 +02:00
Andrey Prygunkov
6436c3657d fixed compiler warning in par2-module 2015-07-17 00:11:26 +02:00
Andrey Prygunkov
8d1ffa4947 Merge branch '28-disk-flush' into develop 2015-07-17 00:06:49 +02:00
Andrey Prygunkov
5d6dab779e #28: option "FlushQueue" is now enabled by default 2015-07-17 00:06:03 +02:00
Andrey Prygunkov
36d1378881 #28: implemented disk flush on POSIX
with extra specifics for Linux and OS X.
2015-07-16 23:56:37 +02:00
Andrey Prygunkov
187679443f fixed: false memory leaks reports when running tests on Windows 2015-07-16 20:16:33 +02:00
Andrey Prygunkov
97e2776480 #28: implemented disk flush on Windows 2015-07-15 23:17:49 +02:00
Andrey Prygunkov
d7ab37ad31 #28: disk state handling for disk flush
Reworked disk state handling to use disk flush function. The function
itself is not implemented yet.
2015-07-15 23:17:17 +02:00
Andrey Prygunkov
1f7c15628a #28: new option "FlushQueue"
The function is without function yet.
2015-07-15 23:13:47 +02:00
hugbug
15e8a853fb fixed #55: not working endianness detection in Linux installer (affected only mipseb achitecture) 2015-07-14 22:19:40 +02:00
Andrey Prygunkov
1b248721e9 Merge branch '51-signing' into develop 2015-07-13 21:19:37 +02:00
Andrey Prygunkov
fde5f7e744 #51: removed extra switch when calling nzbget
from Linux update script
2015-07-13 21:17:35 +02:00
Andrey Prygunkov
f28e1e76ff #51: implemented verification in Windows update script 2015-07-13 21:15:53 +02:00
Andrey Prygunkov
4daf01e683 fixed few compiler warnings in Windows 2015-07-13 21:13:26 +02:00
Andrey Prygunkov
3752a78fa1 bbc86a15a1: fixed compilation error on Windows 2015-07-13 21:13:05 +02:00
Andrey Prygunkov
bbc86a15a1 corrected an include to fix compiling error on certain systems 2015-07-12 20:54:24 +02:00
hugbug
9864184606 #51: implemented signature verification in Linux update script 2015-07-12 17:35:09 +02:00
hugbug
a0730475f1 Merge branch 'develop' into 51-signing 2015-07-12 14:25:45 +02:00
Andrey Prygunkov
d2f6350fab #51: signatures file format compatible with jsonp 2015-07-11 19:40:55 +02:00
hugbug
d535ac781e closes #27: taking download URL from info file
when updating via built-in update function on Linux.
2015-07-11 15:43:52 +02:00
Andrey Prygunkov
332647c296 #54: corrected message text 2015-07-11 12:58:13 +02:00
Andrey Prygunkov
30f0051976 #54: improved error reporting for passworded archives 2015-07-11 12:51:48 +02:00
Andrey Prygunkov
1efb67b60c #52: fixed: file size was not shown correctly...
for very large files on tab “Files” in “download details dialog”.
2015-07-11 12:03:56 +02:00
Andrey Prygunkov
4c3bec2a3f fixed #52: supporting creating of very large sparse files 2015-07-11 02:37:18 +02:00
hugbug
39063e4bcf #51: added public key to Linux installer 2015-07-11 00:29:10 +02:00
hugbug
da67342419 Merge branch 'develop' into 51-signing 2015-07-11 00:27:51 +02:00
hugbug
50155a0838 #48: fixed broken linux build script 2015-07-11 00:02:42 +02:00
Andrey Prygunkov
25f773efa8 #51: implement signature verification
Command to verify:
    nzbget -n -B verify pubkey.pem signatures.txt installer-package

File “signatures.txt” can contain multiple signatures for many files -
one line per file, in format:
    RSA-SHA256(installer-package)= signature-hex-dump
2015-07-10 20:32:19 +02:00
Andrey Prygunkov
c1fcf0b075 #51: added public key to repository 2015-07-10 19:37:21 +02:00
Andrey Prygunkov
063d5a22ba Merge branch '48-cleanup-rootdir' into develop 2015-07-10 18:04:13 +02:00
hugbug
c92c1c9a3d #48: removed unnecessary Visual Studio solution file (project file is sufficient) 2015-07-10 00:00:39 +02:00
hugbug
213eb2c7c1 #48: removed unnecessary files from project root directory; moved other (necessary) files into new subdirectory "posix" 2015-07-09 23:49:17 +02:00
Andrey Prygunkov
b284dcc7ef #27: taking download URL from info file
… when updating via built-in update function on Windows.
2015-07-08 19:23:43 +02:00
Andrey Prygunkov
9822eae8ff closed #46: devel version-revision in "Check for Updates"
Showing correct development version-revision in "Check for
Updates"-dialog.
2015-07-07 22:19:48 +02:00
Andrey Prygunkov
c3dd57abc6 fixed #47, #14: RPC-API method "readurl" follows redirects
the method is used by "Check for Updates"-function in web-interface
2015-07-07 22:10:31 +02:00
Andrey Prygunkov
3c65d13c00 fixed #45: incorrect subject parsing
… for obfuscated filenames without extensions.
2015-07-06 22:13:42 +02:00
Andrey Prygunkov
b84bab52e0 #45: created test case for subject parsing 2015-07-06 22:12:46 +02:00
hugbug
059bd2b54e set correct file permissions for source code 2015-07-06 21:56:25 +02:00
Andrey Prygunkov
ec29f55f53 fixed: compiler error when building tests on Windows 2015-07-06 21:49:58 +02:00
Andrey Prygunkov
547e0e73de #5: corrected an URL 2015-07-05 15:07:30 +02:00
Andrey Prygunkov
d4f1660a1a #5: corrected typo 2015-07-05 15:05:13 +02:00
Andrey Prygunkov
6c81365ee7 #5: created README.md
as entry point for GitHub's first time visitors
2015-07-05 14:15:03 +02:00
Andrey Prygunkov
f0e779c9ea addition to ec47da608f: fixed: option "DownloadRate" were incorrectly read from config file 2015-07-01 18:39:47 +02:00
Andrey Prygunkov
71bf3815c3 Merge branch '18-feed-script' into develop 2015-06-30 23:51:25 +02:00
Andrey Prygunkov
d7c14201ac closes #19: hidden option "rowSelect" now works for feed view too 2015-06-30 23:48:27 +02:00
hugbug
e963ccefe5 #42: shortened the texts, improved robustness 2015-06-30 00:35:12 +02:00
Andrey Prygunkov
37252faedc Merge pull request #42 from sanderjo/show-ip-address
Improved detection of local IP-address in Linux installer
2015-06-30 00:28:07 +02:00
sanderjo
5144f8ba02 Show correct LAN/WLAN ip address after installing 2015-06-29 23:16:58 +02:00
Andrey Prygunkov
16f83417fe #18: added new files to VC project file 2015-06-29 20:16:09 +02:00
hugbug
17a506009e #18: added new files to Makefile 2015-06-29 19:43:08 +02:00
Andrey Prygunkov
0b0d7784e0 #18: added missing files 2015-06-29 19:46:00 +02:00
Andrey Prygunkov
151204c8d1 #18: UI editor for option "FeedScript"
… in web-interface.
2015-06-29 19:31:12 +02:00
Andrey Prygunkov
ced1536195 #18: add support for feed scripts
via new option “FeedScript”.
2015-06-29 19:30:31 +02:00
Andrey Prygunkov
cce367b83c #18: new option "FeedScript" 2015-06-29 19:29:57 +02:00
hugbug
8101780fa1 #41: disabled spin locks in builds for Linux installer 2015-06-28 22:04:16 +02:00
hugbug
20fcd3436c #9: merge 5b8dc9788966d68248dd04d516c46623c7a31038 into develop 2015-06-28 21:44:36 +02:00
Andrey Prygunkov
215521b800 Merge pull request #38 from teonar/develop
Search string (in the search box) now supports or(|) and not(!) qualifiers.
2015-06-26 22:12:06 +02:00
teonar
34f8b9f82c was using svn sources 2015-06-26 19:47:09 +02:00
teonar
23fd1fb35e Merge branch 'develop' of https://github.com/teonar/nzbget into develop 2015-06-26 19:43:38 +02:00
teonar
91e362ca15 Implemented or(|) not(!) qualifiers. and(&) is the default.
e.g.
!earth !moon
will display items that doesn't have the words (earth or moon)
|earth |moon
will display items that have moon or earth
!earth moon
will display items that does not have earth but does have moon
!earth |moon
will display items that does not have earth but does have moon
2015-06-26 19:42:14 +02:00
Andrey Prygunkov
0027df28a3 fixed #8: spaces in URLs are now automatically encoded 2015-06-26 17:05:07 +02:00
teonar
9f9fcaedee Implemented or(|) not(!) qualifiers. and(&) is the default.
e.g.
!earth !moon
  will display items that doesn't have the words (earth or moon)
|earth |moon
  will display items that have moon or earth
!earth moon
  will display items that does not have earth but does have moon
!earth |moon
  will display items that does not have earth but does have moon
2015-06-26 15:16:10 +02:00
Andrey Prygunkov
a91f296562 Merge branch '32-rss-description-cleanup' into develop 2015-06-25 23:42:16 +02:00
Andrey Prygunkov
708b9d93ff #32: replacing unknown html-entities (better version)
When fetching rss feeds the unknown html-entities in the description
field are now replaced with spaces (example: &mdash;).
2015-06-24 23:05:16 +02:00
Andrey Prygunkov
08c9c8f5fb #32, 517f860c6b: reverted
Reverted the replacing of unknown xml-entities. It was buggy and not a
good idea. Replacing of unknown html-entities should be separate
function (if needed).
2015-06-24 22:37:28 +02:00
Andrey Prygunkov
b12b51d17a fixed #33: can't deleted active URL download 2015-06-24 18:53:25 +02:00
Andrey Prygunkov
7b99aadb3f Merge branch 'develop' into 32-rss-description-cleanup 2015-06-24 00:32:27 +02:00
Andrey Prygunkov
c5b551d68e increased size of version string buffer
since the version name now can include branch name, which can be long
2015-06-24 00:25:36 +02:00
Andrey Prygunkov
fdfb7ce628 #32: cleanup field "description"
… when reading rss feed.
2015-06-24 00:16:59 +02:00
hugbug
eceb7bd14b #32: fixed test-unit compilation error on Linux 2015-06-23 23:54:57 +02:00
hugbug
1e527c900a #32: added new test-unit to Makefile 2015-06-23 23:54:21 +02:00
Andrey Prygunkov
517f860c6b #32: replacing unknown html-entities
Function **XmlDecode** replaces unknown xml-entities with spaces.
Example: &mdash; It’s better to replace them than keep unchanged.
2015-06-23 23:41:04 +02:00
Andrey Prygunkov
0e4da5719c #32: created cleanup-function
… and a test for it.
2015-06-23 22:48:49 +02:00
Andrey Prygunkov
7f1f9d6394 ec47da608f: fixed compiling error on Windows 2015-06-21 23:42:36 +02:00
Andrey Prygunkov
d25f723ae2 #4: corrected .gitattributes for line endings
as suggested by @rcdailey in the issue discussion.
2015-06-21 18:14:14 +02:00
Andrey Prygunkov
dd81ffeb00 #4: normalize all the line endings (again) 2015-06-21 12:26:27 +02:00
Andrey Prygunkov
f225ea8905 #4: normalize all the line endings 2015-06-21 12:24:26 +02:00
Andrey Prygunkov
5b6999232f #4: corrections for line endings 2015-06-21 12:23:07 +02:00
Andrey Prygunkov
17d2b0da7c closes #6: deleted unneeded Makefile.cvs 2015-06-21 00:05:31 +02:00
Andrey Prygunkov
7768035da2 closes #4: configured line endings
... for git repository
2015-06-20 23:53:26 +02:00
Andrey Prygunkov
d4b53ac007 #3: corrected a comment
For naming testing releases.
2015-06-20 23:49:07 +02:00
hugbug
67e07c8fcd #4: updated .gitignore for GNU automake 2015-06-20 23:35:04 +02:00
Andrey Prygunkov
2737c63903 Merge pull request #17 from nzbget/build-nzbget
Updated linux build script
2015-06-20 01:40:21 +02:00
Andrey Prygunkov
a367698670 #9: removed debug code 2015-06-20 01:38:45 +02:00
Andrey Prygunkov
eb904280e9 closes #9: updated linux build script
The script now works with git.
2015-06-20 01:36:41 +02:00
Andrey Prygunkov
2ec4ad331c #4: created .gitattributes 2015-06-19 20:29:04 +02:00
Andrey Prygunkov
393c9af054 Merge pull request #7 from nzbget/migration-naming
Naming for testing builds
2015-06-18 01:30:36 +02:00
Andrey Prygunkov
0f28e3e689 #3: implemented naming for testing builds
Naming:
 - for master-branch: no suffix;
 - for develop-branch: suffix “rXXXX”, for example “16.0-testing-r1257”;
 - for other branches: suffix “rXXXX (<branch>)”, for example
“16.0-testing-r1257M (migration-naming)”.
2015-06-18 01:21:20 +02:00
Andrey Prygunkov
c072ff570b #4: created .gitignore-file 2015-06-18 01:05:40 +02:00
Andrey Prygunkov
ec47da608f refactor: reducing usage of "float"-type where possible 2015-06-05 11:24:05 +00:00
Andrey Prygunkov
734dbfc98b refactor: changed one parameter in par2-module from "double" to "int" 2015-06-05 10:55:11 +00:00
Andrey Prygunkov
a78649773f improved linux installer: 1) better compatibility with android; 2) added support for paths with spaces in parameter "--destdir" 2015-05-26 21:30:10 +00:00
Andrey Prygunkov
dc2429d9b7 addition to r1304: added missing file 2015-05-25 20:52:56 +00:00
Andrey Prygunkov
965dabc415 integrated unit testing framework; created few first unit tests for: command line parser, options parser, rss feed filter, par-checker/repairer and par-renamer; new configure parameter "--enable-tests" to build the program with tests; use "nzbget --tests" to execute all tests or "nzbget --tests -h" for more options 2015-05-25 20:36:29 +00:00
Andrey Prygunkov
b04bdb0b9f addition to r1298: fixed compilation error on Windows 2015-05-25 18:04:35 +00:00
Andrey Prygunkov
9ce304ea52 addition to r1292: fixed: an error message was printed by command line commands "-h" and "-v" 2015-05-25 13:26:51 +00:00
Andrey Prygunkov
77a351c94c fixed: installation via universal Linux installer failed on certain WD NAS models due to Busybox limitations 2015-05-24 12:11:25 +00:00
Andrey Prygunkov
5d24697b0c refactor: reworked declaration of global objects (singletones) 2015-05-22 20:28:05 +00:00
Andrey Prygunkov
0cbeb2fc52 addition to r1297: fixed compilation error on Linux 2015-05-21 18:56:13 +00:00
Andrey Prygunkov
934c9e23ba refactor: new directory "extension" to hold all extension script related modules 2015-05-21 18:42:33 +00:00
Andrey Prygunkov
2441cc208f refactor: reducing module dependencies for easier testing: extracted config handling code from module "Options" into new module "ScriptConfig", which can be instantiated separately 2015-05-21 16:10:17 +00:00
Andrey Prygunkov
27fd8989d8 fixed: par-verification of repaired files were sometimes not skipped in quick verification mode (option "ParQuick=yes") 2015-05-21 14:41:14 +00:00
Andrey Prygunkov
a641bd8bd1 refactor: reducing module dependencies for easier testing: extracted par file name parsing code from module "ParCoordinator" into new module "ParParser", which can be instantiated separately 2015-05-21 14:33:16 +00:00
Andrey Prygunkov
366cb2e456 refactor: extracted function "CopyFile" from "MoveFile"; the new function is useful for testing 2015-05-21 10:59:25 +00:00
Andrey Prygunkov
31a7e133fa refactor: moved initialization of logging from main module into module "Log"; removed (now unused) global function "abort" 2015-05-21 10:55:06 +00:00
Andrey Prygunkov
c808b38778 refactor: reducing module dependencies for easier testing: extracted command line parsing code from module "Options" into new module "CommandLineParser"; modules "Options" and "CommandLineParser" do not depend on other modules and can be instantiated separately; they do not immediately abort program execution on fatal errors and instead report errors via state variables 2015-05-21 10:42:18 +00:00
Andrey Prygunkov
ac04dc248c refactor: reworked dependencies in rss feeds for easier filter tests 2015-05-20 20:29:58 +00:00
Andrey Prygunkov
15eb927137 updated version string to 16.0-testing 2015-05-20 18:17:01 +00:00
182 changed files with 24323 additions and 10153 deletions

25
.gitattributes vendored Normal file
View File

@@ -0,0 +1,25 @@
* text=auto
# Use CRLF for certain Windows files.
*.vcproj eol=crlf
*.sln eol=crlf
*.bat eol=crlf
README-WINDOWS.txt eol=crlf
nzbget-setup.nsi eol=crlf
windows/package-info.json eol=crlf
windows/resources/resource.h eol=crlf
windows/resources/nzbget.rc eol=crlf
# Configure GitHub's language detector
lib/* linguist-vendored linguist-language=C++
webui/lib/* linguist-vendored
Makefile.in linguist-vendored
configure linguist-vendored
config.sub linguist-vendored
aclocal.m4 linguist-vendored
config.guess linguist-vendored
depcomp linguist-vendored
install-sh linguist-vendored
missing linguist-vendored
configure.ac linguist-vendored=false
Makefile.am linguist-vendored=false

63
.gitignore vendored Executable file
View File

@@ -0,0 +1,63 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
# GNU Autotools
.deps/
config.h
config.log
config.status
Makefile
stamp-h1
autom4te.cache/
# Visual Studio User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
.vs/
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
*.ilk
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.vspscc
*.vssscc
*.pidb
*.svclog
*.scc
*.sln
# NZBGet specific
nzbget
code_revision.cpp

185
ChangeLog
View File

@@ -1,3 +1,180 @@
nzbget-16.4:
- fixed resource (socket) leak which may cause "too many open files"
errors with a possible crash.
nzbget-16.3:
- fixed: certain downloads may fail due to a bug in the workaround
implemented in v16.2.
nzbget-16.2:
- implemented workaround to deal with malformed news server responses,
which may still contain useful data.
nzbget-16.1:
- fixed issues with reverse proxies;
- fixed unpack failure on older AMD CPUs, when installed via
universal Linux installer;
- fixed: when the program was started from setup the default directories
were created with wrong permission (Windows only).
nzbget-16.0:
- moved project hosting to GitHub:
- moved source code repository from subversion to git;
- updated POSIX makefile to generate revision number for testing
releases;
- updated Linux installer build script to work with git;
- adjusted function "check for updates" in web-interface;
- update-scripts for Linux installer and Windows setup fetch new
versions from GitHub releases area;
- cleaned up project root directory, removed many unneeded files which
were required by GNU build tools;
- added verification for setup authenticity during update on Linux and Windows;
- improvements in Linux installer:
- improved compatibility with android;
- added support for paths with spaces in parameter "--destdir";
- auto-selecting "armhf"-architecture on ARM 64 bit systems (aarch64);
- ignored nzbs are now added to history and processed by queue scripts:
- when an nzb-file isnt added to queue, for some reason, the file is now
also added to history (in addition to messages printed to log);
- on one hand that makes it easier to see errors (as history items instead
of error log messages), on the other hand that provides more info for
extension scripts and third-party programs;
- for malformed nzb-files which cannot be parsed the status in history is
"DELETE: SCAN";
- for duplicate files with exactly same content status "DELETE: COPY";
- for duplicate files having history items with status "GOOD" and for
duplicate files having hidden history items with status "SUCCESS" which
do not have any visible duplicates - status "DELETE: GOOD";
- new values for field "DeleteStatus" of API-Method "history": "GOOD",
"COPY", "SCAN";
- new values for field "Status" of API-Method "history": "FAILURE/SCAN",
"DELETED/COPY", "DELETED/GOOD" (they will also be passed to pp-scripts
as NZBPP_STATUS);
- new queue-script event "NZB_DELETED";
- new queue event "URL_COMPLETED", with possible details: "FAILURE",
"SCAN_SKIPPED", "SCAN_FAILURE";
- improved quick filter (the search box at the top of the page):
- now supporting OR, AND, NOT, parenthesis;
- can search in specific fields;
- can search in API-fields which are not shown in the table;
- filters can be saved and loaded using new drop down menu;
- new advanced duplicate par-check mode:
- can be activated via option "ParScan=Dupe";
- the new mode is based on the fact that the same releases are posted to
Usenet multiple times;
- when an item requires repair but doesn't have enough par-blocks the
par-checker can reuse parts downloaded in other duplicates of the same
title;
- that makes it sometimes possible to repair downloads which would fail
if tried to repair individually;
- the downloads must be identifiable as duplicates (same nzb name or same
duplicate key);
- when par-checker needs more par-blocks it goes through the history and
scans the download directories of duplicates until it finds missing
blocks; it's smart enough to abort the scanning if the files come from
different releases (based on video file size);
- adjusted option "HealthCheck"; when set to "Delete" and duplicate
par-scan is active, the download is aborted only if the completion is
below 10%; that's to avoid deletion of damaged downloads which can be
potentially repaired using new par-check mode;
- downloads which were repaired using the new mode or which have donated
their blocks to repair other downloads are distinguishable in the
history details dialog with new status "EXPAR: RECIPIENT" or "EXPAR:
DONOR"; a tooltip on the status shows amount of par-blocks
received/donated;
- new field "ExParStatus" returned by API-method "history";
- to quickly find related history items use quick filter
"-exparstatus:none" in history list;
- when adding nzb-files via web-interface it's now possible to change name and
other properties:
- nzb-files in the upload-list are now clickable;
- the click opens properties dialog where the name, password, duplicate
key and duplicate score can be changed;
- queue script activity is now indicated in web-interface:
- items in download list may have new statuses "QS-QUEUED" (gray) or
"QUEUE-SCRIPT" (green);
- new values for field "Status" in API-method "listgroups": "QS_QUEUED",
"QS_EXECUTING";
- the number of active (and queued) scripts are shown in the status dialog
in web-interface; this new row is hidden if no scripts are queued;
- active queue scripts account for activity indicator in web-interface
(rotating button);
- new field "QueueScriptCount" in API-method "status" indicates number of
queue-scripts queued for execution including the currently running;
- added scripting support to RSS Feeds:
- new option "FeedScript" to set global rss feed scripts;
- new option "FeedX.FeedScript" to define per rss feed scripts;
- new option "FeedX.Backlog" to control the RSS feed behavior when fetched for
the first time or after changing of URL or filter;
- implemented cleanup for field "description" in RSS feeds to remove HTML
formatting;
- new option "FlushQueue" ("yes" by default) to force disk cache flush when
saving queue;
- quick toggle of speed limit; "Command/Control + click-on-speed-icon" toggles
between "all servers active and speed-limit=none" and "servers and speed
limit as in the config file";
- new option "RequiredDir" to wait for external drives mount on boot;
- hidden webui option "rowSelect" now works for feed view too;
- improved error message for password protected archives;
- increased limit for log-entries in history dialog from 1000 to 10000;
- completion tab of download details dialog (and history details dialog)
shows per server article completion in percents; now there are also
tooltips to show article counts;
- do not reporting bad blocks for missing files (which are already reported as
missing);
- new setting to set tray icon behavior on Windows;
- improvements in built-in web-server to fix communication errors which may
occur on certain systems, in particular on OS X Safari:
- implemented graceful disconnect strategy in web-server;
- added authorization via X-Auth-Token to overcome Safaris bug, where
it may stop sending HTTP Basic Auth header when executing ajax
requests;
- pp-script EMail.py now supports new TLS/SSL mode "Force". When active the
secure communication with SMTP server is built using secure socket on
connection level instead of plain connection and following switch into
secure mode using SMTP-command "STARTLS". This new mode is in particular
required when using GMail on port 465;
- speed improvement in built-in web-server on Windows when serving API
requests (web-interface) for very large queue or history (with thousands
items);
- better performance when deleting many items from queue at once (hundreds or
thousands);
- improved performance in web-interface when working with very large queue or
history (thousands of items);
- integrated unit testing framework, created few first unit tests:
- new configure parameter "--enable-tests" to build the program with
tests;
- use "nzbget --tests" to execute all tests or "nzbget --tests -h" for
more options;
- fixes in Linux installer:
- fixed: installer may show wrong IP-address in the quick help message
printed after installation (thanks to @sanderjo);
- fixed: installation failed on certain WD NAS models due to Busybox
limitations;
- fixed: not working endianness detection on mipseb architecture;
- fixed: unrar too slow on x86_64 architecture;
- fixed: reporting of bad blocks for empty files could print garbage file
names;
- fixed: par-check did not work on UNC paths (Windows only);
- fixed: config error messages were not printed to log or screen but only to
stdout, where users typically dont see them;
- fixed: incorrect reading of UrlStatus from disk state;
- fixed: total articles wasn't reset when downloading again;
- fixed: crash on reload if a queue-script is running;
- fixed: mark as bad may return items to queue if used on multiple items
simultaneously;
- fixed: updating may fail if NZBGet was not installed on the system
drive (Windows only);
- fixed: the program may hang during multithreading par-repair, only certain
Linux system affected;
- fixed: active URL download could not be deleted;
- fixed: par-verification of repaired files were sometimes not skipped in
quick verification mode (option "ParQuick=yes");
- fixed: when parsing nzb-files filenames may be incorrectly detected causing
certain downloads to fail;
- fixed: nzb-files containing very large individual files (many GB) may cause
program to crash or print error "Could not create file ...".
nzbget-15.0:
- improved application for Windows:
- added tray icon (near clock);
@@ -2272,10 +2449,10 @@ nzbget-0.3.0:
install/remove nzbget-Service. Servers and clients can run on diferrent
operating systems;
- Improved compatibility with POSIX systems; Tested on:
- Linux Debian 3.1 on x86;
- Linux BusyBox with uClibc on MIPSEL;
- PC-BSD 1.4 (based on FreeBSD 6.2) on x86;
- Solaris 10 on x86;
- Linux Debian 3.1 on x86;
- Linux BusyBox with uClibc on MIPSEL;
- PC-BSD 1.4 (based on FreeBSD 6.2) on x86;
- Solaris 10 on x86;
- Many memory-leaks and thread issues were fixed;
- The program was thoroughly worked over. Almost every line of code was
revised.

167
INSTALL
View File

@@ -1,167 +0,0 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes a while. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Type `make install' to install the programs and any data files and
documentation.
4. You can remove the program binaries and object files from the
source code directory by typing `make clean'.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

View File

@@ -1,7 +1,7 @@
#
# This file is part of nzbget
#
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -28,6 +28,20 @@ nzbget_SOURCES = \
daemon/connect/TLS.h \
daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h \
daemon/extension/FeedScript.cpp \
daemon/extension/FeedScript.h \
daemon/extension/NzbScript.cpp \
daemon/extension/NzbScript.h \
daemon/extension/PostScript.cpp \
daemon/extension/PostScript.h \
daemon/extension/QueueScript.cpp \
daemon/extension/QueueScript.h \
daemon/extension/ScanScript.cpp \
daemon/extension/ScanScript.h \
daemon/extension/SchedulerScript.cpp \
daemon/extension/SchedulerScript.h \
daemon/extension/ScriptConfig.cpp \
daemon/extension/ScriptConfig.h \
daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h \
daemon/feed/FeedFile.cpp \
@@ -44,6 +58,10 @@ nzbget_SOURCES = \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/CommandLineParser.cpp \
daemon/main/CommandLineParser.h \
daemon/main/DiskService.cpp \
daemon/main/DiskService.h \
daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h \
daemon/main/nzbget.cpp \
@@ -68,14 +86,18 @@ nzbget_SOURCES = \
daemon/nntp/ServerPool.h \
daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h \
daemon/postprocess/Cleanup.cpp \
daemon/postprocess/Cleanup.h \
daemon/postprocess/DupeMatcher.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/PostScript.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp \
@@ -94,8 +116,6 @@ nzbget_SOURCES = \
daemon/queue/QueueCoordinator.h \
daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h \
daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h \
daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h \
daemon/queue/UrlCoordinator.cpp \
@@ -119,9 +139,11 @@ nzbget_SOURCES = \
daemon/util/Script.h \
daemon/util/Thread.cpp \
daemon/util/Thread.h \
daemon/util/Service.cpp \
daemon/util/Service.h \
daemon/util/Util.cpp \
daemon/util/Util.h \
svn_version.cpp
code_revision.cpp
if WITH_PAR2
nzbget_SOURCES += \
@@ -171,6 +193,7 @@ endif
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-I$(srcdir)/daemon/extension \
-I$(srcdir)/daemon/feed \
-I$(srcdir)/daemon/frontend \
-I$(srcdir)/daemon/main \
@@ -181,11 +204,31 @@ AM_CPPFLAGS = \
-I$(srcdir)/daemon/util \
-I$(srcdir)/lib/par2
if WITH_TESTS
nzbget_SOURCES += \
lib/catch/catch.h \
tests/suite/TestMain.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/queue/NZBFileTest.cpp \
tests/util/UtilTest.cpp
AM_CPPFLAGS += \
-I$(srcdir)/lib/catch \
-I$(srcdir)/tests/suite
endif
EXTRA_DIST = \
Makefile.cvs \
$(windows_FILES) \
$(osx_FILES) \
$(linux_FILES)
$(linux_FILES) \
$(testdata_FILES)
windows_FILES = \
daemon/windows/NTService.cpp \
@@ -193,7 +236,6 @@ windows_FILES = \
daemon/windows/win32.h \
daemon/windows/WinConsole.cpp \
daemon/windows/WinConsole.h \
nzbget.sln \
nzbget.vcproj \
windows/nzbget-command-shell.bat \
windows/install-update.bat \
@@ -251,7 +293,6 @@ linux_FILES = \
doc_FILES = \
lib/par2/AUTHORS \
lib/par2/README \
AUTHORS \
README \
ChangeLog \
COPYING
@@ -295,6 +336,23 @@ scripts_FILES = \
scripts/EMail.py \
scripts/Logger.py
testdata_FILES = \
tests/testdata/dupematcher1/testfile.part01.rar \
tests/testdata/dupematcher1/testfile.part24.rar \
tests/testdata/dupematcher2/testfile.part04.rar \
tests/testdata/dupematcher2/testfile.part43.rar \
tests/testdata/nzbfile/dotless.nzb \
tests/testdata/nzbfile/dotless.txt \
tests/testdata/nzbfile/plain.nzb \
tests/testdata/nzbfile/plain.txt \
tests/testdata/parchecker/crc.txt \
tests/testdata/parchecker/testfile.dat \
tests/testdata/parchecker/testfile.nfo \
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
# Install
dist_doc_DATA = $(doc_FILES)
exampleconfdir = $(datadir)/nzbget
@@ -335,44 +393,57 @@ install-conf:
uninstall-conf:
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf"
# Determining subversion revision:
# 1) If directory ".svn" exists we take revision from it using program svnversion (part of subversion package)
# Determining git revision:
# 1) If directory ".git" exists we take revision from git log.
# File is recreated only if revision number was changed.
# 2) If directory ".svn" doesn't exists we keep and reuse file "svn_version.cpp",
# 2) If directory ".git" doesn't exists we keep and reuse file "code_revision.cpp",
# which was possibly created early.
# 3) If neither directory ".svn" nor file "svn_version.cpp" are available
# we create new file "svn_version.c" with empty revision number.
svn_version.cpp: FORCE
@ if test -d ./.svn ; then \
V="$(shell svnversion -n .)"; \
H="$(shell test -f ./svn_version.cpp && head -n 1 svn_version.cpp)"; \
# 3) If neither directory ".git" nor file "code_revision.cpp" are available
# we create new file "code_revision.c" with empty revision number.
code_revision.cpp: FORCE
@ if test -d ./.git ; then \
B="$(shell git branch | sed -n -e 's/^\* \(.*\)/\1/p')"; \
M="$(shell git status --porcelain)" ; \
if test "$$M" != "" ; then \
M="M" ; \
fi ; \
if test "$$B" = "master" ; then \
V="$$M" ; \
elif test "$$B" = "develop" ; then \
V="$(shell git rev-list HEAD | wc -l | xargs)" ; \
V="$${V}$$M" ; \
else \
V="$(shell git rev-list HEAD | wc -l | xargs)" ; \
V="$${V}$$M ($$B)" ; \
fi ; \
H="$(shell test -f ./code_revision.cpp && head -n 1 code_revision.cpp)"; \
if test "/* $$V */" != "$$H" ; then \
( \
echo "/* $$V */" ;\
echo "/* This file is automatically regenerated on each build. Do not edit it. */" ;\
echo "const char* svn_version(void)" ;\
echo "const char* code_revision(void)" ;\
echo "{" ;\
echo " const char* SVN_Version = \"$$V\";" ;\
echo " return SVN_Version;" ;\
echo " const char* revision = \"$$V\";" ;\
echo " return revision;" ;\
echo "}" ;\
) > svn_version.cpp ; \
) > code_revision.cpp ; \
fi \
elif test -f ./svn_version.cpp ; then \
elif test -f ./code_revision.cpp ; then \
test "ok, reuse existing file"; \
else \
( \
echo "/* */" ;\
echo "/* This file is automatically regenerated on each build. Do not edit it. */" ;\
echo "const char* svn_version(void)" ;\
echo "const char* code_revision(void)" ;\
echo "{" ;\
echo " const char* SVN_Version = \"\";" ;\
echo " return SVN_Version;" ;\
echo " const char* revision = \"\";" ;\
echo " return revision;" ;\
echo "}" ;\
) > svn_version.cpp ; \
) > code_revision.cpp ; \
fi
FORCE:
# Ignore "svn_version.cpp" in distcleancheck
# Ignore "code_revision.cpp" in distcleancheck
distcleancheck_listfiles = \
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
sh '{}' ';'
@@ -384,4 +455,5 @@ dist-hook:
find $(distdir)/daemon -type f -print -exec chmod -x {} \;
find $(distdir)/webui -type f -print -exec chmod -x {} \;
find $(distdir)/lib -type f -print -exec chmod -x {} \;
find $(distdir)/tests -type f -print -exec chmod -x {} \;

View File

@@ -1,8 +0,0 @@
default: all
all:
aclocal
autoheader
automake
autoconf

628
Makefile.in vendored
View File

@@ -17,7 +17,7 @@
#
# This file is part of nzbget
#
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -57,9 +57,6 @@ POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
bin_PROGRAMS = nzbget$(EXEEXT)
@WITH_PAR2_TRUE@am__append_1 = \
@WITH_PAR2_TRUE@ lib/par2/commandline.cpp \
@@ -105,13 +102,31 @@ bin_PROGRAMS = nzbget$(EXEEXT)
@WITH_PAR2_TRUE@ lib/par2/verificationpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/verificationpacket.h
@WITH_TESTS_TRUE@am__append_2 = \
@WITH_TESTS_TRUE@ lib/catch/catch.h \
@WITH_TESTS_TRUE@ tests/suite/TestMain.cpp \
@WITH_TESTS_TRUE@ tests/suite/TestMain.h \
@WITH_TESTS_TRUE@ tests/suite/TestUtil.cpp \
@WITH_TESTS_TRUE@ tests/suite/TestUtil.h \
@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/queue/NZBFileTest.cpp \
@WITH_TESTS_TRUE@ tests/util/UtilTest.cpp
@WITH_TESTS_TRUE@am__append_3 = \
@WITH_TESTS_TRUE@ -I$(srcdir)/lib/catch \
@WITH_TESTS_TRUE@ -I$(srcdir)/tests/suite
subdir = .
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
$(dist_exampleconf_DATA) $(nobase_dist_scripts_SCRIPTS) \
$(nobase_dist_webui_DATA) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
config.guess config.sub depcomp install-sh missing
subdir = .
$(top_srcdir)/configure COPYING ChangeLog posix/depcomp \
posix/install-sh posix/missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
@@ -129,17 +144,30 @@ PROGRAMS = $(bin_PROGRAMS)
am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
daemon/connect/Connection.h daemon/connect/TLS.cpp \
daemon/connect/TLS.h daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h daemon/frontend/ColoredFrontend.cpp \
daemon/connect/WebDownloader.h daemon/extension/FeedScript.cpp \
daemon/extension/FeedScript.h daemon/extension/NzbScript.cpp \
daemon/extension/NzbScript.h daemon/extension/PostScript.cpp \
daemon/extension/PostScript.h daemon/extension/QueueScript.cpp \
daemon/extension/QueueScript.h daemon/extension/ScanScript.cpp \
daemon/extension/ScanScript.h \
daemon/extension/SchedulerScript.cpp \
daemon/extension/SchedulerScript.h \
daemon/extension/ScriptConfig.cpp \
daemon/extension/ScriptConfig.h \
daemon/feed/FeedCoordinator.cpp daemon/feed/FeedCoordinator.h \
daemon/feed/FeedFile.cpp daemon/feed/FeedFile.h \
daemon/feed/FeedFilter.cpp daemon/feed/FeedFilter.h \
daemon/feed/FeedInfo.cpp daemon/feed/FeedInfo.h \
daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h daemon/frontend/Frontend.cpp \
daemon/frontend/Frontend.h \
daemon/frontend/LoggableFrontend.cpp \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h daemon/main/Maintenance.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/CommandLineParser.cpp \
daemon/main/CommandLineParser.h daemon/main/DiskService.cpp \
daemon/main/DiskService.h daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h daemon/main/nzbget.cpp \
daemon/main/nzbget.h daemon/main/Options.cpp \
daemon/main/Options.h daemon/main/Scheduler.cpp \
@@ -151,14 +179,18 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
daemon/nntp/NewsServer.h daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/ParChecker.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/Cleanup.cpp \
daemon/postprocess/Cleanup.h \
daemon/postprocess/DupeMatcher.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/PostScript.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
@@ -170,8 +202,7 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
daemon/queue/HistoryCoordinator.h daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h daemon/queue/Scanner.cpp \
daemon/queue/QueueEditor.h daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h daemon/remote/MessageBase.h \
@@ -182,8 +213,9 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
daemon/util/Log.cpp daemon/util/Log.h daemon/util/Observer.cpp \
daemon/util/Observer.h daemon/util/Script.cpp \
daemon/util/Script.h daemon/util/Thread.cpp \
daemon/util/Thread.h daemon/util/Util.cpp daemon/util/Util.h \
svn_version.cpp lib/par2/commandline.cpp \
daemon/util/Thread.h daemon/util/Service.cpp \
daemon/util/Service.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 \
@@ -203,7 +235,14 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
lib/par2/recoverypacket.h lib/par2/reedsolomon.cpp \
lib/par2/reedsolomon.h lib/par2/verificationhashtable.cpp \
lib/par2/verificationhashtable.h \
lib/par2/verificationpacket.cpp lib/par2/verificationpacket.h
lib/par2/verificationpacket.cpp lib/par2/verificationpacket.h \
lib/catch/catch.h tests/suite/TestMain.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/queue/NZBFileTest.cpp tests/util/UtilTest.cpp
@WITH_PAR2_TRUE@am__objects_1 = commandline.$(OBJEXT) crc.$(OBJEXT) \
@WITH_PAR2_TRUE@ creatorpacket.$(OBJEXT) \
@WITH_PAR2_TRUE@ criticalpacket.$(OBJEXT) datablock.$(OBJEXT) \
@@ -218,28 +257,41 @@ am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
@WITH_PAR2_TRUE@ reedsolomon.$(OBJEXT) \
@WITH_PAR2_TRUE@ verificationhashtable.$(OBJEXT) \
@WITH_PAR2_TRUE@ verificationpacket.$(OBJEXT)
@WITH_TESTS_TRUE@am__objects_2 = TestMain.$(OBJEXT) TestUtil.$(OBJEXT) \
@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@ NZBFileTest.$(OBJEXT) UtilTest.$(OBJEXT)
am_nzbget_OBJECTS = Connection.$(OBJEXT) TLS.$(OBJEXT) \
WebDownloader.$(OBJEXT) FeedCoordinator.$(OBJEXT) \
WebDownloader.$(OBJEXT) FeedScript.$(OBJEXT) \
NzbScript.$(OBJEXT) PostScript.$(OBJEXT) QueueScript.$(OBJEXT) \
ScanScript.$(OBJEXT) SchedulerScript.$(OBJEXT) \
ScriptConfig.$(OBJEXT) FeedCoordinator.$(OBJEXT) \
FeedFile.$(OBJEXT) FeedFilter.$(OBJEXT) FeedInfo.$(OBJEXT) \
ColoredFrontend.$(OBJEXT) Frontend.$(OBJEXT) \
LoggableFrontend.$(OBJEXT) NCursesFrontend.$(OBJEXT) \
CommandLineParser.$(OBJEXT) DiskService.$(OBJEXT) \
Maintenance.$(OBJEXT) nzbget.$(OBJEXT) Options.$(OBJEXT) \
Scheduler.$(OBJEXT) StackTrace.$(OBJEXT) \
ArticleDownloader.$(OBJEXT) ArticleWriter.$(OBJEXT) \
Decoder.$(OBJEXT) NewsServer.$(OBJEXT) \
NNTPConnection.$(OBJEXT) ServerPool.$(OBJEXT) \
StatMeter.$(OBJEXT) ParChecker.$(OBJEXT) \
ParCoordinator.$(OBJEXT) ParRenamer.$(OBJEXT) \
PostScript.$(OBJEXT) PrePostProcessor.$(OBJEXT) \
Unpack.$(OBJEXT) DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
StatMeter.$(OBJEXT) Cleanup.$(OBJEXT) DupeMatcher.$(OBJEXT) \
ParChecker.$(OBJEXT) ParCoordinator.$(OBJEXT) \
ParParser.$(OBJEXT) ParRenamer.$(OBJEXT) \
PrePostProcessor.$(OBJEXT) Unpack.$(OBJEXT) \
DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
DupeCoordinator.$(OBJEXT) HistoryCoordinator.$(OBJEXT) \
NZBFile.$(OBJEXT) QueueCoordinator.$(OBJEXT) \
QueueEditor.$(OBJEXT) QueueScript.$(OBJEXT) Scanner.$(OBJEXT) \
QueueEditor.$(OBJEXT) Scanner.$(OBJEXT) \
UrlCoordinator.$(OBJEXT) BinRpc.$(OBJEXT) \
RemoteClient.$(OBJEXT) RemoteServer.$(OBJEXT) \
WebServer.$(OBJEXT) XmlRpc.$(OBJEXT) Log.$(OBJEXT) \
Observer.$(OBJEXT) Script.$(OBJEXT) Thread.$(OBJEXT) \
Util.$(OBJEXT) svn_version.$(OBJEXT) $(am__objects_1)
Service.$(OBJEXT) Util.$(OBJEXT) code_revision.$(OBJEXT) \
$(am__objects_1) $(am__objects_2)
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
nzbget_LDADD = $(LDADD)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@@ -251,7 +303,7 @@ am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
nobase_dist_scriptsSCRIPT_INSTALL = $(install_sh_SCRIPT)
SCRIPTS = $(nobase_dist_scripts_SCRIPTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp = $(SHELL) $(top_srcdir)/depcomp
depcomp = $(SHELL) $(top_srcdir)/posix/depcomp
am__depfiles_maybe = depfiles
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
@@ -329,6 +381,8 @@ TAR = @TAR@
VERSION = @VERSION@
WITH_PAR2_FALSE = @WITH_PAR2_FALSE@
WITH_PAR2_TRUE = @WITH_PAR2_TRUE@
WITH_TESTS_FALSE = @WITH_TESTS_FALSE@
WITH_TESTS_TRUE = @WITH_TESTS_TRUE@
ac_ct_CXX = @ac_ct_CXX@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
@@ -338,21 +392,13 @@ am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
@@ -375,25 +421,34 @@ psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/connect/Connection.h daemon/connect/TLS.cpp \
daemon/connect/TLS.h daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h daemon/frontend/ColoredFrontend.cpp \
daemon/connect/WebDownloader.h daemon/extension/FeedScript.cpp \
daemon/extension/FeedScript.h daemon/extension/NzbScript.cpp \
daemon/extension/NzbScript.h daemon/extension/PostScript.cpp \
daemon/extension/PostScript.h daemon/extension/QueueScript.cpp \
daemon/extension/QueueScript.h daemon/extension/ScanScript.cpp \
daemon/extension/ScanScript.h \
daemon/extension/SchedulerScript.cpp \
daemon/extension/SchedulerScript.h \
daemon/extension/ScriptConfig.cpp \
daemon/extension/ScriptConfig.h \
daemon/feed/FeedCoordinator.cpp daemon/feed/FeedCoordinator.h \
daemon/feed/FeedFile.cpp daemon/feed/FeedFile.h \
daemon/feed/FeedFilter.cpp daemon/feed/FeedFilter.h \
daemon/feed/FeedInfo.cpp daemon/feed/FeedInfo.h \
daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h daemon/frontend/Frontend.cpp \
daemon/frontend/Frontend.h \
daemon/frontend/LoggableFrontend.cpp \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h daemon/main/Maintenance.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/CommandLineParser.cpp \
daemon/main/CommandLineParser.h daemon/main/DiskService.cpp \
daemon/main/DiskService.h daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h daemon/main/nzbget.cpp \
daemon/main/nzbget.h daemon/main/Options.cpp \
daemon/main/Options.h daemon/main/Scheduler.cpp \
@@ -405,14 +460,18 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/nntp/NewsServer.h daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/ParChecker.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/Cleanup.cpp \
daemon/postprocess/Cleanup.h \
daemon/postprocess/DupeMatcher.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/PostScript.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
@@ -424,8 +483,7 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/queue/HistoryCoordinator.h daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h daemon/queue/Scanner.cpp \
daemon/queue/QueueEditor.h daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h daemon/remote/MessageBase.h \
@@ -436,25 +494,20 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/util/Log.cpp daemon/util/Log.h daemon/util/Observer.cpp \
daemon/util/Observer.h daemon/util/Script.cpp \
daemon/util/Script.h daemon/util/Thread.cpp \
daemon/util/Thread.h daemon/util/Util.cpp daemon/util/Util.h \
svn_version.cpp $(am__append_1)
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-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
daemon/util/Thread.h daemon/util/Service.cpp \
daemon/util/Service.h daemon/util/Util.cpp daemon/util/Util.h \
code_revision.cpp $(am__append_1) $(am__append_2)
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)
EXTRA_DIST = \
Makefile.cvs \
$(windows_FILES) \
$(osx_FILES) \
$(linux_FILES)
$(linux_FILES) \
$(testdata_FILES)
windows_FILES = \
daemon/windows/NTService.cpp \
@@ -462,7 +515,6 @@ windows_FILES = \
daemon/windows/win32.h \
daemon/windows/WinConsole.cpp \
daemon/windows/WinConsole.h \
nzbget.sln \
nzbget.vcproj \
windows/nzbget-command-shell.bat \
windows/install-update.bat \
@@ -520,7 +572,6 @@ linux_FILES = \
doc_FILES = \
lib/par2/AUTHORS \
lib/par2/README \
AUTHORS \
README \
ChangeLog \
COPYING
@@ -564,6 +615,23 @@ scripts_FILES = \
scripts/EMail.py \
scripts/Logger.py
testdata_FILES = \
tests/testdata/dupematcher1/testfile.part01.rar \
tests/testdata/dupematcher1/testfile.part24.rar \
tests/testdata/dupematcher2/testfile.part04.rar \
tests/testdata/dupematcher2/testfile.part43.rar \
tests/testdata/nzbfile/dotless.nzb \
tests/testdata/nzbfile/dotless.txt \
tests/testdata/nzbfile/plain.nzb \
tests/testdata/nzbfile/plain.txt \
tests/testdata/parchecker/crc.txt \
tests/testdata/parchecker/testfile.dat \
tests/testdata/parchecker/testfile.nfo \
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
# Install
dist_doc_DATA = $(doc_FILES)
@@ -574,7 +642,7 @@ nobase_dist_webui_DATA = $(webui_FILES)
scriptsdir = $(datadir)/nzbget
nobase_dist_scripts_SCRIPTS = $(scripts_FILES)
# Ignore "svn_version.cpp" in distcleancheck
# Ignore "code_revision.cpp" in distcleancheck
distcleancheck_listfiles = \
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
sh '{}' ';'
@@ -590,15 +658,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
cd $(srcdir) && $(AUTOMAKE) --gnu \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
cd $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
$(AUTOMAKE) --foreign Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -695,16 +763,23 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArticleDownloader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArticleWriter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BinRpc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cleanup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColoredFrontend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CommandLineParser.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CommandLineParserTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Connection.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Decoder.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DiskService.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DiskState.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadInfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DupeCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DupeMatcher.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedFile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedFilter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedFilterTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedInfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedScript.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Frontend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HistoryCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Log.Po@am__quote@
@@ -713,12 +788,18 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NCursesFrontend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NNTPConnection.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)/NewsServer.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@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PostScript.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PrePostProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueCoordinator.Po@am__quote@
@@ -726,20 +807,28 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueScript.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)/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@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SchedulerScript.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Script.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ScriptConfig.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Service.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StackTrace.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StatMeter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TLS.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestMain.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestUtil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Unpack.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UrlCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
@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)/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@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/creatorpacket.Po@am__quote@
@@ -759,7 +848,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parheaders.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recoverypacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reedsolomon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svn_version.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verificationhashtable.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verificationpacket.Po@am__quote@
@@ -819,6 +907,104 @@ WebDownloader.obj: daemon/connect/WebDownloader.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 WebDownloader.obj `if test -f 'daemon/connect/WebDownloader.cpp'; then $(CYGPATH_W) 'daemon/connect/WebDownloader.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/connect/WebDownloader.cpp'; fi`
FeedScript.o: daemon/extension/FeedScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FeedScript.o -MD -MP -MF "$(DEPDIR)/FeedScript.Tpo" -c -o FeedScript.o `test -f 'daemon/extension/FeedScript.cpp' || echo '$(srcdir)/'`daemon/extension/FeedScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/FeedScript.Tpo" "$(DEPDIR)/FeedScript.Po"; else rm -f "$(DEPDIR)/FeedScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/FeedScript.cpp' object='FeedScript.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 FeedScript.o `test -f 'daemon/extension/FeedScript.cpp' || echo '$(srcdir)/'`daemon/extension/FeedScript.cpp
FeedScript.obj: daemon/extension/FeedScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FeedScript.obj -MD -MP -MF "$(DEPDIR)/FeedScript.Tpo" -c -o FeedScript.obj `if test -f 'daemon/extension/FeedScript.cpp'; then $(CYGPATH_W) 'daemon/extension/FeedScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/FeedScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/FeedScript.Tpo" "$(DEPDIR)/FeedScript.Po"; else rm -f "$(DEPDIR)/FeedScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/FeedScript.cpp' object='FeedScript.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 FeedScript.obj `if test -f 'daemon/extension/FeedScript.cpp'; then $(CYGPATH_W) 'daemon/extension/FeedScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/FeedScript.cpp'; fi`
NzbScript.o: daemon/extension/NzbScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NzbScript.o -MD -MP -MF "$(DEPDIR)/NzbScript.Tpo" -c -o NzbScript.o `test -f 'daemon/extension/NzbScript.cpp' || echo '$(srcdir)/'`daemon/extension/NzbScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NzbScript.Tpo" "$(DEPDIR)/NzbScript.Po"; else rm -f "$(DEPDIR)/NzbScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/NzbScript.cpp' object='NzbScript.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 NzbScript.o `test -f 'daemon/extension/NzbScript.cpp' || echo '$(srcdir)/'`daemon/extension/NzbScript.cpp
NzbScript.obj: daemon/extension/NzbScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NzbScript.obj -MD -MP -MF "$(DEPDIR)/NzbScript.Tpo" -c -o NzbScript.obj `if test -f 'daemon/extension/NzbScript.cpp'; then $(CYGPATH_W) 'daemon/extension/NzbScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/NzbScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NzbScript.Tpo" "$(DEPDIR)/NzbScript.Po"; else rm -f "$(DEPDIR)/NzbScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/NzbScript.cpp' object='NzbScript.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 NzbScript.obj `if test -f 'daemon/extension/NzbScript.cpp'; then $(CYGPATH_W) 'daemon/extension/NzbScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/NzbScript.cpp'; fi`
PostScript.o: daemon/extension/PostScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT PostScript.o -MD -MP -MF "$(DEPDIR)/PostScript.Tpo" -c -o PostScript.o `test -f 'daemon/extension/PostScript.cpp' || echo '$(srcdir)/'`daemon/extension/PostScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/PostScript.Tpo" "$(DEPDIR)/PostScript.Po"; else rm -f "$(DEPDIR)/PostScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/PostScript.cpp' object='PostScript.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 PostScript.o `test -f 'daemon/extension/PostScript.cpp' || echo '$(srcdir)/'`daemon/extension/PostScript.cpp
PostScript.obj: daemon/extension/PostScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT PostScript.obj -MD -MP -MF "$(DEPDIR)/PostScript.Tpo" -c -o PostScript.obj `if test -f 'daemon/extension/PostScript.cpp'; then $(CYGPATH_W) 'daemon/extension/PostScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/PostScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/PostScript.Tpo" "$(DEPDIR)/PostScript.Po"; else rm -f "$(DEPDIR)/PostScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/PostScript.cpp' object='PostScript.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 PostScript.obj `if test -f 'daemon/extension/PostScript.cpp'; then $(CYGPATH_W) 'daemon/extension/PostScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/PostScript.cpp'; fi`
QueueScript.o: daemon/extension/QueueScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT QueueScript.o -MD -MP -MF "$(DEPDIR)/QueueScript.Tpo" -c -o QueueScript.o `test -f 'daemon/extension/QueueScript.cpp' || echo '$(srcdir)/'`daemon/extension/QueueScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/QueueScript.Tpo" "$(DEPDIR)/QueueScript.Po"; else rm -f "$(DEPDIR)/QueueScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/QueueScript.cpp' object='QueueScript.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 QueueScript.o `test -f 'daemon/extension/QueueScript.cpp' || echo '$(srcdir)/'`daemon/extension/QueueScript.cpp
QueueScript.obj: daemon/extension/QueueScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT QueueScript.obj -MD -MP -MF "$(DEPDIR)/QueueScript.Tpo" -c -o QueueScript.obj `if test -f 'daemon/extension/QueueScript.cpp'; then $(CYGPATH_W) 'daemon/extension/QueueScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/QueueScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/QueueScript.Tpo" "$(DEPDIR)/QueueScript.Po"; else rm -f "$(DEPDIR)/QueueScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/QueueScript.cpp' object='QueueScript.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 QueueScript.obj `if test -f 'daemon/extension/QueueScript.cpp'; then $(CYGPATH_W) 'daemon/extension/QueueScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/QueueScript.cpp'; fi`
ScanScript.o: daemon/extension/ScanScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ScanScript.o -MD -MP -MF "$(DEPDIR)/ScanScript.Tpo" -c -o ScanScript.o `test -f 'daemon/extension/ScanScript.cpp' || echo '$(srcdir)/'`daemon/extension/ScanScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ScanScript.Tpo" "$(DEPDIR)/ScanScript.Po"; else rm -f "$(DEPDIR)/ScanScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/ScanScript.cpp' object='ScanScript.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 ScanScript.o `test -f 'daemon/extension/ScanScript.cpp' || echo '$(srcdir)/'`daemon/extension/ScanScript.cpp
ScanScript.obj: daemon/extension/ScanScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ScanScript.obj -MD -MP -MF "$(DEPDIR)/ScanScript.Tpo" -c -o ScanScript.obj `if test -f 'daemon/extension/ScanScript.cpp'; then $(CYGPATH_W) 'daemon/extension/ScanScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/ScanScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ScanScript.Tpo" "$(DEPDIR)/ScanScript.Po"; else rm -f "$(DEPDIR)/ScanScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/ScanScript.cpp' object='ScanScript.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 ScanScript.obj `if test -f 'daemon/extension/ScanScript.cpp'; then $(CYGPATH_W) 'daemon/extension/ScanScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/ScanScript.cpp'; fi`
SchedulerScript.o: daemon/extension/SchedulerScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SchedulerScript.o -MD -MP -MF "$(DEPDIR)/SchedulerScript.Tpo" -c -o SchedulerScript.o `test -f 'daemon/extension/SchedulerScript.cpp' || echo '$(srcdir)/'`daemon/extension/SchedulerScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/SchedulerScript.Tpo" "$(DEPDIR)/SchedulerScript.Po"; else rm -f "$(DEPDIR)/SchedulerScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/SchedulerScript.cpp' object='SchedulerScript.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 SchedulerScript.o `test -f 'daemon/extension/SchedulerScript.cpp' || echo '$(srcdir)/'`daemon/extension/SchedulerScript.cpp
SchedulerScript.obj: daemon/extension/SchedulerScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SchedulerScript.obj -MD -MP -MF "$(DEPDIR)/SchedulerScript.Tpo" -c -o SchedulerScript.obj `if test -f 'daemon/extension/SchedulerScript.cpp'; then $(CYGPATH_W) 'daemon/extension/SchedulerScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/SchedulerScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/SchedulerScript.Tpo" "$(DEPDIR)/SchedulerScript.Po"; else rm -f "$(DEPDIR)/SchedulerScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/SchedulerScript.cpp' object='SchedulerScript.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 SchedulerScript.obj `if test -f 'daemon/extension/SchedulerScript.cpp'; then $(CYGPATH_W) 'daemon/extension/SchedulerScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/SchedulerScript.cpp'; fi`
ScriptConfig.o: daemon/extension/ScriptConfig.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ScriptConfig.o -MD -MP -MF "$(DEPDIR)/ScriptConfig.Tpo" -c -o ScriptConfig.o `test -f 'daemon/extension/ScriptConfig.cpp' || echo '$(srcdir)/'`daemon/extension/ScriptConfig.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ScriptConfig.Tpo" "$(DEPDIR)/ScriptConfig.Po"; else rm -f "$(DEPDIR)/ScriptConfig.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/ScriptConfig.cpp' object='ScriptConfig.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 ScriptConfig.o `test -f 'daemon/extension/ScriptConfig.cpp' || echo '$(srcdir)/'`daemon/extension/ScriptConfig.cpp
ScriptConfig.obj: daemon/extension/ScriptConfig.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ScriptConfig.obj -MD -MP -MF "$(DEPDIR)/ScriptConfig.Tpo" -c -o ScriptConfig.obj `if test -f 'daemon/extension/ScriptConfig.cpp'; then $(CYGPATH_W) 'daemon/extension/ScriptConfig.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/ScriptConfig.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ScriptConfig.Tpo" "$(DEPDIR)/ScriptConfig.Po"; else rm -f "$(DEPDIR)/ScriptConfig.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/extension/ScriptConfig.cpp' object='ScriptConfig.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 ScriptConfig.obj `if test -f 'daemon/extension/ScriptConfig.cpp'; then $(CYGPATH_W) 'daemon/extension/ScriptConfig.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/extension/ScriptConfig.cpp'; fi`
FeedCoordinator.o: daemon/feed/FeedCoordinator.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FeedCoordinator.o -MD -MP -MF "$(DEPDIR)/FeedCoordinator.Tpo" -c -o FeedCoordinator.o `test -f 'daemon/feed/FeedCoordinator.cpp' || echo '$(srcdir)/'`daemon/feed/FeedCoordinator.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/FeedCoordinator.Tpo" "$(DEPDIR)/FeedCoordinator.Po"; else rm -f "$(DEPDIR)/FeedCoordinator.Tpo"; exit 1; fi
@@ -931,6 +1117,34 @@ NCursesFrontend.obj: daemon/frontend/NCursesFrontend.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 NCursesFrontend.obj `if test -f 'daemon/frontend/NCursesFrontend.cpp'; then $(CYGPATH_W) 'daemon/frontend/NCursesFrontend.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/frontend/NCursesFrontend.cpp'; fi`
CommandLineParser.o: daemon/main/CommandLineParser.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CommandLineParser.o -MD -MP -MF "$(DEPDIR)/CommandLineParser.Tpo" -c -o CommandLineParser.o `test -f 'daemon/main/CommandLineParser.cpp' || echo '$(srcdir)/'`daemon/main/CommandLineParser.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CommandLineParser.Tpo" "$(DEPDIR)/CommandLineParser.Po"; else rm -f "$(DEPDIR)/CommandLineParser.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/CommandLineParser.cpp' object='CommandLineParser.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 CommandLineParser.o `test -f 'daemon/main/CommandLineParser.cpp' || echo '$(srcdir)/'`daemon/main/CommandLineParser.cpp
CommandLineParser.obj: daemon/main/CommandLineParser.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CommandLineParser.obj -MD -MP -MF "$(DEPDIR)/CommandLineParser.Tpo" -c -o CommandLineParser.obj `if test -f 'daemon/main/CommandLineParser.cpp'; then $(CYGPATH_W) 'daemon/main/CommandLineParser.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/CommandLineParser.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CommandLineParser.Tpo" "$(DEPDIR)/CommandLineParser.Po"; else rm -f "$(DEPDIR)/CommandLineParser.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/CommandLineParser.cpp' object='CommandLineParser.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 CommandLineParser.obj `if test -f 'daemon/main/CommandLineParser.cpp'; then $(CYGPATH_W) 'daemon/main/CommandLineParser.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/CommandLineParser.cpp'; fi`
DiskService.o: daemon/main/DiskService.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DiskService.o -MD -MP -MF "$(DEPDIR)/DiskService.Tpo" -c -o DiskService.o `test -f 'daemon/main/DiskService.cpp' || echo '$(srcdir)/'`daemon/main/DiskService.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DiskService.Tpo" "$(DEPDIR)/DiskService.Po"; else rm -f "$(DEPDIR)/DiskService.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/DiskService.cpp' object='DiskService.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 DiskService.o `test -f 'daemon/main/DiskService.cpp' || echo '$(srcdir)/'`daemon/main/DiskService.cpp
DiskService.obj: daemon/main/DiskService.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DiskService.obj -MD -MP -MF "$(DEPDIR)/DiskService.Tpo" -c -o DiskService.obj `if test -f 'daemon/main/DiskService.cpp'; then $(CYGPATH_W) 'daemon/main/DiskService.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/DiskService.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DiskService.Tpo" "$(DEPDIR)/DiskService.Po"; else rm -f "$(DEPDIR)/DiskService.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/DiskService.cpp' object='DiskService.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 DiskService.obj `if test -f 'daemon/main/DiskService.cpp'; then $(CYGPATH_W) 'daemon/main/DiskService.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/DiskService.cpp'; fi`
Maintenance.o: daemon/main/Maintenance.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Maintenance.o -MD -MP -MF "$(DEPDIR)/Maintenance.Tpo" -c -o Maintenance.o `test -f 'daemon/main/Maintenance.cpp' || echo '$(srcdir)/'`daemon/main/Maintenance.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Maintenance.Tpo" "$(DEPDIR)/Maintenance.Po"; else rm -f "$(DEPDIR)/Maintenance.Tpo"; exit 1; fi
@@ -1099,6 +1313,34 @@ StatMeter.obj: daemon/nntp/StatMeter.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 StatMeter.obj `if test -f 'daemon/nntp/StatMeter.cpp'; then $(CYGPATH_W) 'daemon/nntp/StatMeter.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nntp/StatMeter.cpp'; fi`
Cleanup.o: daemon/postprocess/Cleanup.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Cleanup.o -MD -MP -MF "$(DEPDIR)/Cleanup.Tpo" -c -o Cleanup.o `test -f 'daemon/postprocess/Cleanup.cpp' || echo '$(srcdir)/'`daemon/postprocess/Cleanup.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Cleanup.Tpo" "$(DEPDIR)/Cleanup.Po"; else rm -f "$(DEPDIR)/Cleanup.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Cleanup.cpp' object='Cleanup.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 Cleanup.o `test -f 'daemon/postprocess/Cleanup.cpp' || echo '$(srcdir)/'`daemon/postprocess/Cleanup.cpp
Cleanup.obj: daemon/postprocess/Cleanup.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Cleanup.obj -MD -MP -MF "$(DEPDIR)/Cleanup.Tpo" -c -o Cleanup.obj `if test -f 'daemon/postprocess/Cleanup.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Cleanup.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Cleanup.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Cleanup.Tpo" "$(DEPDIR)/Cleanup.Po"; else rm -f "$(DEPDIR)/Cleanup.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/Cleanup.cpp' object='Cleanup.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 Cleanup.obj `if test -f 'daemon/postprocess/Cleanup.cpp'; then $(CYGPATH_W) 'daemon/postprocess/Cleanup.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/Cleanup.cpp'; fi`
DupeMatcher.o: daemon/postprocess/DupeMatcher.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DupeMatcher.o -MD -MP -MF "$(DEPDIR)/DupeMatcher.Tpo" -c -o DupeMatcher.o `test -f 'daemon/postprocess/DupeMatcher.cpp' || echo '$(srcdir)/'`daemon/postprocess/DupeMatcher.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DupeMatcher.Tpo" "$(DEPDIR)/DupeMatcher.Po"; else rm -f "$(DEPDIR)/DupeMatcher.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/DupeMatcher.cpp' object='DupeMatcher.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 DupeMatcher.o `test -f 'daemon/postprocess/DupeMatcher.cpp' || echo '$(srcdir)/'`daemon/postprocess/DupeMatcher.cpp
DupeMatcher.obj: daemon/postprocess/DupeMatcher.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DupeMatcher.obj -MD -MP -MF "$(DEPDIR)/DupeMatcher.Tpo" -c -o DupeMatcher.obj `if test -f 'daemon/postprocess/DupeMatcher.cpp'; then $(CYGPATH_W) 'daemon/postprocess/DupeMatcher.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/DupeMatcher.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DupeMatcher.Tpo" "$(DEPDIR)/DupeMatcher.Po"; else rm -f "$(DEPDIR)/DupeMatcher.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/DupeMatcher.cpp' object='DupeMatcher.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 DupeMatcher.obj `if test -f 'daemon/postprocess/DupeMatcher.cpp'; then $(CYGPATH_W) 'daemon/postprocess/DupeMatcher.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/DupeMatcher.cpp'; fi`
ParChecker.o: daemon/postprocess/ParChecker.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParChecker.o -MD -MP -MF "$(DEPDIR)/ParChecker.Tpo" -c -o ParChecker.o `test -f 'daemon/postprocess/ParChecker.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParChecker.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParChecker.Tpo" "$(DEPDIR)/ParChecker.Po"; else rm -f "$(DEPDIR)/ParChecker.Tpo"; exit 1; fi
@@ -1127,6 +1369,20 @@ ParCoordinator.obj: daemon/postprocess/ParCoordinator.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 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
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/ParParser.cpp' object='ParParser.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 ParParser.o `test -f 'daemon/postprocess/ParParser.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParParser.cpp
ParParser.obj: daemon/postprocess/ParParser.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParParser.obj -MD -MP -MF "$(DEPDIR)/ParParser.Tpo" -c -o ParParser.obj `if test -f 'daemon/postprocess/ParParser.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParParser.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParParser.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParParser.Tpo" "$(DEPDIR)/ParParser.Po"; else rm -f "$(DEPDIR)/ParParser.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/ParParser.cpp' object='ParParser.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 ParParser.obj `if test -f 'daemon/postprocess/ParParser.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParParser.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParParser.cpp'; fi`
ParRenamer.o: daemon/postprocess/ParRenamer.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ParRenamer.o -MD -MP -MF "$(DEPDIR)/ParRenamer.Tpo" -c -o ParRenamer.o `test -f 'daemon/postprocess/ParRenamer.cpp' || echo '$(srcdir)/'`daemon/postprocess/ParRenamer.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ParRenamer.Tpo" "$(DEPDIR)/ParRenamer.Po"; else rm -f "$(DEPDIR)/ParRenamer.Tpo"; exit 1; fi
@@ -1141,20 +1397,6 @@ ParRenamer.obj: daemon/postprocess/ParRenamer.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 ParRenamer.obj `if test -f 'daemon/postprocess/ParRenamer.cpp'; then $(CYGPATH_W) 'daemon/postprocess/ParRenamer.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/ParRenamer.cpp'; fi`
PostScript.o: daemon/postprocess/PostScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT PostScript.o -MD -MP -MF "$(DEPDIR)/PostScript.Tpo" -c -o PostScript.o `test -f 'daemon/postprocess/PostScript.cpp' || echo '$(srcdir)/'`daemon/postprocess/PostScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/PostScript.Tpo" "$(DEPDIR)/PostScript.Po"; else rm -f "$(DEPDIR)/PostScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/PostScript.cpp' object='PostScript.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 PostScript.o `test -f 'daemon/postprocess/PostScript.cpp' || echo '$(srcdir)/'`daemon/postprocess/PostScript.cpp
PostScript.obj: daemon/postprocess/PostScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT PostScript.obj -MD -MP -MF "$(DEPDIR)/PostScript.Tpo" -c -o PostScript.obj `if test -f 'daemon/postprocess/PostScript.cpp'; then $(CYGPATH_W) 'daemon/postprocess/PostScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/PostScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/PostScript.Tpo" "$(DEPDIR)/PostScript.Po"; else rm -f "$(DEPDIR)/PostScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/postprocess/PostScript.cpp' object='PostScript.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 PostScript.obj `if test -f 'daemon/postprocess/PostScript.cpp'; then $(CYGPATH_W) 'daemon/postprocess/PostScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/postprocess/PostScript.cpp'; fi`
PrePostProcessor.o: daemon/postprocess/PrePostProcessor.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT PrePostProcessor.o -MD -MP -MF "$(DEPDIR)/PrePostProcessor.Tpo" -c -o PrePostProcessor.o `test -f 'daemon/postprocess/PrePostProcessor.cpp' || echo '$(srcdir)/'`daemon/postprocess/PrePostProcessor.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/PrePostProcessor.Tpo" "$(DEPDIR)/PrePostProcessor.Po"; else rm -f "$(DEPDIR)/PrePostProcessor.Tpo"; exit 1; fi
@@ -1281,20 +1523,6 @@ QueueEditor.obj: daemon/queue/QueueEditor.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 QueueEditor.obj `if test -f 'daemon/queue/QueueEditor.cpp'; then $(CYGPATH_W) 'daemon/queue/QueueEditor.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/queue/QueueEditor.cpp'; fi`
QueueScript.o: daemon/queue/QueueScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT QueueScript.o -MD -MP -MF "$(DEPDIR)/QueueScript.Tpo" -c -o QueueScript.o `test -f 'daemon/queue/QueueScript.cpp' || echo '$(srcdir)/'`daemon/queue/QueueScript.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/QueueScript.Tpo" "$(DEPDIR)/QueueScript.Po"; else rm -f "$(DEPDIR)/QueueScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/queue/QueueScript.cpp' object='QueueScript.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 QueueScript.o `test -f 'daemon/queue/QueueScript.cpp' || echo '$(srcdir)/'`daemon/queue/QueueScript.cpp
QueueScript.obj: daemon/queue/QueueScript.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT QueueScript.obj -MD -MP -MF "$(DEPDIR)/QueueScript.Tpo" -c -o QueueScript.obj `if test -f 'daemon/queue/QueueScript.cpp'; then $(CYGPATH_W) 'daemon/queue/QueueScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/queue/QueueScript.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/QueueScript.Tpo" "$(DEPDIR)/QueueScript.Po"; else rm -f "$(DEPDIR)/QueueScript.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/queue/QueueScript.cpp' object='QueueScript.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 QueueScript.obj `if test -f 'daemon/queue/QueueScript.cpp'; then $(CYGPATH_W) 'daemon/queue/QueueScript.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/queue/QueueScript.cpp'; fi`
Scanner.o: daemon/queue/Scanner.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Scanner.o -MD -MP -MF "$(DEPDIR)/Scanner.Tpo" -c -o Scanner.o `test -f 'daemon/queue/Scanner.cpp' || echo '$(srcdir)/'`daemon/queue/Scanner.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Scanner.Tpo" "$(DEPDIR)/Scanner.Po"; else rm -f "$(DEPDIR)/Scanner.Tpo"; exit 1; fi
@@ -1449,6 +1677,20 @@ Thread.obj: daemon/util/Thread.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 Thread.obj `if test -f 'daemon/util/Thread.cpp'; then $(CYGPATH_W) 'daemon/util/Thread.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/util/Thread.cpp'; fi`
Service.o: daemon/util/Service.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Service.o -MD -MP -MF "$(DEPDIR)/Service.Tpo" -c -o Service.o `test -f 'daemon/util/Service.cpp' || echo '$(srcdir)/'`daemon/util/Service.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Service.Tpo" "$(DEPDIR)/Service.Po"; else rm -f "$(DEPDIR)/Service.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/util/Service.cpp' object='Service.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 Service.o `test -f 'daemon/util/Service.cpp' || echo '$(srcdir)/'`daemon/util/Service.cpp
Service.obj: daemon/util/Service.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Service.obj -MD -MP -MF "$(DEPDIR)/Service.Tpo" -c -o Service.obj `if test -f 'daemon/util/Service.cpp'; then $(CYGPATH_W) 'daemon/util/Service.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/util/Service.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Service.Tpo" "$(DEPDIR)/Service.Po"; else rm -f "$(DEPDIR)/Service.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/util/Service.cpp' object='Service.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 Service.obj `if test -f 'daemon/util/Service.cpp'; then $(CYGPATH_W) 'daemon/util/Service.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/util/Service.cpp'; fi`
Util.o: daemon/util/Util.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Util.o -MD -MP -MF "$(DEPDIR)/Util.Tpo" -c -o Util.o `test -f 'daemon/util/Util.cpp' || echo '$(srcdir)/'`daemon/util/Util.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Util.Tpo" "$(DEPDIR)/Util.Po"; else rm -f "$(DEPDIR)/Util.Tpo"; exit 1; fi
@@ -1742,6 +1984,132 @@ verificationpacket.obj: lib/par2/verificationpacket.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/verificationpacket.cpp' object='verificationpacket.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 verificationpacket.obj `if test -f 'lib/par2/verificationpacket.cpp'; then $(CYGPATH_W) 'lib/par2/verificationpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/verificationpacket.cpp'; fi`
TestMain.o: tests/suite/TestMain.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestMain.o -MD -MP -MF "$(DEPDIR)/TestMain.Tpo" -c -o TestMain.o `test -f 'tests/suite/TestMain.cpp' || echo '$(srcdir)/'`tests/suite/TestMain.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/TestMain.Tpo" "$(DEPDIR)/TestMain.Po"; else rm -f "$(DEPDIR)/TestMain.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/suite/TestMain.cpp' object='TestMain.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 TestMain.o `test -f 'tests/suite/TestMain.cpp' || echo '$(srcdir)/'`tests/suite/TestMain.cpp
TestMain.obj: tests/suite/TestMain.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestMain.obj -MD -MP -MF "$(DEPDIR)/TestMain.Tpo" -c -o TestMain.obj `if test -f 'tests/suite/TestMain.cpp'; then $(CYGPATH_W) 'tests/suite/TestMain.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/suite/TestMain.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/TestMain.Tpo" "$(DEPDIR)/TestMain.Po"; else rm -f "$(DEPDIR)/TestMain.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/suite/TestMain.cpp' object='TestMain.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 TestMain.obj `if test -f 'tests/suite/TestMain.cpp'; then $(CYGPATH_W) 'tests/suite/TestMain.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/suite/TestMain.cpp'; fi`
TestUtil.o: tests/suite/TestUtil.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestUtil.o -MD -MP -MF "$(DEPDIR)/TestUtil.Tpo" -c -o TestUtil.o `test -f 'tests/suite/TestUtil.cpp' || echo '$(srcdir)/'`tests/suite/TestUtil.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/TestUtil.Tpo" "$(DEPDIR)/TestUtil.Po"; else rm -f "$(DEPDIR)/TestUtil.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/suite/TestUtil.cpp' object='TestUtil.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 TestUtil.o `test -f 'tests/suite/TestUtil.cpp' || echo '$(srcdir)/'`tests/suite/TestUtil.cpp
TestUtil.obj: tests/suite/TestUtil.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT TestUtil.obj -MD -MP -MF "$(DEPDIR)/TestUtil.Tpo" -c -o TestUtil.obj `if test -f 'tests/suite/TestUtil.cpp'; then $(CYGPATH_W) 'tests/suite/TestUtil.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/suite/TestUtil.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/TestUtil.Tpo" "$(DEPDIR)/TestUtil.Po"; else rm -f "$(DEPDIR)/TestUtil.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/suite/TestUtil.cpp' object='TestUtil.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 TestUtil.obj `if test -f 'tests/suite/TestUtil.cpp'; then $(CYGPATH_W) 'tests/suite/TestUtil.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/suite/TestUtil.cpp'; fi`
CommandLineParserTest.o: tests/main/CommandLineParserTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CommandLineParserTest.o -MD -MP -MF "$(DEPDIR)/CommandLineParserTest.Tpo" -c -o CommandLineParserTest.o `test -f 'tests/main/CommandLineParserTest.cpp' || echo '$(srcdir)/'`tests/main/CommandLineParserTest.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CommandLineParserTest.Tpo" "$(DEPDIR)/CommandLineParserTest.Po"; else rm -f "$(DEPDIR)/CommandLineParserTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/main/CommandLineParserTest.cpp' object='CommandLineParserTest.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 CommandLineParserTest.o `test -f 'tests/main/CommandLineParserTest.cpp' || echo '$(srcdir)/'`tests/main/CommandLineParserTest.cpp
CommandLineParserTest.obj: tests/main/CommandLineParserTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CommandLineParserTest.obj -MD -MP -MF "$(DEPDIR)/CommandLineParserTest.Tpo" -c -o CommandLineParserTest.obj `if test -f 'tests/main/CommandLineParserTest.cpp'; then $(CYGPATH_W) 'tests/main/CommandLineParserTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/main/CommandLineParserTest.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CommandLineParserTest.Tpo" "$(DEPDIR)/CommandLineParserTest.Po"; else rm -f "$(DEPDIR)/CommandLineParserTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/main/CommandLineParserTest.cpp' object='CommandLineParserTest.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 CommandLineParserTest.obj `if test -f 'tests/main/CommandLineParserTest.cpp'; then $(CYGPATH_W) 'tests/main/CommandLineParserTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/main/CommandLineParserTest.cpp'; fi`
OptionsTest.o: tests/main/OptionsTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT OptionsTest.o -MD -MP -MF "$(DEPDIR)/OptionsTest.Tpo" -c -o OptionsTest.o `test -f 'tests/main/OptionsTest.cpp' || echo '$(srcdir)/'`tests/main/OptionsTest.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/OptionsTest.Tpo" "$(DEPDIR)/OptionsTest.Po"; else rm -f "$(DEPDIR)/OptionsTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/main/OptionsTest.cpp' object='OptionsTest.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 OptionsTest.o `test -f 'tests/main/OptionsTest.cpp' || echo '$(srcdir)/'`tests/main/OptionsTest.cpp
OptionsTest.obj: tests/main/OptionsTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT OptionsTest.obj -MD -MP -MF "$(DEPDIR)/OptionsTest.Tpo" -c -o OptionsTest.obj `if test -f 'tests/main/OptionsTest.cpp'; then $(CYGPATH_W) 'tests/main/OptionsTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/main/OptionsTest.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/OptionsTest.Tpo" "$(DEPDIR)/OptionsTest.Po"; else rm -f "$(DEPDIR)/OptionsTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/main/OptionsTest.cpp' object='OptionsTest.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 OptionsTest.obj `if test -f 'tests/main/OptionsTest.cpp'; then $(CYGPATH_W) 'tests/main/OptionsTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/main/OptionsTest.cpp'; fi`
FeedFilterTest.o: tests/feed/FeedFilterTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FeedFilterTest.o -MD -MP -MF "$(DEPDIR)/FeedFilterTest.Tpo" -c -o FeedFilterTest.o `test -f 'tests/feed/FeedFilterTest.cpp' || echo '$(srcdir)/'`tests/feed/FeedFilterTest.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/FeedFilterTest.Tpo" "$(DEPDIR)/FeedFilterTest.Po"; else rm -f "$(DEPDIR)/FeedFilterTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/feed/FeedFilterTest.cpp' object='FeedFilterTest.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 FeedFilterTest.o `test -f 'tests/feed/FeedFilterTest.cpp' || echo '$(srcdir)/'`tests/feed/FeedFilterTest.cpp
FeedFilterTest.obj: tests/feed/FeedFilterTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT FeedFilterTest.obj -MD -MP -MF "$(DEPDIR)/FeedFilterTest.Tpo" -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`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/FeedFilterTest.Tpo" "$(DEPDIR)/FeedFilterTest.Po"; else rm -f "$(DEPDIR)/FeedFilterTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/feed/FeedFilterTest.cpp' object='FeedFilterTest.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 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`
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
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/queue/NZBFileTest.cpp' object='NZBFileTest.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 NZBFileTest.o `test -f 'tests/queue/NZBFileTest.cpp' || echo '$(srcdir)/'`tests/queue/NZBFileTest.cpp
NZBFileTest.obj: tests/queue/NZBFileTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT NZBFileTest.obj -MD -MP -MF "$(DEPDIR)/NZBFileTest.Tpo" -c -o NZBFileTest.obj `if test -f 'tests/queue/NZBFileTest.cpp'; then $(CYGPATH_W) 'tests/queue/NZBFileTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/queue/NZBFileTest.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/NZBFileTest.Tpo" "$(DEPDIR)/NZBFileTest.Po"; else rm -f "$(DEPDIR)/NZBFileTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/queue/NZBFileTest.cpp' object='NZBFileTest.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 NZBFileTest.obj `if test -f 'tests/queue/NZBFileTest.cpp'; then $(CYGPATH_W) 'tests/queue/NZBFileTest.cpp'; else $(CYGPATH_W) '$(srcdir)/tests/queue/NZBFileTest.cpp'; fi`
UtilTest.o: tests/util/UtilTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT UtilTest.o -MD -MP -MF "$(DEPDIR)/UtilTest.Tpo" -c -o UtilTest.o `test -f 'tests/util/UtilTest.cpp' || echo '$(srcdir)/'`tests/util/UtilTest.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/UtilTest.Tpo" "$(DEPDIR)/UtilTest.Po"; else rm -f "$(DEPDIR)/UtilTest.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tests/util/UtilTest.cpp' object='UtilTest.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 UtilTest.o `test -f 'tests/util/UtilTest.cpp' || echo '$(srcdir)/'`tests/util/UtilTest.cpp
UtilTest.obj: tests/util/UtilTest.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT UtilTest.obj -MD -MP -MF "$(DEPDIR)/UtilTest.Tpo" -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`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/UtilTest.Tpo" "$(DEPDIR)/UtilTest.Po"; else rm -f "$(DEPDIR)/UtilTest.Tpo"; exit 1; fi
@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`
uninstall-info-am:
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
@@ -1848,7 +2216,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)/scripts $(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)/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 \
@@ -2117,40 +2485,53 @@ install-conf:
uninstall-conf:
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf"
# Determining subversion revision:
# 1) If directory ".svn" exists we take revision from it using program svnversion (part of subversion package)
# Determining git revision:
# 1) If directory ".git" exists we take revision from git log.
# File is recreated only if revision number was changed.
# 2) If directory ".svn" doesn't exists we keep and reuse file "svn_version.cpp",
# 2) If directory ".git" doesn't exists we keep and reuse file "code_revision.cpp",
# which was possibly created early.
# 3) If neither directory ".svn" nor file "svn_version.cpp" are available
# we create new file "svn_version.c" with empty revision number.
svn_version.cpp: FORCE
@ if test -d ./.svn ; then \
V="$(shell svnversion -n .)"; \
H="$(shell test -f ./svn_version.cpp && head -n 1 svn_version.cpp)"; \
# 3) If neither directory ".git" nor file "code_revision.cpp" are available
# we create new file "code_revision.c" with empty revision number.
code_revision.cpp: FORCE
@ if test -d ./.git ; then \
B="$(shell git branch | sed -n -e 's/^\* \(.*\)/\1/p')"; \
M="$(shell git status --porcelain)" ; \
if test "$$M" != "" ; then \
M="M" ; \
fi ; \
if test "$$B" = "master" ; then \
V="$$M" ; \
elif test "$$B" = "develop" ; then \
V="$(shell git rev-list HEAD | wc -l | xargs)" ; \
V="$${V}$$M" ; \
else \
V="$(shell git rev-list HEAD | wc -l | xargs)" ; \
V="$${V}$$M ($$B)" ; \
fi ; \
H="$(shell test -f ./code_revision.cpp && head -n 1 code_revision.cpp)"; \
if test "/* $$V */" != "$$H" ; then \
( \
echo "/* $$V */" ;\
echo "/* This file is automatically regenerated on each build. Do not edit it. */" ;\
echo "const char* svn_version(void)" ;\
echo "const char* code_revision(void)" ;\
echo "{" ;\
echo " const char* SVN_Version = \"$$V\";" ;\
echo " return SVN_Version;" ;\
echo " const char* revision = \"$$V\";" ;\
echo " return revision;" ;\
echo "}" ;\
) > svn_version.cpp ; \
) > code_revision.cpp ; \
fi \
elif test -f ./svn_version.cpp ; then \
elif test -f ./code_revision.cpp ; then \
test "ok, reuse existing file"; \
else \
( \
echo "/* */" ;\
echo "/* This file is automatically regenerated on each build. Do not edit it. */" ;\
echo "const char* svn_version(void)" ;\
echo "const char* code_revision(void)" ;\
echo "{" ;\
echo " const char* SVN_Version = \"\";" ;\
echo " return SVN_Version;" ;\
echo " const char* revision = \"\";" ;\
echo " return revision;" ;\
echo "}" ;\
) > svn_version.cpp ; \
) > code_revision.cpp ; \
fi
FORCE:
@@ -2161,6 +2542,7 @@ dist-hook:
find $(distdir)/daemon -type f -print -exec chmod -x {} \;
find $(distdir)/webui -type f -print -exec chmod -x {} \;
find $(distdir)/lib -type f -print -exec chmod -x {} \;
find $(distdir)/tests -type f -print -exec chmod -x {} \;
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

0
NEWS
View File

7
README
View File

@@ -457,12 +457,15 @@ Since then the program has been completely rewritten.
NZBGet distribution archive includes additional components
written by other authors:
PAR2:
Par2:
Peter Brian Clements <peterbclements@users.sourceforge.net>
PAR2 library API:
Par2 library API:
Francois Lesueur <flesueur@users.sourceforge.net>
Catch:
Two Blue Cubes Ltd <https://github.com/philsquared/Catch>
jQuery:
John Resig <http://jquery.com>
The Dojo Foundation <http://sizzlejs.com>

15
README.md Normal file
View File

@@ -0,0 +1,15 @@
# NZBGet #
NZBGet is a binary downloader, which downloads files from Usenet
based on information given in nzb-files.
NZBGet is written in C++ and is known for its extraordinary performance and efficiency.
NZBGet can be run at almost every platform - classic PCs, NAS, media players, SAT-receivers, WLAN-routers, etc.
The download area provides precompiled binaries
for Windows, Mac OS X and Linux (compatible with many CPUs and platform variants). For other platforms
the program can be compiled from sources.
- [Home page (nzbget.net)](http://nzbget.net) - for first time visitors, learn more about NZBGet;
- [Downloads](http://nzbget.net/download) - get the binaries and sources;
- [Documentation](https://github.com/nzbget/nzbget/wiki) - installation manuals, HOW-TOs, API;
- [Forum](http://forum.nzbget.net) - get support, share your ideas, scripts, add-ons.

1500
config.guess vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,9 @@
/* Define to 1 to not use TLS/SSL */
#undef DISABLE_TLS
/* Define to 1 to enable unit and integration tests */
#undef ENABLE_TESTS
/* Define to the name of macro which returns the name of function being
compiled */
#undef FUNCTION_MACRO_NAME
@@ -42,9 +45,15 @@
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if fdatasync is supported */
#undef HAVE_FDATASYNC
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
/* Define to 1 if F_FULLFSYNC is supported */
#undef HAVE_FULLFSYNC
/* Define to 1 if getaddrinfo is supported */
#undef HAVE_GETADDRINFO
@@ -99,9 +108,6 @@
/* Define to 1 if _SC_NPROCESSORS_ONLN is present in unistd.h */
#undef HAVE_SC_NPROCESSORS_ONLN
/* Define to 1 if spinlocks are supported */
#undef HAVE_SPINLOCK
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H

1616
config.sub vendored
View File

File diff suppressed because it is too large Load Diff

618
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for nzbget 15.0.
# Generated by GNU Autoconf 2.61 for nzbget 16.4.
#
# 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='15.0'
PACKAGE_STRING='nzbget 15.0'
PACKAGE_VERSION='16.4'
PACKAGE_STRING='nzbget 16.4'
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
ac_unique_file="daemon/main/nzbget.cpp"
@@ -652,18 +652,6 @@ LIBS
build_alias
host_alias
target_alias
build
build_cpu
build_vendor
build_os
host
host_cpu
host_vendor
host_os
target
target_cpu
target_vendor
target_os
INSTALL_PROGRAM
INSTALL_SCRIPT
INSTALL_DATA
@@ -714,6 +702,8 @@ WITH_PAR2_TRUE
WITH_PAR2_FALSE
openssl_CFLAGS
openssl_LIBS
WITH_TESTS_TRUE
WITH_TESTS_FALSE
LTLIBOBJS'
ac_subst_files=''
ac_precious_vars='build_alias
@@ -1233,7 +1223,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 15.0 to adapt to many kinds of systems.
\`configure' configures nzbget 16.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1294,17 +1284,12 @@ Program names:
--program-prefix=PREFIX prepend PREFIX to installed program names
--program-suffix=SUFFIX append SUFFIX to installed program names
--program-transform-name=PROGRAM run sed PROGRAM on installed program names
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
--target=TARGET configure for building compilers for TARGET [HOST]
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of nzbget 15.0:";;
short | recursive ) echo "Configuration of nzbget 16.4:";;
esac
cat <<\_ACEOF
@@ -1325,6 +1310,7 @@ Optional Features:
do not use sigchld-handler (the disabling may be
neccessary on 32-Bit BSD)
--enable-debug enable debugging
--enable-tests enable unit and integration tests
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1435,7 +1421,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
nzbget configure 15.0
nzbget configure 16.4
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1449,7 +1435,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 15.0, which was
It was created by nzbget $as_me 16.4, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -1803,7 +1789,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
for ac_dir in posix "$srcdir"/posix; do
if test -f "$ac_dir/install-sh"; then
ac_aux_dir=$ac_dir
ac_install_sh="$ac_aux_dir/install-sh -c"
@@ -1819,8 +1805,8 @@ for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
fi
done
if test -z "$ac_aux_dir"; then
{ { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
{ { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in posix \"$srcdir\"/posix" >&5
echo "$as_me: error: cannot find install-sh or install.sh in posix \"$srcdir\"/posix" >&2;}
{ (exit 1); exit 1; }; }
fi
@@ -1833,132 +1819,6 @@ ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
{ { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
{ (exit 1); exit 1; }; }
{ echo "$as_me:$LINENO: checking build system type" >&5
echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
if test "${ac_cv_build+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
{ { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
{ (exit 1); exit 1; }; }
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
{ { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
{ (exit 1); exit 1; }; }
fi
{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
echo "${ECHO_T}$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
echo "$as_me: error: invalid value of canonical build" >&2;}
{ (exit 1); exit 1; }; };;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
{ echo "$as_me:$LINENO: checking host system type" >&5
echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
if test "${ac_cv_host+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "x$host_alias" = x; then
ac_cv_host=$ac_cv_build
else
ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
{ { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
{ (exit 1); exit 1; }; }
fi
fi
{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
echo "${ECHO_T}$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
echo "$as_me: error: invalid value of canonical host" >&2;}
{ (exit 1); exit 1; }; };;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_host
shift
host_cpu=$1
host_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
host_os=$*
IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
{ echo "$as_me:$LINENO: checking target system type" >&5
echo $ECHO_N "checking target system type... $ECHO_C" >&6; }
if test "${ac_cv_target+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "x$target_alias" = x; then
ac_cv_target=$ac_cv_host
else
ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
{ { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5
echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;}
{ (exit 1); exit 1; }; }
fi
fi
{ echo "$as_me:$LINENO: result: $ac_cv_target" >&5
echo "${ECHO_T}$ac_cv_target" >&6; }
case $ac_cv_target in
*-*-*) ;;
*) { { echo "$as_me:$LINENO: error: invalid value of canonical target" >&5
echo "$as_me: error: invalid value of canonical target" >&2;}
{ (exit 1); exit 1; }; };;
esac
target=$ac_cv_target
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_target
shift
target_cpu=$1
target_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
target_os=$*
IFS=$ac_save_IFS
case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
# The aliases save the names the user supplied, while $host etc.
# will get canonicalized.
test -n "$target_alias" &&
test "$program_prefix$program_suffix$program_transform_name" = \
NONENONEs,x,x, &&
program_prefix=${target_alias}-
am__api_version="1.9"
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -2244,8 +2104,8 @@ fi
# Define the identity of the package.
PACKAGE=nzbget
VERSION=15.0
PACKAGE='nzbget'
VERSION='16.4'
cat >>confdefs.h <<_ACEOF
@@ -4704,6 +4564,157 @@ fi
{ echo "$as_me:$LINENO: checking for fdatasync" >&5
echo $ECHO_N "checking for fdatasync... $ECHO_C" >&6; }
if test "${ac_cv_func_fdatasync+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define fdatasync to an innocuous variant, in case <limits.h> declares fdatasync.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define fdatasync innocuous_fdatasync
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char fdatasync (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef fdatasync
/* 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 fdatasync ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_fdatasync || defined __stub___fdatasync
choke me
#endif
int
main ()
{
return fdatasync ();
;
return 0;
}
_ACEOF
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_func_fdatasync=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_func_fdatasync=no
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $ac_cv_func_fdatasync" >&5
echo "${ECHO_T}$ac_cv_func_fdatasync" >&6; }
if test $ac_cv_func_fdatasync = yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_FDATASYNC 1
_ACEOF
fi
{ echo "$as_me:$LINENO: checking whether F_FULLFSYNC is declared" >&5
echo $ECHO_N "checking whether F_FULLFSYNC is declared... $ECHO_C" >&6; }
if test "${ac_cv_have_decl_F_FULLFSYNC+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <fcntl.h>
int
main ()
{
#ifndef F_FULLFSYNC
(void) F_FULLFSYNC;
#endif
;
return 0;
}
_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_cv_have_decl_F_FULLFSYNC=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_have_decl_F_FULLFSYNC=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_F_FULLFSYNC" >&5
echo "${ECHO_T}$ac_cv_have_decl_F_FULLFSYNC" >&6; }
if test $ac_cv_have_decl_F_FULLFSYNC = yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_FULLFSYNC 1
_ACEOF
fi
# Check whether --enable-largefile was given.
if test "${enable_largefile+set}" = set; then
enableval=$enable_largefile;
@@ -5595,180 +5606,6 @@ fi
fi
{ echo "$as_me:$LINENO: checking for pthread_spin_init" >&5
echo $ECHO_N "checking for pthread_spin_init... $ECHO_C" >&6; }
if test "${ac_cv_func_pthread_spin_init+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define pthread_spin_init to an innocuous variant, in case <limits.h> declares pthread_spin_init.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define pthread_spin_init innocuous_pthread_spin_init
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char pthread_spin_init (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef pthread_spin_init
/* 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 pthread_spin_init ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_pthread_spin_init || defined __stub___pthread_spin_init
choke me
#endif
int
main ()
{
return pthread_spin_init ();
;
return 0;
}
_ACEOF
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_func_pthread_spin_init=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_func_pthread_spin_init=no
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $ac_cv_func_pthread_spin_init" >&5
echo "${ECHO_T}$ac_cv_func_pthread_spin_init" >&6; }
if test $ac_cv_func_pthread_spin_init = yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_SPINLOCK 1
_ACEOF
{ echo "$as_me:$LINENO: checking for library containing pthread_spin_init" >&5
echo $ECHO_N "checking for library containing pthread_spin_init... $ECHO_C" >&6; }
if test "${ac_cv_search_pthread_spin_init+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 pthread_spin_init ();
int
main ()
{
return pthread_spin_init ();
;
return 0;
}
_ACEOF
for ac_lib in '' pthread; 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_pthread_spin_init=$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_pthread_spin_init+set}" = set; then
break
fi
done
if test "${ac_cv_search_pthread_spin_init+set}" = set; then
:
else
ac_cv_search_pthread_spin_init=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ echo "$as_me:$LINENO: result: $ac_cv_search_pthread_spin_init" >&5
echo "${ECHO_T}$ac_cv_search_pthread_spin_init" >&6; }
ac_res=$ac_cv_search_pthread_spin_init
if test "$ac_res" != no; then
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
fi
{ echo "$as_me:$LINENO: checking for type of socket length (socklen_t)" >&5
echo $ECHO_N "checking for type of socket length (socklen_t)... $ECHO_C" >&6; }
cat >conftest.$ac_ext <<_ACEOF
@@ -10325,6 +10162,46 @@ _ACEOF
fi
{ echo "$as_me:$LINENO: checking whether to enable unit and integration tests" >&5
echo $ECHO_N "checking whether to enable unit and integration tests... $ECHO_C" >&6; }
# Check whether --enable-tests was given.
if test "${enable_tests+set}" = set; then
enableval=$enable_tests; ENABLETESTS=$enableval
else
ENABLETESTS=no
fi
{ echo "$as_me:$LINENO: result: $ENABLETESTS" >&5
echo "${ECHO_T}$ENABLETESTS" >&6; }
if test "$ENABLETESTS" = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define ENABLE_TESTS 1
_ACEOF
if true; then
WITH_TESTS_TRUE=
WITH_TESTS_FALSE='#'
else
WITH_TESTS_TRUE='#'
WITH_TESTS_FALSE=
fi
else
if false; then
WITH_TESTS_TRUE=
WITH_TESTS_FALSE='#'
else
WITH_TESTS_TRUE='#'
WITH_TESTS_FALSE=
fi
fi
ac_config_files="$ac_config_files Makefile"
cat >confcache <<\_ACEOF
@@ -10451,6 +10328,20 @@ echo "$as_me: error: conditional \"WITH_PAR2\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${WITH_TESTS_TRUE}" && test -z "${WITH_TESTS_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"WITH_TESTS\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
echo "$as_me: error: conditional \"WITH_TESTS\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${WITH_TESTS_TRUE}" && test -z "${WITH_TESTS_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"WITH_TESTS\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
echo "$as_me: error: conditional \"WITH_TESTS\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
: ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files
@@ -10751,7 +10642,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 15.0, which was
This file was extended by nzbget $as_me 16.4, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -10804,7 +10695,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
nzbget config.status 15.0
nzbget config.status 16.4
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
@@ -11019,18 +10910,6 @@ LIBS!$LIBS$ac_delim
build_alias!$build_alias$ac_delim
host_alias!$host_alias$ac_delim
target_alias!$target_alias$ac_delim
build!$build$ac_delim
build_cpu!$build_cpu$ac_delim
build_vendor!$build_vendor$ac_delim
build_os!$build_os$ac_delim
host!$host$ac_delim
host_cpu!$host_cpu$ac_delim
host_vendor!$host_vendor$ac_delim
host_os!$host_os$ac_delim
target!$target$ac_delim
target_cpu!$target_cpu$ac_delim
target_vendor!$target_vendor$ac_delim
target_os!$target_os$ac_delim
INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
INSTALL_DATA!$INSTALL_DATA$ac_delim
@@ -11079,9 +10958,14 @@ libxml2_LIBS!$libxml2_LIBS$ac_delim
LIBOBJS!$LIBOBJS$ac_delim
WITH_PAR2_TRUE!$WITH_PAR2_TRUE$ac_delim
WITH_PAR2_FALSE!$WITH_PAR2_FALSE$ac_delim
openssl_CFLAGS!$openssl_CFLAGS$ac_delim
openssl_LIBS!$openssl_LIBS$ac_delim
WITH_TESTS_TRUE!$WITH_TESTS_TRUE$ac_delim
WITH_TESTS_FALSE!$WITH_TESTS_FALSE$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -11100,50 +10984,6 @@ fi
cat >>$CONFIG_STATUS <<_ACEOF
cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
_ACEOF
sed '
s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
s/^/s,@/; s/!/@,|#_!!_#|/
:n
t n
s/'"$ac_delim"'$/,g/; t
s/$/\\/; p
N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
' >>$CONFIG_STATUS <conf$$subs.sed
rm -f conf$$subs.sed
cat >>$CONFIG_STATUS <<_ACEOF
CEOF$ac_eof
_ACEOF
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
cat >conf$$subs.sed <<_ACEOF
openssl_CFLAGS!$openssl_CFLAGS$ac_delim
openssl_LIBS!$openssl_LIBS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 3; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
{ (exit 1); exit 1; }; }
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
done
ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
if test -n "$ac_eof"; then
ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
ac_eof=`expr $ac_eof + 1`
fi
cat >>$CONFIG_STATUS <<_ACEOF
cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
_ACEOF
sed '
@@ -11406,7 +11246,7 @@ s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out
" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
{ ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&

View File

@@ -23,9 +23,9 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(nzbget, 15.0, hugbug@users.sourceforge.net)
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(nzbget, 15.0)
AC_INIT(nzbget, 16.4, hugbug@users.sourceforge.net)
AC_CONFIG_AUX_DIR(posix)
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_SRCDIR([daemon/main/nzbget.cpp])
AC_CONFIG_HEADERS([config.h])
@@ -76,6 +76,14 @@ AC_CHECK_FUNC(getopt_long,
[AC_DEFINE([HAVE_GETOPT_LONG], 1, [Define to 1 if getopt_long is supported])],)
dnl
dnl fsync
dnl
AC_CHECK_FUNC(fdatasync,
[AC_DEFINE([HAVE_FDATASYNC], 1, [Define to 1 if fdatasync is supported])],)
AC_CHECK_DECL(F_FULLFSYNC,
[AC_DEFINE([HAVE_FULLFSYNC], 1, [Define to 1 if F_FULLFSYNC is supported])],,[#include <fcntl.h>])
dnl
dnl use 64-Bits for file sizes
dnl
@@ -163,14 +171,6 @@ if test "$FOUND" = "no"; then
fi
dnl
dnl Check if spinlocks are available
dnl
AC_CHECK_FUNC(pthread_spin_init,
[AC_DEFINE([HAVE_SPINLOCK], 1, [Define to 1 if spinlocks are supported])]
AC_SEARCH_LIBS([pthread_spin_init], [pthread]),)
dnl
dnl Determine what socket length (socklen_t) data type is
dnl
@@ -592,5 +592,21 @@ AC_DEFINE([NDEBUG],1,Define to 1 to exclude debug-code)
fi
dnl
dnl Enable test suite. Deafult: no.
dnl
AC_MSG_CHECKING(whether to enable unit and integration tests)
AC_ARG_ENABLE(tests,
[AS_HELP_STRING([--enable-tests], [enable unit and integration tests])],
[ ENABLETESTS=$enableval ],
[ ENABLETESTS=no] )
AC_MSG_RESULT($ENABLETESTS)
if test "$ENABLETESTS" = "yes"; then
AC_DEFINE([ENABLE_TESTS],1,[Define to 1 to enable unit and integration tests])
AM_CONDITIONAL(WITH_TESTS, true)
else
AM_CONDITIONAL(WITH_TESTS, false)
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@@ -66,6 +66,44 @@ Mutex* Connection::m_pMutexGetHostByName = NULL;
#endif
#endif
void closesocket_gracefully(SOCKET iSocket)
{
char buf[1024];
struct linger linger;
// Set linger option to avoid socket hanging out after close. This prevent
// ephemeral port exhaust problem under high QPS.
linger.l_onoff = 1;
linger.l_linger = 1;
setsockopt(iSocket, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
// Send FIN to the client
shutdown(iSocket, SHUT_WR);
// Set non-blocking mode
#ifdef WIN32
unsigned long on = 1;
ioctlsocket(iSocket, FIONBIO, &on);
#else
int flags;
flags = fcntl(iSocket, F_GETFL, 0);
fcntl(iSocket, F_SETFL, flags | O_NONBLOCK);
#endif
// Read and discard pending incoming data. If we do not do that and close the
// socket, the data in the send buffer may be discarded. This
// behaviour is seen on Windows, when client keeps sending data
// when server decides to close the connection; then when client
// does recv() it gets no data back.
int n;
do {
n = recv(iSocket, buf, sizeof(buf), 0);
} while (n > 0);
// Now we know that our FIN is ACK-ed, safe to close
closesocket(iSocket);
}
void Connection::Init()
{
debug("Initializing global connection data");
@@ -132,6 +170,7 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
m_iTotalBytesRead = 0;
m_bBroken = false;
m_bGracefull = false;
#ifndef DISABLE_TLS
m_pTLSSocket = NULL;
m_bTLSError = false;
@@ -576,6 +615,11 @@ bool Connection::DoConnect()
}
triedAddr.push_back(sa);
if (m_iSocket != INVALID_SOCKET)
{
closesocket(m_iSocket);
}
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_iSocket, HANDLE_FLAG_INHERIT, 0);
@@ -805,7 +849,14 @@ bool Connection::DoDisconnect()
#ifndef DISABLE_TLS
CloseTLS();
#endif
closesocket(m_iSocket);
if (m_bGracefull)
{
closesocket_gracefully(m_iSocket);
}
else
{
closesocket(m_iSocket);
}
m_iSocket = INVALID_SOCKET;
}

View File

@@ -62,6 +62,7 @@ protected:
char m_szRemoteAddr[20];
int m_iTotalBytesRead;
bool m_bBroken;
bool m_bGracefull;
struct SockAddr
{
@@ -136,6 +137,8 @@ public:
void SetSuppressErrors(bool bSuppressErrors);
bool GetSuppressErrors() { return m_bSuppressErrors; }
const char* GetRemoteAddr();
bool GetGracefull() { return m_bGracefull; }
void SetGracefull(bool bGracefull) { m_bGracefull = bGracefull; }
#ifndef DISABLE_TLS
bool StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile);
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,8 +49,6 @@
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
WebDownloader::WebDownloader()
{
debug("Creating WebDownloader");
@@ -90,7 +88,7 @@ void WebDownloader::SetInfoName(const char* v)
void WebDownloader::SetURL(const char * szURL)
{
free(m_szURL);
m_szURL = strdup(szURL);
m_szURL = WebUtil::URLEncode(szURL);
}
void WebDownloader::SetStatus(EStatus eStatus)
@@ -113,14 +111,13 @@ void WebDownloader::Run()
iRemainedConnectRetries = 1;
}
m_iRedirects = 0;
EStatus Status = adFailed;
while (!IsStopped() && iRemainedDownloadRetries > 0 && iRemainedConnectRetries > 0)
{
SetLastUpdateTimeNow();
Status = Download();
Status = DownloadWithRedirects(5);
if ((((Status == adFailed) && (iRemainedDownloadRetries > 1)) ||
((Status == adConnectError) && (iRemainedConnectRetries > 1)))
@@ -147,17 +144,6 @@ void WebDownloader::Run()
break;
}
if (Status == adRedirect)
{
m_iRedirects++;
if (m_iRedirects > 5)
{
warn("Too many redirects for %s", m_szInfoName);
Status = adFailed;
break;
}
}
if (Status != adConnectError)
{
iRemainedDownloadRetries--;
@@ -246,6 +232,24 @@ WebDownloader::EStatus WebDownloader::Download()
return Status;
}
WebDownloader::EStatus WebDownloader::DownloadWithRedirects(int iMaxRedirects)
{
// do sync download, following redirects
EStatus eStatus = adRedirect;
while (eStatus == adRedirect && iMaxRedirects >= 0)
{
iMaxRedirects--;
eStatus = Download();
}
if (eStatus == adRedirect && iMaxRedirects < 0)
{
warn("Too many redirects for %s", m_szInfoName);
eStatus = adFailed;
}
return eStatus;
}
WebDownloader::EStatus WebDownloader::CreateConnection(URL *pUrl)
{
@@ -591,15 +595,46 @@ void WebDownloader::ParseRedirect(const char* szLocation)
URL newUrl(szNewURL);
if (!newUrl.IsValid())
{
// relative address
// redirect within host
char szResource[1024];
URL oldUrl(m_szURL);
if (oldUrl.GetPort() > 0)
if (*szLocation == '/')
{
snprintf(szUrlBuf, 1024, "%s://%s:%i%s", oldUrl.GetProtocol(), oldUrl.GetHost(), oldUrl.GetPort(), szNewURL);
// absolute path within host
strncpy(szResource, szLocation, 1024);
szResource[1024-1] = '\0';
}
else
{
snprintf(szUrlBuf, 1024, "%s://%s%s", oldUrl.GetProtocol(), oldUrl.GetHost(), szNewURL);
// relative path within host
strncpy(szResource, oldUrl.GetResource(), 1024);
szResource[1024-1] = '\0';
char* p = strchr(szResource, '?');
if (p)
{
*p = '\0';
}
p = strrchr(szResource, '/');
if (p)
{
p[1] = '\0';
}
strncat(szResource, szLocation, 1024 - strlen(szResource));
szResource[1024-1] = '\0';
}
if (oldUrl.GetPort() > 0)
{
snprintf(szUrlBuf, 1024, "%s://%s:%i%s", oldUrl.GetProtocol(), oldUrl.GetHost(), oldUrl.GetPort(), szResource);
}
else
{
snprintf(szUrlBuf, 1024, "%s://%s%s", oldUrl.GetProtocol(), oldUrl.GetHost(), szResource);
}
szUrlBuf[1024-1] = '\0';
szNewURL = szUrlBuf;

View File

@@ -64,7 +64,6 @@ private:
bool m_bForce;
bool m_bRedirecting;
bool m_bRedirected;
int m_iRedirects;
bool m_bGZip;
bool m_bRetry;
#ifndef DISABLE_GZIP
@@ -93,6 +92,7 @@ public:
virtual void Run();
virtual void Stop();
EStatus Download();
EStatus DownloadWithRedirects(int iMaxRedirects);
bool Terminate();
void SetInfoName(const char* v);
const char* GetInfoName() { return m_szInfoName; }

View File

@@ -0,0 +1,95 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdio.h>
#include "nzbget.h"
#include "FeedScript.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
void FeedScriptController::ExecuteScripts(const char* szFeedScript, const char* szFeedFile, int iFeedID)
{
FeedScriptController* pScriptController = new FeedScriptController();
pScriptController->m_szFeedFile = szFeedFile;
pScriptController->m_iFeedID = iFeedID;
pScriptController->ExecuteScriptList(szFeedScript);
delete pScriptController;
}
void FeedScriptController::ExecuteScript(ScriptConfig::Script* pScript)
{
if (!pScript->GetFeedScript())
{
return;
}
PrintMessage(Message::mkInfo, "Executing feed-script %s for Feed%i", pScript->GetName(), m_iFeedID);
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "feed-script %s for Feed%i", pScript->GetName(), m_iFeedID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void FeedScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetEnvVar("NZBFP_FILENAME", m_szFeedFile);
SetIntEnvVar("NZBFP_FEEDID", m_iFeedID);
PrepareEnvScript(NULL, szScriptName);
}

View File

@@ -0,0 +1,46 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef FEEDSCRIPT_H
#define FEEDSCRIPT_H
#include "NzbScript.h"
class FeedScriptController : public NZBScriptController
{
private:
const char* m_szFeedFile;
int m_iFeedID;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(ScriptConfig::Script* pScript);
public:
static void ExecuteScripts(const char* szFeedScript, const char* szFeedFile, int iFeedID);
};
#endif

View File

@@ -0,0 +1,125 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdio.h>
#include <algorithm>
#include "nzbget.h"
#include "NzbScript.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
/**
* If szStripPrefix is not NULL, only pp-parameters, whose names start with the prefix
* are processed. The prefix is then stripped from the names.
* If szStripPrefix is NULL, all pp-parameters are processed; without stripping.
*/
void NZBScriptController::PrepareEnvParameters(NZBParameterList* pParameters, const char* szStripPrefix)
{
int iPrefixLen = szStripPrefix ? strlen(szStripPrefix) : 0;
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szValue = pParameter->GetValue();
#ifdef WIN32
char* szAnsiValue = strdup(szValue);
WebUtil::Utf8ToAnsi(szAnsiValue, strlen(szAnsiValue) + 1);
szValue = szAnsiValue;
#endif
if (szStripPrefix && !strncmp(pParameter->GetName(), szStripPrefix, iPrefixLen) && (int)strlen(pParameter->GetName()) > iPrefixLen)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName() + iPrefixLen, szValue);
}
else if (!szStripPrefix)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName(), szValue);
}
#ifdef WIN32
free(szAnsiValue);
#endif
}
}
void NZBScriptController::PrepareEnvScript(NZBParameterList* pParameters, const char* szScriptName)
{
if (pParameters)
{
PrepareEnvParameters(pParameters, NULL);
}
char szParamPrefix[1024];
snprintf(szParamPrefix, 1024, "%s:", szScriptName);
szParamPrefix[1024-1] = '\0';
if (pParameters)
{
PrepareEnvParameters(pParameters, szParamPrefix);
}
PrepareEnvOptions(szParamPrefix);
}
void NZBScriptController::ExecuteScriptList(const char* szScriptList)
{
for (ScriptConfig::Scripts::iterator it = g_pScriptConfig->GetScripts()->begin(); it != g_pScriptConfig->GetScripts()->end(); it++)
{
ScriptConfig::Script* pScript = *it;
if (szScriptList && *szScriptList)
{
// split szScriptList into tokens
Tokenizer tok(szScriptList, ",;");
while (const char* szScriptName = tok.Next())
{
if (Util::SameFilename(szScriptName, pScript->GetName()))
{
ExecuteScript(pScript);
break;
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef NZBSCRIPT_H
#define NZBSCRIPT_H
#include "Script.h"
#include "DownloadInfo.h"
#include "ScriptConfig.h"
class NZBScriptController : public ScriptController
{
protected:
void PrepareEnvParameters(NZBParameterList* pParameters, const char* szStripPrefix);
void PrepareEnvScript(NZBParameterList* pParameters, const char* szScriptName);
void ExecuteScriptList(const char* szScriptList);
virtual void ExecuteScript(ScriptConfig::Script* pScript) = 0;
};
#endif

View File

@@ -45,8 +45,6 @@
#include "Util.h"
#include "Options.h"
extern Options* g_pOptions;
static const int POSTPROCESS_PARCHECK = 92;
static const int POSTPROCESS_SUCCESS = 93;
static const int POSTPROCESS_ERROR = 94;
@@ -94,7 +92,7 @@ void PostScriptController::Run()
m_pPostInfo->SetWorking(false);
}
void PostScriptController::ExecuteScript(Options::Script* pScript)
void PostScriptController::ExecuteScript(ScriptConfig::Script* pScript)
{
// if any script has requested par-check, do not execute other scripts
if (!pScript->GetPostScript() || m_pPostInfo->GetRequestParCheck())
@@ -155,6 +153,12 @@ void PostScriptController::PrepareParams(const char* szScriptName)
SetIntEnvVar("NZBPP_HEALTH", m_pPostInfo->GetNZBInfo()->CalcHealth());
SetIntEnvVar("NZBPP_CRITICALHEALTH", m_pPostInfo->GetNZBInfo()->CalcCriticalHealth(false));
SetEnvVar("NZBPP_DUPEKEY", m_pPostInfo->GetNZBInfo()->GetDupeKey());
SetIntEnvVar("NZBPP_DUPESCORE", m_pPostInfo->GetNZBInfo()->GetDupeScore());
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
SetEnvVar("NZBPP_DUPEMODE", szDupeModeName[m_pPostInfo->GetNZBInfo()->GetDupeMode()]);
char szStatus[256];
strncpy(szStatus, m_pPostInfo->GetNZBInfo()->MakeTextStatus(true), sizeof(szStatus));
szStatus[256-1] = '\0';

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,23 +27,20 @@
#define POSTSCRIPT_H
#include "Thread.h"
#include "Log.h"
#include "QueueScript.h"
#include "DownloadInfo.h"
#include "Options.h"
#include "NzbScript.h"
class PostScriptController : public Thread, public NZBScriptController
{
private:
PostInfo* m_pPostInfo;
int m_iPrefixLen;
Options::Script* m_pScript;
ScriptConfig::Script* m_pScript;
void PrepareParams(const char* szScriptName);
ScriptStatus::EStatus AnalyseExitCode(int iExitCode);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void ExecuteScript(ScriptConfig::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,18 +39,15 @@
#endif
#include <sys/stat.h>
#include <stdio.h>
#include <algorithm>
#include "nzbget.h"
#include "QueueScript.h"
#include "NzbScript.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
static const char* QUEUE_EVENT_NAMES[] = { "FILE_DOWNLOADED", "NZB_ADDED", "NZB_DOWNLOADED" };
static const char* QUEUE_EVENT_NAMES[] = { "FILE_DOWNLOADED", "URL_COMPLETED", "NZB_ADDED", "NZB_DOWNLOADED", "NZB_DELETED" };
class QueueScriptController : public Thread, public NZBScriptController
{
@@ -62,102 +59,30 @@ private:
char* m_szDestDir;
int m_iID;
int m_iPriority;
char* m_szDupeKey;
EDupeMode m_eDupeMode;
int m_iDupeScore;
NZBParameterList m_Parameters;
int m_iPrefixLen;
Options::Script* m_pScript;
ScriptConfig::Script* m_pScript;
QueueScriptCoordinator::EEvent m_eEvent;
bool m_bMarkBad;
NZBInfo::EDeleteStatus m_eDeleteStatus;
NZBInfo::EUrlStatus m_eUrlStatus;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void ExecuteScript(ScriptConfig::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual ~QueueScriptController();
virtual void Run();
static void StartScript(NZBInfo* pNZBInfo, Options::Script* pScript, QueueScriptCoordinator::EEvent eEvent);
static void StartScript(NZBInfo* pNZBInfo, ScriptConfig::Script* pScript, QueueScriptCoordinator::EEvent eEvent);
};
/**
* If szStripPrefix is not NULL, only pp-parameters, whose names start with the prefix
* are processed. The prefix is then stripped from the names.
* If szStripPrefix is NULL, all pp-parameters are processed; without stripping.
*/
void NZBScriptController::PrepareEnvParameters(NZBParameterList* pParameters, const char* szStripPrefix)
{
int iPrefixLen = szStripPrefix ? strlen(szStripPrefix) : 0;
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szValue = pParameter->GetValue();
#ifdef WIN32
char* szAnsiValue = strdup(szValue);
WebUtil::Utf8ToAnsi(szAnsiValue, strlen(szAnsiValue) + 1);
szValue = szAnsiValue;
#endif
if (szStripPrefix && !strncmp(pParameter->GetName(), szStripPrefix, iPrefixLen) && (int)strlen(pParameter->GetName()) > iPrefixLen)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName() + iPrefixLen, szValue);
}
else if (!szStripPrefix)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName(), szValue);
}
#ifdef WIN32
free(szAnsiValue);
#endif
}
}
void NZBScriptController::PrepareEnvScript(NZBParameterList* pParameters, const char* szScriptName)
{
if (pParameters)
{
PrepareEnvParameters(pParameters, NULL);
}
char szParamPrefix[1024];
snprintf(szParamPrefix, 1024, "%s:", szScriptName);
szParamPrefix[1024-1] = '\0';
if (pParameters)
{
PrepareEnvParameters(pParameters, szParamPrefix);
}
PrepareEnvOptions(szParamPrefix);
}
void NZBScriptController::ExecuteScriptList(const char* szScriptList)
{
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
if (szScriptList && *szScriptList)
{
// split szScriptList into tokens
Tokenizer tok(szScriptList, ",;");
while (const char* szScriptName = tok.Next())
{
if (Util::SameFilename(szScriptName, pScript->GetName()))
{
ExecuteScript(pScript);
break;
}
}
}
}
}
QueueScriptController::~QueueScriptController()
{
free(m_szNZBName);
@@ -165,9 +90,10 @@ QueueScriptController::~QueueScriptController()
free(m_szUrl);
free(m_szCategory);
free(m_szDestDir);
free(m_szDupeKey);
}
void QueueScriptController::StartScript(NZBInfo* pNZBInfo, Options::Script* pScript, QueueScriptCoordinator::EEvent eEvent)
void QueueScriptController::StartScript(NZBInfo* pNZBInfo, ScriptConfig::Script* pScript, QueueScriptCoordinator::EEvent eEvent)
{
QueueScriptController* pScriptController = new QueueScriptController();
@@ -178,11 +104,16 @@ void QueueScriptController::StartScript(NZBInfo* pNZBInfo, Options::Script* pScr
pScriptController->m_szDestDir = strdup(pNZBInfo->GetDestDir());
pScriptController->m_iID = pNZBInfo->GetID();
pScriptController->m_iPriority = pNZBInfo->GetPriority();
pScriptController->m_szDupeKey = strdup(pNZBInfo->GetDupeKey());
pScriptController->m_eDupeMode = pNZBInfo->GetDupeMode();
pScriptController->m_iDupeScore = pNZBInfo->GetDupeScore();
pScriptController->m_Parameters.CopyFrom(pNZBInfo->GetParameters());
pScriptController->m_pScript = pScript;
pScriptController->m_eEvent = eEvent;
pScriptController->m_iPrefixLen = 0;
pScriptController->m_bMarkBad = false;
pScriptController->m_eDeleteStatus = pNZBInfo->GetDeleteStatus();
pScriptController->m_eUrlStatus = pNZBInfo->GetUrlStatus();
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
@@ -210,7 +141,7 @@ void QueueScriptController::Run()
g_pQueueScriptCoordinator->CheckQueue();
}
void QueueScriptController::ExecuteScript(Options::Script* pScript)
void QueueScriptController::ExecuteScript(ScriptConfig::Script* pScript)
{
PrintMessage(m_eEvent == QueueScriptCoordinator::qeFileDownloaded ? Message::mkDetail : Message::mkInfo,
"Executing queue-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBName));
@@ -244,8 +175,21 @@ void QueueScriptController::PrepareParams(const char* szScriptName)
SetEnvVar("NZBNA_CATEGORY", m_szCategory);
SetIntEnvVar("NZBNA_PRIORITY", m_iPriority);
SetIntEnvVar("NZBNA_LASTID", m_iID); // deprecated
SetEnvVar("NZBNA_DUPEKEY", m_szDupeKey);
SetIntEnvVar("NZBNA_DUPESCORE", m_iDupeScore);
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
SetEnvVar("NZBNA_DUPEMODE", szDupeModeName[m_eDupeMode]);
SetEnvVar("NZBNA_EVENT", QUEUE_EVENT_NAMES[m_eEvent]);
const char* szDeleteStatusName[] = { "NONE", "MANUAL", "HEALTH", "DUPE", "BAD", "GOOD", "COPY", "SCAN" };
SetEnvVar("NZBNA_DELETESTATUS", szDeleteStatusName[m_eDeleteStatus]);
const char* szUrlStatusName[] = { "NONE", "UNKNOWN", "SUCCESS", "FAILURE", "UNKNOWN", "SCAN_SKIPPED", "SCAN_FAILURE" };
SetEnvVar("NZBNA_URLSTATUS", szUrlStatusName[m_eUrlStatus]);
PrepareEnvScript(&m_Parameters, szScriptName);
}
@@ -303,7 +247,7 @@ void QueueScriptController::AddMessage(Message::EKind eKind, const char* szText)
}
QueueScriptCoordinator::QueueItem::QueueItem(int iNZBID, Options::Script* pScript, EEvent eEvent)
QueueScriptCoordinator::QueueItem::QueueItem(int iNZBID, ScriptConfig::Script* pScript, EEvent eEvent)
{
m_iNZBID = iNZBID;
m_pScript = pScript;
@@ -313,12 +257,13 @@ QueueScriptCoordinator::QueueItem::QueueItem(int iNZBID, Options::Script* pScrip
QueueScriptCoordinator::QueueScriptCoordinator()
{
m_pCurItem = NULL;
m_bStopped = false;
}
QueueScriptCoordinator::~QueueScriptCoordinator()
{
delete m_pCurItem;
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); )
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); it++ )
{
delete *it;
}
@@ -327,9 +272,9 @@ QueueScriptCoordinator::~QueueScriptCoordinator()
void QueueScriptCoordinator::InitOptions()
{
m_bHasQueueScripts = false;
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
for (ScriptConfig::Scripts::iterator it = g_pScriptConfig->GetScripts()->begin(); it != g_pScriptConfig->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
ScriptConfig::Script* pScript = *it;
if (pScript->GetQueueScript())
{
m_bHasQueueScripts = true;
@@ -374,9 +319,9 @@ void QueueScriptCoordinator::EnqueueScript(NZBInfo* pNZBInfo, EEvent eEvent)
return;
}
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
for (ScriptConfig::Scripts::iterator it = g_pScriptConfig->GetScripts()->begin(); it != g_pScriptConfig->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
ScriptConfig::Script* pScript = *it;
if (!pScript->GetQueueScript())
{
@@ -465,8 +410,31 @@ void QueueScriptCoordinator::EnqueueScript(NZBInfo* pNZBInfo, EEvent eEvent)
m_mutexQueue.Unlock();
}
NZBInfo* QueueScriptCoordinator::FindNZBInfo(DownloadQueue* pDownloadQueue, int iNZBID)
{
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(iNZBID);
if (!pNZBInfo)
{
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetNZBInfo() && pHistoryInfo->GetNZBInfo()->GetID() == iNZBID)
{
pNZBInfo = pHistoryInfo->GetNZBInfo();
break;
}
}
}
return pNZBInfo;
}
void QueueScriptCoordinator::CheckQueue()
{
if (m_bStopped)
{
return;
}
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
m_mutexQueue.Lock();
@@ -480,10 +448,11 @@ void QueueScriptCoordinator::CheckQueue()
{
QueueItem* pQueueItem = *it;
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(pQueueItem->GetNZBID());
NZBInfo* pNZBInfo = FindNZBInfo(pDownloadQueue, pQueueItem->GetNZBID());
// in a case this nzb must not be processed further - delete queue script from queue
if (!pNZBInfo || pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone ||
if (!pNZBInfo ||
(pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone && pQueueItem->GetEvent() != qeNzbDeleted) ||
pNZBInfo->GetMarkStatus() == NZBInfo::ksBad)
{
delete pQueueItem;
@@ -517,10 +486,14 @@ void QueueScriptCoordinator::StartScript(NZBInfo* pNZBInfo, QueueItem* pQueueIte
QueueScriptController::StartScript(pNZBInfo, pQueueItem->GetScript(), pQueueItem->GetEvent());
}
bool QueueScriptCoordinator::HasJob(int iNZBID)
bool QueueScriptCoordinator::HasJob(int iNZBID, bool* pActive)
{
m_mutexQueue.Lock();
bool bWorking = m_pCurItem && m_pCurItem->GetNZBID() == iNZBID;
if (pActive)
{
*pActive = bWorking;
}
if (!bWorking)
{
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); it++)
@@ -537,3 +510,16 @@ bool QueueScriptCoordinator::HasJob(int iNZBID)
return bWorking;
}
int QueueScriptCoordinator::GetQueueSize()
{
m_mutexQueue.Lock();
int iQueuedCount = m_Queue.size();
if (m_pCurItem)
{
iQueuedCount++;
}
m_mutexQueue.Unlock();
return iQueuedCount;
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,19 +28,8 @@
#include <list>
#include "Script.h"
#include "Thread.h"
#include "DownloadInfo.h"
#include "Options.h"
class NZBScriptController : public ScriptController
{
protected:
void PrepareEnvParameters(NZBParameterList* pParameters, const char* szStripPrefix);
void PrepareEnvScript(NZBParameterList* pParameters, const char* szScriptName);
void ExecuteScriptList(const char* szScriptList);
virtual void ExecuteScript(Options::Script* pScript) = 0;
};
#include "ScriptConfig.h"
class QueueScriptCoordinator
{
@@ -48,8 +37,10 @@ public:
enum EEvent
{
qeFileDownloaded, // lowest priority
qeUrlCompleted,
qeNzbAdded,
qeNzbDownloaded // highest priority
qeNzbDownloaded,
qeNzbDeleted // highest priority
};
private:
@@ -57,12 +48,12 @@ private:
{
private:
int m_iNZBID;
Options::Script* m_pScript;
ScriptConfig::Script* m_pScript;
EEvent m_eEvent;
public:
QueueItem(int iNZBID, Options::Script* pScript, EEvent eEvent);
QueueItem(int iNZBID, ScriptConfig::Script* pScript, EEvent eEvent);
int GetNZBID() { return m_iNZBID; }
Options::Script* GetScript() { return m_pScript; }
ScriptConfig::Script* GetScript() { return m_pScript; }
EEvent GetEvent() { return m_eEvent; }
};
@@ -72,16 +63,22 @@ private:
Mutex m_mutexQueue;
QueueItem* m_pCurItem;
bool m_bHasQueueScripts;
bool m_bStopped;
void StartScript(NZBInfo* pNZBInfo, QueueItem* pQueueItem);
NZBInfo* FindNZBInfo(DownloadQueue* pDownloadQueue, int iNZBID);
public:
QueueScriptCoordinator();
~QueueScriptCoordinator();
void Stop() { m_bStopped = true; }
void InitOptions();
void EnqueueScript(NZBInfo* pNZBInfo, EEvent eEvent);
void CheckQueue();
bool HasJob(int iNZBID);
bool HasJob(int iNZBID, bool* pActive);
int GetQueueSize();
};
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
#endif

View File

@@ -0,0 +1,207 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdio.h>
#include "nzbget.h"
#include "ScanScript.h"
#include "Scanner.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
void ScanScriptController::ExecuteScripts(const char* szNZBFilename,
const char* szUrl, const char* szDirectory, char** pNZBName, char** pCategory,
int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode)
{
ScanScriptController* pScriptController = new ScanScriptController();
pScriptController->m_szNZBFilename = szNZBFilename;
pScriptController->m_szUrl = szUrl;
pScriptController->m_szDirectory = szDirectory;
pScriptController->m_pNZBName = pNZBName;
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameters = pParameters;
pScriptController->m_iPriority = iPriority;
pScriptController->m_bAddTop = bAddTop;
pScriptController->m_bAddPaused = bAddPaused;
pScriptController->m_pDupeKey = pDupeKey;
pScriptController->m_iDupeScore = iDupeScore;
pScriptController->m_eDupeMode = eDupeMode;
pScriptController->m_iPrefixLen = 0;
pScriptController->ExecuteScriptList(g_pOptions->GetScanScript());
delete pScriptController;
}
void ScanScriptController::ExecuteScript(ScriptConfig::Script* pScript)
{
if (!pScript->GetScanScript() || !Util::FileExists(m_szNZBFilename))
{
return;
}
PrintMessage(Message::mkInfo, "Executing scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void ScanScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetEnvVar("NZBNP_FILENAME", m_szNZBFilename);
SetEnvVar("NZBNP_URL", m_szUrl);
SetEnvVar("NZBNP_NZBNAME", strlen(*m_pNZBName) > 0 ? *m_pNZBName : Util::BaseFileName(m_szNZBFilename));
SetEnvVar("NZBNP_CATEGORY", *m_pCategory);
SetIntEnvVar("NZBNP_PRIORITY", *m_iPriority);
SetIntEnvVar("NZBNP_TOP", *m_bAddTop ? 1 : 0);
SetIntEnvVar("NZBNP_PAUSED", *m_bAddPaused ? 1 : 0);
SetEnvVar("NZBNP_DUPEKEY", *m_pDupeKey);
SetIntEnvVar("NZBNP_DUPESCORE", *m_iDupeScore);
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
SetEnvVar("NZBNP_DUPEMODE", szDupeModeName[*m_eDupeMode]);
// remove trailing slash
char szDir[1024];
strncpy(szDir, m_szDirectory, 1024);
szDir[1024-1] = '\0';
int iLen = strlen(szDir);
if (szDir[iLen-1] == PATH_SEPARATOR)
{
szDir[iLen-1] = '\0';
}
SetEnvVar("NZBNP_DIRECTORY", szDir);
PrepareEnvScript(m_pParameters, szScriptName);
}
void ScanScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "NZBNAME=", 8))
{
free(*m_pNZBName);
*m_pNZBName = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "CATEGORY=", 9))
{
free(*m_pCategory);
*m_pCategory = strdup(szMsgText + 6 + 9);
g_pScanner->InitPPParameters(*m_pCategory, m_pParameters, true);
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
m_pParameters->SetParameter(szParam, szValue + 1);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szMsgText + 6 + 9);
}
else if (!strncmp(szMsgText + 6, "TOP=", 4))
{
*m_bAddTop = atoi(szMsgText + 6 + 4) != 0;
}
else if (!strncmp(szMsgText + 6, "PAUSED=", 7))
{
*m_bAddPaused = atoi(szMsgText + 6 + 7) != 0;
}
else if (!strncmp(szMsgText + 6, "DUPEKEY=", 8))
{
free(*m_pDupeKey);
*m_pDupeKey = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "DUPESCORE=", 10))
{
*m_iDupeScore = atoi(szMsgText + 6 + 10);
}
else if (!strncmp(szMsgText + 6, "DUPEMODE=", 9))
{
const char* szDupeMode = szMsgText + 6 + 9;
if (strcasecmp(szDupeMode, "score") && strcasecmp(szDupeMode, "all") && strcasecmp(szDupeMode, "force"))
{
error("Invalid value \"%s\" for command \"DUPEMODE\" received from %s", szDupeMode, GetInfoName());
return;
}
*m_eDupeMode = !strcasecmp(szDupeMode, "all") ? dmAll :
!strcasecmp(szDupeMode, "force") ? dmForce : dmScore;
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, szText);
}
}

View File

@@ -0,0 +1,61 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef SCANSCRIPT_H
#define SCANSCRIPT_H
#include "NzbScript.h"
class ScanScriptController : public NZBScriptController
{
private:
const char* m_szNZBFilename;
const char* m_szUrl;
const char* m_szDirectory;
char** m_pNZBName;
char** m_pCategory;
int* m_iPriority;
NZBParameterList* m_pParameters;
bool* m_bAddTop;
bool* m_bAddPaused;
char** m_pDupeKey;
int* m_iDupeScore;
EDupeMode* m_eDupeMode;
int m_iPrefixLen;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(ScriptConfig::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
static void ExecuteScripts(const char* szNZBFilename, const char* szUrl,
const char* szDirectory, char** pNZBName, char** pCategory, int* iPriority,
NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode);
};
#endif

View File

@@ -0,0 +1,143 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdio.h>
#include "nzbget.h"
#include "SchedulerScript.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
SchedulerScriptController::~SchedulerScriptController()
{
free(m_szScript);
}
void SchedulerScriptController::StartScript(const char* szParam, bool bExternalProcess, int iTaskID)
{
char** argv = NULL;
if (bExternalProcess && !Util::SplitCommandLine(szParam, &argv))
{
error("Could not execute scheduled process-script, failed to parse command line: %s", szParam);
return;
}
SchedulerScriptController* pScriptController = new SchedulerScriptController();
pScriptController->m_bExternalProcess = bExternalProcess;
pScriptController->m_szScript = strdup(szParam);
pScriptController->m_iTaskID = iTaskID;
if (bExternalProcess)
{
pScriptController->SetScript(argv[0]);
pScriptController->SetArgs((const char**)argv, true);
}
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
}
void SchedulerScriptController::Run()
{
if (m_bExternalProcess)
{
ExecuteExternalProcess();
}
else
{
ExecuteScriptList(m_szScript);
}
}
void SchedulerScriptController::ExecuteScript(ScriptConfig::Script* pScript)
{
if (!pScript->GetSchedulerScript())
{
return;
}
PrintMessage(Message::mkInfo, "Executing scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void SchedulerScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetIntEnvVar("NZBSP_TASKID", m_iTaskID);
PrepareEnvScript(NULL, szScriptName);
}
void SchedulerScriptController::ExecuteExternalProcess()
{
info("Executing scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
SetLogPrefix(szLogPrefix);
Execute();
}

View File

@@ -0,0 +1,50 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef SCHEDULERSCRIPT_H
#define SCHEDULERSCRIPT_H
#include "NzbScript.h"
class SchedulerScriptController : public Thread, public NZBScriptController
{
private:
char* m_szScript;
bool m_bExternalProcess;
int m_iTaskID;
void PrepareParams(const char* szScriptName);
void ExecuteExternalProcess();
protected:
virtual void ExecuteScript(ScriptConfig::Script* pScript);
public:
virtual ~SchedulerScriptController();
virtual void Run();
static void StartScript(const char* szParam, bool bExternalProcess, int iTaskID);
};
#endif

View File

@@ -0,0 +1,559 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#include <set>
#include "nzbget.h"
#include "Util.h"
#include "Options.h"
#include "Log.h"
#include "ScriptConfig.h"
static const char* BEGIN_SCRIPT_SIGNATURE = "### NZBGET ";
static const char* POST_SCRIPT_SIGNATURE = "POST-PROCESSING";
static const char* SCAN_SCRIPT_SIGNATURE = "SCAN";
static const char* QUEUE_SCRIPT_SIGNATURE = "QUEUE";
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* g_pScriptConfig = NULL;
ScriptConfig::ConfigTemplate::ConfigTemplate(Script* pScript, const char* szTemplate)
{
m_pScript = pScript;
m_szTemplate = strdup(szTemplate ? szTemplate : "");
}
ScriptConfig::ConfigTemplate::~ConfigTemplate()
{
delete m_pScript;
free(m_szTemplate);
}
ScriptConfig::ConfigTemplates::~ConfigTemplates()
{
for (iterator it = begin(); it != end(); it++)
{
delete *it;
}
}
ScriptConfig::Script::Script(const char* szName, const char* szLocation)
{
m_szName = strdup(szName);
m_szLocation = strdup(szLocation);
m_szDisplayName = strdup(szName);
m_bPostScript = false;
m_bScanScript = false;
m_bQueueScript = false;
m_bSchedulerScript = false;
m_bFeedScript = false;
m_szQueueEvents = NULL;
}
ScriptConfig::Script::~Script()
{
free(m_szName);
free(m_szLocation);
free(m_szDisplayName);
free(m_szQueueEvents);
}
void ScriptConfig::Script::SetDisplayName(const char* szDisplayName)
{
free(m_szDisplayName);
m_szDisplayName = strdup(szDisplayName);
}
void ScriptConfig::Script::SetQueueEvents(const char* szQueueEvents)
{
free(m_szQueueEvents);
m_szQueueEvents = szQueueEvents ? strdup(szQueueEvents) : NULL;
}
ScriptConfig::Scripts::~Scripts()
{
Clear();
}
void ScriptConfig::Scripts::Clear()
{
for (iterator it = begin(); it != end(); it++)
{
delete *it;
}
clear();
}
ScriptConfig::Script* ScriptConfig::Scripts::Find(const char* szName)
{
for (iterator it = begin(); it != end(); it++)
{
Script* pScript = *it;
if (!strcmp(pScript->GetName(), szName))
{
return pScript;
}
}
return NULL;
}
ScriptConfig::ScriptConfig()
{
InitScripts();
InitConfigTemplates();
}
ScriptConfig::~ScriptConfig()
{
}
bool ScriptConfig::LoadConfig(Options::OptEntries* pOptEntries)
{
// read config file
FILE* infile = fopen(g_pOptions->GetConfigFilename(), FOPEN_RB);
if (!infile)
{
return false;
}
int iBufLen = (int)Util::FileSize(g_pOptions->GetConfigFilename()) + 1;
char* buf = (char*)malloc(iBufLen);
while (fgets(buf, iBufLen - 1, infile))
{
// remove trailing '\n' and '\r' and spaces
Util::TrimRight(buf);
// skip comments and empty lines
if (buf[0] == 0 || buf[0] == '#' || strspn(buf, " ") == strlen(buf))
{
continue;
}
char* optname;
char* optvalue;
if (g_pOptions->SplitOptionString(buf, &optname, &optvalue))
{
Options::OptEntry* pOptEntry = new Options::OptEntry();
pOptEntry->SetName(optname);
pOptEntry->SetValue(optvalue);
pOptEntries->push_back(pOptEntry);
free(optname);
free(optvalue);
}
}
fclose(infile);
free(buf);
return true;
}
bool ScriptConfig::SaveConfig(Options::OptEntries* pOptEntries)
{
// save to config file
FILE* infile = fopen(g_pOptions->GetConfigFilename(), FOPEN_RBP);
if (!infile)
{
return false;
}
std::vector<char*> config;
std::set<Options::OptEntry*> writtenOptions;
// read config file into memory array
int iBufLen = (int)Util::FileSize(g_pOptions->GetConfigFilename()) + 1;
char* buf = (char*)malloc(iBufLen);
while (fgets(buf, iBufLen - 1, infile))
{
config.push_back(strdup(buf));
}
free(buf);
// write config file back to disk, replace old values of existing options with new values
rewind(infile);
for (std::vector<char*>::iterator it = config.begin(); it != config.end(); it++)
{
char* buf = *it;
const char* eq = strchr(buf, '=');
if (eq && buf[0] != '#')
{
// remove trailing '\n' and '\r' and spaces
Util::TrimRight(buf);
char* optname;
char* optvalue;
if (g_pOptions->SplitOptionString(buf, &optname, &optvalue))
{
Options::OptEntry *pOptEntry = pOptEntries->FindOption(optname);
if (pOptEntry)
{
fputs(pOptEntry->GetName(), infile);
fputs("=", infile);
fputs(pOptEntry->GetValue(), infile);
fputs("\n", infile);
writtenOptions.insert(pOptEntry);
}
free(optname);
free(optvalue);
}
}
else
{
fputs(buf, infile);
}
free(buf);
}
// write new options
for (Options::OptEntries::iterator it = pOptEntries->begin(); it != pOptEntries->end(); it++)
{
Options::OptEntry* pOptEntry = *it;
std::set<Options::OptEntry*>::iterator fit = writtenOptions.find(pOptEntry);
if (fit == writtenOptions.end())
{
fputs(pOptEntry->GetName(), infile);
fputs("=", infile);
fputs(pOptEntry->GetValue(), infile);
fputs("\n", infile);
}
}
// close and truncate the file
int pos = (int)ftell(infile);
fclose(infile);
Util::TruncateFile(g_pOptions->GetConfigFilename(), pos);
return true;
}
bool ScriptConfig::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
{
char* szBuffer;
int iLength;
if (!Util::LoadFileIntoBuffer(g_pOptions->GetConfigTemplate(), &szBuffer, &iLength))
{
return false;
}
ConfigTemplate* pConfigTemplate = new ConfigTemplate(NULL, szBuffer);
pConfigTemplates->push_back(pConfigTemplate);
free(szBuffer);
if (!g_pOptions->GetScriptDir())
{
return true;
}
Scripts scriptList;
LoadScripts(&scriptList);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
const int iQueueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
for (Scripts::iterator it = scriptList.begin(); it != scriptList.end(); it++)
{
Script* pScript = *it;
FILE* infile = fopen(pScript->GetLocation(), FOPEN_RB);
if (!infile)
{
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript, "");
pConfigTemplates->push_back(pConfigTemplate);
continue;
}
StringBuilder stringBuilder;
char buf[1024];
bool bInConfig = false;
while (fgets(buf, sizeof(buf) - 1, infile))
{
if (!strncmp(buf, BEGIN_SCRIPT_SIGNATURE, iBeginSignatureLen) &&
strstr(buf, END_SCRIPT_SIGNATURE) &&
(strstr(buf, POST_SCRIPT_SIGNATURE) ||
strstr(buf, SCAN_SCRIPT_SIGNATURE) ||
strstr(buf, QUEUE_SCRIPT_SIGNATURE) ||
strstr(buf, SCHEDULER_SCRIPT_SIGNATURE) ||
strstr(buf, FEED_SCRIPT_SIGNATURE)))
{
if (bInConfig)
{
break;
}
bInConfig = true;
continue;
}
bool bSkip = !strncmp(buf, QUEUE_EVENTS_SIGNATURE, iQueueEventsSignatureLen);
if (bInConfig && !bSkip)
{
stringBuilder.Append(buf);
}
}
fclose(infile);
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript, stringBuilder.GetBuffer());
pConfigTemplates->push_back(pConfigTemplate);
}
// clearing the list without deleting of objects, which are in pConfigTemplates now
scriptList.clear();
return true;
}
void ScriptConfig::InitConfigTemplates()
{
if (!LoadConfigTemplates(&m_ConfigTemplates))
{
error("Could not read configuration templates");
}
}
void ScriptConfig::InitScripts()
{
LoadScripts(&m_Scripts);
}
void ScriptConfig::LoadScripts(Scripts* pScripts)
{
if (strlen(g_pOptions->GetScriptDir()) == 0)
{
return;
}
Scripts tmpScripts;
LoadScriptDir(&tmpScripts, g_pOptions->GetScriptDir(), false);
tmpScripts.sort(CompareScripts);
// first add all scripts from m_szScriptOrder
Tokenizer tok(g_pOptions->GetScriptOrder(), ",;");
while (const char* szScriptName = tok.Next())
{
Script* pScript = tmpScripts.Find(szScriptName);
if (pScript)
{
tmpScripts.remove(pScript);
pScripts->push_back(pScript);
}
}
// second add all other scripts from scripts directory
for (Scripts::iterator it = tmpScripts.begin(); it != tmpScripts.end(); it++)
{
Script* pScript = *it;
if (!pScripts->Find(pScript->GetName()))
{
pScripts->push_back(pScript);
}
}
tmpScripts.clear();
BuildScriptDisplayNames(pScripts);
}
void ScriptConfig::LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIsSubDir)
{
int iBufSize = 1024*10;
char* szBuffer = (char*)malloc(iBufSize+1);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
const int iQueueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
DirBrowser dir(szDirectory);
while (const char* szFilename = dir.Next())
{
if (szFilename[0] != '.' && szFilename[0] != '_')
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%s", szDirectory, szFilename);
szFullFilename[1024-1] = '\0';
if (!Util::DirectoryExists(szFullFilename))
{
// check if the file contains pp-script-signature
FILE* infile = fopen(szFullFilename, FOPEN_RB);
if (infile)
{
// read first 10KB of the file and look for signature
int iReadBytes = fread(szBuffer, 1, iBufSize, infile);
fclose(infile);
szBuffer[iReadBytes] = 0;
// split buffer into lines
Tokenizer tok(szBuffer, "\n\r", true);
while (char* szLine = tok.Next())
{
if (!strncmp(szLine, BEGIN_SCRIPT_SIGNATURE, iBeginSignatureLen) &&
strstr(szLine, END_SCRIPT_SIGNATURE))
{
bool bPostScript = strstr(szLine, POST_SCRIPT_SIGNATURE);
bool bScanScript = strstr(szLine, SCAN_SCRIPT_SIGNATURE);
bool bQueueScript = strstr(szLine, QUEUE_SCRIPT_SIGNATURE);
bool bSchedulerScript = strstr(szLine, SCHEDULER_SCRIPT_SIGNATURE);
bool bFeedScript = strstr(szLine, FEED_SCRIPT_SIGNATURE);
if (bPostScript || bScanScript || bQueueScript || bSchedulerScript || bFeedScript)
{
char szScriptName[1024];
if (bIsSubDir)
{
char szDirectory2[1024];
snprintf(szDirectory2, 1024, "%s", szDirectory);
szDirectory2[1024-1] = '\0';
int iLen = strlen(szDirectory2);
if (szDirectory2[iLen-1] == PATH_SEPARATOR || szDirectory2[iLen-1] == ALT_PATH_SEPARATOR)
{
// trim last path-separator
szDirectory2[iLen-1] = '\0';
}
snprintf(szScriptName, 1024, "%s%c%s", Util::BaseFileName(szDirectory2), PATH_SEPARATOR, szFilename);
}
else
{
snprintf(szScriptName, 1024, "%s", szFilename);
}
szScriptName[1024-1] = '\0';
char* szQueueEvents = NULL;
if (bQueueScript)
{
while (char* szLine = tok.Next())
{
if (!strncmp(szLine, QUEUE_EVENTS_SIGNATURE, iQueueEventsSignatureLen))
{
szQueueEvents = szLine + iQueueEventsSignatureLen;
break;
}
}
}
Script* pScript = new Script(szScriptName, szFullFilename);
pScript->SetPostScript(bPostScript);
pScript->SetScanScript(bScanScript);
pScript->SetQueueScript(bQueueScript);
pScript->SetSchedulerScript(bSchedulerScript);
pScript->SetFeedScript(bFeedScript);
pScript->SetQueueEvents(szQueueEvents);
pScripts->push_back(pScript);
break;
}
}
}
}
}
else if (!bIsSubDir)
{
snprintf(szFullFilename, 1024, "%s%s%c", szDirectory, szFilename, PATH_SEPARATOR);
szFullFilename[1024-1] = '\0';
LoadScriptDir(pScripts, szFullFilename, true);
}
}
}
free(szBuffer);
}
bool ScriptConfig::CompareScripts(Script* pScript1, Script* pScript2)
{
return strcmp(pScript1->GetName(), pScript2->GetName()) < 0;
}
void ScriptConfig::BuildScriptDisplayNames(Scripts* pScripts)
{
// trying to use short name without path and extension.
// if there are other scripts with the same short name - using a longer name instead (with ot without extension)
for (Scripts::iterator it = pScripts->begin(); it != pScripts->end(); it++)
{
Script* pScript = *it;
char szShortName[256];
strncpy(szShortName, pScript->GetName(), 256);
szShortName[256-1] = '\0';
if (char* ext = strrchr(szShortName, '.')) *ext = '\0'; // strip file extension
const char* szDisplayName = Util::BaseFileName(szShortName);
for (Scripts::iterator it2 = pScripts->begin(); it2 != pScripts->end(); it2++)
{
Script* pScript2 = *it2;
char szShortName2[256];
strncpy(szShortName2, pScript2->GetName(), 256);
szShortName2[256-1] = '\0';
if (char* ext = strrchr(szShortName2, '.')) *ext = '\0'; // strip file extension
const char* szDisplayName2 = Util::BaseFileName(szShortName2);
if (!strcmp(szDisplayName, szDisplayName2) && pScript->GetName() != pScript2->GetName())
{
if (!strcmp(szShortName, szShortName2))
{
szDisplayName = pScript->GetName();
}
else
{
szDisplayName = szShortName;
}
break;
}
}
pScript->SetDisplayName(szDisplayName);
}
}

View File

@@ -0,0 +1,128 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef SCRIPTCONFIG_H
#define SCRIPTCONFIG_H
#include <vector>
#include <list>
#include <time.h>
#include "Options.h"
class ScriptConfig
{
public:
class Script
{
private:
char* m_szName;
char* m_szLocation;
char* m_szDisplayName;
bool m_bPostScript;
bool m_bScanScript;
bool m_bQueueScript;
bool m_bSchedulerScript;
bool m_bFeedScript;
char* m_szQueueEvents;
public:
Script(const char* szName, const char* szLocation);
~Script();
const char* GetName() { return m_szName; }
const char* GetLocation() { return m_szLocation; }
void SetDisplayName(const char* szDisplayName);
const char* GetDisplayName() { return m_szDisplayName; }
bool GetPostScript() { return m_bPostScript; }
void SetPostScript(bool bPostScript) { m_bPostScript = bPostScript; }
bool GetScanScript() { return m_bScanScript; }
void SetScanScript(bool bScanScript) { m_bScanScript = bScanScript; }
bool GetQueueScript() { return m_bQueueScript; }
void SetQueueScript(bool bQueueScript) { m_bQueueScript = bQueueScript; }
bool GetSchedulerScript() { return m_bSchedulerScript; }
void SetSchedulerScript(bool bSchedulerScript) { m_bSchedulerScript = bSchedulerScript; }
bool GetFeedScript() { return m_bFeedScript; }
void SetFeedScript(bool bFeedScript) { m_bFeedScript = bFeedScript; }
void SetQueueEvents(const char* szQueueEvents);
const char* GetQueueEvents() { return m_szQueueEvents; }
};
typedef std::list<Script*> ScriptsBase;
class Scripts: public ScriptsBase
{
public:
~Scripts();
void Clear();
Script* Find(const char* szName);
};
class ConfigTemplate
{
private:
Script* m_pScript;
char* m_szTemplate;
friend class Options;
public:
ConfigTemplate(Script* pScript, const char* szTemplate);
~ConfigTemplate();
Script* GetScript() { return m_pScript; }
const char* GetTemplate() { return m_szTemplate; }
};
typedef std::vector<ConfigTemplate*> ConfigTemplatesBase;
class ConfigTemplates: public ConfigTemplatesBase
{
public:
~ConfigTemplates();
};
private:
Scripts m_Scripts;
ConfigTemplates m_ConfigTemplates;
void InitScripts();
void InitConfigTemplates();
static bool CompareScripts(Script* pScript1, Script* pScript2);
void LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIsSubDir);
void BuildScriptDisplayNames(Scripts* pScripts);
void LoadScripts(Scripts* pScripts);
public:
ScriptConfig();
~ScriptConfig();
Scripts* GetScripts() { return &m_Scripts; }
bool LoadConfig(Options::OptEntries* pOptEntries);
bool SaveConfig(Options::OptEntries* pOptEntries);
bool LoadConfigTemplates(ConfigTemplates* pConfigTemplates);
ConfigTemplates* GetConfigTemplates() { return &m_ConfigTemplates; }
};
extern ScriptConfig* g_pScriptConfig;
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,10 +47,9 @@
#include "Util.h"
#include "FeedFile.h"
#include "FeedFilter.h"
#include "FeedScript.h"
#include "DiskState.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
#include "DupeCoordinator.h"
FeedCoordinator::FeedCacheItem::FeedCacheItem(const char* szUrl, int iCacheTimeSec,const char* szCacheId,
time_t tLastUsage, FeedItemInfos* pFeedItemInfos)
@@ -70,6 +69,42 @@ FeedCoordinator::FeedCacheItem::~FeedCacheItem()
m_pFeedItemInfos->Release();
}
FeedCoordinator::FilterHelper::FilterHelper()
{
m_pSeasonEpisodeRegEx = NULL;
}
FeedCoordinator::FilterHelper::~FilterHelper()
{
delete m_pSeasonEpisodeRegEx;
}
void FeedCoordinator::FilterHelper::CalcDupeStatus(const char* szTitle, const char* szDupeKey, char* szStatusBuf, int iBufLen)
{
const char* szDupeStatusName[] = { "", "QUEUED", "DOWNLOADING", "3", "SUCCESS", "5", "6", "7", "WARNING",
"9", "10", "11", "12", "13", "14", "15", "FAILURE" };
char szStatuses[200];
szStatuses[0] = '\0';
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DupeCoordinator::EDupeStatus eDupeStatus = g_pDupeCoordinator->GetDupeStatus(pDownloadQueue, szTitle, szDupeKey);
DownloadQueue::Unlock();
for (int i = 1; i <= (int)DupeCoordinator::dsFailure; i = i << 1)
{
if (eDupeStatus & i)
{
if (*szStatuses)
{
strcat(szStatuses, ",");
}
strcat(szStatuses, szDupeStatusName[i]);
}
}
strncpy(szStatusBuf, szStatuses, iBufLen);
}
FeedCoordinator::FeedCoordinator()
{
debug("Creating FeedCoordinator");
@@ -361,6 +396,9 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* pFeedDownloader)
{
if (!pFeedInfo->GetPreview())
{
FeedScriptController::ExecuteScripts(
!Util::EmptyStr(pFeedInfo->GetFeedScript()) ? pFeedInfo->GetFeedScript(): g_pOptions->GetFeedScript(),
pFeedInfo->GetOutputFilename(), pFeedInfo->GetID());
FeedFile* pFeedFile = FeedFile::Create(pFeedInfo->GetOutputFilename());
remove(pFeedInfo->GetOutputFilename());
@@ -414,6 +452,7 @@ void FeedCoordinator::FilterFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemIn
pFeedItemInfo->SetAddCategory(pFeedInfo->GetCategory());
pFeedItemInfo->SetDupeScore(0);
pFeedItemInfo->SetDupeMode(dmScore);
pFeedItemInfo->SetFeedFilterHelper(&m_FilterHelper);
pFeedItemInfo->BuildDupeKey(NULL, NULL);
if (pFeedFilter)
{
@@ -440,7 +479,7 @@ void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemI
{
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pFeedItemInfo->GetUrl());
FeedHistoryInfo::EStatus eStatus = FeedHistoryInfo::hsUnknown;
if (bFirstFetch)
if (bFirstFetch && pFeedInfo->GetBacklog())
{
eStatus = FeedHistoryInfo::hsBacklog;
}
@@ -479,6 +518,7 @@ NZBInfo* FeedCoordinator::CreateNZBInfo(FeedInfo* pFeedInfo, FeedItemInfo* pFeed
NZBInfo* pNZBInfo = new NZBInfo();
pNZBInfo->SetKind(NZBInfo::nkUrl);
pNZBInfo->SetFeedID(pFeedInfo->GetID());
pNZBInfo->SetURL(pFeedItemInfo->GetUrl());
// add .nzb-extension if not present
@@ -517,18 +557,19 @@ bool FeedCoordinator::ViewFeed(int iID, FeedItemInfos** ppFeedItemInfos)
FeedInfo* pFeedInfo = m_Feeds.at(iID - 1);
return PreviewFeed(pFeedInfo->GetName(), pFeedInfo->GetUrl(), pFeedInfo->GetFilter(),
pFeedInfo->GetPauseNzb(), pFeedInfo->GetCategory(), pFeedInfo->GetPriority(),
0, NULL, ppFeedItemInfos);
return PreviewFeed(pFeedInfo->GetID(), pFeedInfo->GetName(), pFeedInfo->GetUrl(), pFeedInfo->GetFilter(),
pFeedInfo->GetBacklog(), pFeedInfo->GetPauseNzb(), pFeedInfo->GetCategory(),
pFeedInfo->GetPriority(), pFeedInfo->GetInterval(), pFeedInfo->GetFeedScript(), 0, NULL, ppFeedItemInfos);
}
bool FeedCoordinator::PreviewFeed(const char* szName, const char* szUrl, const char* szFilter,
bool bPauseNzb, const char* szCategory, int iPriority,
bool FeedCoordinator::PreviewFeed(int iID, const char* szName, const char* szUrl, const char* szFilter,
bool bBacklog, bool bPauseNzb, const char* szCategory, int iPriority, int iInterval, const char* szFeedScript,
int iCacheTimeSec, const char* szCacheId, FeedItemInfos** ppFeedItemInfos)
{
debug("Preview feed %s", szName);
FeedInfo* pFeedInfo = new FeedInfo(0, szName, szUrl, 0, szFilter, bPauseNzb, szCategory, iPriority);
FeedInfo* pFeedInfo = new FeedInfo(iID, szName, szUrl, bBacklog, iInterval,
szFilter, bPauseNzb, szCategory, iPriority, szFeedScript);
pFeedInfo->SetPreview(true);
FeedItemInfos* pFeedItemInfos = NULL;
@@ -583,6 +624,9 @@ bool FeedCoordinator::PreviewFeed(const char* szName, const char* szUrl, const c
if (pFeedInfo->GetStatus() == FeedInfo::fsFinished)
{
FeedScriptController::ExecuteScripts(
!Util::EmptyStr(pFeedInfo->GetFeedScript()) ? pFeedInfo->GetFeedScript(): g_pOptions->GetFeedScript(),
pFeedInfo->GetOutputFilename(), pFeedInfo->GetID());
pFeedFile = FeedFile::Create(pFeedInfo->GetOutputFilename());
}
@@ -601,7 +645,7 @@ bool FeedCoordinator::PreviewFeed(const char* szName, const char* szUrl, const c
for (FeedItemInfos::iterator it = pFeedItemInfos->begin(); it != pFeedItemInfos->end(); it++)
{
FeedItemInfo* pFeedItemInfo = *it;
pFeedItemInfo->SetStatus(bFirstFetch ? FeedItemInfo::isBacklog : FeedItemInfo::isNew);
pFeedItemInfo->SetStatus(bFirstFetch && pFeedInfo->GetBacklog() ? FeedItemInfo::isBacklog : FeedItemInfo::isNew);
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pFeedItemInfo->GetUrl());
if (pFeedHistoryInfo)
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@
#include "DownloadInfo.h"
#include "FeedInfo.h"
#include "Observer.h"
#include "Util.h"
class FeedDownloader;
@@ -71,6 +72,17 @@ private:
FeedItemInfos* GetFeedItemInfos() { return m_pFeedItemInfos; }
};
class FilterHelper : public FeedFilterHelper
{
private:
RegEx* m_pSeasonEpisodeRegEx;
public:
FilterHelper();
~FilterHelper();
virtual RegEx** GetSeasonEpisodeRegEx() { return &m_pSeasonEpisodeRegEx; };
virtual void CalcDupeStatus(const char* szTitle, const char* szDupeKey, char* szStatusBuf, int iBufLen);
};
typedef std::deque<FeedCacheItem*> FeedCache;
typedef std::list<FeedDownloader*> ActiveDownloads;
@@ -83,6 +95,7 @@ private:
bool m_bForce;
bool m_bSave;
FeedCache m_FeedCache;
FilterHelper m_FilterHelper;
void StartFeedDownload(FeedInfo* pFeedInfo, bool bForce);
void FeedCompleted(FeedDownloader* pFeedDownloader);
@@ -105,8 +118,8 @@ public:
virtual void Stop();
void Update(Subject* pCaller, void* pAspect);
void AddFeed(FeedInfo* pFeedInfo);
bool PreviewFeed(const char* szName, const char* szUrl, const char* szFilter,
bool bPauseNzb, const char* szCategory, int iPriority,
bool PreviewFeed(int iID, const char* szName, const char* szUrl, const char* szFilter, bool bBacklog,
bool bPauseNzb, const char* szCategory, int iPriority, int iInterval, const char* szFeedScript,
int iCacheTimeSec, const char* szCacheId, FeedItemInfos** ppFeedItemInfos);
bool ViewFeed(int iID, FeedItemInfos** ppFeedItemInfos);
void FetchFeed(int iID);
@@ -114,6 +127,8 @@ public:
Feeds* GetFeeds() { return &m_Feeds; }
};
extern FeedCoordinator* g_pFeedCoordinator;
class FeedDownloader : public WebDownloader
{
private:

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,8 +51,6 @@ using namespace MSXML;
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
FeedFile::FeedFile(const char* szFileName)
{
debug("Creating FeedFile");
@@ -246,7 +244,13 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
if (tag)
{
_bstr_t description(tag->Gettext());
pFeedItemInfo->SetDescription(description);
// cleanup CDATA
char* szDescription = strdup((const char*)description);
WebUtil::XmlStripTags(szDescription);
WebUtil::XmlDecode(szDescription);
WebUtil::XmlRemoveEntities(szDescription);
pFeedItemInfo->SetDescription(szDescription);
free(szDescription);
}
//<enclosure url="http://myindexer.com/fetch/9eeb264aecce961a6e0d" length="150263340" type="application/x-nzb" />
@@ -494,7 +498,13 @@ void FeedFile::Parse_EndElement(const char *name)
}
else if (!strcmp("description", name) && m_pFeedItemInfo)
{
m_pFeedItemInfo->SetDescription(m_szTagContent);
// cleanup CDATA
char* szDescription = strdup(m_szTagContent);
WebUtil::XmlStripTags(szDescription);
WebUtil::XmlDecode(szDescription);
WebUtil::XmlRemoveEntities(szDescription);
m_pFeedItemInfo->SetDescription(szDescription);
free(szDescription);
ResetTagContent();
}
else if (!strcmp("pubDate", name) && m_pFeedItemInfo)

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,21 +39,20 @@
#include "nzbget.h"
#include "FeedInfo.h"
#include "DupeCoordinator.h"
#include "Util.h"
extern DupeCoordinator* g_pDupeCoordinator;
FeedInfo::FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval,
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority)
FeedInfo::FeedInfo(int iID, const char* szName, const char* szUrl, bool bBacklog, int iInterval,
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority, const char* szFeedScript)
{
m_iID = iID;
m_szName = strdup(szName ? szName : "");
m_szUrl = strdup(szUrl ? szUrl : "");
m_szFilter = strdup(szFilter ? szFilter : "");
m_bBacklog = bBacklog;
m_iFilterHash = Util::HashBJ96(m_szFilter, strlen(m_szFilter), 0);
m_szCategory = strdup(szCategory ? szCategory : "");
m_iInterval = iInterval;
m_szFeedScript = strdup(szFeedScript ? szFeedScript : "");
m_bPauseNzb = bPauseNzb;
m_iPriority = iPriority;
m_tLastUpdate = 0;
@@ -71,6 +70,7 @@ FeedInfo::~FeedInfo()
free(m_szFilter);
free(m_szCategory);
free(m_szOutputFilename);
free(m_szFeedScript);
}
void FeedInfo::SetOutputFilename(const char* szOutputFilename)
@@ -123,7 +123,7 @@ FeedItemInfo::Attr* FeedItemInfo::Attributes::Find(const char* szName)
FeedItemInfo::FeedItemInfo()
{
m_pSharedFeedData = NULL;
m_pFeedFilterHelper = NULL;
m_szTitle = NULL;
m_szFilename = NULL;
m_szUrl = NULL;
@@ -300,20 +300,24 @@ void FeedItemInfo::ParseSeasonEpisode()
{
m_bSeasonEpisodeParsed = true;
RegEx* pRegEx = m_pSharedFeedData->GetSeasonEpisodeRegEx();
RegEx** ppRegEx = m_pFeedFilterHelper->GetSeasonEpisodeRegEx();
if (!*ppRegEx)
{
*ppRegEx = new RegEx("[^[:alnum:]]s?([0-9]+)[ex]([0-9]+(-?e[0-9]+)?)[^[:alnum:]]", 10);
}
if (pRegEx->Match(m_szTitle))
if ((*ppRegEx)->Match(m_szTitle))
{
char szRegValue[100];
char szValue[100];
snprintf(szValue, 100, "S%02d", atoi(m_szTitle + pRegEx->GetMatchStart(1)));
snprintf(szValue, 100, "S%02d", atoi(m_szTitle + (*ppRegEx)->GetMatchStart(1)));
szValue[100-1] = '\0';
SetSeason(szValue);
int iLen = pRegEx->GetMatchLen(2);
int iLen = (*ppRegEx)->GetMatchLen(2);
iLen = iLen < 99 ? iLen : 99;
strncpy(szRegValue, m_szTitle + pRegEx->GetMatchStart(2), pRegEx->GetMatchLen(2));
strncpy(szRegValue, m_szTitle + (*ppRegEx)->GetMatchStart(2), (*ppRegEx)->GetMatchLen(2));
szRegValue[iLen] = '\0';
snprintf(szValue, 100, "E%s", szRegValue);
szValue[100-1] = '\0';
@@ -327,27 +331,9 @@ const char* FeedItemInfo::GetDupeStatus()
{
if (!m_szDupeStatus)
{
const char* szDupeStatusName[] = { "", "QUEUED", "DOWNLOADING", "3", "SUCCESS", "5", "6", "7", "WARNING",
"9", "10", "11", "12", "13", "14", "15", "FAILURE" };
char szStatuses[200];
szStatuses[0] = '\0';
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DupeCoordinator::EDupeStatus eDupeStatus = g_pDupeCoordinator->GetDupeStatus(pDownloadQueue, m_szTitle, m_szDupeKey);
DownloadQueue::Unlock();
for (int i = 1; i <= (int)DupeCoordinator::dsFailure; i = i << 1)
{
if (eDupeStatus & i)
{
if (*szStatuses)
{
strcat(szStatuses, ",");
}
strcat(szStatuses, szDupeStatusName[i]);
}
}
m_pFeedFilterHelper->CalcDupeStatus(m_szTitle, m_szDupeKey, szStatuses, sizeof(szStatuses));
m_szDupeStatus = strdup(szStatuses);
}
@@ -450,26 +436,4 @@ void FeedItemInfos::Release()
void FeedItemInfos::Add(FeedItemInfo* pFeedItemInfo)
{
push_back(pFeedItemInfo);
pFeedItemInfo->SetSharedFeedData(&m_SharedFeedData);
}
SharedFeedData::SharedFeedData()
{
m_pSeasonEpisodeRegEx = NULL;
}
SharedFeedData::~SharedFeedData()
{
delete m_pSeasonEpisodeRegEx;
}
RegEx* SharedFeedData::GetSeasonEpisodeRegEx()
{
if (!m_pSeasonEpisodeRegEx)
{
m_pSeasonEpisodeRegEx = new RegEx("[^[:alnum:]]s?([0-9]+)[ex]([0-9]+(-?e[0-9]+)?)[^[:alnum:]]", 10);
}
return m_pSeasonEpisodeRegEx;
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,6 +53,7 @@ private:
unsigned int m_iFilterHash;
bool m_bPauseNzb;
char* m_szCategory;
char* m_szFeedScript;
int m_iPriority;
time_t m_tLastUpdate;
bool m_bPreview;
@@ -60,10 +61,12 @@ private:
char* m_szOutputFilename;
bool m_bFetch;
bool m_bForce;
bool m_bBacklog;
public:
FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval,
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority);
FeedInfo(int iID, const char* szName, const char* szUrl, bool bBacklog, int iInterval,
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority,
const char* szFeedScript);
~FeedInfo();
int GetID() { return m_iID; }
const char* GetName() { return m_szName; }
@@ -74,6 +77,7 @@ public:
bool GetPauseNzb() { return m_bPauseNzb; }
const char* GetCategory() { return m_szCategory; }
int GetPriority() { return m_iPriority; }
const char* GetFeedScript() { return m_szFeedScript; }
time_t GetLastUpdate() { return m_tLastUpdate; }
void SetLastUpdate(time_t tLastUpdate) { m_tLastUpdate = tLastUpdate; }
bool GetPreview() { return m_bPreview; }
@@ -86,19 +90,17 @@ public:
void SetFetch(bool bFetch) { m_bFetch = bFetch; }
bool GetForce() { return m_bForce; }
void SetForce(bool bForce) { m_bForce = bForce; }
bool GetBacklog() { return m_bBacklog; }
void SetBacklog(bool bBacklog) { m_bBacklog = bBacklog; }
};
typedef std::deque<FeedInfo*> Feeds;
class SharedFeedData
class FeedFilterHelper
{
private:
RegEx* m_pSeasonEpisodeRegEx;
public:
SharedFeedData();
~SharedFeedData();
RegEx* GetSeasonEpisodeRegEx();
virtual RegEx** GetSeasonEpisodeRegEx() = 0;
virtual void CalcDupeStatus(const char* szTitle, const char* szDupeKey, char* szStatusBuf, int iBufLen) = 0;
};
class FeedItemInfo
@@ -166,7 +168,7 @@ private:
int m_iDupeScore;
EDupeMode m_eDupeMode;
char* m_szDupeStatus;
SharedFeedData* m_pSharedFeedData;
FeedFilterHelper* m_pFeedFilterHelper;
Attributes m_Attributes;
int ParsePrefixedInt(const char *szValue);
@@ -175,7 +177,7 @@ private:
public:
FeedItemInfo();
~FeedItemInfo();
void SetSharedFeedData(SharedFeedData* pSharedFeedData) { m_pSharedFeedData = pSharedFeedData; }
void SetFeedFilterHelper(FeedFilterHelper* pFeedFilterHelper) { m_pFeedFilterHelper = pFeedFilterHelper; }
const char* GetTitle() { return m_szTitle; }
void SetTitle(const char* szTitle);
const char* GetFilename() { return m_szFilename; }
@@ -230,7 +232,6 @@ class FeedItemInfos : public FeedItemInfosBase
{
private:
int m_iRefCount;
SharedFeedData m_SharedFeedData;
public:
FeedItemInfos();

View File

@@ -88,7 +88,7 @@ void ColoredFrontend::PrintStatus()
char szDownloadLimit[128];
if (m_iDownloadLimit > 0)
{
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
sprintf(szDownloadLimit, ", Limit %i KB/s", m_iDownloadLimit / 1024);
}
else
{
@@ -112,10 +112,12 @@ void ColoredFrontend::PrintStatus()
const char* szControlSeq = "\033[K";
#endif
snprintf(tmp, 1024, " %d threads, %.*f KB/s, %.2f MB remaining%s%s%s%s%s\n",
m_iThreadCount, (iCurrentDownloadSpeed >= 10*1024 ? 0 : 1), (float)iCurrentDownloadSpeed / 1024.0,
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
char szFileSize[20];
char szCurrendSpeed[20];
snprintf(tmp, 1024, " %d threads, %s, %s remaining%s%s%s%s%s\n",
m_iThreadCount, Util::FormatSpeed(szCurrendSpeed, sizeof(szCurrendSpeed), iCurrentDownloadSpeed),
Util::FormatSize(szFileSize, sizeof(szFileSize), m_lRemainingSize),
timeString, szPostStatus, m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
szDownloadLimit, szControlSeq);
tmp[1024-1] = '\0';
printf("%s", tmp);

View File

@@ -51,9 +51,6 @@
#include "Util.h"
#include "StatMeter.h"
extern Options* g_pOptions;
extern StatMeter* g_pStatMeter;
Frontend::Frontend()
{
debug("Creating Frontend");
@@ -85,7 +82,8 @@ bool Frontend::PrepareData()
}
if (!RequestMessages() || ((m_bSummary || m_bFileList) && !RequestFileList()))
{
printf("\nUnable to send request to nzbget-server at %s (port %i) \n", g_pOptions->GetControlIP(), g_pOptions->GetControlPort());
const char* szControlIP = !strcmp(g_pOptions->GetControlIP(), "0.0.0.0") ? "127.0.0.1" : g_pOptions->GetControlIP();
printf("\nUnable to send request to nzbget-server at %s (port %i) \n", szControlIP, g_pOptions->GetControlPort());
Stop();
return false;
}
@@ -218,7 +216,8 @@ void Frontend::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest, int
bool Frontend::RequestMessages()
{
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
const char* szControlIP = !strcmp(g_pOptions->GetControlIP(), "0.0.0.0") ? "127.0.0.1" : g_pOptions->GetControlIP();
Connection connection(szControlIP, g_pOptions->GetControlPort(), false);
bool OK = connection.Connect();
if (!OK)
@@ -289,7 +288,8 @@ bool Frontend::RequestMessages()
bool Frontend::RequestFileList()
{
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
const char* szControlIP = !strcmp(g_pOptions->GetControlIP(), "0.0.0.0") ? "127.0.0.1" : g_pOptions->GetControlIP();
Connection connection(szControlIP, g_pOptions->GetControlPort(), false);
bool OK = connection.Connect();
if (!OK)

View File

@@ -73,7 +73,6 @@ void curses_clear()
#undef clear
#endif
extern Options* g_pOptions;
extern void ExitProc();
static const int NCURSES_COLORPAIR_TEXT = 1;
@@ -137,7 +136,7 @@ NCursesFrontend::NCursesFrontend()
m_bShowNZBname = g_pOptions->GetCursesNZBName();
m_bShowTimestamp = g_pOptions->GetCursesTime();
m_bGroupFiles = g_pOptions->GetCursesGroup();
m_QueueWindowPercentage = 0.5f;
m_QueueWindowPercentage = 50;
m_iDataUpdatePos = 0;
m_bUpdateNextTime = false;
m_iLastEditEntry = -1;
@@ -363,7 +362,7 @@ void NCursesFrontend::CalcWindowSizes()
int iQueueSize = CalcQueueSize();
m_iQueueWinTop = 0;
m_iQueueWinHeight = (int)((float) (m_iScreenHeight - 2) * m_QueueWindowPercentage);
m_iQueueWinHeight = (m_iScreenHeight - 2) * m_QueueWindowPercentage / 100;
if (m_iQueueWinHeight - 1 > iQueueSize)
{
m_iQueueWinHeight = iQueueSize > 0 ? iQueueSize + 1 : 1 + 1;
@@ -626,7 +625,7 @@ void NCursesFrontend::PrintStatus()
char szDownloadLimit[128];
if (m_iDownloadLimit > 0)
{
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
sprintf(szDownloadLimit, ", Limit %i KB/s", m_iDownloadLimit / 1024);
}
else
{
@@ -643,13 +642,16 @@ void NCursesFrontend::PrintStatus()
szPostStatus[0] = 0;
}
float fAverageSpeed = (float)(Util::Int64ToFloat(m_iDnTimeSec > 0 ? m_iAllBytes / m_iDnTimeSec : 0) / 1024.0);
char szCurrentSpeed[20];
char szAverageSpeed[20];
char szRemainingSize[20];
int iAverageSpeed = (int)(m_iDnTimeSec > 0 ? m_iAllBytes / m_iDnTimeSec : 0);
snprintf(tmp, MAX_SCREEN_WIDTH, " %d threads, %.*f KB/s, %.2f MB remaining%s%s%s%s, Avg. %.*f KB/s",
m_iThreadCount, (iCurrentDownloadSpeed >= 10*1024 ? 0 : 1), (float)iCurrentDownloadSpeed / 1024.0,
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
szDownloadLimit, (fAverageSpeed >= 10 ? 0 : 1), fAverageSpeed);
snprintf(tmp, MAX_SCREEN_WIDTH, " %d threads, %s, %s remaining%s%s%s%s, Avg. %s",
m_iThreadCount, Util::FormatSpeed(szCurrentSpeed, sizeof(szCurrentSpeed), iCurrentDownloadSpeed),
Util::FormatSize(szRemainingSize, sizeof(szRemainingSize), m_lRemainingSize),
timeString, szPostStatus, m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
szDownloadLimit, Util::FormatSpeed(szAverageSpeed, sizeof(szAverageSpeed), iAverageSpeed));
tmp[MAX_SCREEN_WIDTH - 1] = '\0';
PlotLine(tmp, iStatusRow, 0, NCURSES_COLORPAIR_STATUS);
}
@@ -776,15 +778,13 @@ void NCursesFrontend::PrintFileQueue()
if (iFileNum > 0)
{
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lRemaining);
char szUnpaused[20];
Util::FormatFileSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused);
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), " %sFiles for downloading - %i / %i files in queue - %s / %s",
m_bUseColor ? "" : "*** ", iFileNum,
iFileNum - iPausedFiles, szRemaining, szUnpaused);
iFileNum - iPausedFiles,
Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining),
Util::FormatSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused));
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, m_iQueueWinTop, true);
}
@@ -837,7 +837,7 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
szCompleted[0] = '\0';
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
{
sprintf(szCompleted, ", %i%%", (int)(100 - Util::Int64ToFloat(pFileInfo->GetRemainingSize()) * 100.0 / Util::Int64ToFloat(pFileInfo->GetSize())));
sprintf(szCompleted, ", %i%%", (int)(100 - pFileInfo->GetRemainingSize() * 100 / pFileInfo->GetSize()));
}
char szNZBNiceName[1024];
@@ -853,10 +853,11 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
szNZBNiceName[0] = '\0';
}
char szSize[20];
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s%s%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(),
Brace2, szPriority, szDownloading, szNZBNiceName, pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s%s%s %s%s (%s%s)%s", Brace1, pFileInfo->GetID(),
Brace2, szPriority, szDownloading, szNZBNiceName, pFileInfo->GetFilename(),
Util::FormatSize(szSize, sizeof(szSize), pFileInfo->GetSize()),
szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
@@ -967,10 +968,10 @@ void NCursesFrontend::PrintGroupQueue()
}
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lRemaining);
Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining);
char szUnpaused[20];
Util::FormatFileSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused);
Util::FormatSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused);
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), " %sNZBs for downloading - %i NZBs in queue - %s / %s",
@@ -1012,7 +1013,7 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
long long lUnpausedRemainingSize = pNZBInfo->GetRemainingSize() - pNZBInfo->GetPausedSize();
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
Util::FormatSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
char szPriority[100];
szPriority[0] = '\0';
@@ -1046,7 +1047,7 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
szFiles[20-1] = '\0';
char szTotal[20];
Util::FormatFileSize(szTotal, sizeof(szTotal), pNZBInfo->GetSize());
Util::FormatSize(szTotal, sizeof(szTotal), pNZBInfo->GetSize());
char szNameWithIds[1024];
snprintf(szNameWithIds, 1024, "%c%i%c%s%s %s", chBrace1, pNZBInfo->GetID(), chBrace2,
@@ -1059,7 +1060,7 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
if (pNZBInfo->GetPausedSize() > 0 && lUnpausedRemainingSize == 0)
{
snprintf(szTime, 100, "[paused]");
Util::FormatFileSize(szRemaining, sizeof(szRemaining), pNZBInfo->GetRemainingSize());
Util::FormatSize(szRemaining, sizeof(szRemaining), pNZBInfo->GetRemainingSize());
}
else if (iCurrentDownloadSpeed > 0 && !m_bPauseDownload)
{
@@ -1257,17 +1258,17 @@ void NCursesFrontend::UpdateInput(int initialKey)
break;
case 'w':
// swicth window sizes
if (m_QueueWindowPercentage == 0.5)
if (m_QueueWindowPercentage == 50)
{
m_QueueWindowPercentage = 1;
m_QueueWindowPercentage = 100;
}
else if (m_QueueWindowPercentage == 1 && m_eInputMode != eEditQueue)
else if (m_QueueWindowPercentage == 100 && m_eInputMode != eEditQueue)
{
m_QueueWindowPercentage = 0;
}
else
{
m_QueueWindowPercentage = 0.5;
m_QueueWindowPercentage = 50;
}
CalcWindowSizes();
SetCurrentQueueEntry(m_iSelectedQueueEntry);
@@ -1302,7 +1303,7 @@ void NCursesFrontend::UpdateInput(int initialKey)
m_eInputMode = eEditQueue;
if (m_QueueWindowPercentage == 0)
{
m_QueueWindowPercentage = 0.5;
m_QueueWindowPercentage = 50;
}
return;
}

View File

@@ -85,7 +85,7 @@ private:
bool m_bShowNZBname;
bool m_bShowTimestamp;
bool m_bGroupFiles;
float m_QueueWindowPercentage;
int m_QueueWindowPercentage;
#ifdef WIN32
void init_pair(int iColorNumber, WORD wForeColor, WORD wBackColor);

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef COMMANDLINEPARSER_H
#define COMMANDLINEPARSER_H
#include <vector>
#include <list>
#include <time.h>
class CommandLineParser
{
public:
enum EClientOperation
{
opClientNoOperation,
opClientRequestDownload,
opClientRequestListFiles,
opClientRequestListGroups,
opClientRequestListStatus,
opClientRequestSetRate,
opClientRequestDumpDebug,
opClientRequestEditQueue,
opClientRequestLog,
opClientRequestShutdown,
opClientRequestReload,
opClientRequestVersion,
opClientRequestPostQueue,
opClientRequestWriteLog,
opClientRequestScanSync,
opClientRequestScanAsync,
opClientRequestDownloadPause,
opClientRequestDownloadUnpause,
opClientRequestPostPause,
opClientRequestPostUnpause,
opClientRequestScanPause,
opClientRequestScanUnpause,
opClientRequestHistory,
opClientRequestHistoryAll
};
enum EMatchMode
{
mmID = 1,
mmName,
mmRegEx
};
typedef std::vector<char*> NameList;
private:
bool m_bNoConfig;
char* m_szConfigFilename;
// Parsed command-line parameters
bool m_bErrors;
bool m_bPrintVersion;
bool m_bPrintUsage;
bool m_bServerMode;
bool m_bDaemonMode;
bool m_bRemoteClientMode;
EClientOperation m_eClientOperation;
NameList m_OptionList;
int m_iEditQueueAction;
int m_iEditQueueOffset;
int* m_pEditQueueIDList;
int m_iEditQueueIDCount;
NameList m_EditQueueNameList;
EMatchMode m_EMatchMode;
char* m_szEditQueueText;
char* m_szArgFilename;
char* m_szAddCategory;
int m_iAddPriority;
bool m_bAddPaused;
char* m_szAddNZBFilename;
char* m_szLastArg;
bool m_bPrintOptions;
bool m_bAddTop;
char* m_szAddDupeKey;
int m_iAddDupeScore;
int m_iAddDupeMode;
int m_iSetRate;
int m_iLogLines;
int m_iWriteLogKind;
bool m_bTestBacktrace;
bool m_bWebGet;
char* m_szWebGetFilename;
bool m_bSigVerify;
char* m_szPubKeyFilename;
char* m_szSigFilename;
bool m_bPauseDownload;
void InitCommandLine(int argc, const char* argv[]);
void InitFileArg(int argc, const char* argv[]);
void ParseFileIDList(int argc, const char* argv[], int optind);
void ParseFileNameList(int argc, const char* argv[], int optind);
bool ParseTime(const char* szTime, int* pHours, int* pMinutes);
void ReportError(const char* szErrMessage);
public:
CommandLineParser(int argc, const char* argv[]);
~CommandLineParser();
void PrintUsage(const char* com);
bool GetErrors() { return m_bErrors; }
bool GetNoConfig() { return m_bNoConfig; }
const char* GetConfigFilename() { return m_szConfigFilename; }
bool GetServerMode() { return m_bServerMode; }
bool GetDaemonMode() { return m_bDaemonMode; }
bool GetRemoteClientMode() { return m_bRemoteClientMode; }
EClientOperation GetClientOperation() { return m_eClientOperation; }
NameList* GetOptionList() { return &m_OptionList; }
int GetEditQueueAction() { return m_iEditQueueAction; }
int GetEditQueueOffset() { return m_iEditQueueOffset; }
int* GetEditQueueIDList() { return m_pEditQueueIDList; }
int GetEditQueueIDCount() { return m_iEditQueueIDCount; }
NameList* GetEditQueueNameList() { return &m_EditQueueNameList; }
EMatchMode GetMatchMode() { return m_EMatchMode; }
const char* GetEditQueueText() { return m_szEditQueueText; }
const char* GetArgFilename() { return m_szArgFilename; }
const char* GetAddCategory() { return m_szAddCategory; }
bool GetAddPaused() { return m_bAddPaused; }
const char* GetLastArg() { return m_szLastArg; }
int GetAddPriority() { return m_iAddPriority; }
char* GetAddNZBFilename() { return m_szAddNZBFilename; }
bool GetAddTop() { return m_bAddTop; }
const char* GetAddDupeKey() { return m_szAddDupeKey; }
int GetAddDupeScore() { return m_iAddDupeScore; }
int GetAddDupeMode() { return m_iAddDupeMode; }
int GetSetRate() { return m_iSetRate; }
int GetLogLines() { return m_iLogLines; }
int GetWriteLogKind() { return m_iWriteLogKind; }
bool GetTestBacktrace() { return m_bTestBacktrace; }
bool GetWebGet() { return m_bWebGet; }
const char* GetWebGetFilename() { return m_szWebGetFilename; }
bool GetSigVerify() { return m_bSigVerify; }
const char* GetPubKeyFilename() { return m_szPubKeyFilename; }
const char* GetSigFilename() { return m_szSigFilename; }
bool GetPrintOptions() { return m_bPrintOptions; }
bool GetPrintVersion() { return m_bPrintVersion; }
bool GetPrintUsage() { return m_bPrintUsage; }
bool GetPauseDownload() const { return m_bPauseDownload; }
};
extern CommandLineParser* g_pCommandLineParser;
#endif

131
daemon/main/DiskService.cpp Normal file
View File

@@ -0,0 +1,131 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include "nzbget.h"
#include "DiskService.h"
#include "Options.h"
#include "StatMeter.h"
#include "Log.h"
#include "Util.h"
DiskService::DiskService()
{
m_iInterval = 0;
m_bWaitingReported = false;
m_bWaitingRequiredDir = true;
}
void DiskService::ServiceWork()
{
m_iInterval++;
if (m_iInterval == 5)
{
if (!g_pOptions->GetPauseDownload() &&
g_pOptions->GetDiskSpace() > 0 && !g_pStatMeter->GetStandBy())
{
// check free disk space every 1 second
CheckDiskSpace();
}
m_iInterval = 0;
}
if (m_bWaitingRequiredDir)
{
CheckRequiredDir();
}
}
void DiskService::CheckDiskSpace()
{
long long lFreeSpace = Util::FreeDiskSize(g_pOptions->GetDestDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetDestDir());
g_pOptions->SetPauseDownload(true);
}
if (!Util::EmptyStr(g_pOptions->GetInterDir()))
{
lFreeSpace = Util::FreeDiskSize(g_pOptions->GetInterDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetInterDir());
g_pOptions->SetPauseDownload(true);
}
}
}
void DiskService::CheckRequiredDir()
{
if (!Util::EmptyStr(g_pOptions->GetRequiredDir()))
{
bool bAllExist = true;
bool bWasWaitingReported = m_bWaitingReported;
// split RequiredDir into tokens
Tokenizer tok(g_pOptions->GetRequiredDir(), ",;");
while (const char* szDir = tok.Next())
{
if (!Util::FileExists(szDir) && !Util::DirectoryExists(szDir))
{
if (!bWasWaitingReported)
{
info("Waiting for required directory %s", szDir);
m_bWaitingReported = true;
}
bAllExist = false;
}
}
if (!bAllExist)
{
return;
}
}
if (m_bWaitingReported)
{
info("All required directories available");
}
g_pOptions->SetTempPauseDownload(false);
g_pOptions->SetTempPausePostprocess(false);
m_bWaitingRequiredDir = false;
}

49
daemon/main/DiskService.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef DISKSERVICE_H
#define DISKSERVICE_H
#include "Service.h"
class DiskService : public Service
{
private:
int m_iInterval;
bool m_bWaitingRequiredDir;
bool m_bWaitingReported;
void CheckDiskSpace();
void CheckRequiredDir();
protected:
virtual int ServiceInterval() { return 200; }
virtual void ServiceWork();
public:
DiskService();
};
#endif

View File

@@ -40,18 +40,47 @@
#endif
#include <errno.h>
#ifdef HAVE_OPENSSL
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#endif /* HAVE_OPENSSL */
#include "nzbget.h"
#include "Log.h"
#include "Util.h"
#include "Maintenance.h"
#include "Options.h"
#include "CommandLineParser.h"
extern Options* g_pOptions;
extern Maintenance* g_pMaintenance;
extern void ExitProc();
extern int g_iArgumentCount;
extern char* (*g_szArguments)[];
#ifdef HAVE_OPENSSL
class Signature
{
private:
const char* m_szInFilename;
const char* m_szSigFilename;
const char* m_szPubKeyFilename;
unsigned char m_InHash[SHA256_DIGEST_LENGTH];
unsigned char m_Signature[256];
RSA* m_pPubKey;
bool ReadSignature();
bool ComputeInHash();
bool ReadPubKey();
public:
Signature(const char* szInFilename, const char* szSigFilename, const char* szPubKeyFilename);
~Signature();
bool Verify();
};
#endif
Maintenance::Maintenance()
{
m_iIDMessageGen = 0;
@@ -234,6 +263,16 @@ bool Maintenance::ReadPackageInfoStr(const char* szKey, char** pValue)
return true;
}
bool Maintenance::VerifySignature(const char* szInFilename, const char* szSigFilename, const char* szPubKeyFilename)
{
#ifdef HAVE_OPENSSL
Signature signature(szInFilename, szSigFilename, szPubKeyFilename);
return signature.Verify();
#else
return false;
#endif
}
void UpdateScriptController::Run()
{
// the update-script should not be automatically terminated when the program quits
@@ -250,7 +289,7 @@ void UpdateScriptController::Run()
const char* szBranchName[] = { "STABLE", "TESTING", "DEVEL" };
SetEnvVar("NZBUP_BRANCH", szBranchName[m_eBranch]);
SetEnvVar("NZBUP_RUNMODE", g_pOptions->GetDaemonMode() ? "DAEMON" : "SERVER");
SetEnvVar("NZBUP_RUNMODE", g_pCommandLineParser->GetDaemonMode() ? "DAEMON" : "SERVER");
for (int i = 0; i < g_iArgumentCount; i++)
{
@@ -359,3 +398,110 @@ void UpdateInfoScriptController::AddMessage(Message::EKind eKind, const char* sz
ScriptController::AddMessage(eKind, szText);
}
}
#ifdef HAVE_OPENSSL
Signature::Signature(const char *szInFilename, const char *szSigFilename, const char *szPubKeyFilename)
{
m_szInFilename = szInFilename;
m_szSigFilename = szSigFilename;
m_szPubKeyFilename = szPubKeyFilename;
m_pPubKey = NULL;
}
Signature::~Signature()
{
RSA_free(m_pPubKey);
}
// Calculate SHA-256 for input file (m_szInFilename)
bool Signature::ComputeInHash()
{
FILE* infile = fopen(m_szInFilename, FOPEN_RB);
if (!infile)
{
return false;
}
SHA256_CTX sha256;
SHA256_Init(&sha256);
const int bufSize = 32*1024;
char* buffer = (char*)malloc(bufSize);
while(int bytesRead = fread(buffer, 1, bufSize, infile))
{
SHA256_Update(&sha256, buffer, bytesRead);
}
SHA256_Final(m_InHash, &sha256);
free(buffer);
fclose(infile);
return true;
}
// Read signature from file (m_szSigFilename) into memory
bool Signature::ReadSignature()
{
char szSigTitle[256];
snprintf(szSigTitle, sizeof(szSigTitle), "\"RSA-SHA256(%s)\" : \"", Util::BaseFileName(m_szInFilename));
szSigTitle[256-1] = '\0';
FILE* infile = fopen(m_szSigFilename, FOPEN_RB);
if (!infile)
{
return false;
}
bool bOK = false;
int iTitLen = strlen(szSigTitle);
char buf[1024];
unsigned char* output = m_Signature;
while (fgets(buf, sizeof(buf) - 1, infile))
{
if (!strncmp(buf, szSigTitle, iTitLen))
{
char* szHexSig = buf + iTitLen;
int iSigLen = strlen(szHexSig);
if (iSigLen > 2)
{
szHexSig[iSigLen - 2] = '\0'; // trim trailing ",
}
for (; *szHexSig && *(szHexSig+1);)
{
unsigned char c1 = *szHexSig++;
unsigned char c2 = *szHexSig++;
c1 = '0' <= c1 && c1 <= '9' ? c1 - '0' : 'A' <= c1 && c1 <= 'F' ? c1 - 'A' + 10 :
'a' <= c1 && c1 <= 'f' ? c1 - 'a' + 10 : 0;
c2 = '0' <= c2 && c2 <= '9' ? c2 - '0' : 'A' <= c2 && c2 <= 'F' ? c2 - 'A' + 10 :
'a' <= c2 && c2 <= 'f' ? c2 - 'a' + 10 : 0;
unsigned char ch = (c1 << 4) + c2;
*output++ = (char)ch;
}
bOK = output == m_Signature + sizeof(m_Signature);
break;
}
}
fclose(infile);
return bOK;
}
// Read public key from file (m_szPubKeyFilename) into memory
bool Signature::ReadPubKey()
{
char* keybuf;
int keybuflen;
if (!Util::LoadFileIntoBuffer(m_szPubKeyFilename, &keybuf, &keybuflen))
{
return false;
}
BIO* mem = BIO_new_mem_buf(keybuf, keybuflen);
m_pPubKey = PEM_read_bio_RSA_PUBKEY(mem, NULL, NULL, NULL);
BIO_free(mem);
free(keybuf);
return m_pPubKey != NULL;
}
bool Signature::Verify()
{
return ComputeInHash() && ReadSignature() && ReadPubKey() &&
RSA_verify(NID_sha256, m_InHash, sizeof(m_InHash), m_Signature, sizeof(m_Signature), m_pPubKey) == 1;
}
#endif /* HAVE_OPENSSL */

View File

@@ -60,8 +60,11 @@ public:
bool StartUpdate(EBranch eBranch);
void ResetUpdateController();
bool CheckUpdates(char** pUpdateInfo);
static bool VerifySignature(const char* szInFilename, const char* szSigFilename, const char* szPubKeyFilename);
};
extern Maintenance* g_pMaintenance;
class UpdateScriptController : public Thread, public ScriptController
{
private:

View File

File diff suppressed because it is too large Load Diff

View File

@@ -37,33 +37,6 @@
class Options
{
public:
enum EClientOperation
{
opClientNoOperation,
opClientRequestDownload,
opClientRequestListFiles,
opClientRequestListGroups,
opClientRequestListStatus,
opClientRequestSetRate,
opClientRequestDumpDebug,
opClientRequestEditQueue,
opClientRequestLog,
opClientRequestShutdown,
opClientRequestReload,
opClientRequestVersion,
opClientRequestPostQueue,
opClientRequestWriteLog,
opClientRequestScanSync,
opClientRequestScanAsync,
opClientRequestDownloadPause,
opClientRequestDownloadUnpause,
opClientRequestPostPause,
opClientRequestPostUnpause,
opClientRequestScanPause,
opClientRequestScanUnpause,
opClientRequestHistory,
opClientRequestHistoryAll
};
enum EWriteLog
{
wlNone,
@@ -94,8 +67,9 @@ public:
enum EParScan
{
psLimited,
psExtended,
psFull,
psAuto
psDupe
};
enum EHealthCheck
{
@@ -103,11 +77,20 @@ public:
hcDelete,
hcNone
};
enum EMatchMode
enum ESchedulerCommand
{
mmID = 1,
mmName,
mmRegEx
scPauseDownload,
scUnpauseDownload,
scPausePostProcess,
scUnpausePostProcess,
scDownloadRate,
scScript,
scProcess,
scPauseScan,
scUnpauseScan,
scActivateServer,
scDeactivateServer,
scFetchFeed
};
class OptEntry
@@ -118,8 +101,6 @@ public:
char* m_szDefValue;
int m_iLineNo;
void SetName(const char* szName);
void SetValue(const char* szValue);
void SetLineNo(int iLineNo) { m_iLineNo = iLineNo; }
friend class Options;
@@ -128,7 +109,9 @@ public:
OptEntry();
OptEntry(const char* szName, const char* szValue);
~OptEntry();
void SetName(const char* szName);
const char* GetName() { return m_szName; }
void SetValue(const char* szValue);
const char* GetValue() { return m_szValue; }
const char* GetDefValue() { return m_szDefValue; }
int GetLineNo() { return m_iLineNo; }
@@ -145,6 +128,7 @@ public:
};
typedef std::vector<char*> NameList;
typedef std::vector<const char*> CmdOptList;
class Category
{
@@ -174,77 +158,28 @@ public:
Category* FindCategory(const char* szName, bool bSearchAliases);
};
class Script
{
private:
char* m_szName;
char* m_szLocation;
char* m_szDisplayName;
bool m_bPostScript;
bool m_bScanScript;
bool m_bQueueScript;
bool m_bSchedulerScript;
char* m_szQueueEvents;
public:
Script(const char* szName, const char* szLocation);
~Script();
const char* GetName() { return m_szName; }
const char* GetLocation() { return m_szLocation; }
void SetDisplayName(const char* szDisplayName);
const char* GetDisplayName() { return m_szDisplayName; }
bool GetPostScript() { return m_bPostScript; }
void SetPostScript(bool bPostScript) { m_bPostScript = bPostScript; }
bool GetScanScript() { return m_bScanScript; }
void SetScanScript(bool bScanScript) { m_bScanScript = bScanScript; }
bool GetQueueScript() { return m_bQueueScript; }
void SetQueueScript(bool bQueueScript) { m_bQueueScript = bQueueScript; }
bool GetSchedulerScript() { return m_bSchedulerScript; }
void SetSchedulerScript(bool bSchedulerScript) { m_bSchedulerScript = bSchedulerScript; }
void SetQueueEvents(const char* szQueueEvents);
const char* GetQueueEvents() { return m_szQueueEvents; }
};
typedef std::list<Script*> ScriptsBase;
class Scripts: public ScriptsBase
class Extender
{
public:
~Scripts();
void Clear();
Script* Find(const char* szName);
};
class ConfigTemplate
{
private:
Script* m_pScript;
char* m_szTemplate;
friend class Options;
public:
ConfigTemplate(Script* pScript, const char* szTemplate);
~ConfigTemplate();
Script* GetScript() { return m_pScript; }
const char* GetTemplate() { return m_szTemplate; }
};
typedef std::vector<ConfigTemplate*> ConfigTemplatesBase;
class ConfigTemplates: public ConfigTemplatesBase
{
public:
~ConfigTemplates();
virtual void AddNewsServer(int iID, bool bActive, const char* szName, const char* szHost,
int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
bool bTLS, const char* szCipher, int iMaxConnections, int iRetention,
int iLevel, int iGroup) = 0;
virtual void AddFeed(int iID, const char* szName, const char* szUrl, int iInterval,
const char* szFilter, bool bBacklog, bool bPauseNzb, const char* szCategory,
int iPriority, const char* szFeedScript) {}
virtual void AddTask(int iID, int iHours, int iMinutes, int iWeekDaysBits, ESchedulerCommand eCommand,
const char* szParam) {}
virtual void SetupFirstStart() {}
};
private:
OptEntries m_OptEntries;
bool m_bConfigInitialized;
Mutex m_mutexOptEntries;
Categories m_Categories;
Scripts m_Scripts;
ConfigTemplates m_ConfigTemplates;
bool m_bNoDiskAccess;
bool m_bFatalError;
Extender* m_pExtender;
// Options
bool m_bConfigErrors;
@@ -259,6 +194,7 @@ private:
char* m_szWebDir;
char* m_szConfigTemplate;
char* m_szScriptDir;
char* m_szRequiredDir;
EMessageTarget m_eInfoTarget;
EMessageTarget m_eWarningTarget;
EMessageTarget m_eErrorTarget;
@@ -275,6 +211,7 @@ private:
int m_iRetries;
int m_iRetryInterval;
bool m_bSaveQueue;
bool m_bFlushQueue;
bool m_bDupeCheck;
char* m_szControlIP;
char* m_szControlUsername;
@@ -310,6 +247,7 @@ private:
char* m_szScriptOrder;
char* m_szScanScript;
char* m_szQueueScript;
char* m_szFeedScript;
bool m_bNoConfig;
int m_iUMask;
int m_iUpdateInterval;
@@ -347,99 +285,61 @@ private:
int m_iArticleCache;
int m_iEventInterval;
// Parsed command-line parameters
bool m_bServerMode;
bool m_bDaemonMode;
bool m_bRemoteClientMode;
int m_iEditQueueAction;
int m_iEditQueueOffset;
int* m_pEditQueueIDList;
int m_iEditQueueIDCount;
NameList m_EditQueueNameList;
EMatchMode m_EMatchMode;
char* m_szEditQueueText;
char* m_szArgFilename;
char* m_szAddCategory;
int m_iAddPriority;
bool m_bAddPaused;
char* m_szAddNZBFilename;
char* m_szLastArg;
bool m_bPrintOptions;
bool m_bAddTop;
char* m_szAddDupeKey;
int m_iAddDupeScore;
int m_iAddDupeMode;
int m_iSetRate;
int m_iLogLines;
int m_iWriteLogKind;
bool m_bTestBacktrace;
bool m_bWebGet;
char* m_szWebGetFilename;
// Current state
bool m_bServerMode;
bool m_bRemoteClientMode;
bool m_bPauseDownload;
bool m_bPausePostProcess;
bool m_bPauseScan;
bool m_bTempPauseDownload;
int m_iDownloadRate;
EClientOperation m_eClientOperation;
time_t m_tResumeTime;
int m_iLocalTimeOffset;
bool m_bTempPausePostprocess;
void InitDefault();
void InitOptFile();
void InitCommandLine(int argc, char* argv[]);
void Init(const char* szExeName, const char* szConfigFilename, bool bNoConfig,
CmdOptList* pCommandLineOptions, bool bNoDiskAccess, Extender* pExtender);
void InitDefaults();
void InitOptions();
void InitFileArg(int argc, char* argv[]);
void InitOptFile();
void InitServers();
void InitCategories();
void InitScheduler();
void InitFeeds();
void InitScripts();
void InitConfigTemplates();
void InitCommandLineOptions(CmdOptList* pCommandLineOptions);
void CheckOptions();
void PrintUsage(char* com);
void Dump();
int ParseEnumValue(const char* OptName, int argc, const char* argn[], const int argv[]);
int ParseIntValue(const char* OptName, int iBase);
float ParseFloatValue(const char* OptName);
OptEntry* FindOption(const char* optname);
const char* GetOption(const char* optname);
void SetOption(const char* optname, const char* value);
bool SetOptionString(const char* option);
bool SplitOptionString(const char* option, char** pOptName, char** pOptValue);
bool ValidateOptionName(const char* optname, const char* optvalue);
void LoadConfigFile();
void CheckDir(char** dir, const char* szOptionName, const char* szParentDir,
bool bAllowEmpty, bool bCreate);
void ParseFileIDList(int argc, char* argv[], int optind);
void ParseFileNameList(int argc, char* argv[], int optind);
bool ParseTime(const char* szTime, int* pHours, int* pMinutes);
bool ParseWeekDays(const char* szWeekDays, int* pWeekDaysBits);
void ConfigError(const char* msg, ...);
void ConfigWarn(const char* msg, ...);
void LocateOptionSrcPos(const char *szOptionName);
void ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue, int iValueBufLen);
static bool CompareScripts(Script* pScript1, Script* pScript2);
void LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIsSubDir);
void BuildScriptDisplayNames(Scripts* pScripts);
void LoadScripts(Scripts* pScripts);
public:
Options();
Options(const char* szExeName, const char* szConfigFilename, bool bNoConfig,
CmdOptList* pCommandLineOptions, Extender* pExtender);
Options(CmdOptList* pCommandLineOptions, Extender* pExtender);
~Options();
void Init(int argc, char* argv[]);
bool LoadConfig(OptEntries* pOptEntries);
bool SaveConfig(OptEntries* pOptEntries);
bool LoadConfigTemplates(ConfigTemplates* pConfigTemplates);
Scripts* GetScripts() { return &m_Scripts; }
ConfigTemplates* GetConfigTemplates() { return &m_ConfigTemplates; }
// Options
bool SplitOptionString(const char* option, char** pOptName, char** pOptValue);
bool GetFatalError() { return m_bFatalError; }
OptEntries* LockOptEntries();
void UnlockOptEntries();
// Options
const char* GetConfigFilename() { return m_szConfigFilename; }
bool GetConfigErrors() { return m_bConfigErrors; }
const char* GetAppDir() { return m_szAppDir; }
const char* GetDestDir() { return m_szDestDir; }
const char* GetInterDir() { return m_szInterDir; }
@@ -449,6 +349,7 @@ public:
const char* GetWebDir() { return m_szWebDir; }
const char* GetConfigTemplate() { return m_szConfigTemplate; }
const char* GetScriptDir() { return m_szScriptDir; }
const char* GetRequiredDir() { return m_szRequiredDir; }
bool GetBrokenLog() const { return m_bBrokenLog; }
bool GetNzbLog() const { return m_bNzbLog; }
EMessageTarget GetInfoTarget() const { return m_eInfoTarget; }
@@ -465,8 +366,9 @@ public:
int GetRetries() { return m_iRetries; }
int GetRetryInterval() { return m_iRetryInterval; }
bool GetSaveQueue() { return m_bSaveQueue; }
bool GetFlushQueue() { return m_bFlushQueue; }
bool GetDupeCheck() { return m_bDupeCheck; }
const char* GetControlIP();
const char* GetControlIP() { return m_szControlIP; }
const char* GetControlUsername() { return m_szControlUsername; }
const char* GetControlPassword() { return m_szControlPassword; }
const char* GetRestrictedUsername() { return m_szRestrictedUsername; }
@@ -500,6 +402,7 @@ public:
const char* GetPostScript() { return m_szPostScript; }
const char* GetScanScript() { return m_szScanScript; }
const char* GetQueueScript() { return m_szQueueScript; }
const char* GetFeedScript() { return m_szFeedScript; }
int GetUMask() { return m_iUMask; }
int GetUpdateInterval() {return m_iUpdateInterval; }
bool GetCursesNZBName() { return m_bCursesNZBName; }
@@ -539,36 +442,11 @@ public:
Categories* GetCategories() { return &m_Categories; }
Category* FindCategory(const char* szName, bool bSearchAliases) { return m_Categories.FindCategory(szName, bSearchAliases); }
// Parsed command-line parameters
bool GetServerMode() { return m_bServerMode; }
bool GetDaemonMode() { return m_bDaemonMode; }
bool GetRemoteClientMode() { return m_bRemoteClientMode; }
EClientOperation GetClientOperation() { return m_eClientOperation; }
int GetEditQueueAction() { return m_iEditQueueAction; }
int GetEditQueueOffset() { return m_iEditQueueOffset; }
int* GetEditQueueIDList() { return m_pEditQueueIDList; }
int GetEditQueueIDCount() { return m_iEditQueueIDCount; }
NameList* GetEditQueueNameList() { return &m_EditQueueNameList; }
EMatchMode GetMatchMode() { return m_EMatchMode; }
const char* GetEditQueueText() { return m_szEditQueueText; }
const char* GetArgFilename() { return m_szArgFilename; }
const char* GetAddCategory() { return m_szAddCategory; }
bool GetAddPaused() { return m_bAddPaused; }
const char* GetLastArg() { return m_szLastArg; }
int GetAddPriority() { return m_iAddPriority; }
char* GetAddNZBFilename() { return m_szAddNZBFilename; }
bool GetAddTop() { return m_bAddTop; }
const char* GetAddDupeKey() { return m_szAddDupeKey; }
int GetAddDupeScore() { return m_iAddDupeScore; }
int GetAddDupeMode() { return m_iAddDupeMode; }
int GetSetRate() { return m_iSetRate; }
int GetLogLines() { return m_iLogLines; }
int GetWriteLogKind() { return m_iWriteLogKind; }
bool GetTestBacktrace() { return m_bTestBacktrace; }
bool GetWebGet() { return m_bWebGet; }
const char* GetWebGetFilename() { return m_szWebGetFilename; }
// Current state
void SetServerMode(bool bServerMode) { m_bServerMode = bServerMode; }
bool GetServerMode() { return m_bServerMode; }
void SetRemoteClientMode(bool bRemoteClientMode) { m_bRemoteClientMode = bRemoteClientMode; }
bool GetRemoteClientMode() { return m_bRemoteClientMode; }
void SetPauseDownload(bool bPauseDownload) { m_bPauseDownload = bPauseDownload; }
bool GetPauseDownload() const { return m_bPauseDownload; }
void SetPausePostProcess(bool bPausePostProcess) { m_bPausePostProcess = bPausePostProcess; }
@@ -577,6 +455,8 @@ public:
bool GetPauseScan() const { return m_bPauseScan; }
void SetTempPauseDownload(bool bTempPauseDownload) { m_bTempPauseDownload = bTempPauseDownload; }
bool GetTempPauseDownload() const { return m_bTempPauseDownload; }
bool GetTempPausePostprocess() const { return m_bTempPausePostprocess; }
void SetTempPausePostprocess(bool bTempPausePostprocess) { m_bTempPausePostprocess = bTempPausePostprocess; }
void SetDownloadRate(int iRate) { m_iDownloadRate = iRate; }
int GetDownloadRate() const { return m_iDownloadRate; }
void SetResumeTime(time_t tResumeTime) { m_tResumeTime = tResumeTime; }
@@ -585,4 +465,6 @@ public:
int GetLocalTimeOffset() { return m_iLocalTimeOffset; }
};
extern Options* g_pOptions;
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,30 +45,7 @@
#include "ServerPool.h"
#include "FeedInfo.h"
#include "FeedCoordinator.h"
#include "QueueScript.h"
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern FeedCoordinator* g_pFeedCoordinator;
class SchedulerScriptController : public Thread, public NZBScriptController
{
private:
char* m_szScript;
bool m_bExternalProcess;
int m_iTaskID;
void PrepareParams(const char* szScriptName);
void ExecuteExternalProcess();
protected:
virtual void ExecuteScript(Options::Script* pScript);
public:
virtual ~SchedulerScriptController();
virtual void Run();
static void StartScript(const char* szParam, bool bExternalProcess, int iTaskID);
};
#include "SchedulerScript.h"
Scheduler::Task::Task(int iID, int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand, const char* szParam)
{
@@ -91,6 +68,7 @@ Scheduler::Scheduler()
{
debug("Creating Scheduler");
m_bFirstChecked = false;
m_tLastCheck = 0;
m_TaskList.clear();
}
@@ -128,8 +106,20 @@ void Scheduler::FirstCheck()
CheckTasks();
}
void Scheduler::IntervalCheck()
void Scheduler::ServiceWork()
{
if (!DownloadQueue::IsLoaded())
{
return;
}
if (!m_bFirstChecked)
{
FirstCheck();
m_bFirstChecked = true;
return;
}
m_bExecuteProcess = true;
CheckTasks();
CheckScheduledResume();
@@ -385,99 +375,3 @@ void Scheduler::CheckScheduledResume()
g_pOptions->SetPauseScan(false);
}
}
SchedulerScriptController::~SchedulerScriptController()
{
free(m_szScript);
}
void SchedulerScriptController::StartScript(const char* szParam, bool bExternalProcess, int iTaskID)
{
char** argv = NULL;
if (bExternalProcess && !Util::SplitCommandLine(szParam, &argv))
{
error("Could not execute scheduled process-script, failed to parse command line: %s", szParam);
return;
}
SchedulerScriptController* pScriptController = new SchedulerScriptController();
pScriptController->m_bExternalProcess = bExternalProcess;
pScriptController->m_szScript = strdup(szParam);
pScriptController->m_iTaskID = iTaskID;
if (bExternalProcess)
{
pScriptController->SetScript(argv[0]);
pScriptController->SetArgs((const char**)argv, true);
}
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
}
void SchedulerScriptController::Run()
{
if (m_bExternalProcess)
{
ExecuteExternalProcess();
}
else
{
ExecuteScriptList(m_szScript);
}
}
void SchedulerScriptController::ExecuteScript(Options::Script* pScript)
{
if (!pScript->GetSchedulerScript())
{
return;
}
PrintMessage(Message::mkInfo, "Executing scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void SchedulerScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetIntEnvVar("NZBSP_TASKID", m_iTaskID);
PrepareEnvScript(NULL, szScriptName);
}
void SchedulerScriptController::ExecuteExternalProcess()
{
info("Executing scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
SetLogPrefix(szLogPrefix);
Execute();
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,8 +31,9 @@
#include <time.h>
#include "Thread.h"
#include "Service.h"
class Scheduler
class Scheduler : public Service
{
public:
enum ECommand
@@ -84,6 +85,8 @@ private:
bool m_bPauseScanChanged;
bool m_bServerChanged;
ServerStatusList m_ServerStatusList;
bool m_bFirstChecked;
void ExecuteTask(Task* pTask);
void CheckTasks();
static bool CompareTasks(Scheduler::Task* pTask1, Scheduler::Task* pTask2);
@@ -92,13 +95,18 @@ private:
void EditServer(bool bActive, const char* szServerList);
void FetchFeed(const char* szFeedList);
void CheckScheduledResume();
void FirstCheck();
protected:
virtual int ServiceInterval() { return 1000; }
virtual void ServiceWork();
public:
Scheduler();
~Scheduler();
void AddTask(Task* pTask);
void FirstCheck();
void IntervalCheck();
};
extern Scheduler* g_pScheduler;
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,7 +54,6 @@
#include "Options.h"
#include "StackTrace.h"
extern Options* g_pOptions;
extern void ExitProc();
#ifdef WIN32

View File

@@ -58,12 +58,15 @@
#include "Log.h"
#include "NZBFile.h"
#include "Options.h"
#include "CommandLineParser.h"
#include "ScriptConfig.h"
#include "Thread.h"
#include "ColoredFrontend.h"
#include "NCursesFrontend.h"
#include "QueueCoordinator.h"
#include "UrlCoordinator.h"
#include "RemoteServer.h"
#include "WebServer.h"
#include "RemoteClient.h"
#include "MessageBase.h"
#include "DiskState.h"
@@ -74,6 +77,8 @@
#include "Scheduler.h"
#include "Scanner.h"
#include "FeedCoordinator.h"
#include "Service.h"
#include "DiskService.h"
#include "Maintenance.h"
#include "ArticleWriter.h"
#include "StatMeter.h"
@@ -85,6 +90,9 @@
#include "WinConsole.h"
#include "WebDownloader.h"
#endif
#ifdef ENABLE_TESTS
#include "TestMain.h"
#endif
// Prototypes
void RunMain();
@@ -93,22 +101,23 @@ void Reload();
void Cleanup();
void ProcessClientRequest();
void ProcessWebGet();
void ProcessSigVerify();
#ifndef WIN32
void Daemonize();
#endif
#ifndef DISABLE_PARCHECK
void DisableCout();
#endif
void BootConfig();
Thread* g_pFrontend = NULL;
Options* g_pOptions = NULL;
CommandLineParser* g_pCommandLineParser = NULL;
ServerPool* g_pServerPool = NULL;
QueueCoordinator* g_pQueueCoordinator = NULL;
UrlCoordinator* g_pUrlCoordinator = NULL;
RemoteServer* g_pRemoteServer = NULL;
RemoteServer* g_pRemoteSecureServer = NULL;
StatMeter* g_pStatMeter = NULL;
Log* g_pLog = NULL;
PrePostProcessor* g_pPrePostProcessor = NULL;
HistoryCoordinator* g_pHistoryCoordinator = NULL;
DupeCoordinator* g_pDupeCoordinator = NULL;
@@ -119,6 +128,8 @@ FeedCoordinator* g_pFeedCoordinator = NULL;
Maintenance* g_pMaintenance = NULL;
ArticleCache* g_pArticleCache = NULL;
QueueScriptCoordinator* g_pQueueScriptCoordinator = NULL;
ServiceCoordinator* g_pServiceCoordinator = NULL;
DiskService* g_pDiskService = NULL;
int g_iArgumentCount;
char* (*g_szEnvironmentVariables)[] = NULL;
char* (*g_szArguments)[] = NULL;
@@ -144,8 +155,26 @@ int main(int argc, char *argv[], char *argp[])
#endif
#endif
Util::InitVersionRevision();
Util::Init();
g_iArgumentCount = argc;
g_szArguments = (char*(*)[])argv;
g_szEnvironmentVariables = (char*(*)[])argp;
if (argc > 1 && (!strcmp(argv[1], "-tests") || !strcmp(argv[1], "--tests")))
{
#ifdef ENABLE_TESTS
return TestMain(argc, argv);
#else
printf("ERROR: Could not start tests, the program was compiled without tests\n");
return 1;
#endif
}
#ifdef ENABLE_TESTS
TestCleanup();
#endif
#ifdef WIN32
InstallUninstallServiceCheck(argc, argv);
#endif
@@ -154,11 +183,7 @@ int main(int argc, char *argv[], char *argp[])
DisableCout();
#endif
srand (time(NULL));
g_iArgumentCount = argc;
g_szArguments = (char*(*)[])argv;
g_szEnvironmentVariables = (char*(*)[])argp;
srand(time(NULL));
#ifdef WIN32
for (int i=0; i < argc; i++)
@@ -197,7 +222,7 @@ void RunMain()
void Run(bool bReload)
{
g_pLog = new Log();
Log::Init();
debug("nzbget %s", Util::VersionRevision());
@@ -211,6 +236,7 @@ void Run(bool bReload)
g_pWinConsole->InitAppMode();
#endif
g_pServiceCoordinator = new ServiceCoordinator();
g_pServerPool = new ServerPool();
g_pScheduler = new Scheduler();
g_pQueueCoordinator = new QueueCoordinator();
@@ -224,10 +250,9 @@ void Run(bool bReload)
g_pArticleCache = new ArticleCache();
g_pMaintenance = new Maintenance();
g_pQueueScriptCoordinator = new QueueScriptCoordinator();
g_pDiskService = new DiskService();
debug("Reading options");
g_pOptions = new Options();
g_pOptions->Init(g_iArgumentCount, *g_szArguments);
BootConfig();
#ifndef WIN32
if (g_pOptions->GetUMask() < 01000)
@@ -237,11 +262,10 @@ void Run(bool bReload)
}
#endif
g_pLog->InitOptions();
g_pScanner->InitOptions();
g_pQueueScriptCoordinator->InitOptions();
if (g_pOptions->GetDaemonMode())
if (g_pCommandLineParser->GetDaemonMode())
{
#ifdef WIN32
info("nzbget %s service-mode", Util::VersionRevision());
@@ -257,7 +281,7 @@ void Run(bool bReload)
{
info("nzbget %s server-mode", Util::VersionRevision());
}
else if (g_pOptions->GetRemoteClientMode())
else if (g_pCommandLineParser->GetRemoteClientMode())
{
info("nzbget %s remote-mode", Util::VersionRevision());
}
@@ -267,7 +291,7 @@ void Run(bool bReload)
Connection::Init();
}
if (!g_pOptions->GetRemoteClientMode())
if (!g_pCommandLineParser->GetRemoteClientMode())
{
g_pServerPool->InitConnections();
g_pStatMeter->Init();
@@ -276,20 +300,26 @@ void Run(bool bReload)
InstallErrorHandler();
#ifdef DEBUG
if (g_pOptions->GetTestBacktrace())
if (g_pCommandLineParser->GetTestBacktrace())
{
TestSegFault();
}
#endif
if (g_pOptions->GetWebGet())
if (g_pCommandLineParser->GetWebGet())
{
ProcessWebGet();
return;
}
if (g_pCommandLineParser->GetSigVerify())
{
ProcessSigVerify();
return;
}
// client request
if (g_pOptions->GetClientOperation() != Options::opClientNoOperation)
if (g_pCommandLineParser->GetClientOperation() != CommandLineParser::opClientNoOperation)
{
ProcessClientRequest();
Cleanup();
@@ -299,6 +329,7 @@ void Run(bool bReload)
// Setup the network-server
if (g_pOptions->GetServerMode())
{
WebProcessor::Init();
g_pRemoteServer = new RemoteServer(false);
g_pRemoteServer->Start();
@@ -310,7 +341,7 @@ void Run(bool bReload)
}
// Create the frontend
if (!g_pOptions->GetDaemonMode())
if (!g_pCommandLineParser->GetDaemonMode())
{
switch (g_pOptions->GetOutputMode())
{
@@ -335,16 +366,17 @@ void Run(bool bReload)
}
// Starting QueueCoordinator and PrePostProcessor
if (!g_pOptions->GetRemoteClientMode())
if (!g_pCommandLineParser->GetRemoteClientMode())
{
// Standalone-mode
if (!g_pOptions->GetServerMode())
if (!g_pCommandLineParser->GetServerMode())
{
const char* szCategory = g_pOptions->GetAddCategory() ? g_pOptions->GetAddCategory() : "";
NZBFile* pNZBFile = NZBFile::Create(g_pOptions->GetArgFilename(), szCategory);
if (!pNZBFile)
const char* szCategory = g_pCommandLineParser->GetAddCategory() ? g_pCommandLineParser->GetAddCategory() : "";
NZBFile* pNZBFile = new NZBFile(g_pCommandLineParser->GetArgFilename(), szCategory);
if (!pNZBFile->Parse())
{
abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A");
printf("Parsing NZB-document %s failed\n\n", g_pCommandLineParser->GetArgFilename() ? g_pCommandLineParser->GetArgFilename() : "N/A");
delete pNZBFile;
return;
}
g_pScanner->InitPPParameters(szCategory, pNZBFile->GetNZBInfo()->GetParameters(), false);
@@ -364,6 +396,7 @@ void Run(bool bReload)
g_pUrlCoordinator->Start();
g_pPrePostProcessor->Start();
g_pFeedCoordinator->Start();
g_pServiceCoordinator->Start();
if (g_pOptions->GetArticleCache() > 0)
{
g_pArticleCache->Start();
@@ -374,6 +407,7 @@ void Run(bool bReload)
g_pUrlCoordinator->IsRunning() ||
g_pPrePostProcessor->IsRunning() ||
g_pFeedCoordinator->IsRunning() ||
g_pServiceCoordinator->IsRunning() ||
#ifdef WIN32
g_pWinConsole->IsRunning() ||
#endif
@@ -405,6 +439,10 @@ void Run(bool bReload)
{
g_pArticleCache->Stop();
}
if (!g_pServiceCoordinator->IsStopped())
{
g_pServiceCoordinator->Stop();
}
}
usleep(100 * 1000);
}
@@ -414,6 +452,7 @@ void Run(bool bReload)
debug("UrlCoordinator stopped");
debug("PrePostProcessor stopped");
debug("FeedCoordinator stopped");
debug("ServiceCoordinator stopped");
debug("ArticleCache stopped");
}
@@ -459,7 +498,7 @@ void Run(bool bReload)
// Stop Frontend
if (g_pFrontend)
{
if (!g_pOptions->GetRemoteClientMode())
if (!g_pCommandLineParser->GetRemoteClientMode())
{
debug("Stopping Frontend");
g_pFrontend->Stop();
@@ -474,107 +513,184 @@ void Run(bool bReload)
Cleanup();
}
class OptionsExtender : public Options::Extender
{
protected:
#ifdef WIN32
virtual void SetupFirstStart()
{
g_pWinConsole->SetupFirstStart();
}
#endif
virtual void AddNewsServer(int iID, bool bActive, const char* szName, const char* szHost,
int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
bool bTLS, const char* szCipher, int iMaxConnections, int iRetention,
int iLevel, int iGroup)
{
g_pServerPool->AddServer(new NewsServer(iID, bActive, szName, szHost, iPort, szUser, szPass, bJoinGroup,
bTLS, szCipher, iMaxConnections, iRetention, iLevel, iGroup));
}
virtual void AddFeed(int iID, const char* szName, const char* szUrl, int iInterval,
const char* szFilter, bool bBacklog, bool bPauseNzb, const char* szCategory,
int iPriority, const char* szFeedScript)
{
g_pFeedCoordinator->AddFeed(new FeedInfo(iID, szName, szUrl, bBacklog, iInterval, szFilter, bPauseNzb, szCategory, iPriority, szFeedScript));
}
virtual void AddTask(int iID, int iHours, int iMinutes, int iWeekDaysBits,
Options::ESchedulerCommand eCommand, const char* szParam)
{
g_pScheduler->AddTask(new Scheduler::Task(iID, iHours, iMinutes, iWeekDaysBits, (Scheduler::ECommand)eCommand, szParam));
}
} g_OptionsExtender;
void BootConfig()
{
debug("Parsing command line");
g_pCommandLineParser = new CommandLineParser(g_iArgumentCount, (const char**)(*g_szArguments));
if (g_pCommandLineParser->GetPrintVersion())
{
printf("nzbget version: %s\n", Util::VersionRevision());
exit(0);
}
if (g_pCommandLineParser->GetPrintUsage() || g_pCommandLineParser->GetErrors() || g_iArgumentCount <= 1)
{
g_pCommandLineParser->PrintUsage(((const char**)(*g_szArguments))[0]);
exit(0);
}
debug("Reading options");
g_pOptions = new Options((*g_szArguments)[0], g_pCommandLineParser->GetConfigFilename(),
g_pCommandLineParser->GetNoConfig(), (Options::CmdOptList*)g_pCommandLineParser->GetOptionList(),
&g_OptionsExtender);
g_pOptions->SetRemoteClientMode(g_pCommandLineParser->GetRemoteClientMode());
g_pOptions->SetServerMode(g_pCommandLineParser->GetServerMode());
g_pOptions->SetPauseDownload(g_pCommandLineParser->GetPauseDownload());
g_pLog->InitOptions();
if (g_pOptions->GetFatalError())
{
exit(1);
}
else if (g_pOptions->GetConfigErrors() &&
g_pCommandLineParser->GetClientOperation() == CommandLineParser::opClientNoOperation)
{
info("Pausing all activities due to errors in configuration");
g_pOptions->SetPauseDownload(true);
g_pOptions->SetPausePostProcess(true);
g_pOptions->SetPauseScan(true);
}
g_pServerPool->SetTimeout(g_pOptions->GetArticleTimeout());
g_pServerPool->SetRetryInterval(g_pOptions->GetRetryInterval());
g_pScriptConfig = new ScriptConfig();
}
void ProcessClientRequest()
{
RemoteClient* Client = new RemoteClient();
switch (g_pOptions->GetClientOperation())
switch (g_pCommandLineParser->GetClientOperation())
{
case Options::opClientRequestListFiles:
Client->RequestServerList(true, false, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
case CommandLineParser::opClientRequestListFiles:
Client->RequestServerList(true, false, g_pCommandLineParser->GetMatchMode() == CommandLineParser::mmRegEx ? g_pCommandLineParser->GetEditQueueText() : NULL);
break;
case Options::opClientRequestListGroups:
Client->RequestServerList(false, true, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
case CommandLineParser::opClientRequestListGroups:
Client->RequestServerList(false, true, g_pCommandLineParser->GetMatchMode() == CommandLineParser::mmRegEx ? g_pCommandLineParser->GetEditQueueText() : NULL);
break;
case Options::opClientRequestListStatus:
case CommandLineParser::opClientRequestListStatus:
Client->RequestServerList(false, false, NULL);
break;
case Options::opClientRequestDownloadPause:
case CommandLineParser::opClientRequestDownloadPause:
Client->RequestServerPauseUnpause(true, eRemotePauseUnpauseActionDownload);
break;
case Options::opClientRequestDownloadUnpause:
case CommandLineParser::opClientRequestDownloadUnpause:
Client->RequestServerPauseUnpause(false, eRemotePauseUnpauseActionDownload);
break;
case Options::opClientRequestSetRate:
Client->RequestServerSetDownloadRate(g_pOptions->GetSetRate());
case CommandLineParser::opClientRequestSetRate:
Client->RequestServerSetDownloadRate(g_pCommandLineParser->GetSetRate());
break;
case Options::opClientRequestDumpDebug:
case CommandLineParser::opClientRequestDumpDebug:
Client->RequestServerDumpDebug();
break;
case Options::opClientRequestEditQueue:
Client->RequestServerEditQueue((DownloadQueue::EEditAction)g_pOptions->GetEditQueueAction(),
g_pOptions->GetEditQueueOffset(), g_pOptions->GetEditQueueText(),
g_pOptions->GetEditQueueIDList(), g_pOptions->GetEditQueueIDCount(),
g_pOptions->GetEditQueueNameList(), (eRemoteMatchMode)g_pOptions->GetMatchMode());
case CommandLineParser::opClientRequestEditQueue:
Client->RequestServerEditQueue((DownloadQueue::EEditAction)g_pCommandLineParser->GetEditQueueAction(),
g_pCommandLineParser->GetEditQueueOffset(), g_pCommandLineParser->GetEditQueueText(),
g_pCommandLineParser->GetEditQueueIDList(), g_pCommandLineParser->GetEditQueueIDCount(),
g_pCommandLineParser->GetEditQueueNameList(), (eRemoteMatchMode)g_pCommandLineParser->GetMatchMode());
break;
case Options::opClientRequestLog:
Client->RequestServerLog(g_pOptions->GetLogLines());
case CommandLineParser::opClientRequestLog:
Client->RequestServerLog(g_pCommandLineParser->GetLogLines());
break;
case Options::opClientRequestShutdown:
case CommandLineParser::opClientRequestShutdown:
Client->RequestServerShutdown();
break;
case Options::opClientRequestReload:
case CommandLineParser::opClientRequestReload:
Client->RequestServerReload();
break;
case Options::opClientRequestDownload:
Client->RequestServerDownload(g_pOptions->GetAddNZBFilename(), g_pOptions->GetArgFilename(),
g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority(),
g_pOptions->GetAddDupeKey(), g_pOptions->GetAddDupeMode(), g_pOptions->GetAddDupeScore());
case CommandLineParser::opClientRequestDownload:
Client->RequestServerDownload(g_pCommandLineParser->GetAddNZBFilename(), g_pCommandLineParser->GetArgFilename(),
g_pCommandLineParser->GetAddCategory(), g_pCommandLineParser->GetAddTop(), g_pCommandLineParser->GetAddPaused(), g_pCommandLineParser->GetAddPriority(),
g_pCommandLineParser->GetAddDupeKey(), g_pCommandLineParser->GetAddDupeMode(), g_pCommandLineParser->GetAddDupeScore());
break;
case Options::opClientRequestVersion:
case CommandLineParser::opClientRequestVersion:
Client->RequestServerVersion();
break;
case Options::opClientRequestPostQueue:
case CommandLineParser::opClientRequestPostQueue:
Client->RequestPostQueue();
break;
case Options::opClientRequestWriteLog:
Client->RequestWriteLog(g_pOptions->GetWriteLogKind(), g_pOptions->GetLastArg());
case CommandLineParser::opClientRequestWriteLog:
Client->RequestWriteLog(g_pCommandLineParser->GetWriteLogKind(), g_pCommandLineParser->GetLastArg());
break;
case Options::opClientRequestScanAsync:
case CommandLineParser::opClientRequestScanAsync:
Client->RequestScan(false);
break;
case Options::opClientRequestScanSync:
case CommandLineParser::opClientRequestScanSync:
Client->RequestScan(true);
break;
case Options::opClientRequestPostPause:
case CommandLineParser::opClientRequestPostPause:
Client->RequestServerPauseUnpause(true, eRemotePauseUnpauseActionPostProcess);
break;
case Options::opClientRequestPostUnpause:
case CommandLineParser::opClientRequestPostUnpause:
Client->RequestServerPauseUnpause(false, eRemotePauseUnpauseActionPostProcess);
break;
case Options::opClientRequestScanPause:
case CommandLineParser::opClientRequestScanPause:
Client->RequestServerPauseUnpause(true, eRemotePauseUnpauseActionScan);
break;
case Options::opClientRequestScanUnpause:
case CommandLineParser::opClientRequestScanUnpause:
Client->RequestServerPauseUnpause(false, eRemotePauseUnpauseActionScan);
break;
case Options::opClientRequestHistory:
case Options::opClientRequestHistoryAll:
Client->RequestHistory(g_pOptions->GetClientOperation() == Options::opClientRequestHistoryAll);
case CommandLineParser::opClientRequestHistory:
case CommandLineParser::opClientRequestHistoryAll:
Client->RequestHistory(g_pCommandLineParser->GetClientOperation() == CommandLineParser::opClientRequestHistoryAll);
break;
case Options::opClientNoOperation:
case CommandLineParser::opClientNoOperation:
break;
}
@@ -584,31 +700,37 @@ void ProcessClientRequest()
void ProcessWebGet()
{
WebDownloader downloader;
downloader.SetURL(g_pOptions->GetLastArg());
downloader.SetURL(g_pCommandLineParser->GetLastArg());
downloader.SetForce(true);
downloader.SetRetry(false);
downloader.SetOutputFilename(g_pOptions->GetWebGetFilename());
downloader.SetOutputFilename(g_pCommandLineParser->GetWebGetFilename());
downloader.SetInfoName("WebGet");
int iRedirects = 0;
WebDownloader::EStatus eStatus = WebDownloader::adRedirect;
while (eStatus == WebDownloader::adRedirect && iRedirects < 5)
{
iRedirects++;
eStatus = downloader.Download();
}
WebDownloader::EStatus eStatus = downloader.DownloadWithRedirects(5);
bool bOK = eStatus == WebDownloader::adFinished;
exit(bOK ? 0 : 1);
}
void ProcessSigVerify()
{
#ifdef HAVE_OPENSSL
bool bOK = Maintenance::VerifySignature(g_pCommandLineParser->GetLastArg(),
g_pCommandLineParser->GetSigFilename(), g_pCommandLineParser->GetPubKeyFilename());
exit(bOK ? 93 : 1);
#else
printf("ERROR: Could not verify signature, the program was compiled without OpenSSL support\n");
exit(1);
#endif
}
void ExitProc()
{
if (!g_bReloading)
{
info("Stopping, please wait...");
}
if (g_pOptions->GetRemoteClientMode())
if (g_pCommandLineParser->GetRemoteClientMode())
{
if (g_pFrontend)
{
@@ -621,11 +743,13 @@ void ExitProc()
if (g_pQueueCoordinator)
{
debug("Stopping QueueCoordinator");
g_pServiceCoordinator->Stop();
g_pQueueCoordinator->Stop();
g_pUrlCoordinator->Stop();
g_pPrePostProcessor->Stop();
g_pFeedCoordinator->Stop();
g_pArticleCache->Stop();
g_pQueueScriptCoordinator->Stop();
#ifdef WIN32
g_pWinConsole->Stop();
#endif
@@ -694,16 +818,31 @@ void Cleanup()
debug("Deleting Options");
if (g_pOptions)
{
if (g_pOptions->GetDaemonMode() && !g_bReloading)
if (g_pCommandLineParser->GetDaemonMode() && !g_bReloading)
{
info("Deleting lock file");
remove(g_pOptions->GetLockFile());
}
delete g_pOptions;
g_pOptions = NULL;
}
debug("Options deleted");
debug("Deleting CommandLineParser");
if (g_pCommandLineParser)
{
delete g_pCommandLineParser;
g_pCommandLineParser = NULL;
}
debug("CommandLineParser deleted");
debug("Deleting ScriptConfig");
if (g_pScriptConfig)
{
delete g_pScriptConfig;
g_pScriptConfig = NULL;
}
debug("ScriptConfig deleted");
debug("Deleting ServerPool");
delete g_pServerPool;
g_pServerPool = NULL;
@@ -739,6 +878,16 @@ void Cleanup()
g_pStatMeter = NULL;
debug("StatMeter deleted");
debug("Deleting ServiceCoordinator");
delete g_pServiceCoordinator;
g_pServiceCoordinator = NULL;
debug("ServiceCoordinator deleted");
debug("Deleting DiskService");
delete g_pDiskService;
g_pDiskService = NULL;
debug("DiskService deleted");
if (!g_bReloading)
{
Connection::Final();
@@ -752,8 +901,7 @@ void Cleanup()
debug("Global objects cleaned up");
delete g_pLog;
g_pLog = NULL;
Log::Final();
}
#ifndef WIN32
@@ -849,3 +997,4 @@ void DisableCout()
std::cout.rdbuf(&NullStreamBufInstance);
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,9 @@
#define gmtime_r(time, tm) gmtime_s(tm, time)
#define strtok_r(str, delim, saveptr) strtok_s(str, delim, saveptr)
#define strerror_r(errnum, buffer, size) strerror_s(buffer, size, errnum)
#if (_MSC_VER < 1600)
#define int32_t __int32
#endif
#define mkdir(dir, flags) _mkdir(dir)
#define rmdir _rmdir
#define strcasecmp(a, b) _stricmp(a, b)
@@ -60,6 +62,9 @@
#define atoll _atoi64
#define fseek _fseeki64
#define ftell _ftelli64
#if _MSC_VER < 1800 // va_copy is available in vc2013 and onwards
#define va_copy(d,s) ((d) = (s))
#endif
#ifndef FSCTL_SET_SPARSE
#define FSCTL_SET_SPARSE 590020
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,10 +54,6 @@
#include "StatMeter.h"
#include "Util.h"
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern StatMeter* g_pStatMeter;
ArticleDownloader::ArticleDownloader()
{
debug("Creating ArticleDownloader");
@@ -456,9 +452,16 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
}
}
}
else if (m_eFormat == Decoder::efUnknown && g_pOptions->GetDecode())
if (m_eFormat == Decoder::efUnknown && g_pOptions->GetDecode())
{
m_eFormat = Decoder::DetectFormat(line, iLen);
m_eFormat = Decoder::DetectFormat(line, iLen, bBody);
if (m_eFormat != Decoder::efUnknown)
{
// sometimes news servers misbehave and send article body without new line separator between headers and body
// if we found decoder signature we know the body is already arrived
bBody = true;
}
}
// write to output file

View File

@@ -51,11 +51,6 @@
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
extern ArticleCache* g_pArticleCache;
ArticleWriter::ArticleWriter()
{
debug("Creating ArticleWriter");

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -99,4 +99,6 @@ public:
bool FileBusy(FileInfo* pFileInfo) { return pFileInfo == m_pFileInfo; }
};
extern ArticleCache* g_pArticleCache;
#endif

View File

@@ -65,14 +65,14 @@ void Decoder::Clear()
m_szArticleFilename = NULL;
}
Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len)
Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len, bool inBody)
{
if (!strncmp(buffer, "=ybegin ", 8))
{
return efYenc;
}
if ((len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
if (inBody && (len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
{
return efUx;
}

View File

@@ -58,7 +58,7 @@ public:
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len) = 0;
const char* GetArticleFilename() { return m_szArticleFilename; }
static EFormat DetectFormat(const char* buffer, int len);
static EFormat DetectFormat(const char* buffer, int len, bool inBody);
};
class YDecoder: public Decoder

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -87,4 +87,6 @@ public:
void BlockServer(NewsServer* pNewsServer);
};
extern ServerPool* g_pServerPool;
#endif

View File

@@ -42,10 +42,6 @@
#include "DiskState.h"
#include "Util.h"
extern ServerPool* g_pServerPool;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
static const int DAYS_UP_TO_2013_JAN_1 = 15706;
static const int DAYS_IN_TWENTY_YEARS = 366*20;
@@ -388,11 +384,7 @@ void StatMeter::AddSpeedReading(int iBytes)
if (g_pOptions->GetAccurateRate())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Lock();
#else
m_mutexSpeed.Lock();
#endif
}
if (tCurTime != m_tCurSecTime)
@@ -445,11 +437,7 @@ void StatMeter::AddSpeedReading(int iBytes)
if (g_pOptions->GetAccurateRate())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Unlock();
#else
m_mutexSpeed.Unlock();
#endif
}
}
@@ -472,9 +460,9 @@ void StatMeter::ResetSpeedStat()
void StatMeter::LogDebugInfo()
{
info(" ---------- SpeedMeter");
float fSpeed = (float)(CalcCurrentDownloadSpeed() / 1024.0);
int iSpeed = CalcCurrentDownloadSpeed() / 1024;
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
info(" Speed: %f", fSpeed);
info(" Speed: %i", iSpeed);
info(" SpeedStartTime: %i", m_iSpeedStartTime);
info(" SpeedTotalBytes: %i", m_iSpeedTotalBytes);
info(" SpeedBytesIndex: %i", m_iSpeedBytesIndex);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -95,11 +95,7 @@ private:
int m_iSpeedBytesIndex;
int m_iCurSecBytes;
time_t m_tCurSecTime;
#ifdef HAVE_SPINLOCK
SpinLock m_spinlockSpeed;
#else
Mutex m_mutexSpeed;
#endif
// time
long long m_iAllBytes;
@@ -140,4 +136,6 @@ public:
bool Load(bool* pPerfectServerMatch);
};
extern StatMeter* g_pStatMeter;
#endif

View File

@@ -0,0 +1,278 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <errno.h>
#include "nzbget.h"
#include "Cleanup.h"
#include "Log.h"
#include "Util.h"
#include "ParParser.h"
#include "Options.h"
void MoveController::StartJob(PostInfo* pPostInfo)
{
MoveController* pMoveController = new MoveController();
pMoveController->m_pPostInfo = pPostInfo;
pMoveController->SetAutoDestroy(false);
pPostInfo->SetPostThread(pMoveController);
pMoveController->Start();
}
void MoveController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
szNZBName[1024-1] = '\0';
char szInfoName[1024];
snprintf(szInfoName, 1024, "move for %s", m_pPostInfo->GetNZBInfo()->GetName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
strncpy(m_szInterDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
m_szInterDir[1024-1] = '\0';
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szDestDir, 1024);
m_szDestDir[1024-1] = '\0';
DownloadQueue::Unlock();
PrintMessage(Message::mkInfo, "Moving completed files for %s", szNZBName);
bool bOK = MoveFiles();
szInfoName[0] = 'M'; // uppercase
if (bOK)
{
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
// save new dest dir
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir);
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msSuccess);
DownloadQueue::Unlock();
}
else
{
PrintMessage(Message::mkError, "%s failed", szInfoName);
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msFailure);
}
m_pPostInfo->SetStage(PostInfo::ptQueued);
m_pPostInfo->SetWorking(false);
}
bool MoveController::MoveFiles()
{
char szErrBuf[1024];
if (!Util::ForceDirectories(m_szDestDir, szErrBuf, sizeof(szErrBuf)))
{
PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szDestDir, szErrBuf);
return false;
}
bool bOK = true;
DirBrowser dir(m_szInterDir);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, ".."))
{
char szSrcFile[1024];
snprintf(szSrcFile, 1024, "%s%c%s", m_szInterDir, PATH_SEPARATOR, filename);
szSrcFile[1024-1] = '\0';
char szDstFile[1024];
Util::MakeUniqueFilename(szDstFile, 1024, m_szDestDir, filename);
bool bHiddenFile = filename[0] == '.';
if (!bHiddenFile)
{
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
}
if (!Util::MoveFile(szSrcFile, szDstFile) && !bHiddenFile)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
bOK = false;
}
}
}
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir, szErrBuf, sizeof(szErrBuf)))
{
PrintMessage(Message::mkWarning, "Could not delete intermediate directory %s: %s", m_szInterDir, szErrBuf);
}
return bOK;
}
void MoveController::AddMessage(Message::EKind eKind, const char* szText)
{
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
}
void CleanupController::StartJob(PostInfo* pPostInfo)
{
CleanupController* pCleanupController = new CleanupController();
pCleanupController->m_pPostInfo = pPostInfo;
pCleanupController->SetAutoDestroy(false);
pPostInfo->SetPostThread(pCleanupController);
pCleanupController->Start();
}
void CleanupController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
szNZBName[1024-1] = '\0';
char szInfoName[1024];
snprintf(szInfoName, 1024, "cleanup for %s", m_pPostInfo->GetNZBInfo()->GetName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
m_szDestDir[1024-1] = '\0';
bool bInterDir = strlen(g_pOptions->GetInterDir()) > 0 &&
!strncmp(m_szDestDir, g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
if (bInterDir)
{
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szFinalDir, 1024);
m_szFinalDir[1024-1] = '\0';
}
else
{
m_szFinalDir[0] = '\0';
}
DownloadQueue::Unlock();
PrintMessage(Message::mkInfo, "Cleaning up %s", szNZBName);
bool bDeleted = false;
bool bOK = Cleanup(m_szDestDir, &bDeleted);
if (bOK && m_szFinalDir[0] != '\0')
{
bool bDeleted2 = false;
bOK = Cleanup(m_szFinalDir, &bDeleted2);
bDeleted = bDeleted || bDeleted2;
}
szInfoName[0] = 'C'; // uppercase
if (bOK && bDeleted)
{
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
}
else if (bOK)
{
PrintMessage(Message::mkInfo, "Nothing to cleanup for %s", szNZBName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
}
else
{
PrintMessage(Message::mkError, "%s failed", szInfoName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csFailure);
}
m_pPostInfo->SetStage(PostInfo::ptQueued);
m_pPostInfo->SetWorking(false);
}
bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
{
*bDeleted = false;
bool bOK = true;
DirBrowser dir(szDestDir);
while (const char* filename = dir.Next())
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
bool bIsDir = Util::DirectoryExists(szFullFilename);
if (strcmp(filename, ".") && strcmp(filename, "..") && bIsDir)
{
bOK &= Cleanup(szFullFilename, bDeleted);
}
// check file extension
bool bDeleteIt = Util::MatchFileExt(filename, g_pOptions->GetExtCleanupDisk(), ",;") && !bIsDir;
if (bDeleteIt)
{
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
if (remove(szFullFilename) != 0)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not delete file %s: %s", szFullFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
bOK = false;
}
*bDeleted = true;
}
}
return bOK;
}
void CleanupController::AddMessage(Message::EKind eKind, const char* szText)
{
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
}

View File

@@ -0,0 +1,68 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef CLEANUP_H
#define CLEANUP_H
#include "Log.h"
#include "Thread.h"
#include "DownloadInfo.h"
#include "Script.h"
class MoveController : public Thread, public ScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szInterDir[1024];
char m_szDestDir[1024];
bool MoveFiles();
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
static void StartJob(PostInfo* pPostInfo);
};
class CleanupController : public Thread, public ScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szDestDir[1024];
char m_szFinalDir[1024];
bool Cleanup(const char* szDestDir, bool *bDeleted);
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
static void StartJob(PostInfo* pPostInfo);
};
#endif

View File

@@ -0,0 +1,260 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <errno.h>
#include "nzbget.h"
#include "DupeMatcher.h"
#include "Log.h"
#include "Util.h"
#include "Options.h"
#include "Script.h"
#include "Thread.h"
class RarLister : public Thread, public ScriptController
{
private:
DupeMatcher* m_pOwner;
long long m_lMaxSize;
bool m_bCompressed;
bool m_bLastSizeMax;
long long m_lExpectedSize;
char* m_szFilenameBuf;
int m_iFilenameBufLen;
char m_szLastFilename[1024];
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
static bool FindLargestFile(DupeMatcher* pOwner, const char* szDirectory,
char* szFilenameBuf, int iFilenameBufLen, long long lExpectedSize,
int iTimeoutSec, long long* pMaxSize, bool* pCompressed);
};
bool RarLister::FindLargestFile(DupeMatcher* pOwner, const char* szDirectory,
char* szFilenameBuf, int iFilenameBufLen, long long lExpectedSize,
int iTimeoutSec, long long* pMaxSize, bool* pCompressed)
{
RarLister unrar;
unrar.m_pOwner = pOwner;
unrar.m_lExpectedSize = lExpectedSize;
unrar.m_lMaxSize = -1;
unrar.m_bCompressed = false;
unrar.m_bLastSizeMax = false;
unrar.m_szFilenameBuf = szFilenameBuf;
unrar.m_iFilenameBufLen = iFilenameBufLen;
char** pCmdArgs = NULL;
if (!Util::SplitCommandLine(g_pOptions->GetUnrarCmd(), &pCmdArgs))
{
return false;
}
const char* szUnrarPath = *pCmdArgs;
unrar.SetScript(szUnrarPath);
const char* szArgs[4];
szArgs[0] = szUnrarPath;
szArgs[1] = "lt";
szArgs[2] = "*.rar";
szArgs[3] = NULL;
unrar.SetArgs(szArgs, false);
unrar.SetWorkingDir(szDirectory);
time_t curTime = time(NULL);
unrar.Start();
// wait up to iTimeoutSec for unrar output
while (unrar.IsRunning() &&
curTime + iTimeoutSec > time(NULL) &&
curTime >= time(NULL)) // in a case clock was changed
{
usleep(200 * 1000);
}
if (unrar.IsRunning())
{
unrar.Terminate();
}
// wait until terminated or killed
while (unrar.IsRunning())
{
usleep(200 * 1000);
}
for (char** szArgPtr = pCmdArgs; *szArgPtr; szArgPtr++)
{
free(*szArgPtr);
}
free(pCmdArgs);
*pMaxSize = unrar.m_lMaxSize;
*pCompressed = unrar.m_bCompressed;
return true;
}
void RarLister::Run()
{
Execute();
}
void RarLister::AddMessage(Message::EKind eKind, const char* szText)
{
if (!strncasecmp(szText, "Archive: ", 9))
{
m_pOwner->PrintMessage(Message::mkDetail, "Reading file %s", szText + 9);
}
else if (!strncasecmp(szText, " Name: ", 14))
{
strncpy(m_szLastFilename, szText + 14, sizeof(m_szLastFilename));
m_szLastFilename[sizeof(m_szLastFilename)-1] = '\0';
}
else if (!strncasecmp(szText, " Size: ", 14))
{
m_bLastSizeMax = false;
long long lSize = atoll(szText + 14);
if (lSize > m_lMaxSize)
{
m_lMaxSize = lSize;
m_bLastSizeMax = true;
strncpy(m_szFilenameBuf, m_szLastFilename, m_iFilenameBufLen);
m_szFilenameBuf[m_iFilenameBufLen-1] = '\0';
}
return;
}
if (m_bLastSizeMax && !strncasecmp(szText, " Compression: ", 14))
{
m_bCompressed = !strstr(szText, " -m0");
if (m_lMaxSize > m_lExpectedSize ||
DupeMatcher::SizeDiffOK(m_lMaxSize, m_lExpectedSize, 20))
{
// alread found the largest file, aborting unrar
Terminate();
}
}
}
DupeMatcher::DupeMatcher(const char* szDestDir, long long lExpectedSize)
{
m_szDestDir = strdup(szDestDir);
m_lExpectedSize = lExpectedSize;
m_lMaxSize = -1;
m_bCompressed = false;
}
DupeMatcher::~DupeMatcher()
{
free(m_szDestDir);
}
bool DupeMatcher::SizeDiffOK(long long lSize1, long long lSize2, int iMaxDiffPercent)
{
if (lSize1 == 0 || lSize2 == 0)
{
return false;
}
long long lDiff = lSize1 - lSize2;
lDiff = lDiff > 0 ? lDiff : -lDiff;
long long lMax = lSize1 > lSize2 ? lSize1 : lSize2;
int lDiffPercent = (int)(lDiff * 100 / lMax);
return lDiffPercent < iMaxDiffPercent;
}
bool DupeMatcher::Prepare()
{
char szFilename[1024];
FindLargestFile(m_szDestDir, szFilename, sizeof(szFilename), &m_lMaxSize, &m_bCompressed);
bool bSizeOK = SizeDiffOK(m_lMaxSize, m_lExpectedSize, 20);
PrintMessage(Message::mkDetail, "Found main file %s with size %lli bytes%s",
szFilename, m_lMaxSize, bSizeOK ? "" : ", size mismatch");
return bSizeOK;
}
bool DupeMatcher::MatchDupeContent(const char* szDupeDir)
{
long long lDupeMaxSize = 0;
bool lDupeCompressed = false;
char szFilename[1024];
FindLargestFile(szDupeDir, szFilename, sizeof(szFilename), &lDupeMaxSize, &lDupeCompressed);
bool bOK = lDupeMaxSize == m_lMaxSize && lDupeCompressed == m_bCompressed;
PrintMessage(Message::mkDetail, "Found main file %s with size %lli bytes%s",
szFilename, m_lMaxSize, bOK ? "" : ", size mismatch");
return bOK;
}
void DupeMatcher::FindLargestFile(const char* szDirectory, char* szFilenameBuf, int iBufLen,
long long* pMaxSize, bool* pCompressed)
{
*pMaxSize = 0;
*pCompressed = false;
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, ".."))
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
long long lFileSize = Util::FileSize(szFullFilename);
if (lFileSize > *pMaxSize)
{
*pMaxSize = lFileSize;
strncpy(szFilenameBuf, filename, iBufLen);
szFilenameBuf[iBufLen-1] = '\0';
}
if (Util::MatchFileExt(filename, ".rar", ","))
{
RarLister::FindLargestFile(this, szDirectory, szFilenameBuf, iBufLen,
m_lMaxSize, 60, pMaxSize, pCompressed);
return;
}
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef DUPEMATCHER_H
#define DUPEMATCHER_H
#include "Log.h"
class DupeMatcher
{
private:
char* m_szDestDir;
long long m_lExpectedSize;
long long m_lMaxSize;
bool m_bCompressed;
void FindLargestFile(const char* szDirectory, char* szFilenameBuf, int iBufLen,
long long* pMaxSize, bool* pCompressed);
friend class RarLister;
protected:
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
public:
DupeMatcher(const char* szDestDir, long long lExpectedSize);
~DupeMatcher();
bool Prepare();
bool MatchDupeContent(const char* szDupeDir);
static bool SizeDiffOK(long long lSize1, long long lSize2, int iMaxDiffPercent);
};
#endif

View File

@@ -50,13 +50,11 @@
#include "nzbget.h"
#include "Thread.h"
#include "ParChecker.h"
#include "ParCoordinator.h"
#include "ParParser.h"
#include "Log.h"
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
const char* Par2CmdLineErrStr[] = { "OK",
"data files are damaged and there is enough recovery data available to repair them",
"data files are damaged and there is insufficient recovery data available to be able to repair them",
@@ -86,12 +84,7 @@ private:
ParChecker* m_pOwner;
Threads m_Threads;
bool m_bParallel;
#ifdef HAVE_SPINLOCK
SpinLock progresslock;
#else
Mutex progresslock;
#endif
virtual void BeginRepair();
virtual void EndRepair();
@@ -99,7 +92,7 @@ private:
protected:
virtual void sig_filename(std::string filename) { m_pOwner->signal_filename(filename); }
virtual void sig_progress(double progress) { m_pOwner->signal_progress(progress); }
virtual void sig_progress(int progress) { m_pOwner->signal_progress(progress); }
virtual void sig_done(std::string filename, int available, int total) { m_pOwner->signal_done(filename, available, total); }
virtual bool ScanDataFile(DiskFile *diskfile, Par2RepairerSourceFile* &sourcefile,
@@ -171,7 +164,9 @@ Result Repairer::PreProcess(const char *szParFilename)
Result Repairer::Process(bool dorepair)
{
return Par2Repairer::Process(commandLine, dorepair);
Result res = Par2Repairer::Process(commandLine, dorepair);
debug("ParChecker: Process-result=%i", res);
return res;
}
@@ -186,16 +181,19 @@ bool Repairer::ScanDataFile(DiskFile *diskfile, Par2RepairerSourceFile* &sourcef
sig_filename(name);
int iAvailableBlocks = sourcefile->BlockCount();
ParChecker::EFileStatus eFileStatus = m_pOwner->VerifyDataFile(diskfile, sourcefile, &iAvailableBlocks);
if (eFileStatus != ParChecker::fsUnknown)
if (!(m_pOwner->GetStage() == ParChecker::ptVerifyingRepaired && m_pOwner->GetParFull()))
{
sig_done(name, iAvailableBlocks, sourcefile->BlockCount());
sig_progress(1000.0);
matchtype = eFileStatus == ParChecker::fsSuccess ? eFullMatch :
eFileStatus == ParChecker::fsPartial ? ePartialMatch : eNoMatch;
m_pOwner->SetParFull(false);
return true;
int iAvailableBlocks = sourcefile->BlockCount();
ParChecker::EFileStatus eFileStatus = m_pOwner->VerifyDataFile(diskfile, sourcefile, &iAvailableBlocks);
if (eFileStatus != ParChecker::fsUnknown)
{
sig_done(name, iAvailableBlocks, sourcefile->BlockCount());
sig_progress(1000);
matchtype = eFileStatus == ParChecker::fsSuccess ? eFullMatch :
eFileStatus == ParChecker::fsPartial ? ePartialMatch : eNoMatch;
m_pOwner->SetParFull(false);
return true;
}
}
}
@@ -395,6 +393,18 @@ ParChecker::SegmentList::~SegmentList()
}
}
ParChecker::DupeSource::DupeSource(int iID, const char* szDirectory)
{
m_iID = iID;
m_szDirectory = strdup(szDirectory);
m_iUsedBlocks = 0;
}
ParChecker::DupeSource::~DupeSource()
{
free(m_szDirectory);
}
ParChecker::ParChecker()
{
@@ -411,6 +421,7 @@ ParChecker::ParChecker()
m_iFileProgress = 0;
m_iStageProgress = 0;
m_iExtraFiles = 0;
m_iQuickFiles = 0;
m_bVerifyingExtraFiles = false;
m_bCancelled = false;
m_eStage = ptLoadingPars;
@@ -450,6 +461,12 @@ void ParChecker::Cleanup()
m_sourceFiles.clear();
for (DupeSourceList::iterator it = m_DupeSources.begin(); it != m_DupeSources.end() ;it++)
{
free(*it);
}
m_DupeSources.clear();
free(m_szErrMsg);
m_szErrMsg = NULL;
}
@@ -488,8 +505,8 @@ void ParChecker::Run()
ParChecker::EStatus ParChecker::RunParCheckAll()
{
ParCoordinator::ParFileList fileList;
if (!ParCoordinator::FindMainPars(m_szDestDir, &fileList))
ParParser::ParFileList fileList;
if (!ParParser::FindMainPars(m_szDestDir, &fileList))
{
PrintMessage(Message::mkError, "Could not start par-check for %s. Could not find any par-files", m_szNZBName);
return psFailed;
@@ -499,7 +516,7 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
m_bCancelled = false;
m_bParFull = true;
for (ParCoordinator::ParFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
for (ParParser::ParFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
{
char* szParFilename = *it;
debug("Found par: %s", szParFilename);
@@ -512,7 +529,7 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
char szInfoName[1024];
int iBaseLen = 0;
ParCoordinator::ParseParFilename(szParFilename, &iBaseLen, NULL);
ParParser::ParseParFilename(szParFilename, &iBaseLen, NULL);
int maxlen = iBaseLen < 1024 ? iBaseLen : 1024 - 1;
strncpy(szInfoName, szParFilename, maxlen);
szInfoName[maxlen] = '\0';
@@ -550,6 +567,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
m_eStage = ptLoadingPars;
m_iProcessedFiles = 0;
m_iExtraFiles = 0;
m_iQuickFiles = 0;
m_bVerifyingExtraFiles = false;
m_bHasDamagedFiles = false;
EStatus eStatus = psFailed;
@@ -574,7 +592,6 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
m_eStage = ptVerifyingSources;
Repairer* pRepairer = (Repairer*)m_pRepairer;
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
if (!m_bParQuick)
{
@@ -588,18 +605,17 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
if (bAddedSplittedFragments)
{
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
}
if (m_bHasDamagedFiles && !IsStopped() && pRepairer->missingfilecount > 0 &&
!(bAddedSplittedFragments && res == eRepairPossible) &&
g_pOptions->GetParScan() == Options::psAuto)
(g_pOptions->GetParScan() == Options::psExtended ||
g_pOptions->GetParScan() == Options::psDupe))
{
if (AddMissingFiles())
{
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
}
@@ -608,6 +624,19 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
res = (Result)ProcessMorePars();
}
if (m_bHasDamagedFiles && !IsStopped() && res == eRepairNotPossible &&
g_pOptions->GetParScan() == Options::psDupe)
{
if (AddDupeFiles())
{
res = pRepairer->Process(false);
if (!IsStopped() && res == eRepairNotPossible)
{
res = (Result)ProcessMorePars();
}
}
}
if (IsStopped())
{
Cleanup();
@@ -639,11 +668,11 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
UpdateProgress();
res = pRepairer->Process(true);
debug("ParChecker: Process-result=%i", res);
if (res == eSuccess)
{
PrintMessage(Message::mkInfo, "Successfully repaired %s", m_szInfoName);
eStatus = psRepaired;
StatDupeSources(&m_DupeSources);
DeleteLeftovers();
}
}
@@ -858,7 +887,6 @@ int ParChecker::ProcessMorePars()
{
pRepairer->UpdateVerificationResults();
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
}
@@ -908,20 +936,9 @@ void ParChecker::QueueChanged()
bool ParChecker::AddSplittedFragments()
{
char szDirectory[1024];
strncpy(szDirectory, m_szParFilename, 1024);
szDirectory[1024-1] = '\0';
char* szBasename = Util::BaseFileName(szDirectory);
if (szBasename == szDirectory)
{
return false;
}
szBasename[-1] = '\0';
std::list<CommandLine::ExtraFile> extrafiles;
DirBrowser dir(szDirectory);
DirBrowser dir(m_szDestDir);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt") &&
@@ -948,7 +965,7 @@ bool ParChecker::AddSplittedFragments()
debug("Found splitted fragment %s", filename);
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
snprintf(fullfilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
fullfilename[1024-1] = '\0';
CommandLine::ExtraFile extrafile(fullfilename, Util::FileSize(fullfilename));
@@ -977,18 +994,64 @@ bool ParChecker::AddSplittedFragments()
bool ParChecker::AddMissingFiles()
{
PrintMessage(Message::mkInfo, "Performing extra par-scan for %s", m_szInfoName);
return AddExtraFiles(true, false, m_szDestDir);
}
bool ParChecker::AddDupeFiles()
{
char szDirectory[1024];
strncpy(szDirectory, m_szParFilename, 1024);
szDirectory[1024-1] = '\0';
char* szBasename = Util::BaseFileName(szDirectory);
if (szBasename == szDirectory)
bool bAdded = AddExtraFiles(false, false, szDirectory);
if (((Repairer*)m_pRepairer)->missingblockcount > 0)
{
return false;
// scanning directories of duplicates
RequestDupeSources(&m_DupeSources);
if (!m_DupeSources.empty())
{
int iWasBlocksMissing = ((Repairer*)m_pRepairer)->missingblockcount;
for (DupeSourceList::iterator it = m_DupeSources.begin(); it != m_DupeSources.end(); it++)
{
DupeSource* pDupeSource = *it;
if (((Repairer*)m_pRepairer)->missingblockcount > 0 && Util::DirectoryExists(pDupeSource->GetDirectory()))
{
int iWasBlocksMissing2 = ((Repairer*)m_pRepairer)->missingblockcount;
bool bOneAdded = AddExtraFiles(false, true, pDupeSource->GetDirectory());
bAdded |= bOneAdded;
int iBlocksMissing2 = ((Repairer*)m_pRepairer)->missingblockcount;
pDupeSource->SetUsedBlocks(pDupeSource->GetUsedBlocks() + (iWasBlocksMissing2 - iBlocksMissing2));
}
}
int iBlocksMissing = ((Repairer*)m_pRepairer)->missingblockcount;
if (iBlocksMissing < iWasBlocksMissing)
{
PrintMessage(Message::mkInfo, "Found extra %i blocks in dupe sources", iWasBlocksMissing - iBlocksMissing);
}
else
{
PrintMessage(Message::mkInfo, "No extra blocks found in dupe sources");
}
}
}
return bAdded;
}
bool ParChecker::AddExtraFiles(bool bOnlyMissing, bool bExternalDir, const char* szDirectory)
{
if (bExternalDir)
{
PrintMessage(Message::mkInfo, "Performing dupe par-scan for %s in %s", m_szInfoName, Util::BaseFileName(szDirectory));
}
else
{
PrintMessage(Message::mkInfo, "Performing extra par-scan for %s", m_szInfoName);
}
szBasename[-1] = '\0';
std::list<CommandLine::ExtraFile*> extrafiles;
@@ -996,7 +1059,7 @@ bool ParChecker::AddMissingFiles()
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt") &&
!IsParredFile(filename) && !IsProcessedFile(filename))
(bExternalDir || (!IsParredFile(filename) && !IsProcessedFile(filename))))
{
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
@@ -1023,7 +1086,7 @@ bool ParChecker::AddMissingFiles()
// adding files one by one until all missing files are found
while (!IsStopped() && !m_bCancelled && extrafiles.size() > 0 && ((Repairer*)m_pRepairer)->missingfilecount > 0)
while (!IsStopped() && !m_bCancelled && extrafiles.size() > 0)
{
CommandLine::ExtraFile* pExtraFile = extrafiles.front();
extrafiles.pop_front();
@@ -1031,19 +1094,40 @@ bool ParChecker::AddMissingFiles()
extrafiles1.clear();
extrafiles1.push_back(*pExtraFile);
int iWasMissing = ((Repairer*)m_pRepairer)->missingfilecount;
int iWasFilesMissing = ((Repairer*)m_pRepairer)->missingfilecount;
int iWasBlocksMissing = ((Repairer*)m_pRepairer)->missingblockcount;
((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles1);
bool bAdded = iWasMissing > (int)((Repairer*)m_pRepairer)->missingfilecount;
if (bAdded)
((Repairer*)m_pRepairer)->UpdateVerificationResults();
bool bFileAdded = iWasFilesMissing > (int)((Repairer*)m_pRepairer)->missingfilecount;
bool bBlockAdded = iWasBlocksMissing > (int)((Repairer*)m_pRepairer)->missingblockcount;
if (bFileAdded && !bExternalDir)
{
PrintMessage(Message::mkInfo, "Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str()));
RegisterParredFile(Util::BaseFileName(pExtraFile->FileName().c_str()));
}
else if (bBlockAdded)
{
PrintMessage(Message::mkInfo, "Found %i missing blocks", iWasBlocksMissing - (int)((Repairer*)m_pRepairer)->missingblockcount);
}
bFilesAdded |= bAdded;
((Repairer*)m_pRepairer)->UpdateVerificationResults();
bFilesAdded |= bFileAdded | bBlockAdded;
delete pExtraFile;
if (bOnlyMissing && ((Repairer*)m_pRepairer)->missingfilecount == 0)
{
PrintMessage(Message::mkInfo, "All missing files found, aborting par-scan");
break;
}
if (!bOnlyMissing && ((Repairer*)m_pRepairer)->missingblockcount == 0)
{
PrintMessage(Message::mkInfo, "All missing blocks found, aborting par-scan");
break;
}
}
m_bVerifyingExtraFiles = false;
@@ -1106,7 +1190,7 @@ void ParChecker::signal_filename(std::string str)
UpdateProgress();
}
void ParChecker::signal_progress(double progress)
void ParChecker::signal_progress(int progress)
{
m_iFileProgress = (int)progress;
@@ -1120,6 +1204,7 @@ void ParChecker::signal_progress(double progress)
// processing individual files
int iTotalFiles = 0;
int iProcessedFiles = m_iProcessedFiles;
if (m_eStage == ptVerifyingRepaired)
{
// repairing individual files
@@ -1129,17 +1214,25 @@ void ParChecker::signal_progress(double progress)
{
// verifying individual files
iTotalFiles = ((Repairer*)m_pRepairer)->sourcefiles.size() + m_iExtraFiles;
if (m_iExtraFiles > 0)
{
// during extra par scan don't count quickly verified files;
// extra files require much more time for verification;
// counting only fully scanned files improves estimated time accuracy.
iTotalFiles -= m_iQuickFiles;
iProcessedFiles -= m_iQuickFiles;
}
}
if (iTotalFiles > 0)
{
if (m_iFileProgress < 1000)
{
m_iStageProgress = (m_iProcessedFiles * 1000 + m_iFileProgress) / iTotalFiles;
m_iStageProgress = (iProcessedFiles * 1000 + m_iFileProgress) / iTotalFiles;
}
else
{
m_iStageProgress = m_iProcessedFiles * 1000 / iTotalFiles;
m_iStageProgress = iProcessedFiles * 1000 / iTotalFiles;
}
}
else
@@ -1148,7 +1241,7 @@ void ParChecker::signal_progress(double progress)
}
}
debug("Current-progres: %i, Total-progress: %i", m_iFileProgress, m_iStageProgress);
debug("Current-progress: %i, Total-progress: %i", m_iFileProgress, m_iStageProgress);
UpdateProgress();
}
@@ -1190,6 +1283,11 @@ void ParChecker::signal_done(std::string str, int available, int total)
PrintMessage(Message::mkWarning, "File %s with %i block(s) is missing%s",
szFilename, total, bIgnore ? ", ignoring" : "");
}
if (!IsProcessedFile(szFilename))
{
m_ProcessedFiles.push_back(strdup(szFilename));
}
}
}
}
@@ -1204,12 +1302,14 @@ void ParChecker::CheckEmptyFiles()
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
{
Par2RepairerSourceFile *sourcefile = *it;
Par2RepairerSourceFile* sourcefile = *it;
if (sourcefile && sourcefile->GetDescriptionPacket())
{
const char* szFilename = sourcefile->GetDescriptionPacket()->FileName().c_str();
if (!IsProcessedFile(szFilename))
// GetDescriptionPacket()->FileName() returns a temp string object, which we need to hold for a while
std::string filename = sourcefile->GetDescriptionPacket()->FileName();
const char* szFilename = filename.c_str();
if (!Util::EmptyStr(szFilename) && !IsProcessedFile(szFilename))
{
bool bIgnore = Util::MatchFileExt(szFilename, g_pOptions->GetParIgnoreExt(), ",;") ||
Util::MatchFileExt(szFilename, g_pOptions->GetExtCleanupDisk(), ",;");
@@ -1424,6 +1524,7 @@ ParChecker::EFileStatus ParChecker::VerifyDataFile(void* pDiskfile, void* pSourc
}
}
m_iQuickFiles++;
PrintMessage(Message::mkDetail, "Quickly verified %s file %s",
eFileStatus == fsSuccess ? "good" : "damaged", Util::BaseFileName(szFilename));

View File

@@ -86,6 +86,24 @@ public:
~SegmentList();
};
class DupeSource
{
private:
int m_iID;
char* m_szDirectory;
int m_iUsedBlocks;
public:
DupeSource(int iID, const char* szDirectory);
~DupeSource();
int GetID() { return m_iID; }
const char* GetDirectory() { return m_szDirectory; }
int GetUsedBlocks() { return m_iUsedBlocks; }
void SetUsedBlocks(int iUsedBlocks) { m_iUsedBlocks = iUsedBlocks; }
};
typedef std::deque<DupeSource*> DupeSourceList;
typedef std::deque<char*> FileList;
typedef std::deque<void*> SourceList;
typedef std::vector<bool> ValidBlocks;
@@ -109,6 +127,7 @@ private:
int m_iProcessedFiles;
int m_iFilesToRepair;
int m_iExtraFiles;
int m_iQuickFiles;
bool m_bVerifyingExtraFiles;
char* m_szProgressLabel;
int m_iFileProgress;
@@ -120,6 +139,7 @@ private:
bool m_bParQuick;
bool m_bForceRepair;
bool m_bParFull;
DupeSourceList m_DupeSources;
void Cleanup();
EStatus RunParCheckAll();
@@ -130,12 +150,14 @@ private:
bool LoadMorePars();
bool AddSplittedFragments();
bool AddMissingFiles();
bool AddDupeFiles();
bool AddExtraFiles(bool bOnlyMissing, bool bExternalDir, const char* szDirectory);
bool IsProcessedFile(const char* szFilename);
void WriteBrokenLog(EStatus eStatus);
void SaveSourceList();
void DeleteLeftovers();
void signal_filename(std::string str);
void signal_progress(double progress);
void signal_progress(int progress);
void signal_done(std::string str, int available, int total);
// declared as void* to prevent the including of libpar2-headers into this header-file
// DiskFile* pDiskfile, Par2RepairerSourceFile* pSourcefile
@@ -160,6 +182,8 @@ protected:
virtual void RegisterParredFile(const char* szFilename) {}
virtual bool IsParredFile(const char* szFilename) { return false; }
virtual EFileStatus FindFileCrc(const char* szFilename, unsigned long* lCrc, SegmentList* pSegments) { return fsUnknown; }
virtual void RequestDupeSources(DupeSourceList* pDupeSourceList) {}
virtual void StatDupeSources(DupeSourceList* pDupeSourceList) {}
EStage GetStage() { return m_eStage; }
const char* GetProgressLabel() { return m_szProgressLabel; }
int GetFileProgress() { return m_iFileProgress; }

View File

@@ -44,14 +44,13 @@
#include "nzbget.h"
#include "ParCoordinator.h"
#include "DupeCoordinator.h"
#include "ParParser.h"
#include "Options.h"
#include "DiskState.h"
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
#ifndef DISABLE_PARCHECK
bool ParCoordinator::PostParChecker::RequestMorePars(int iBlockNeeded, int* pBlockFound)
{
@@ -146,6 +145,69 @@ ParChecker::EFileStatus ParCoordinator::PostParChecker::FindFileCrc(const char*
ParChecker::fsUnknown;
}
void ParCoordinator::PostParChecker::RequestDupeSources(DupeSourceList* pDupeSourceList)
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
NZBList dupeList;
g_pDupeCoordinator->ListHistoryDupes(pDownloadQueue, m_pPostInfo->GetNZBInfo(), &dupeList);
if (!dupeList.empty())
{
PostDupeMatcher dupeMatcher(m_pPostInfo);
PrintMessage(Message::mkInfo, "Checking %s for dupe scan usability", m_pPostInfo->GetNZBInfo()->GetName());
bool bSizeComparisonPossible = dupeMatcher.Prepare();
for (NZBList::iterator it = dupeList.begin(); it != dupeList.end(); it++)
{
NZBInfo* pDupeNZBInfo = *it;
if (bSizeComparisonPossible)
{
PrintMessage(Message::mkInfo, "Checking %s for dupe scan usability", Util::BaseFileName(pDupeNZBInfo->GetDestDir()));
}
bool bUseDupe = !bSizeComparisonPossible || dupeMatcher.MatchDupeContent(pDupeNZBInfo->GetDestDir());
if (bUseDupe)
{
PrintMessage(Message::mkInfo, "Adding %s to dupe scan sources", Util::BaseFileName(pDupeNZBInfo->GetDestDir()));
pDupeSourceList->push_back(new ParChecker::DupeSource(pDupeNZBInfo->GetID(), pDupeNZBInfo->GetDestDir()));
}
}
if (pDupeSourceList->empty())
{
PrintMessage(Message::mkInfo, "No usable dupe scan sources found");
}
}
DownloadQueue::Unlock();
}
void ParCoordinator::PostParChecker::StatDupeSources(DupeSourceList* pDupeSourceList)
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
int iTotalExtraParBlocks = 0;
for (DupeSourceList::iterator it = pDupeSourceList->begin(); it != pDupeSourceList->end(); it++)
{
DupeSource* pDupeSource = *it;
if (pDupeSource->GetUsedBlocks() > 0)
{
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
pHistoryInfo->GetNZBInfo()->GetID() == pDupeSource->GetID())
{
pHistoryInfo->GetNZBInfo()->SetExtraParBlocks(pHistoryInfo->GetNZBInfo()->GetExtraParBlocks() - pDupeSource->GetUsedBlocks());
}
}
}
iTotalExtraParBlocks += pDupeSource->GetUsedBlocks();
}
m_pPostInfo->GetNZBInfo()->SetExtraParBlocks(m_pPostInfo->GetNZBInfo()->GetExtraParBlocks() + iTotalExtraParBlocks);
DownloadQueue::Unlock();
}
void ParCoordinator::PostParRenamer::UpdateProgress()
{
m_pOwner->UpdateParRenameProgress();
@@ -184,6 +246,18 @@ void ParCoordinator::PostParRenamer::RegisterRenamedFile(const char* szOldFilena
}
}
void ParCoordinator::PostDupeMatcher::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
{
char szText[1024];
va_list args;
va_start(args, szFormat);
vsnprintf(szText, 1024, szFormat, args);
va_end(args);
szText[1024-1] = '\0';
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
}
#endif
ParCoordinator::ParCoordinator()
@@ -235,111 +309,6 @@ void ParCoordinator::PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
DownloadQueue::eaGroupPauseExtraPars, 0, NULL);
}
bool ParCoordinator::FindMainPars(const char* szPath, ParFileList* pFileList)
{
if (pFileList)
{
pFileList->clear();
}
DirBrowser dir(szPath);
while (const char* filename = dir.Next())
{
int iBaseLen = 0;
if (ParseParFilename(filename, &iBaseLen, NULL))
{
if (!pFileList)
{
return true;
}
// check if the base file already added to list
bool exists = false;
for (ParFileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
{
const char* filename2 = *it;
exists = SameParCollection(filename, filename2);
if (exists)
{
break;
}
}
if (!exists)
{
pFileList->push_back(strdup(filename));
}
}
}
return pFileList && !pFileList->empty();
}
bool ParCoordinator::SameParCollection(const char* szFilename1, const char* szFilename2)
{
int iBaseLen1 = 0, iBaseLen2 = 0;
return ParseParFilename(szFilename1, &iBaseLen1, NULL) &&
ParseParFilename(szFilename2, &iBaseLen2, NULL) &&
iBaseLen1 == iBaseLen2 &&
!strncasecmp(szFilename1, szFilename2, iBaseLen1);
}
bool ParCoordinator::ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks)
{
char szFilename[1024];
strncpy(szFilename, szParFilename, 1024);
szFilename[1024-1] = '\0';
for (char* p = szFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
int iLen = strlen(szFilename);
if (iLen < 6)
{
return false;
}
// find last occurence of ".par2" and trim filename after it
char* szEnd = szFilename;
while (char* p = strstr(szEnd, ".par2")) szEnd = p + 5;
*szEnd = '\0';
iLen = strlen(szFilename);
if (iLen < 6)
{
return false;
}
if (strcasecmp(szFilename + iLen - 5, ".par2"))
{
return false;
}
*(szFilename + iLen - 5) = '\0';
int blockcnt = 0;
char* p = strrchr(szFilename, '.');
if (p && !strncasecmp(p, ".vol", 4))
{
char* b = strchr(p, '+');
if (!b)
{
b = strchr(p, '-');
}
if (b)
{
blockcnt = atoi(b+1);
*p = '\0';
}
}
if (iBaseNameLen)
{
*iBaseNameLen = strlen(szFilename);
}
if (iBlocks)
{
*iBlocks = blockcnt;
}
return true;
}
#ifndef DISABLE_PARCHECK
/**
@@ -471,7 +440,9 @@ void ParCoordinator::ParCheckCompleted()
/**
* Unpause par2-files
* returns true, if the files with required number of blocks were unpaused,
* or false if there are no more files in queue for this collection or not enough blocks
* or false if there are no more files in queue for this collection or not enough blocks.
* 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* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound)
{
@@ -549,6 +520,17 @@ bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilenam
}
}
bool bHasUnpausedParFiles = false;
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (pFileInfo->GetParFile() && !pFileInfo->GetPaused())
{
bHasUnpausedParFiles = true;
break;
}
}
DownloadQueue::Unlock();
if (pBlockFound)
@@ -562,7 +544,7 @@ bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilenam
}
blocks.clear();
bool bOK = iBlockNeeded <= 0;
bool bOK = iBlockNeeded <= 0 || bHasUnpausedParFiles;
return bOK;
}
@@ -576,7 +558,7 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
char* szBaseParFilename = Util::BaseFileName(szParFilename);
char szMainBaseFilename[1024];
int iMainBaseLen = 0;
if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
if (!ParParser::ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
{
// should not happen
pNZBInfo->PrintMessage(Message::mkError, "Internal error: could not parse filename %s", szBaseParFilename);
@@ -591,14 +573,14 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
{
FileInfo* pFileInfo = *it;
int iBlocks = 0;
if (ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
if (ParParser::ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
iBlocks > 0)
{
bool bUseFile = true;
if (bExactParName)
{
bUseFile = SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(szParFilename));
bUseFile = ParParser::SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(szParFilename));
}
else if (bStrictParName)
{

View File

@@ -34,6 +34,7 @@
#ifndef DISABLE_PARCHECK
#include "ParChecker.h"
#include "ParRenamer.h"
#include "DupeMatcher.h"
#endif
class ParCoordinator
@@ -56,6 +57,8 @@ private:
virtual void RegisterParredFile(const char* szFilename);
virtual bool IsParredFile(const char* szFilename);
virtual EFileStatus FindFileCrc(const char* szFilename, unsigned long* lCrc, SegmentList* pSegments);
virtual void RequestDupeSources(DupeSourceList* pDupeSourceList);
virtual void StatDupeSources(DupeSourceList* pDupeSourceList);
public:
PostInfo* GetPostInfo() { return m_pPostInfo; }
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
@@ -86,7 +89,20 @@ private:
friend class ParCoordinator;
};
class PostDupeMatcher: public DupeMatcher
{
private:
PostInfo* m_pPostInfo;
protected:
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
public:
PostDupeMatcher(PostInfo* pPostInfo):
DupeMatcher(pPostInfo->GetNZBInfo()->GetDestDir(),
pPostInfo->GetNZBInfo()->GetSize() - pPostInfo->GetNZBInfo()->GetParSize()),
m_pPostInfo(pPostInfo) {}
};
struct BlockInfo
{
FileInfo* m_pFileInfo;
@@ -116,15 +132,9 @@ protected:
bool RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound);
#endif
public:
typedef std::deque<char*> ParFileList;
public:
ParCoordinator();
virtual ~ParCoordinator();
static bool FindMainPars(const char* szPath, ParFileList* pFileList);
static bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
static bool SameParCollection(const char* szFilename1, const char* szFilename2);
void PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
#ifndef DISABLE_PARCHECK

View File

@@ -0,0 +1,152 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include "nzbget.h"
#include "Util.h"
#include "ParParser.h"
bool ParParser::FindMainPars(const char* szPath, ParFileList* pFileList)
{
if (pFileList)
{
pFileList->clear();
}
DirBrowser dir(szPath);
while (const char* filename = dir.Next())
{
int iBaseLen = 0;
if (ParseParFilename(filename, &iBaseLen, NULL))
{
if (!pFileList)
{
return true;
}
// check if the base file already added to list
bool exists = false;
for (ParFileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
{
const char* filename2 = *it;
exists = SameParCollection(filename, filename2);
if (exists)
{
break;
}
}
if (!exists)
{
pFileList->push_back(strdup(filename));
}
}
}
return pFileList && !pFileList->empty();
}
bool ParParser::SameParCollection(const char* szFilename1, const char* szFilename2)
{
int iBaseLen1 = 0, iBaseLen2 = 0;
return ParseParFilename(szFilename1, &iBaseLen1, NULL) &&
ParseParFilename(szFilename2, &iBaseLen2, NULL) &&
iBaseLen1 == iBaseLen2 &&
!strncasecmp(szFilename1, szFilename2, iBaseLen1);
}
bool ParParser::ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks)
{
char szFilename[1024];
strncpy(szFilename, szParFilename, 1024);
szFilename[1024-1] = '\0';
for (char* p = szFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
int iLen = strlen(szFilename);
if (iLen < 6)
{
return false;
}
// find last occurence of ".par2" and trim filename after it
char* szEnd = szFilename;
while (char* p = strstr(szEnd, ".par2")) szEnd = p + 5;
*szEnd = '\0';
iLen = strlen(szFilename);
if (iLen < 6)
{
return false;
}
if (strcasecmp(szFilename + iLen - 5, ".par2"))
{
return false;
}
*(szFilename + iLen - 5) = '\0';
int blockcnt = 0;
char* p = strrchr(szFilename, '.');
if (p && !strncasecmp(p, ".vol", 4))
{
char* b = strchr(p, '+');
if (!b)
{
b = strchr(p, '-');
}
if (b)
{
blockcnt = atoi(b+1);
*p = '\0';
}
}
if (iBaseNameLen)
{
*iBaseNameLen = strlen(szFilename);
}
if (iBlocks)
{
*iBlocks = blockcnt;
}
return true;
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef PARPARSER_H
#define PARPARSER_H
#include <deque>
class ParParser
{
public:
typedef std::deque<char*> ParFileList;
static bool FindMainPars(const char* szPath, ParFileList* pFileList);
static bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
static bool SameParCollection(const char* szFilename1, const char* szFilename2);
};
#endif

View File

@@ -47,13 +47,11 @@
#include "nzbget.h"
#include "ParRenamer.h"
#include "ParCoordinator.h"
#include "ParParser.h"
#include "Log.h"
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
class ParRenamerRepairer : public Par2Repairer
{
public:
@@ -224,10 +222,10 @@ void ParRenamer::BuildDirList(const char* szDestDir)
void ParRenamer::LoadParFiles(const char* szDestDir)
{
ParCoordinator::ParFileList parFileList;
ParCoordinator::FindMainPars(szDestDir, &parFileList);
ParParser::ParFileList parFileList;
ParParser::FindMainPars(szDestDir, &parFileList);
for (ParCoordinator::ParFileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
for (ParParser::ParFileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
{
char* szParFilename = *it;

View File

@@ -50,20 +50,11 @@
#include "DupeCoordinator.h"
#include "PostScript.h"
#include "Util.h"
#include "Scheduler.h"
#include "Scanner.h"
#include "Unpack.h"
#include "Cleanup.h"
#include "NZBFile.h"
#include "StatMeter.h"
#include "QueueScript.h"
extern HistoryCoordinator* g_pHistoryCoordinator;
extern DupeCoordinator* g_pDupeCoordinator;
extern Options* g_pOptions;
extern Scheduler* g_pScheduler;
extern Scanner* g_pScanner;
extern StatMeter* g_pStatMeter;
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
#include "ParParser.h"
PrePostProcessor::PrePostProcessor()
{
@@ -100,54 +91,19 @@ void PrePostProcessor::Run()
DownloadQueue::Unlock();
}
g_pScheduler->FirstCheck();
int iDiskSpaceInterval = 1000;
int iSchedulerInterval = 1000;
int iHistoryInterval = 600000;
const int iStepMSec = 200;
while (!IsStopped())
{
// check incoming nzb directory
g_pScanner->Check();
if (!g_pOptions->GetPauseDownload() &&
g_pOptions->GetDiskSpace() > 0 && !g_pStatMeter->GetStandBy() &&
iDiskSpaceInterval >= 1000)
if (!g_pOptions->GetTempPausePostprocess())
{
// check free disk space every 1 second
CheckDiskSpace();
iDiskSpaceInterval = 0;
// check post-queue every 200 msec
CheckPostQueue();
}
iDiskSpaceInterval += iStepMSec;
// check post-queue every 200 msec
CheckPostQueue();
if (iSchedulerInterval >= 1000)
{
// check scheduler tasks every 1 second
g_pScheduler->IntervalCheck();
iSchedulerInterval = 0;
}
iSchedulerInterval += iStepMSec;
if (iHistoryInterval >= 600000)
{
// check history (remove old entries) every 10 minutes
g_pHistoryCoordinator->IntervalCheck();
iHistoryInterval = 0;
}
iHistoryInterval += iStepMSec;
Util::SetStandByMode(!m_pCurJob);
usleep(iStepMSec * 1000);
usleep(200 * 1000);
}
g_pHistoryCoordinator->Cleanup();
debug("Exiting PrePostProcessor-loop");
}
@@ -257,8 +213,10 @@ void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo
m_ParCoordinator.PausePars(pDownloadQueue, pNZBInfo);
}
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsCopy ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsGood ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsScan)
{
NZBCompleted(pDownloadQueue, pNZBInfo, false);
}
@@ -270,6 +228,12 @@ void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo
void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad)
{
g_pQueueScriptCoordinator->EnqueueScript(pNZBInfo, QueueScriptCoordinator::qeNzbDeleted);
}
if (!pNZBInfo->GetPostInfo() && g_pOptions->GetDecode())
{
pNZBInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", pNZBInfo->GetName());
@@ -332,12 +296,21 @@ void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZB
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad))
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsScan))
{
g_pDupeCoordinator->NZBCompleted(pDownloadQueue, pNZBInfo);
bNeedSave = true;
}
if (pNZBInfo->GetDeleteStatus() > NZBInfo::dsNone &&
pNZBInfo->GetDeleteStatus() != NZBInfo::dsHealth &&
pNZBInfo->GetDeleteStatus() != NZBInfo::dsBad)
// nzbs deleted by health check or marked as bad are processed as downloaded with failure status
{
g_pQueueScriptCoordinator->EnqueueScript(pNZBInfo, QueueScriptCoordinator::qeNzbDeleted);
}
if (!bAddToHistory)
{
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
@@ -396,26 +369,6 @@ void PrePostProcessor::DeleteCleanup(NZBInfo* pNZBInfo)
}
}
void PrePostProcessor::CheckDiskSpace()
{
long long lFreeSpace = Util::FreeDiskSize(g_pOptions->GetDestDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetDestDir());
g_pOptions->SetPauseDownload(true);
}
if (!Util::EmptyStr(g_pOptions->GetInterDir()))
{
lFreeSpace = Util::FreeDiskSize(g_pOptions->GetInterDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetInterDir());
g_pOptions->SetPauseDownload(true);
}
}
}
void PrePostProcessor::CheckPostQueue()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
@@ -500,7 +453,7 @@ NZBInfo* PrePostProcessor::GetNextJob(DownloadQueue* pDownloadQueue)
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo1 = *it;
if (pNZBInfo1->GetPostInfo() && !g_pQueueScriptCoordinator->HasJob(pNZBInfo1->GetID()) &&
if (pNZBInfo1->GetPostInfo() && !g_pQueueScriptCoordinator->HasJob(pNZBInfo1->GetID(), NULL) &&
(!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()) &&
(!g_pOptions->GetPausePostProcess() || pNZBInfo1->GetForcePriority()))
{
@@ -562,7 +515,7 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone &&
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
{
if (m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
if (ParParser::FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-check");
m_ParCoordinator.StartParCheckJob(pPostInfo);
@@ -578,19 +531,24 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
pPostInfo->GetNZBInfo()->CalcHealth() < pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) &&
pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000 &&
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
((g_pOptions->GetParScan() != Options::psDupe &&
pPostInfo->GetNZBInfo()->CalcHealth() < pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) &&
pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000) ||
pPostInfo->GetNZBInfo()->CalcHealth() == 0) &&
ParParser::FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkWarning,
"Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(),
pPostInfo->GetNZBInfo()->CalcHealth() == 0 ?
"Skipping par-check for %s due to health 0%%" :
"Skipping par-check for %s due to health %.1f%% below critical %.1f%%",
pPostInfo->GetNZBInfo()->GetName(),
pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) / 10.0);
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
pPostInfo->GetNZBInfo()->GetFailedSize() - pPostInfo->GetNZBInfo()->GetParFailedSize() > 0 &&
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
ParParser::FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo,
"Collection %s with health %.1f%% needs par-check",

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,7 +57,6 @@ private:
void StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
void SaveQueue(DownloadQueue* pDownloadQueue);
void SanitisePostQueue(DownloadQueue* pDownloadQueue);
void CheckDiskSpace();
void UpdatePauseState(bool bNeedPause, const char* szReason);
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
@@ -80,4 +79,6 @@ public:
void NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
};
extern PrePostProcessor* g_pPrePostProcessor;
#endif

View File

@@ -44,11 +44,9 @@
#include "Unpack.h"
#include "Log.h"
#include "Util.h"
#include "ParCoordinator.h"
#include "ParParser.h"
#include "Options.h"
extern Options* g_pOptions;
void UnpackController::FileList::Clear()
{
for (iterator it = begin(); it != end(); it++)
@@ -148,7 +146,7 @@ void UnpackController::Run()
snprintf(m_szInfoNameUp, 1024, "Unpack for %s", m_szName); // first letter in upper case
m_szInfoNameUp[1024-1] = '\0';
m_bHasParFiles = ParCoordinator::FindMainPars(m_szDestDir, NULL);
m_bHasParFiles = ParParser::FindMainPars(m_szDestDir, NULL);
if (bUnpack)
{
@@ -166,7 +164,11 @@ void UnpackController::Run()
if (m_pPostInfo->GetUnpackTried() && !m_pPostInfo->GetParRepaired() &&
(!Util::EmptyStr(m_szPassword) || Util::EmptyStr(g_pOptions->GetUnpackPassFile()) || m_pPostInfo->GetPassListTried()))
{
PrintMessage(Message::mkError, "%s failed: second unpack attempt skipped due to par-check not repaired anything", m_szInfoNameUp);
PrintMessage(Message::mkInfo, "Second unpack attempt skipped for %s due to par-check not repaired anything", m_szName);
PrintMessage(Message::mkError,
m_pPostInfo->GetLastUnpackStatus() == (int)NZBInfo::usPassword ?
"%s failed: checksum error in the encrypted file. Corrupt file or wrong password." : "%s failed.",
m_szInfoNameUp);
m_pPostInfo->GetNZBInfo()->SetUnpackStatus((NZBInfo::EUnpackStatus)m_pPostInfo->GetLastUnpackStatus());
m_pPostInfo->SetStage(PostInfo::ptQueued);
}
@@ -1038,234 +1040,3 @@ void UnpackController::SetProgressLabel(const char* szProgressLabel)
m_pPostInfo->SetProgressLabel(szProgressLabel);
DownloadQueue::Unlock();
}
void MoveController::StartJob(PostInfo* pPostInfo)
{
MoveController* pMoveController = new MoveController();
pMoveController->m_pPostInfo = pPostInfo;
pMoveController->SetAutoDestroy(false);
pPostInfo->SetPostThread(pMoveController);
pMoveController->Start();
}
void MoveController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
szNZBName[1024-1] = '\0';
char szInfoName[1024];
snprintf(szInfoName, 1024, "move for %s", m_pPostInfo->GetNZBInfo()->GetName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
strncpy(m_szInterDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
m_szInterDir[1024-1] = '\0';
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szDestDir, 1024);
m_szDestDir[1024-1] = '\0';
DownloadQueue::Unlock();
PrintMessage(Message::mkInfo, "Moving completed files for %s", szNZBName);
bool bOK = MoveFiles();
szInfoName[0] = 'M'; // uppercase
if (bOK)
{
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
// save new dest dir
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir);
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msSuccess);
DownloadQueue::Unlock();
}
else
{
PrintMessage(Message::mkError, "%s failed", szInfoName);
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msFailure);
}
m_pPostInfo->SetStage(PostInfo::ptQueued);
m_pPostInfo->SetWorking(false);
}
bool MoveController::MoveFiles()
{
char szErrBuf[1024];
if (!Util::ForceDirectories(m_szDestDir, szErrBuf, sizeof(szErrBuf)))
{
PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szDestDir, szErrBuf);
return false;
}
bool bOK = true;
DirBrowser dir(m_szInterDir);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, ".."))
{
char szSrcFile[1024];
snprintf(szSrcFile, 1024, "%s%c%s", m_szInterDir, PATH_SEPARATOR, filename);
szSrcFile[1024-1] = '\0';
char szDstFile[1024];
Util::MakeUniqueFilename(szDstFile, 1024, m_szDestDir, filename);
bool bHiddenFile = filename[0] == '.';
if (!bHiddenFile)
{
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
}
if (!Util::MoveFile(szSrcFile, szDstFile) && !bHiddenFile)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
bOK = false;
}
}
}
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir, szErrBuf, sizeof(szErrBuf)))
{
PrintMessage(Message::mkWarning, "Could not delete intermediate directory %s: %s", m_szInterDir, szErrBuf);
}
return bOK;
}
void MoveController::AddMessage(Message::EKind eKind, const char* szText)
{
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
}
void CleanupController::StartJob(PostInfo* pPostInfo)
{
CleanupController* pCleanupController = new CleanupController();
pCleanupController->m_pPostInfo = pPostInfo;
pCleanupController->SetAutoDestroy(false);
pPostInfo->SetPostThread(pCleanupController);
pCleanupController->Start();
}
void CleanupController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
szNZBName[1024-1] = '\0';
char szInfoName[1024];
snprintf(szInfoName, 1024, "cleanup for %s", m_pPostInfo->GetNZBInfo()->GetName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
m_szDestDir[1024-1] = '\0';
bool bInterDir = strlen(g_pOptions->GetInterDir()) > 0 &&
!strncmp(m_szDestDir, g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
if (bInterDir)
{
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szFinalDir, 1024);
m_szFinalDir[1024-1] = '\0';
}
else
{
m_szFinalDir[0] = '\0';
}
DownloadQueue::Unlock();
PrintMessage(Message::mkInfo, "Cleaning up %s", szNZBName);
bool bDeleted = false;
bool bOK = Cleanup(m_szDestDir, &bDeleted);
if (bOK && m_szFinalDir[0] != '\0')
{
bool bDeleted2 = false;
bOK = Cleanup(m_szFinalDir, &bDeleted2);
bDeleted = bDeleted || bDeleted2;
}
szInfoName[0] = 'C'; // uppercase
if (bOK && bDeleted)
{
PrintMessage(Message::mkInfo, "%s successful", szInfoName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
}
else if (bOK)
{
PrintMessage(Message::mkInfo, "Nothing to cleanup for %s", szNZBName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
}
else
{
PrintMessage(Message::mkError, "%s failed", szInfoName);
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csFailure);
}
m_pPostInfo->SetStage(PostInfo::ptQueued);
m_pPostInfo->SetWorking(false);
}
bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
{
*bDeleted = false;
bool bOK = true;
DirBrowser dir(szDestDir);
while (const char* filename = dir.Next())
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
bool bIsDir = Util::DirectoryExists(szFullFilename);
if (strcmp(filename, ".") && strcmp(filename, "..") && bIsDir)
{
bOK &= Cleanup(szFullFilename, bDeleted);
}
// check file extension
bool bDeleteIt = Util::MatchFileExt(filename, g_pOptions->GetExtCleanupDisk(), ",;") && !bIsDir;
if (bDeleteIt)
{
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
if (remove(szFullFilename) != 0)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not delete file %s: %s", szFullFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
bOK = false;
}
*bDeleted = true;
}
}
return bOK;
}
void CleanupController::AddMessage(Message::EKind eKind, const char* szText)
{
m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText);
}

View File

@@ -115,38 +115,4 @@ public:
static void StartJob(PostInfo* pPostInfo);
};
class MoveController : public Thread, public ScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szInterDir[1024];
char m_szDestDir[1024];
bool MoveFiles();
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
static void StartJob(PostInfo* pPostInfo);
};
class CleanupController : public Thread, public ScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szDestDir[1024];
char m_szFinalDir[1024];
bool Cleanup(const char* szDestDir, bool *bDeleted);
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
static void StartJob(PostInfo* pPostInfo);
};
#endif

View File

@@ -50,12 +50,10 @@
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
static const char* FORMATVERSION_SIGNATURE = "nzbget diskstate file version ";
#ifdef WIN32
// Windows doesn't have standard "vsscanf"
#if (defined(WIN32) && _MSC_VER < 1800)
// Visual Studio prior 2013 doesn't have standard "vsscanf"
// Hack from http://stackoverflow.com/questions/2457331/replacement-for-vsscanf-on-msvc
int vsscanf(const char *s, const char *fmt, va_list ap)
{
@@ -69,6 +67,170 @@ int vsscanf(const char *s, const char *fmt, va_list ap)
}
#endif
/* Parse signature and return format version number
*/
int ParseFormatVersion(const char* szFormatSignature)
{
if (strncmp(szFormatSignature, FORMATVERSION_SIGNATURE, strlen(FORMATVERSION_SIGNATURE)))
{
return 0;
}
return atoi(szFormatSignature + strlen(FORMATVERSION_SIGNATURE));
}
class StateFile
{
private:
char m_szDestFilename[1024];
char m_szTempFilename[1024];
int m_iFormatVersion;
int m_iFileVersion;
FILE* m_pFile;
public:
StateFile(const char* szFilename, int iFormatVersion);
~StateFile();
void Discard();
bool FileExists();
FILE* BeginWriteTransaction();
bool FinishWriteTransaction();
FILE* BeginReadTransaction();
int GetFileVersion() { return m_iFileVersion; }
const char* GetDestFilename() { return m_szDestFilename; }
};
StateFile::StateFile(const char* szFilename, int iFormatVersion)
{
m_pFile = NULL;
m_iFormatVersion = iFormatVersion;
snprintf(m_szDestFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), szFilename);
m_szDestFilename[1024-1] = '\0';
snprintf(m_szTempFilename, 1024, "%s%s.new", g_pOptions->GetQueueDir(), szFilename);
m_szTempFilename[1024-1] = '\0';
}
StateFile::~StateFile()
{
if (m_pFile)
{
fclose(m_pFile);
}
}
void StateFile::Discard()
{
remove(m_szDestFilename);
}
bool StateFile::FileExists()
{
return Util::FileExists(m_szDestFilename) || Util::FileExists(m_szTempFilename);
}
FILE* StateFile::BeginWriteTransaction()
{
m_pFile = fopen(m_szTempFilename, FOPEN_WB);
if (!m_pFile)
{
char szErrBuf[256];
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf));
error("Error saving diskstate: Could not create file %s: %s", m_szTempFilename, szErrBuf);
return NULL;
}
fprintf(m_pFile, "%s%i\n", FORMATVERSION_SIGNATURE, m_iFormatVersion);
return m_pFile;
}
bool StateFile::FinishWriteTransaction()
{
char szErrBuf[256];
// flush file content before renaming
if (g_pOptions->GetFlushQueue())
{
debug("Flushing data for file %s", Util::BaseFileName(m_szTempFilename));
fflush(m_pFile);
if (!Util::FlushFileBuffers(fileno(m_pFile), szErrBuf, sizeof(szErrBuf)))
{
warn("Could not flush file %s into disk: %s", m_szTempFilename, szErrBuf);
}
}
fclose(m_pFile);
m_pFile = NULL;
// now rename to dest file name
remove(m_szDestFilename);
if (rename(m_szTempFilename, m_szDestFilename))
{
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf));
error("Error saving diskstate: Could not rename file %s to %s: %s",
m_szTempFilename, m_szDestFilename, szErrBuf);
return false;
}
// flush directory buffer after renaming
if (g_pOptions->GetFlushQueue())
{
debug("Flushing directory for file %s", Util::BaseFileName(m_szDestFilename));
if (!Util::FlushDirBuffers(m_szDestFilename, szErrBuf, sizeof(szErrBuf)))
{
warn("Could not flush directory buffers for file %s into disk: %s", m_szDestFilename, szErrBuf);
}
}
return true;
}
FILE* StateFile::BeginReadTransaction()
{
if (!Util::FileExists(m_szDestFilename) && Util::FileExists(m_szTempFilename))
{
// disaster recovery: temp-file exists but the dest-file doesn't
warn("Restoring diskstate file %s from %s", Util::BaseFileName(m_szDestFilename), Util::BaseFileName(m_szTempFilename));
if (rename(m_szTempFilename, m_szDestFilename))
{
char szErrBuf[256];
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf));
error("Error restoring diskstate: Could not rename file %s to %s: %s",
m_szTempFilename, m_szDestFilename, szErrBuf);
return NULL;
}
}
m_pFile = fopen(m_szDestFilename, FOPEN_RB);
if (!m_pFile)
{
char szErrBuf[256];
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf));
error("Error reading diskstate: could not open file %s: %s", m_szDestFilename, szErrBuf);
return NULL;
}
char FileSignatur[128];
fgets(FileSignatur, sizeof(FileSignatur), m_pFile);
m_iFileVersion = ParseFormatVersion(FileSignatur);
if (m_iFileVersion > m_iFormatVersion)
{
error("Could not load diskstate due to file version mismatch");
fclose(m_pFile);
m_pFile = NULL;
return NULL;
}
return m_pFile;
}
/*
* Standard fscanf scans beoynd current line if the next line is empty.
* This wrapper fixes that.
@@ -89,18 +251,6 @@ int DiskState::fscanf(FILE* infile, const char* Format, ...)
return res;
}
/* Parse signature and return format version number
*/
int DiskState::ParseFormatVersion(const char* szFormatSignature)
{
if (strncmp(szFormatSignature, FORMATVERSION_SIGNATURE, strlen(FORMATVERSION_SIGNATURE)))
{
return 0;
}
return atoi(szFormatSignature + strlen(FORMATVERSION_SIGNATURE));
}
/* Save Download Queue to Disk.
* The Disk State consists of file "queue", which contains the order of files,
* and of one diskstate-file for each file in download queue.
@@ -116,78 +266,45 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
{
debug("Saving queue to disk");
char destFilename[1024];
snprintf(destFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
destFilename[1024-1] = '\0';
char tempFilename[1024];
snprintf(tempFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue.new");
tempFilename[1024-1] = '\0';
StateFile stateFile("queue", 55);
if (pDownloadQueue->GetQueue()->empty() &&
pDownloadQueue->GetHistory()->empty())
{
remove(destFilename);
stateFile.Discard();
return true;
}
FILE* outfile = fopen(tempFilename, FOPEN_WB);
FILE* outfile = stateFile.BeginWriteTransaction();
if (!outfile)
{
error("Error saving diskstate: Could not create file %s", tempFilename);
return false;
}
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 53);
// save nzb-infos
SaveNZBQueue(pDownloadQueue, outfile);
// save history
SaveHistory(pDownloadQueue, outfile);
fclose(outfile);
// now rename to dest file name
remove(destFilename);
if (rename(tempFilename, destFilename))
{
error("Error saving diskstate: Could not rename file %s to %s", tempFilename, destFilename);
return false;
}
return true;
return stateFile.FinishWriteTransaction();
}
bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServers)
{
debug("Loading queue from disk");
bool bOK = false;
int iFormatVersion = 0;
char fileName[1024];
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
fileName[1024-1] = '\0';
FILE* infile = fopen(fileName, FOPEN_RB);
StateFile stateFile("queue", 55);
FILE* infile = stateFile.BeginReadTransaction();
if (!infile)
{
error("Error reading diskstate: could not open file %s", fileName);
return false;
}
char FileSignatur[128];
fgets(FileSignatur, sizeof(FileSignatur), infile);
iFormatVersion = ParseFormatVersion(FileSignatur);
if (iFormatVersion < 3 || iFormatVersion > 53)
{
error("Could not load diskstate due to file version mismatch");
fclose(infile);
return false;
}
bool bOK = false;
int iFormatVersion = stateFile.GetFileVersion();
NZBList nzbList(false);
NZBList sortList(false);
@@ -256,10 +373,9 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServe
error:
fclose(infile);
if (!bOK)
{
error("Error reading diskstate for file %s", fileName);
error("Error reading diskstate for download queue and history");
}
NZBInfo::ResetGenID(true);
@@ -356,19 +472,21 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
fprintf(outfile, "%s\n", pNZBInfo->GetQueuedFilename());
fprintf(outfile, "%s\n", pNZBInfo->GetName());
fprintf(outfile, "%s\n", pNZBInfo->GetCategory());
fprintf(outfile, "%i,%i,%i,%i\n", (int)pNZBInfo->GetPriority(),
fprintf(outfile, "%i,%i,%i,%i,%i\n", (int)pNZBInfo->GetPriority(),
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetStage() + 1 : 0,
(int)pNZBInfo->GetDeletePaused(), (int)pNZBInfo->GetManyDupeFiles());
(int)pNZBInfo->GetDeletePaused(), (int)pNZBInfo->GetManyDupeFiles(), pNZBInfo->GetFeedID());
fprintf(outfile, "%i,%i,%i,%i,%i,%i,%i\n", (int)pNZBInfo->GetParStatus(), (int)pNZBInfo->GetUnpackStatus(),
(int)pNZBInfo->GetMoveStatus(), (int)pNZBInfo->GetRenameStatus(), (int)pNZBInfo->GetDeleteStatus(),
(int)pNZBInfo->GetMarkStatus(), (int)pNZBInfo->GetUrlStatus());
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetUnpackCleanedUpDisk(), (int)pNZBInfo->GetHealthPaused(),
(int)pNZBInfo->GetAddUrlPaused());
fprintf(outfile, "%i,%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(), pNZBInfo->GetMessageCount());
fprintf(outfile, "%i,%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(),
pNZBInfo->GetMessageCount());
fprintf(outfile, "%i,%i\n", (int)pNZBInfo->GetMinTime(), (int)pNZBInfo->GetMaxTime());
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetParFull(),
fprintf(outfile, "%i,%i,%i,%i\n", (int)pNZBInfo->GetParFull(),
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceParFull() : 0,
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceRepair() : 0);
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceRepair() : 0,
pNZBInfo->GetExtraParBlocks());
fprintf(outfile, "%u,%u\n", pNZBInfo->GetFullContentHash(), pNZBInfo->GetFilteredContentHash());
@@ -501,8 +619,12 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
if (true) // clang requires a block for goto to work
{
int iPriority = 0, iPostProcess = 0, iPostStage = 0, iDeletePaused = 0, iManyDupeFiles = 0;
if (iFormatVersion >= 45)
int iPriority = 0, iPostProcess = 0, iPostStage = 0, iDeletePaused = 0, iManyDupeFiles = 0, iFeedID = 0;
if (iFormatVersion >= 54)
{
if (fscanf(infile, "%i,%i,%i,%i,%i\n", &iPriority, &iPostStage, &iDeletePaused, &iManyDupeFiles, &iFeedID) != 5) goto error;
}
else if (iFormatVersion >= 45)
{
if (fscanf(infile, "%i,%i,%i,%i\n", &iPriority, &iPostStage, &iDeletePaused, &iManyDupeFiles) != 4) goto error;
}
@@ -530,6 +652,7 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
pNZBInfo->EnterPostProcess();
pNZBInfo->GetPostInfo()->SetStage((PostInfo::EStage)iPostStage);
}
pNZBInfo->SetFeedID(iFeedID);
}
if (iFormatVersion >= 8 && iFormatVersion < 18)
@@ -549,8 +672,8 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
if (iFormatVersion >= 18)
{
int iParStatus, iUnpackStatus, iScriptStatus, iMoveStatus = 0,
iRenameStatus = 0, iDeleteStatus = 0, iMarkStatus = 0, iUrlStatus = 0;
int iParStatus, iUnpackStatus, iScriptStatus, iMoveStatus = 0, iRenameStatus = 0,
iDeleteStatus = 0, iMarkStatus = 0, iUrlStatus = 0;
if (iFormatVersion >= 46)
{
if (fscanf(infile, "%i,%i,%i,%i,%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iMoveStatus,
@@ -592,6 +715,7 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
pNZBInfo->SetDeleteStatus((NZBInfo::EDeleteStatus)iDeleteStatus);
pNZBInfo->SetMarkStatus((NZBInfo::EMarkStatus)iMarkStatus);
if (pNZBInfo->GetKind() == NZBInfo::nkNzb ||
(NZBInfo::EUrlStatus)iUrlStatus >= NZBInfo::lsFailed ||
(NZBInfo::EUrlStatus)iUrlStatus >= NZBInfo::lsScanSkipped)
{
pNZBInfo->SetUrlStatus((NZBInfo::EUrlStatus)iUrlStatus);
@@ -673,9 +797,17 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
if (iFormatVersion >= 51)
{
int iParFull, iForceParFull, iForceRepair;
if (fscanf(infile, "%i,%i,%i\n", &iParFull, &iForceParFull, &iForceRepair) != 3) goto error;
int iParFull, iForceParFull, iForceRepair, iExtraParBlocks = 0;
if (iFormatVersion >= 55)
{
if (fscanf(infile, "%i,%i,%i,%i\n", &iParFull, &iForceParFull, &iForceRepair, &iExtraParBlocks) != 4) goto error;
}
else
{
if (fscanf(infile, "%i,%i,%i\n", &iParFull, &iForceParFull, &iForceRepair) != 3) goto error;
}
pNZBInfo->SetParFull((bool)iParFull);
pNZBInfo->SetExtraParBlocks(iExtraParBlocks);
if (pNZBInfo->GetPostInfo())
{
pNZBInfo->GetPostInfo()->SetForceParFull((bool)iForceParFull);
@@ -2023,81 +2155,49 @@ bool DiskState::SaveFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory)
{
debug("Saving feeds state to disk");
char destFilename[1024];
snprintf(destFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "feeds");
destFilename[1024-1] = '\0';
char tempFilename[1024];
snprintf(tempFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "feeds.new");
tempFilename[1024-1] = '\0';
StateFile stateFile("feeds", 3);
if (pFeeds->empty() && pFeedHistory->empty())
{
remove(destFilename);
stateFile.Discard();
return true;
}
FILE* outfile = fopen(tempFilename, FOPEN_WB);
FILE* outfile = stateFile.BeginWriteTransaction();
if (!outfile)
{
error("Error saving diskstate: Could not create file %s", tempFilename);
return false;
}
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 3);
// save status
SaveFeedStatus(pFeeds, outfile);
// save history
SaveFeedHistory(pFeedHistory, outfile);
fclose(outfile);
// now rename to dest file name
remove(destFilename);
if (rename(tempFilename, destFilename))
{
error("Error saving diskstate: Could not rename file %s to %s", tempFilename, destFilename);
return false;
}
return true;
return stateFile.FinishWriteTransaction();
}
bool DiskState::LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory)
{
debug("Loading feeds state from disk");
bool bOK = false;
StateFile stateFile("feeds", 3);
char fileName[1024];
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "feeds");
fileName[1024-1] = '\0';
if (!Util::FileExists(fileName))
if (!stateFile.FileExists())
{
return true;
}
FILE* infile = fopen(fileName, FOPEN_RB);
FILE* infile = stateFile.BeginReadTransaction();
if (!infile)
{
error("Error reading diskstate: could not open file %s", fileName);
return false;
}
char FileSignatur[128];
fgets(FileSignatur, sizeof(FileSignatur), infile);
int iFormatVersion = ParseFormatVersion(FileSignatur);
if (iFormatVersion > 3)
{
error("Could not load diskstate due to file version mismatch");
fclose(infile);
return false;
}
bool bOK = false;
int iFormatVersion = stateFile.GetFileVersion();
// load feed status
if (!LoadFeedStatus(pFeeds, infile, iFormatVersion)) goto error;
@@ -2109,10 +2209,9 @@ bool DiskState::LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory)
error:
fclose(infile);
if (!bOK)
{
error("Error reading diskstate for file %s", fileName);
error("Error reading diskstate for feeds");
}
return bOK;
@@ -2410,81 +2509,49 @@ bool DiskState::SaveStats(Servers* pServers, ServerVolumes* pServerVolumes)
{
debug("Saving stats to disk");
char destFilename[1024];
snprintf(destFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "stats");
destFilename[1024-1] = '\0';
char tempFilename[1024];
snprintf(tempFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "stats.new");
tempFilename[1024-1] = '\0';
StateFile stateFile("stats", 3);
if (pServers->empty())
{
remove(destFilename);
stateFile.Discard();
return true;
}
FILE* outfile = fopen(tempFilename, FOPEN_WB);
FILE* outfile = stateFile.BeginWriteTransaction();
if (!outfile)
{
error("Error saving diskstate: Could not create file %s", tempFilename);
return false;
}
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 3);
// save server names
SaveServerInfo(pServers, outfile);
// save stat
SaveVolumeStat(pServerVolumes, outfile);
fclose(outfile);
// now rename to dest file name
remove(destFilename);
if (rename(tempFilename, destFilename))
{
error("Error saving diskstate: Could not rename file %s to %s", tempFilename, destFilename);
return false;
}
return true;
return stateFile.FinishWriteTransaction();
}
bool DiskState::LoadStats(Servers* pServers, ServerVolumes* pServerVolumes, bool* pPerfectMatch)
{
debug("Loading stats from disk");
bool bOK = false;
StateFile stateFile("stats", 3);
char fileName[1024];
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "stats");
fileName[1024-1] = '\0';
if (!Util::FileExists(fileName))
if (!stateFile.FileExists())
{
return true;
}
FILE* infile = fopen(fileName, FOPEN_RB);
FILE* infile = stateFile.BeginReadTransaction();
if (!infile)
{
error("Error reading diskstate: could not open file %s", fileName);
return false;
}
char FileSignatur[128];
fgets(FileSignatur, sizeof(FileSignatur), infile);
int iFormatVersion = ParseFormatVersion(FileSignatur);
if (iFormatVersion > 3)
{
error("Could not load diskstate due to file version mismatch");
fclose(infile);
return false;
}
bool bOK = false;
int iFormatVersion = stateFile.GetFileVersion();
if (!LoadServerInfo(pServers, infile, iFormatVersion, pPerfectMatch)) goto error;
@@ -2497,10 +2564,9 @@ bool DiskState::LoadStats(Servers* pServers, ServerVolumes* pServerVolumes, bool
error:
fclose(infile);
if (!bOK)
{
error("Error reading diskstate for file %s", fileName);
error("Error reading diskstate for statistics");
}
return bOK;

View File

@@ -36,7 +36,6 @@ class DiskState
{
private:
int fscanf(FILE* infile, const char* Format, ...);
int ParseFormatVersion(const char* szFormatSignature);
bool SaveFileInfo(FileInfo* pFileInfo, const char* szFilename);
bool LoadFileInfo(FileInfo* pFileInfo, const char* szFilename, bool bFileSummary, bool bArticles);
void SaveNZBQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
@@ -62,6 +61,7 @@ private:
bool LoadAllFileStates(DownloadQueue* pDownloadQueue, Servers* pServers);
void SaveServerStats(ServerStatList* pServerStatList, FILE* outfile);
bool LoadServerStats(ServerStatList* pServerStatList, Servers* pServers, FILE* infile);
bool FinishWriteTransaction(const char* szNewFileName, const char* szDestFileName);
// backward compatibility functions (conversions from older formats)
bool LoadPostQueue12(DownloadQueue* pDownloadQueue, NZBList* pNZBList, FILE* infile, int iFormatVersion);
@@ -97,4 +97,6 @@ public:
void LoadNZBMessages(int iNZBID, MessageList* pMessages);
};
extern DiskState* g_pDiskState;
#endif

View File

@@ -47,10 +47,6 @@
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
extern ArticleCache* g_pArticleCache;
extern DiskState* g_pDiskState;
int FileInfo::m_iIDGen = 0;
int FileInfo::m_iIDMax = 0;
int NZBInfo::m_iIDGen = 0;
@@ -58,7 +54,6 @@ int NZBInfo::m_iIDMax = 0;
DownloadQueue* DownloadQueue::g_pDownloadQueue = NULL;
bool DownloadQueue::g_bLoaded = false;
NZBParameter::NZBParameter(const char* szName)
{
m_szName = strdup(szName);
@@ -308,6 +303,7 @@ NZBInfo::NZBInfo() : m_FileList(true)
m_eDeleteStatus = dsNone;
m_eMarkStatus = ksNone;
m_eUrlStatus = lsNone;
m_iExtraParBlocks = 0;
m_bAddUrlPaused = false;
m_bDeleting = false;
m_bDeletePaused = false;
@@ -347,6 +343,7 @@ NZBInfo::NZBInfo() : m_FileList(true)
m_bParFull = false;
m_iMessageCount = 0;
m_iCachedMessageCount = 0;
m_iFeedID = 0;
}
NZBInfo::~NZBInfo()
@@ -587,9 +584,8 @@ int NZBInfo::CalcHealth()
return 1000;
}
int iHealth = (int)(Util::Int64ToFloat(m_lSize - m_lParSize -
(m_lCurrentFailedSize - m_lParCurrentFailedSize)) * 1000.0 /
Util::Int64ToFloat(m_lSize - m_lParSize));
int iHealth = (int)((m_lSize - m_lParSize -
(m_lCurrentFailedSize - m_lParCurrentFailedSize)) * 1000 / (m_lSize - m_lParSize));
if (iHealth == 1000 && m_lCurrentFailedSize - m_lParCurrentFailedSize > 0)
{
@@ -606,9 +602,13 @@ int NZBInfo::CalcCriticalHealth(bool bAllowEstimation)
return 1000;
}
if (m_lSize == m_lParSize)
{
return 0;
}
long long lGoodParSize = m_lParSize - m_lParCurrentFailedSize;
int iCriticalHealth = (int)(Util::Int64ToFloat(m_lSize - lGoodParSize*2) * 1000.0 /
Util::Int64ToFloat(m_lSize - lGoodParSize));
int iCriticalHealth = (int)((m_lSize - lGoodParSize*2) * 1000 / (m_lSize - lGoodParSize));
if (lGoodParSize*2 > m_lSize)
{
@@ -769,6 +769,7 @@ void NZBInfo::CopyFileList(NZBInfo* pSrcNZBInfo)
SetParFailedSize(pSrcNZBInfo->GetParFailedSize());
SetParCurrentFailedSize(pSrcNZBInfo->GetParCurrentFailedSize());
SetTotalArticles(pSrcNZBInfo->GetTotalArticles());
SetSuccessArticles(pSrcNZBInfo->GetSuccessArticles());
SetFailedArticles(pSrcNZBInfo->GetFailedArticles());
SetCurrentSuccessArticles(pSrcNZBInfo->GetSuccessArticles());
@@ -864,6 +865,18 @@ const char* NZBInfo::MakeTextStatus(bool bIgnoreScriptStatus)
{
szStatus = "FAILURE/BAD";
}
else if (m_eDeleteStatus == NZBInfo::dsGood)
{
szStatus = "DELETED/GOOD";
}
else if (m_eDeleteStatus == NZBInfo::dsCopy)
{
szStatus = "DELETED/COPY";
}
else if (m_eDeleteStatus == NZBInfo::dsScan)
{
szStatus = "FAILURE/SCAN";
}
else if (m_eParStatus == NZBInfo::psFailure)
{
szStatus = "FAILURE/PAR";
@@ -1386,6 +1399,29 @@ void HistoryInfo::GetName(char* szBuffer, int iSize)
}
HistoryList::~HistoryList()
{
for (iterator it = begin(); it != end(); it++)
{
delete *it;
}
}
HistoryInfo* HistoryList::Find(int iID)
{
for (iterator it = begin(); it != end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetID() == iID)
{
return pHistoryInfo;
}
}
return NULL;
}
DownloadQueue* DownloadQueue::Lock()
{
g_pDownloadQueue->m_LockMutex.Lock();

View File

@@ -391,7 +391,10 @@ public:
dsManual,
dsHealth,
dsDupe,
dsBad
dsBad,
dsGood,
dsCopy,
dsScan
};
enum EMarkStatus
@@ -466,6 +469,7 @@ private:
EDeleteStatus m_eDeleteStatus;
EMarkStatus m_eMarkStatus;
EUrlStatus m_eUrlStatus;
int m_iExtraParBlocks;
bool m_bAddUrlPaused;
bool m_bDeletePaused;
bool m_bManyDupeFiles;
@@ -503,6 +507,7 @@ private:
bool m_bParFull;
int m_iMessageCount;
int m_iCachedMessageCount;
int m_iFeedID;
static int m_iIDGen;
static int m_iIDMax;
@@ -602,6 +607,8 @@ public:
EMarkStatus GetMarkStatus() { return m_eMarkStatus; }
void SetMarkStatus(EMarkStatus eMarkStatus) { m_eMarkStatus = eMarkStatus; }
EUrlStatus GetUrlStatus() { return m_eUrlStatus; }
int GetExtraParBlocks() { return m_iExtraParBlocks; }
void SetExtraParBlocks(int iExtraParBlocks) { m_iExtraParBlocks = iExtraParBlocks; }
void SetUrlStatus(EUrlStatus eUrlStatus) { m_eUrlStatus = eUrlStatus; }
const char* GetQueuedFilename() { return m_szQueuedFilename; }
void SetQueuedFilename(const char* szQueuedFilename);
@@ -660,6 +667,8 @@ public:
void SetQueueScriptTime(time_t tQueueScriptTime) { m_tQueueScriptTime = tQueueScriptTime; }
void SetParFull(bool bParFull) { m_bParFull = bParFull; }
bool GetParFull() { return m_bParFull; }
int GetFeedID() { return m_iFeedID; }
void SetFeedID(int iFeedID) { m_iFeedID = iFeedID; }
void CopyFileList(NZBInfo* pSrcNZBInfo);
void UpdateMinMaxTime();
@@ -855,7 +864,14 @@ public:
void GetName(char* szBuffer, int iSize); // needs locking (for shared objects)
};
typedef std::deque<HistoryInfo*> HistoryList;
typedef std::deque<HistoryInfo*> HistoryListBase;
class HistoryList : public HistoryListBase
{
public:
~HistoryList();
HistoryInfo* Find(int iID);
};
class DownloadQueue : public Subject
{
@@ -950,7 +966,6 @@ protected:
static void Loaded() { g_bLoaded = true; }
public:
virtual ~DownloadQueue() {}
static bool IsLoaded() { return g_bLoaded; }
static DownloadQueue* Lock();
static void Unlock();

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,9 +50,6 @@
#include "HistoryCoordinator.h"
#include "DupeCoordinator.h"
extern HistoryCoordinator* g_pHistoryCoordinator;
extern Options* g_pOptions;
bool DupeCoordinator::SameNameOrKey(const char* szName1, const char* szDupeKey1,
const char* szName2, const char* szDupeKey2)
{
@@ -92,18 +89,31 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
// in queue - the new item is skipped
if (pQueuedNZBInfo != pNZBInfo && bSameContent && pNZBInfo->GetKind() == NZBInfo::nkNzb)
{
char szMessage[1024];
if (!strcmp(pNZBInfo->GetName(), pQueuedNZBInfo->GetName()))
{
warn("Skipping duplicate %s, already queued", pNZBInfo->GetName());
snprintf(szMessage, 1024, "Skipping duplicate %s, already queued", pNZBInfo->GetName());
}
else
{
warn("Skipping duplicate %s, already queued as %s",
snprintf(szMessage, 1024, "Skipping duplicate %s, already queued as %s",
pNZBInfo->GetName(), pQueuedNZBInfo->GetName());
}
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
szMessage[1024-1] = '\0';
if (pNZBInfo->GetFeedID())
{
warn("%s", szMessage);
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
}
else
{
pNZBInfo->SetDeleteStatus(NZBInfo::dsCopy);
pNZBInfo->AddMessage(Message::mkWarning, szMessage);
}
return;
}
}
@@ -162,9 +172,9 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
bool bSameContent = false;
const char* szDupeName = NULL;
// find duplicates in queue having exactly same content
// find duplicates in history having exactly same content
// also: nzb-files having duplicates marked as good are skipped
// also (only in score mode): nzb-files having success-duplicates in dup-history but don't having duplicates in recent history are skipped
// also (only in score mode): nzb-files having success-duplicates in dup-history but not having duplicates in recent history are skipped
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
@@ -244,21 +254,33 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
if (bSkip)
{
char szMessage[1024];
if (!strcmp(pNZBInfo->GetName(), szDupeName))
{
warn("Skipping duplicate %s, found in history with %s", pNZBInfo->GetName(),
snprintf(szMessage, 1024, "Skipping duplicate %s, found in history with %s", pNZBInfo->GetName(),
bSameContent ? "exactly same content" : bGood ? "good status" : "success status");
}
else
{
warn("Skipping duplicate %s, found in history %s with %s",
snprintf(szMessage, 1024, "Skipping duplicate %s, found in history %s with %s",
pNZBInfo->GetName(), szDupeName,
bSameContent ? "exactly same content" : bGood ? "good status" : "success status");
}
szMessage[1024-1] = '\0';
if (pNZBInfo->GetFeedID())
{
warn("%s", szMessage);
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
}
else
{
pNZBInfo->SetDeleteStatus(bSameContent ? NZBInfo::dsCopy : NZBInfo::dsGood);
pNZBInfo->AddMessage(Message::mkWarning, szMessage);
}
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
return;
}
@@ -566,3 +588,25 @@ DupeCoordinator::EDupeStatus DupeCoordinator::GetDupeStatus(DownloadQueue* pDown
return eStatuses;
}
void DupeCoordinator::ListHistoryDupes(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, NZBList* pDupeList)
{
if (pNZBInfo->GetDupeMode() == dmForce)
{
return;
}
// find duplicates in history
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(),
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
{
pDupeList->push_back(pHistoryInfo->GetNZBInfo());
}
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,6 +51,9 @@ public:
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, NZBInfo::EMarkStatus eMarkStatus);
EDupeStatus GetDupeStatus(DownloadQueue* pDownloadQueue, const char* szName, const char* szDupeKey);
void ListHistoryDupes(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, NZBList* pDupeList);
};
extern DupeCoordinator* g_pDupeCoordinator;
#endif

View File

@@ -51,16 +51,10 @@
#include "Util.h"
#include "NZBFile.h"
#include "DupeCoordinator.h"
#include "ParCoordinator.h"
#include "ParParser.h"
#include "PrePostProcessor.h"
#include "DupeCoordinator.h"
extern QueueCoordinator* g_pQueueCoordinator;
extern PrePostProcessor* g_pPrePostProcessor;
extern DupeCoordinator* g_pDupeCoordinator;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
HistoryCoordinator::HistoryCoordinator()
{
debug("Creating HistoryCoordinator");
@@ -71,25 +65,10 @@ HistoryCoordinator::~HistoryCoordinator()
debug("Destroying HistoryCoordinator");
}
void HistoryCoordinator::Cleanup()
{
debug("Cleaning up HistoryCoordinator");
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
delete *it;
}
pDownloadQueue->GetHistory()->clear();
DownloadQueue::Unlock();
}
/**
* Removes old entries from (recent) history
*/
void HistoryCoordinator::IntervalCheck()
void HistoryCoordinator::ServiceWork()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
@@ -252,7 +231,9 @@ void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo*
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksBad ? DupInfo::dsBad :
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksSuccess ? DupInfo::dsSuccess :
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe ? DupInfo::dsDupe :
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsManual ? DupInfo::dsDeleted :
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsManual ||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsGood ||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsCopy ? DupInfo::dsDeleted :
pHistoryInfo->GetNZBInfo()->IsDupeSuccess() ? DupInfo::dsSuccess :
DupInfo::dsFailed);
@@ -266,9 +247,28 @@ void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo*
info("Collection %s removed from history", szNiceName);
}
void HistoryCoordinator::PrepareEdit(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction)
{
// First pass: when marking multiple items - mark them bad without performing the mark-logic,
// this will later (on second step) avoid moving other items to download queue, if they are marked bad too.
if (eAction == DownloadQueue::eaHistoryMarkBad)
{
for (IDList::iterator itID = pIDList->begin(); itID != pIDList->end(); itID++)
{
int iID = *itID;
HistoryInfo* pHistoryInfo = pDownloadQueue->GetHistory()->Find(iID);
if (pHistoryInfo && pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
{
pHistoryInfo->GetNZBInfo()->SetMarkStatus(NZBInfo::ksBad);
}
}
}
}
bool HistoryCoordinator::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText)
{
bool bOK = false;
PrepareEdit(pDownloadQueue, pIDList, eAction);
for (IDList::iterator itID = pIDList->begin(); itID != pIDList->end(); itID++)
{
@@ -434,7 +434,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
pNZBInfo->SetPostTotalSec(pNZBInfo->GetPostTotalSec() - pNZBInfo->GetUnpackSec());
pNZBInfo->SetUnpackSec(0);
if (ParCoordinator::FindMainPars(pNZBInfo->GetDestDir(), NULL))
if (ParParser::FindMainPars(pNZBInfo->GetDestDir(), NULL))
{
pNZBInfo->SetParStatus(NZBInfo::psNone);
pNZBInfo->SetPostTotalSec(pNZBInfo->GetPostTotalSec() - pNZBInfo->GetParSec());
@@ -505,11 +505,12 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
return;
}
NZBFile* pNZBFile = NZBFile::Create(pNZBInfo->GetQueuedFilename(), "");
if (pNZBFile == NULL)
NZBFile* pNZBFile = new NZBFile(pNZBInfo->GetQueuedFilename(), "");
if (!pNZBFile->Parse())
{
error("Could not return %s from history back to queue: could not parse nzb-file",
pNZBInfo->GetName());
delete pNZBFile;
return;
}
@@ -555,6 +556,7 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
pNZBInfo->SetParSec(0);
pNZBInfo->SetRepairSec(0);
pNZBInfo->SetUnpackSec(0);
pNZBInfo->SetExtraParBlocks(0);
pNZBInfo->ClearCompletedFiles();
pNZBInfo->GetServerStats()->Clear();
pNZBInfo->GetCurrentServerStats()->Clear();

View File

@@ -27,8 +27,9 @@
#define HISTORYCOORDINATOR_H
#include "DownloadInfo.h"
#include "Service.h"
class HistoryCoordinator
class HistoryCoordinator : public Service
{
private:
void HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bFinal);
@@ -40,6 +41,11 @@ private:
bool HistorySetName(HistoryInfo* pHistoryInfo, const char* szText);
void HistoryTransformToDup(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
void SaveQueue(DownloadQueue* pDownloadQueue);
void PrepareEdit(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction);
protected:
virtual int ServiceInterval() { return 600000; }
virtual void ServiceWork();
public:
HistoryCoordinator();
@@ -49,8 +55,8 @@ public:
void DeleteDiskFiles(NZBInfo* pNZBInfo);
void HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
void Redownload(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo);
void IntervalCheck();
void Cleanup();
};
extern HistoryCoordinator* g_pHistoryCoordinator;
#endif

View File

@@ -54,9 +54,6 @@ using namespace MSXML;
#include "DiskState.h"
#include "Util.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
NZBFile::NZBFile(const char* szFileName, const char* szCategory)
{
debug("Creating NZBFile");
@@ -172,10 +169,32 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
{
// Example subject: some garbage "title" yEnc (10/99)
// strip the "yEnc (10/99)"-suffix
char szSubject[1024];
strncpy(szSubject, pFileInfo->GetSubject(), sizeof(szSubject));
szSubject[1024-1] = '\0';
char* end = szSubject + strlen(szSubject) - 1;
if (*end == ')')
{
end--;
while (strchr("0123456789", *end) && end > szSubject) end--;
if (*end == '/')
{
end--;
while (strchr("0123456789", *end) && end > szSubject) end--;
if (end - 6 > szSubject && !strncmp(end - 6, " yEnc (", 7))
{
end[-6] = '\0';
}
}
}
if (TryQuotes)
{
// try to use the filename in quatation marks
char* p = (char*)pFileInfo->GetSubject();
char* p = szSubject;
char* start = strchr(p, '\"');
if (start)
{
@@ -207,7 +226,7 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
tokens.clear();
// tokenizing
char* p = (char*)pFileInfo->GetSubject();
char* p = szSubject;
char* start = p;
bool quot = false;
while (true)
@@ -496,7 +515,7 @@ void NZBFile::ReadPassword()
}
#ifdef WIN32
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
bool NZBFile::Parse()
{
CoInitialize(NULL);
@@ -506,7 +525,7 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
hr = doc.CreateInstance(MSXML::CLSID_DOMDocument);
if (FAILED(hr))
{
return NULL;
return false;
}
// Load the XML document file...
@@ -515,8 +534,8 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
doc->put_async(VARIANT_FALSE);
// filename needs to be properly encoded
char* szURL = (char*)malloc(strlen(szFileName)*3 + 1);
EncodeURL(szFileName, szURL);
char* szURL = (char*)malloc(strlen(m_szFileName)*3 + 1);
EncodeURL(m_szFileName, szURL);
debug("url=\"%s\"", szURL);
_variant_t v(szURL);
free(szURL);
@@ -526,28 +545,33 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
{
_bstr_t r(doc->GetparseError()->reason);
const char* szErrMsg = r;
error("Error parsing nzb-file %s: %s", Util::BaseFileName(szFileName), szErrMsg);
return NULL;
char szMessageText[1024];
snprintf(szMessageText, 1024, "Error parsing nzb-file %s: %s", Util::BaseFileName(m_szFileName), szErrMsg);
szMessageText[1024-1] = '\0';
m_pNZBInfo->AddMessage(Message::mkError, szMessageText);
return false;
}
NZBFile* pFile = new NZBFile(szFileName, szCategory);
if (!pFile->ParseNZB(doc))
if (!ParseNZB(doc))
{
delete pFile;
return NULL;
return false;
}
if (pFile->GetNZBInfo()->GetFileList()->empty())
if (GetNZBInfo()->GetFileList()->empty())
{
error("Error parsing nzb-file %s: file has no content", Util::BaseFileName(szFileName));
delete pFile;
return NULL;
char szMessageText[1024];
snprintf(szMessageText, 1024, "Error parsing nzb-file %s: file has no content", Util::BaseFileName(m_szFileName));
szMessageText[1024-1] = '\0';
m_pNZBInfo->AddMessage(Message::mkError, szMessageText);
return false;
}
pFile->ProcessFiles();
ProcessFiles();
return pFile;
return true;
}
void NZBFile::EncodeURL(const char* szFilename, char* szURL)
@@ -645,10 +669,8 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
#else
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
bool NZBFile::Parse()
{
NZBFile* pFile = new NZBFile(szFileName, szCategory);
xmlSAXHandler SAX_handler = {0};
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
@@ -656,31 +678,39 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
SAX_handler.error = reinterpret_cast<errorSAXFunc>(SAX_error);
SAX_handler.getEntity = reinterpret_cast<getEntitySAXFunc>(SAX_getEntity);
pFile->m_bIgnoreNextError = false;
m_bIgnoreNextError = false;
int ret = xmlSAXUserParseFile(&SAX_handler, pFile, szFileName);
int ret = xmlSAXUserParseFile(&SAX_handler, this, m_szFileName);
if (ret != 0)
{
error("Error parsing nzb-file %s", Util::BaseFileName(szFileName));
delete pFile;
return NULL;
char szMessageText[1024];
snprintf(szMessageText, 1024, "Error parsing nzb-file %s", Util::BaseFileName(m_szFileName));
szMessageText[1024-1] = '\0';
m_pNZBInfo->AddMessage(Message::mkError, szMessageText);
return false;
}
if (pFile->GetNZBInfo()->GetFileList()->empty())
if (m_pNZBInfo->GetFileList()->empty())
{
error("Error parsing nzb-file %s: file has no content", Util::BaseFileName(szFileName));
delete pFile;
return NULL;
char szMessageText[1024];
snprintf(szMessageText, 1024, "Error parsing nzb-file %s: file has no content", Util::BaseFileName(m_szFileName));
szMessageText[1024-1] = '\0';
m_pNZBInfo->AddMessage(Message::mkError, szMessageText);
return false;
}
pFile->ProcessFiles();
ProcessFiles();
return pFile;
return true;
}
void NZBFile::Parse_StartElement(const char *name, const char **atts)
{
char szTagAttrMessage[1024];
snprintf(szTagAttrMessage, 1024, "Malformed nzb-file, tag <%s> must have attributes", name);
szTagAttrMessage[1024-1] = '\0';
if (m_szTagContent)
{
free(m_szTagContent);
@@ -695,7 +725,7 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
m_pNZBInfo->AddMessage(Message::mkWarning, szTagAttrMessage);
return;
}
@@ -717,13 +747,13 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
{
if (!m_pFileInfo)
{
warn("Malformed nzb-file, tag <segment> without tag <file>");
m_pNZBInfo->AddMessage(Message::mkWarning, "Malformed nzb-file, tag <segment> without tag <file>");
return;
}
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
m_pNZBInfo->AddMessage(Message::mkWarning, szTagAttrMessage);
return;
}
@@ -757,7 +787,7 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
{
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
m_pNZBInfo->AddMessage(Message::mkWarning, szTagAttrMessage);
return;
}
m_bPassword = atts[0] && atts[1] && !strcmp("type", atts[0]) && !strcmp("password", atts[1]);
@@ -870,7 +900,7 @@ void* NZBFile::SAX_getEntity(NZBFile* pFile, const char * name)
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
if (!e)
{
warn("entity not found");
pFile->GetNZBInfo()->AddMessage(Message::mkWarning, "entity not found");
pFile->m_bIgnoreNextError = true;
}
@@ -894,6 +924,10 @@ void NZBFile::SAX_error(NZBFile* pFile, const char *msg, ...)
// remove trailing CRLF
for (char* pend = szErrMsg + strlen(szErrMsg) - 1; pend >= szErrMsg && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
error("Error parsing nzb-file: %s", szErrMsg);
char szTextMessage[1024];
snprintf(szTextMessage, 1024, "Error parsing nzb-file: %s", szErrMsg);
szTextMessage[1024-1] = '\0';
pFile->GetNZBInfo()->AddMessage(Message::mkError, szTextMessage);
}
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,6 @@ private:
char* m_szFileName;
char* m_szPassword;
NZBFile(const char* szFileName, const char* szCategory);
void AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
void AddFileInfo(FileInfo* pFileInfo);
void ParseSubject(FileInfo* pFileInfo, bool TryQuotes);
@@ -72,8 +71,9 @@ private:
#endif
public:
virtual ~NZBFile();
static NZBFile* Create(const char* szFileName, const char* szCategory);
NZBFile(const char* szFileName, const char* szCategory);
~NZBFile();
bool Parse();
const char* GetFileName() const { return m_szFileName; }
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
const char* GetPassword() { return m_szPassword; }

View File

@@ -53,12 +53,6 @@
#include "Decoder.h"
#include "StatMeter.h"
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern DiskState* g_pDiskState;
extern StatMeter* g_pStatMeter;
extern ArticleCache* g_pArticleCache;
bool QueueCoordinator::CoordinatorDownloadQueue::EditEntry(
int ID, EEditAction eAction, int iOffset, const char* szText)
{
@@ -68,15 +62,30 @@ bool QueueCoordinator::CoordinatorDownloadQueue::EditEntry(
bool QueueCoordinator::CoordinatorDownloadQueue::EditList(
IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction, int iOffset, const char* szText)
{
return m_pOwner->m_QueueEditor.EditList(&m_pOwner->m_DownloadQueue, pIDList, pNameList, eMatchMode, eAction, iOffset, szText);
m_bMassEdit = true;
bool bRet = m_pOwner->m_QueueEditor.EditList(&m_pOwner->m_DownloadQueue, pIDList, pNameList, eMatchMode, eAction, iOffset, szText);
m_bMassEdit = false;
if (m_bWantSave)
{
Save();
}
return bRet;
}
void QueueCoordinator::CoordinatorDownloadQueue::Save()
{
if (m_bMassEdit)
{
m_bWantSave = true;
return;
}
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveDownloadQueue(this);
}
m_bWantSave = false;
}
QueueCoordinator::QueueCoordinator()
@@ -873,7 +882,9 @@ void QueueCoordinator::CheckHealth(DownloadQueue* pDownloadQueue, FileInfo* pFil
if (g_pOptions->GetHealthCheck() == Options::hcNone ||
pFileInfo->GetNZBInfo()->GetHealthPaused() ||
pFileInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsHealth ||
pFileInfo->GetNZBInfo()->CalcHealth() >= pFileInfo->GetNZBInfo()->CalcCriticalHealth(true))
pFileInfo->GetNZBInfo()->CalcHealth() >= pFileInfo->GetNZBInfo()->CalcCriticalHealth(true) ||
(g_pOptions->GetParScan() == Options::psDupe && g_pOptions->GetHealthCheck() == Options::hcDelete &&
pFileInfo->GetNZBInfo()->GetSuccessArticles() * 100 / pFileInfo->GetNZBInfo()->GetTotalArticles() > 10))
{
return;
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,8 +49,11 @@ private:
{
private:
QueueCoordinator* m_pOwner;
bool m_bMassEdit;
bool m_bWantSave;
friend class QueueCoordinator;
public:
CoordinatorDownloadQueue(): m_bMassEdit(false), m_bWantSave(false) {}
virtual bool EditEntry(int ID, EEditAction eAction, int iOffset, const char* szText);
virtual bool EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction, int iOffset, const char* szText);
virtual void Save();
@@ -97,4 +100,6 @@ public:
bool SplitQueueEntries(DownloadQueue* pDownloadQueue, FileList* pFileList, const char* szName, NZBInfo** pNewNZBInfo);
};
extern QueueCoordinator* g_pQueueCoordinator;
#endif

View File

@@ -54,15 +54,8 @@
#include "HistoryCoordinator.h"
#include "UrlCoordinator.h"
extern QueueCoordinator* g_pQueueCoordinator;
extern HistoryCoordinator* g_pHistoryCoordinator;
extern UrlCoordinator* g_pUrlCoordinator;
extern PrePostProcessor* g_pPrePostProcessor;
extern Options* g_pOptions;
const int MAX_ID = 1000000000;
class GroupSorter
{
public:

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,204 +46,10 @@
#include "Options.h"
#include "Log.h"
#include "QueueCoordinator.h"
#include "QueueScript.h"
#include "HistoryCoordinator.h"
#include "ScanScript.h"
#include "Util.h"
extern QueueCoordinator* g_pQueueCoordinator;
extern Options* g_pOptions;
extern Scanner* g_pScanner;
class ScanScriptController : public NZBScriptController
{
private:
const char* m_szNZBFilename;
const char* m_szUrl;
const char* m_szDirectory;
char** m_pNZBName;
char** m_pCategory;
int* m_iPriority;
NZBParameterList* m_pParameters;
bool* m_bAddTop;
bool* m_bAddPaused;
char** m_pDupeKey;
int* m_iDupeScore;
EDupeMode* m_eDupeMode;
int m_iPrefixLen;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
static void ExecuteScripts(const char* szNZBFilename, const char* szUrl,
const char* szDirectory, char** pNZBName, char** pCategory, int* iPriority,
NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode);
};
void ScanScriptController::ExecuteScripts(const char* szNZBFilename,
const char* szUrl, const char* szDirectory, char** pNZBName, char** pCategory,
int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode)
{
ScanScriptController* pScriptController = new ScanScriptController();
pScriptController->m_szNZBFilename = szNZBFilename;
pScriptController->m_szUrl = szUrl;
pScriptController->m_szDirectory = szDirectory;
pScriptController->m_pNZBName = pNZBName;
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameters = pParameters;
pScriptController->m_iPriority = iPriority;
pScriptController->m_bAddTop = bAddTop;
pScriptController->m_bAddPaused = bAddPaused;
pScriptController->m_pDupeKey = pDupeKey;
pScriptController->m_iDupeScore = iDupeScore;
pScriptController->m_eDupeMode = eDupeMode;
pScriptController->m_iPrefixLen = 0;
pScriptController->ExecuteScriptList(g_pOptions->GetScanScript());
delete pScriptController;
}
void ScanScriptController::ExecuteScript(Options::Script* pScript)
{
if (!pScript->GetScanScript() || !Util::FileExists(m_szNZBFilename))
{
return;
}
PrintMessage(Message::mkInfo, "Executing scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void ScanScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetEnvVar("NZBNP_FILENAME", m_szNZBFilename);
SetEnvVar("NZBNP_URL", m_szUrl);
SetEnvVar("NZBNP_NZBNAME", strlen(*m_pNZBName) > 0 ? *m_pNZBName : Util::BaseFileName(m_szNZBFilename));
SetEnvVar("NZBNP_CATEGORY", *m_pCategory);
SetIntEnvVar("NZBNP_PRIORITY", *m_iPriority);
SetIntEnvVar("NZBNP_TOP", *m_bAddTop ? 1 : 0);
SetIntEnvVar("NZBNP_PAUSED", *m_bAddPaused ? 1 : 0);
SetEnvVar("NZBNP_DUPEKEY", *m_pDupeKey);
SetIntEnvVar("NZBNP_DUPESCORE", *m_iDupeScore);
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
SetEnvVar("NZBNP_DUPEMODE", szDupeModeName[*m_eDupeMode]);
// remove trailing slash
char szDir[1024];
strncpy(szDir, m_szDirectory, 1024);
szDir[1024-1] = '\0';
int iLen = strlen(szDir);
if (szDir[iLen-1] == PATH_SEPARATOR)
{
szDir[iLen-1] = '\0';
}
SetEnvVar("NZBNP_DIRECTORY", szDir);
PrepareEnvScript(m_pParameters, szScriptName);
}
void ScanScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "NZBNAME=", 8))
{
free(*m_pNZBName);
*m_pNZBName = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "CATEGORY=", 9))
{
free(*m_pCategory);
*m_pCategory = strdup(szMsgText + 6 + 9);
g_pScanner->InitPPParameters(*m_pCategory, m_pParameters, true);
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
m_pParameters->SetParameter(szParam, szValue + 1);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szMsgText + 6 + 9);
}
else if (!strncmp(szMsgText + 6, "TOP=", 4))
{
*m_bAddTop = atoi(szMsgText + 6 + 4) != 0;
}
else if (!strncmp(szMsgText + 6, "PAUSED=", 7))
{
*m_bAddPaused = atoi(szMsgText + 6 + 7) != 0;
}
else if (!strncmp(szMsgText + 6, "DUPEKEY=", 8))
{
free(*m_pDupeKey);
*m_pDupeKey = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "DUPESCORE=", 10))
{
*m_iDupeScore = atoi(szMsgText + 6 + 10);
}
else if (!strncmp(szMsgText + 6, "DUPEMODE=", 9))
{
const char* szDupeMode = szMsgText + 6 + 9;
if (strcasecmp(szDupeMode, "score") && strcasecmp(szDupeMode, "all") && strcasecmp(szDupeMode, "force"))
{
error("Invalid value \"%s\" for command \"DUPEMODE\" received from %s", szDupeMode, GetInfoName());
return;
}
*m_eDupeMode = !strcasecmp(szDupeMode, "all") ? dmAll :
!strcasecmp(szDupeMode, "force") ? dmForce : dmScore;
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, szText);
}
}
Scanner::FileData::FileData(const char* szFilename)
{
m_szFilename = strdup(szFilename);
@@ -346,8 +152,13 @@ void Scanner::ClearQueueList()
m_QueueList.clear();
}
void Scanner::Check()
void Scanner::ServiceWork()
{
if (!DownloadQueue::IsLoaded())
{
return;
}
m_mutexScan.Lock();
if (m_bRequestedNZBDirScan ||
@@ -545,7 +356,6 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
int iDupeScore = 0;
EDupeMode eDupeMode = dmScore;
EAddStatus eAddStatus = asSkipped;
bool bAdded = false;
QueueData* pQueueData = NULL;
NZBInfo* pUrlInfo = NULL;
int iNZBID = 0;
@@ -601,8 +411,9 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024);
if (bRenameOK)
{
bAdded = AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority,
bool bAdded = AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority,
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, pUrlInfo, &iNZBID);
eAddStatus = bAdded ? asSuccess : asFailed;
}
else
{
@@ -613,8 +424,9 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
}
else if (bExists && !strcasecmp(szExtension, ".nzb"))
{
bAdded = AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority,
bool bAdded = AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority,
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, pUrlInfo, &iNZBID);
eAddStatus = bAdded ? asSuccess : asFailed;
}
delete pParameters;
@@ -625,7 +437,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
if (pQueueData)
{
pQueueData->SetAddStatus(eAddStatus == asFailed ? asFailed : bAdded ? asSuccess : asSkipped);
pQueueData->SetAddStatus(eAddStatus);
pQueueData->SetNZBID(iNZBID);
}
}
@@ -650,9 +462,9 @@ void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParame
if (bReset)
{
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
for (ScriptConfig::Scripts::iterator it = g_pScriptConfig->GetScripts()->begin(); it != g_pScriptConfig->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
ScriptConfig::Script* pScript = *it;
char szParam[1024];
snprintf(szParam, 1024, "%s:", pScript->GetName());
szParam[1024-1] = '\0';
@@ -684,8 +496,8 @@ bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, cons
info("Adding collection %s to queue", szBasename);
NZBFile* pNZBFile = NZBFile::Create(szFilename, szCategory);
bool bOK = pNZBFile != NULL;
NZBFile* pNZBFile = new NZBFile(szFilename, szCategory);
bool bOK = pNZBFile->Parse();
if (!bOK)
{
error("Could not add collection %s to queue", szBasename);
@@ -699,54 +511,60 @@ bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, cons
error("Could not rename file %s to %s: %s", szFilename, bakname2, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
}
NZBInfo* pNZBInfo = pNZBFile->GetNZBInfo();
pNZBInfo->SetQueuedFilename(bakname2);
if (szNZBName && strlen(szNZBName) > 0)
{
pNZBInfo->SetName(NULL);
#ifdef WIN32
char* szAnsiFilename = strdup(szNZBName);
WebUtil::Utf8ToAnsi(szAnsiFilename, strlen(szAnsiFilename) + 1);
pNZBInfo->SetFilename(szAnsiFilename);
free(szAnsiFilename);
#else
pNZBInfo->SetFilename(szNZBName);
#endif
pNZBInfo->BuildDestDirName();
}
pNZBInfo->SetDupeKey(szDupeKey);
pNZBInfo->SetDupeScore(iDupeScore);
pNZBInfo->SetDupeMode(eDupeMode);
pNZBInfo->SetPriority(iPriority);
if (pUrlInfo)
{
pNZBInfo->SetURL(pUrlInfo->GetURL());
pNZBInfo->SetUrlStatus(pUrlInfo->GetUrlStatus());
pNZBInfo->SetFeedID(pUrlInfo->GetFeedID());
}
if (pNZBFile->GetPassword())
{
pNZBInfo->GetParameters()->SetParameter("*Unpack:Password", pNZBFile->GetPassword());
}
pNZBInfo->GetParameters()->CopyFrom(pParameters);
for (::FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetPaused(bAddPaused);
}
if (bOK)
{
NZBInfo* pNZBInfo = pNZBFile->GetNZBInfo();
pNZBInfo->SetQueuedFilename(bakname2);
if (szNZBName && strlen(szNZBName) > 0)
{
pNZBInfo->SetName(NULL);
#ifdef WIN32
char* szAnsiFilename = strdup(szNZBName);
WebUtil::Utf8ToAnsi(szAnsiFilename, strlen(szAnsiFilename) + 1);
pNZBInfo->SetFilename(szAnsiFilename);
free(szAnsiFilename);
#else
pNZBInfo->SetFilename(szNZBName);
#endif
pNZBInfo->BuildDestDirName();
}
pNZBInfo->SetDupeKey(szDupeKey);
pNZBInfo->SetDupeScore(iDupeScore);
pNZBInfo->SetDupeMode(eDupeMode);
pNZBInfo->SetPriority(iPriority);
if (pUrlInfo)
{
pNZBInfo->SetURL(pUrlInfo->GetURL());
pNZBInfo->SetUrlStatus(pUrlInfo->GetUrlStatus());
}
if (pNZBFile->GetPassword())
{
pNZBInfo->GetParameters()->SetParameter("*Unpack:Password", pNZBFile->GetPassword());
}
pNZBInfo->GetParameters()->CopyFrom(pParameters);
for (::FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetPaused(bAddPaused);
}
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, pUrlInfo, bAddTop);
}
else if (!pUrlInfo)
{
pNZBFile->GetNZBInfo()->SetDeleteStatus(NZBInfo::dsScan);
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, pUrlInfo, bAddTop);
}
if (pNZBID)
{
*pNZBID = pNZBInfo->GetID();
}
if (pNZBID)
{
*pNZBID = pNZBInfo->GetID();
}
delete pNZBFile;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,8 +30,9 @@
#include <time.h>
#include "DownloadInfo.h"
#include "Thread.h"
#include "Service.h"
class Scanner
class Scanner : public Service
{
public:
enum EAddStatus
@@ -120,12 +121,15 @@ private:
void DropOldFiles();
void ClearQueueList();
protected:
virtual int ServiceInterval() { return 200; }
virtual void ServiceWork();
public:
Scanner();
~Scanner();
void InitOptions();
void ScanNZBDir(bool bSyncMode);
void Check();
EAddStatus AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
@@ -133,4 +137,6 @@ public:
void InitPPParameters(const char* szCategory, NZBParameterList* pParameters, bool bReset);
};
extern Scanner* g_pScanner;
#endif

View File

@@ -48,10 +48,7 @@
#include "NZBFile.h"
#include "Scanner.h"
#include "DiskState.h"
extern Options* g_pOptions;
extern Scanner* g_pScanner;
extern DiskState* g_pDiskState;
#include "QueueScript.h"
UrlDownloader::UrlDownloader() : WebDownloader()
{
@@ -343,7 +340,6 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
{
debug("URL downloaded");
bool bRetry = pUrlDownloader->GetStatus() == WebDownloader::adRetry;
NZBInfo* pNZBInfo = pUrlDownloader->GetNZBInfo();
char filename[1024];
@@ -378,6 +374,8 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
}
pNZBInfo->SetActiveDownloads(0);
bool bRetry = pUrlDownloader->GetStatus() == WebDownloader::adRetry && !pNZBInfo->GetDeleting();
if (pNZBInfo->GetDeleting())
{
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
@@ -432,6 +430,8 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
// the rest of function is only for failed URLs or for failed scans
g_pQueueScriptCoordinator->EnqueueScript(pNZBInfo, QueueScriptCoordinator::qeUrlCompleted);
pDownloadQueue = DownloadQueue::Lock();
// delete URL from queue

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -69,6 +69,8 @@ public:
bool DeleteQueueEntry(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bAvoidHistory);
};
extern UrlCoordinator* g_pUrlCoordinator;
class UrlDownloader : public WebDownloader
{
private:

View File

@@ -52,9 +52,6 @@
#include "Scanner.h"
#include "StatMeter.h"
extern Options* g_pOptions;
extern Scanner* g_pScanner;
extern StatMeter* g_pStatMeter;
extern void ExitProc();
extern void Reload();

View File

@@ -27,6 +27,10 @@
#ifndef MESSAGEBASE_H
#define MESSAGEBASE_H
#if (!(defined(WIN32) && _MSC_VER < 1600))
#include <stdint.h>
#endif
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6228; // = "nzb-XX" (protocol version)
static const int NZBREQUESTFILENAMESIZE = 512;
static const int NZBREQUESTPASSWORDSIZE = 32;

View File

@@ -51,8 +51,6 @@
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
RemoteClient::RemoteClient()
{
m_pConnection = NULL;
@@ -100,13 +98,15 @@ void RemoteClient::perror(const char * msg)
bool RemoteClient::InitConnection()
{
const char* szControlIP = !strcmp(g_pOptions->GetControlIP(), "0.0.0.0") ? "127.0.0.1" : g_pOptions->GetControlIP();
// Create a connection to the server
m_pConnection = new Connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
m_pConnection = new Connection(szControlIP, g_pOptions->GetControlPort(), false);
bool OK = m_pConnection->Connect();
if (!OK)
{
printf("Unable to send request to nzbget-server at %s (port %i)\n", g_pOptions->GetControlIP(), g_pOptions->GetControlPort());
printf("Unable to send request to nzbget-server at %s (port %i)\n", szControlIP, g_pOptions->GetControlPort());
}
return OK;
}
@@ -411,7 +411,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
szCompleted[0] = '\0';
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
{
sprintf(szCompleted, ", %i%s", (int)(100 - Util::Int64ToFloat(pFileInfo->GetRemainingSize()) * 100.0 / Util::Int64ToFloat(pFileInfo->GetSize())), "%");
sprintf(szCompleted, ", %i%s", (int)(100 - pFileInfo->GetRemainingSize() * 100 / pFileInfo->GetSize()), "%");
}
char szThreads[100];
@@ -435,9 +435,10 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
if (!szPattern || ((MatchedFileInfo*)pFileInfo)->m_bMatch)
{
printf("[%i] %s/%s (%.2f MB%s%s)%s\n", pFileInfo->GetID(), pFileInfo->GetNZBInfo()->GetName(),
char szSize[20];
printf("[%i] %s/%s (%s%s%s)%s\n", pFileInfo->GetID(), pFileInfo->GetNZBInfo()->GetName(),
pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
Util::FormatSize(szSize, sizeof(szSize), pFileInfo->GetSize()),
szCompleted, szThreads, szStatus);
iMatches++;
}
@@ -457,14 +458,19 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
{
printf("Matches: %i\n", iMatches);
}
if (lPaused > 0)
{
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0),
(float)(Util::Int64ToFloat(lPaused) / 1024.0 / 1024.0));
char szRemaining[20];
char szPausedSize[20];
printf("Remaining size: %s (+%s paused)\n",
Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining),
Util::FormatSize(szPausedSize, sizeof(szPausedSize), lPaused));
}
else
{
printf("Remaining size: %.2f MB\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0));
char szRemaining[20];
printf("Remaining size: %s\n", Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining));
}
}
}
@@ -498,7 +504,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
lRemaining += lUnpausedRemainingSize;
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
Util::FormatSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
char szPriority[100];
szPriority[0] = '\0';
@@ -512,7 +518,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
if (pNZBInfo->GetPausedSize() > 0)
{
char szPausedSize[20];
Util::FormatFileSize(szPausedSize, sizeof(szPausedSize), pNZBInfo->GetPausedSize());
Util::FormatSize(szPausedSize, sizeof(szPausedSize), pNZBInfo->GetPausedSize());
sprintf(szPaused, " + %s paused", szPausedSize);
lPaused += pNZBInfo->GetPausedSize();
}
@@ -586,14 +592,20 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
printf("Matches: %i\n", iMatches);
}
printf("Files: %i\n", iNrFileEntries);
if (lPaused > 0)
{
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0),
(float)(Util::Int64ToFloat(lPaused) / 1024.0 / 1024.0));
char szRemaining[20];
char szPausedSize[20];
printf("Remaining size: %s (+%s paused)\n",
Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining),
Util::FormatSize(szPausedSize, sizeof(szPausedSize), lPaused));
}
else
{
printf("Remaining size: %.2f MB\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0));
char szRemaining[20];
printf("Remaining size: %s\n",
Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining));
}
DownloadQueue::Unlock();
@@ -606,7 +618,8 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
if (!bFiles && !bGroups)
{
printf("Remaining size: %.2f MB\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0));
char szRemaining[20];
printf("Remaining size: %s\n", Util::FormatSize(szRemaining, sizeof(szRemaining), lRemaining));
}
if (ntohl(ListResponse.m_iDownloadRate) > 0 &&
@@ -621,15 +634,18 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
printf("Remaining time: %.2d:%.2d:%.2d\n", h, m, s);
}
printf("Current download rate: %.1f KB/s\n", (float)(ntohl(ListResponse.m_iDownloadRate) / 1024.0));
char szSpeed[20];
printf("Current download rate: %s\n",
Util::FormatSpeed(szSpeed, sizeof(szSpeed), ntohl(ListResponse.m_iDownloadRate)));
long long iAllBytes = Util::JoinInt64(ntohl(ListResponse.m_iDownloadedBytesHi), ntohl(ListResponse.m_iDownloadedBytesLo));
float fAverageSpeed = Util::Int64ToFloat(ntohl(ListResponse.m_iDownloadTimeSec) > 0 ? iAllBytes / ntohl(ListResponse.m_iDownloadTimeSec) : 0);
printf("Session download rate: %.1f KB/s\n", (float)(fAverageSpeed / 1024.0));
int iAverageSpeed = (int)(ntohl(ListResponse.m_iDownloadTimeSec) > 0 ? iAllBytes / ntohl(ListResponse.m_iDownloadTimeSec) : 0);
printf("Session download rate: %s\n", Util::FormatSpeed(szSpeed, sizeof(szSpeed), iAverageSpeed));
if (ntohl(ListResponse.m_iDownloadLimit) > 0)
{
printf("Speed limit: %.1f KB/s\n", (float)(ntohl(ListResponse.m_iDownloadLimit) / 1024.0));
printf("Speed limit: %s\n",
Util::FormatSpeed(szSpeed, sizeof(szSpeed), ntohl(ListResponse.m_iDownloadLimit)));
}
int sec = ntohl(ListResponse.m_iUpTimeSec);
@@ -644,7 +660,8 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
s = sec % 60;
printf("Download time: %.2d:%.2d:%.2d\n", h, m, s);
printf("Downloaded: %.2f MB\n", (float)(Util::Int64ToFloat(iAllBytes) / 1024.0 / 1024.0));
char szSize[20];
printf("Downloaded: %s\n", Util::FormatSize(szSize, sizeof(szSize), iAllBytes));
printf("Threads running: %i\n", ntohl(ListResponse.m_iThreadCount));
@@ -1182,7 +1199,7 @@ bool RemoteClient::RequestHistory(bool bWithHidden)
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
char szSize[20];
Util::FormatFileSize(szSize, sizeof(szSize), lSize);
Util::FormatSize(szSize, sizeof(szSize), lSize);
const char* szParStatusText[] = { "", "", ", Par failed", ", Par successful", ", Repair possible", ", Repair needed" };
const char* szScriptStatusText[] = { "", ", Script status unknown", ", Script failed", ", Script successful" };

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2015 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,8 +50,6 @@
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
//*****************************************************************
// RemoteServer
@@ -225,6 +223,10 @@ void RequestProcessor::Run()
processor.SetUrl(szUrl);
processor.SetHttpMethod(eHttpMethod);
processor.Execute();
m_pConnection->SetGracefull(true);
m_pConnection->Disconnect();
bOK = true;
}
}

View File

@@ -45,17 +45,47 @@
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
static const char* ERR_HTTP_BAD_REQUEST = "400 Bad Request";
static const char* ERR_HTTP_NOT_FOUND = "404 Not Found";
static const char* ERR_HTTP_SERVICE_UNAVAILABLE = "503 Service Unavailable";
static const int MAX_UNCOMPRESSED_SIZE = 500;
char WebProcessor::m_szServerAuthToken[3][49];
//*****************************************************************
// WebProcessor
void WebProcessor::Init()
{
if (m_szServerAuthToken[0][0] != 0)
{
// already initialized
return;
}
for (int j = uaControl; j <= uaAdd; j++)
{
for (int i = 0; i < sizeof(m_szServerAuthToken[j]) - 1; i++)
{
int ch = rand() % (10 + 26 + 26);
if (0 <= ch && ch < 10)
{
m_szServerAuthToken[j][i] = '0' + ch;
}
else if (10 <= ch && ch < 10 + 26)
{
m_szServerAuthToken[j][i] = 'a' + ch - 10;
}
else
{
m_szServerAuthToken[j][i] = 'A' + ch - 10 - 26;
}
}
m_szServerAuthToken[j][sizeof(m_szServerAuthToken[j]) - 1] = '\0';
debug("X-Auth-Token[%i]: %s", j, m_szServerAuthToken[j]);
}
}
WebProcessor::WebProcessor()
{
m_pConnection = NULL;
@@ -79,49 +109,13 @@ void WebProcessor::SetUrl(const char* szUrl)
void WebProcessor::Execute()
{
m_bGZip =false;
char szAuthInfo[1024];
szAuthInfo[0] = '\0';
m_eUserAccess = uaControl;
m_szAuthInfo[0] = '\0';
m_szAuthToken[0] = '\0';
// reading http header
char szBuffer[1024];
int iContentLen = 0;
while (char* p = m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
{
if (char* pe = strrchr(p, '\r')) *pe = '\0';
debug("header=%s", p);
if (!strncasecmp(p, "Content-Length: ", 16))
{
iContentLen = atoi(p + 16);
}
if (!strncasecmp(p, "Authorization: Basic ", 21))
{
char* szAuthInfo64 = p + 21;
if (strlen(szAuthInfo64) > sizeof(szAuthInfo))
{
error("Invalid-request: auth-info too big");
return;
}
szAuthInfo[WebUtil::DecodeBase64(szAuthInfo64, 0, szAuthInfo)] = '\0';
}
if (!strncasecmp(p, "Accept-Encoding: ", 17))
{
m_bGZip = strstr(p, "gzip");
}
if (!strncasecmp(p, "Origin: ", 8))
{
m_szOrigin = strdup(p + 8);
}
if (*p == '\0')
{
break;
}
}
ParseHeaders();
debug("URL=%s", m_szUrl);
debug("Authorization=%s", szAuthInfo);
if (m_eHttpMethod == hmPost && iContentLen <= 0)
if (m_eHttpMethod == hmPost && m_iContentLen <= 0)
{
error("Invalid-request: content length is 0");
return;
@@ -133,6 +127,82 @@ void WebProcessor::Execute()
return;
}
ParseURL();
if (!CheckCredentials())
{
SendAuthResponse();
return;
}
if (m_eHttpMethod == hmPost)
{
// reading http body (request content)
m_szRequest = (char*)malloc(m_iContentLen + 1);
m_szRequest[m_iContentLen] = '\0';
if (!m_pConnection->Recv(m_szRequest, m_iContentLen))
{
error("Invalid-request: could not read data");
return;
}
debug("Request=%s", m_szRequest);
}
debug("request received from %s", m_pConnection->GetRemoteAddr());
Dispatch();
}
void WebProcessor::ParseHeaders()
{
// reading http header
char szBuffer[1024];
m_iContentLen = 0;
while (char* p = m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
{
if (char* pe = strrchr(p, '\r')) *pe = '\0';
debug("header=%s", p);
if (!strncasecmp(p, "Content-Length: ", 16))
{
m_iContentLen = atoi(p + 16);
}
if (!strncasecmp(p, "Authorization: Basic ", 21))
{
char* szAuthInfo64 = p + 21;
if (strlen(szAuthInfo64) > sizeof(m_szAuthInfo))
{
error("Invalid-request: auth-info too big");
return;
}
m_szAuthInfo[WebUtil::DecodeBase64(szAuthInfo64, 0, m_szAuthInfo)] = '\0';
}
if (!strncasecmp(p, "Accept-Encoding: ", 17))
{
m_bGZip = strstr(p, "gzip");
}
if (!strncasecmp(p, "Origin: ", 8))
{
m_szOrigin = strdup(p + 8);
}
if (!strncasecmp(p, "X-Auth-Token: ", 14))
{
strncpy(m_szAuthToken, p + 14, sizeof(m_szAuthToken)-1);
m_szAuthToken[sizeof(m_szAuthToken)-1] = '\0';
}
if (*p == '\0')
{
break;
}
}
debug("URL=%s", m_szUrl);
debug("Authorization=%s", m_szAuthInfo);
debug("X-Auth-Token=%s", m_szAuthToken);
}
void WebProcessor::ParseURL()
{
// remove subfolder "nzbget" from the path (if exists)
// http://localhost:6789/nzbget/username:password/jsonrpc -> http://localhost:6789/username:password/jsonrpc
if (!strncmp(m_szUrl, "/nzbget/", 8))
@@ -162,48 +232,59 @@ void WebProcessor::Execute()
char* pend = strchr(pstart + 1, '/');
if (pend)
{
iLen = (int)(pend - pstart < (int)sizeof(szAuthInfo) - 1 ? pend - pstart : (int)sizeof(szAuthInfo) - 1);
iLen = (int)(pend - pstart < (int)sizeof(m_szAuthInfo) - 1 ? pend - pstart : (int)sizeof(m_szAuthInfo) - 1);
}
else
{
iLen = strlen(pstart);
}
strncpy(szAuthInfo, pstart, iLen);
szAuthInfo[iLen] = '\0';
strncpy(m_szAuthInfo, pstart, iLen);
m_szAuthInfo[iLen] = '\0';
char* sz_OldUrl = m_szUrl;
m_szUrl = strdup(pend);
free(sz_OldUrl);
}
debug("Final URL=%s", m_szUrl);
}
bool WebProcessor::CheckCredentials()
{
if (!Util::EmptyStr(g_pOptions->GetControlPassword()) &&
!(!Util::EmptyStr(g_pOptions->GetAuthorizedIP()) && IsAuthorizedIP(m_pConnection->GetRemoteAddr())))
{
if (Util::EmptyStr(szAuthInfo))
if (Util::EmptyStr(m_szAuthInfo))
{
SendAuthResponse();
return;
// Authorization via X-Auth-Token
for (int j = uaControl; j <= uaAdd; j++)
{
if (!strcmp(m_szAuthToken, m_szServerAuthToken[j]))
{
m_eUserAccess = (EUserAccess)j;
return true;
}
}
return false;
}
// Authorization
char* pw = strchr(szAuthInfo, ':');
// Authorization via username:password
char* pw = strchr(m_szAuthInfo, ':');
if (pw) *pw++ = '\0';
if ((Util::EmptyStr(g_pOptions->GetControlUsername()) ||
!strcmp(szAuthInfo, g_pOptions->GetControlUsername())) &&
!strcmp(m_szAuthInfo, g_pOptions->GetControlUsername())) &&
pw && !strcmp(pw, g_pOptions->GetControlPassword()))
{
m_eUserAccess = uaControl;
}
else if (!Util::EmptyStr(g_pOptions->GetRestrictedUsername()) &&
!strcmp(szAuthInfo, g_pOptions->GetRestrictedUsername()) &&
!strcmp(m_szAuthInfo, g_pOptions->GetRestrictedUsername()) &&
pw && !strcmp(pw, g_pOptions->GetRestrictedPassword()))
{
m_eUserAccess = uaRestricted;
}
else if (!Util::EmptyStr(g_pOptions->GetAddUsername()) &&
!strcmp(szAuthInfo, g_pOptions->GetAddUsername()) &&
!strcmp(m_szAuthInfo, g_pOptions->GetAddUsername()) &&
pw && !strcmp(pw, g_pOptions->GetAddPassword()))
{
m_eUserAccess = uaAdd;
@@ -211,29 +292,12 @@ void WebProcessor::Execute()
else
{
warn("Request received on port %i from %s, but username or password invalid (%s:%s)",
g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr(), szAuthInfo, pw);
SendAuthResponse();
return;
g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr(), m_szAuthInfo, pw);
return false;
}
}
if (m_eHttpMethod == hmPost)
{
// reading http body (request content)
m_szRequest = (char*)malloc(iContentLen + 1);
m_szRequest[iContentLen] = '\0';
if (!m_pConnection->Recv(m_szRequest, iContentLen))
{
error("Invalid-request: could not read data");
return;
}
debug("Request=%s", m_szRequest);
}
debug("request received from %s", m_pConnection->GetRemoteAddr());
Dispatch();
return true;
}
bool WebProcessor::IsAuthorizedIP(const char* szRemoteAddr)
@@ -404,6 +468,7 @@ void WebProcessor::SendBodyResponse(const char* szBody, int iBodyLen, const char
"Access-Control-Allow-Credentials: true\r\n"
"Access-Control-Max-Age: 86400\r\n"
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
"X-Auth-Token: %s\r\n"
"Content-Length: %i\r\n"
"%s" // Content-Type: xxx
"%s" // Content-Encoding: gzip
@@ -447,7 +512,7 @@ void WebProcessor::SendBodyResponse(const char* szBody, int iBodyLen, const char
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, RESPONSE_HEADER,
m_szOrigin ? m_szOrigin : "",
iBodyLen, szContentTypeHeader,
m_szServerAuthToken[m_eUserAccess], iBodyLen, szContentTypeHeader,
bGZip ? "Content-Encoding: gzip\r\n" : "",
Util::VersionRevision());

Some files were not shown because too many files have changed in this diff Show More