mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-04 12:07:50 -05:00
Compare commits
315 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b87cf1b23 | ||
|
|
ee5a2a320e | ||
|
|
738fd3da58 | ||
|
|
decc08934c | ||
|
|
5f5b7f92cf | ||
|
|
20fa280171 | ||
|
|
e5fa2ef750 | ||
|
|
bd31e25757 | ||
|
|
5b3113d96b | ||
|
|
84b4f7695b | ||
|
|
fc8ea3bcd0 | ||
|
|
9051a4df4d | ||
|
|
a7b42b6c97 | ||
|
|
f7675b1e46 | ||
|
|
db1117d892 | ||
|
|
4b14e19229 | ||
|
|
606021fb8a | ||
|
|
b15499c1dd | ||
|
|
950588cb65 | ||
|
|
7991c06543 | ||
|
|
b335c4ca05 | ||
|
|
cf3773dd28 | ||
|
|
2a3740e49f | ||
|
|
bcbd30ff6e | ||
|
|
571ab9602f | ||
|
|
cfab6a3bb6 | ||
|
|
7c9ab59aff | ||
|
|
7b1d1129a8 | ||
|
|
bf3e8fe3a9 | ||
|
|
baeac17d5b | ||
|
|
68ce6dea4b | ||
|
|
00df4b8920 | ||
|
|
36814514b7 | ||
|
|
381a9a28b0 | ||
|
|
5c364896d3 | ||
|
|
07ce1d44a9 | ||
|
|
1348ac86f7 | ||
|
|
b4c4855a9b | ||
|
|
7a1001a70b | ||
|
|
340a8130e9 | ||
|
|
9eb8de27d2 | ||
|
|
476a43a5bf | ||
|
|
9ab955d026 | ||
|
|
bcedb32cf0 | ||
|
|
6bc266f13c | ||
|
|
ed36feeb0a | ||
|
|
85400cd8f6 | ||
|
|
2866697b32 | ||
|
|
f1a99e1194 | ||
|
|
db47ddf3dc | ||
|
|
2cc4dbd2ba | ||
|
|
a38eef2971 | ||
|
|
e3e197a917 | ||
|
|
361d0befb6 | ||
|
|
ba35c662ea | ||
|
|
45ce763c71 | ||
|
|
73c85a0013 | ||
|
|
26361630c2 | ||
|
|
96c30c509b | ||
|
|
d9b9786486 | ||
|
|
bb9cea260d | ||
|
|
958c2f97ec | ||
|
|
27651f17bf | ||
|
|
71621f7bb5 | ||
|
|
d8add46215 | ||
|
|
e459f570d5 | ||
|
|
5b5057dee0 | ||
|
|
f21becb37d | ||
|
|
9d03eb1ad4 | ||
|
|
cb90c5e616 | ||
|
|
77059f2db0 | ||
|
|
fb72c36a48 | ||
|
|
b2b215a061 | ||
|
|
8d313e4cf8 | ||
|
|
6bb760375e | ||
|
|
025cd043d3 | ||
|
|
3f368d4a8e | ||
|
|
449e41e435 | ||
|
|
bf0062be52 | ||
|
|
3c025c8b52 | ||
|
|
6dc3d954c5 | ||
|
|
c9b7a11a89 | ||
|
|
33cb2d108e | ||
|
|
e053e74b58 | ||
|
|
4e35fc2fbe | ||
|
|
4768d8e459 | ||
|
|
3598cc1d85 | ||
|
|
e3a895b88c | ||
|
|
61eff3ddf0 | ||
|
|
e9268984ae | ||
|
|
f28b35bd28 | ||
|
|
a86618c2c2 | ||
|
|
1f1a4b8fb8 | ||
|
|
a1d0be34c2 | ||
|
|
ef0a04cc1c | ||
|
|
284262b7da | ||
|
|
58b0a17986 | ||
|
|
57abe00c62 | ||
|
|
d014407ba4 | ||
|
|
2e8bfa16f9 | ||
|
|
bf34713b0c | ||
|
|
c46c1a96cd | ||
|
|
2693b62de4 | ||
|
|
18387f6d98 | ||
|
|
08b7356184 | ||
|
|
e30cdfc176 | ||
|
|
cc0ed38e68 | ||
|
|
5ec0d20286 | ||
|
|
e0aa69f605 | ||
|
|
c859f39036 | ||
|
|
5251f62665 | ||
|
|
2b87e2b221 | ||
|
|
c185e9b487 | ||
|
|
b5d9a99f10 | ||
|
|
fec67fe0ea | ||
|
|
987997a986 | ||
|
|
27ef79ca27 | ||
|
|
bcc1932a37 | ||
|
|
2e163e9986 | ||
|
|
5473e57b10 | ||
|
|
b970bad058 | ||
|
|
bea1814cb9 | ||
|
|
45e58f29b4 | ||
|
|
f7a3df635a | ||
|
|
3f67984929 | ||
|
|
bf82171baa | ||
|
|
4c49a7f003 | ||
|
|
57b5d40851 | ||
|
|
ecde2d1627 | ||
|
|
b48e9a31f6 | ||
|
|
f64e5241ed | ||
|
|
4e9d01055a | ||
|
|
9d4ca25499 | ||
|
|
f1ddf9dc2b | ||
|
|
e99b790d58 | ||
|
|
5e4a99c1ad | ||
|
|
c89824bf25 | ||
|
|
1230d9cdd4 | ||
|
|
d3dd8dc686 | ||
|
|
382faa49cb | ||
|
|
5cf4b4663f | ||
|
|
749b4d3083 | ||
|
|
02835d057e | ||
|
|
f5aaaecc48 | ||
|
|
184ff84f92 | ||
|
|
ef56bc1f55 | ||
|
|
9846f7509e | ||
|
|
1cf7cefe83 | ||
|
|
b5f1dbc47b | ||
|
|
37b85491c3 | ||
|
|
30d792b35b | ||
|
|
ac29412b2f | ||
|
|
01c170afaf | ||
|
|
539e0811c9 | ||
|
|
940448ffae | ||
|
|
68a73f96c4 | ||
|
|
87a93745cb | ||
|
|
3b08abca10 | ||
|
|
5e68096a2e | ||
|
|
e3ef11ceae | ||
|
|
575fe8379f | ||
|
|
60feae7e5b | ||
|
|
2b45ecaea1 | ||
|
|
7a3a430137 | ||
|
|
11c0563fe5 | ||
|
|
00018b3e89 | ||
|
|
de787a069d | ||
|
|
5f33ea6013 | ||
|
|
ee74c4c17f | ||
|
|
b031f52ee2 | ||
|
|
77bb01b18c | ||
|
|
d2fdc28c85 | ||
|
|
d34e985a92 | ||
|
|
f0c2c834c3 | ||
|
|
ca0cce9401 | ||
|
|
2a0e211daf | ||
|
|
ea89983e45 | ||
|
|
e4ed1c8fd7 | ||
|
|
d46155bf32 | ||
|
|
9bdf0d8937 | ||
|
|
f56c1226b6 | ||
|
|
bc3e4742f0 | ||
|
|
891b16ac76 | ||
|
|
11a32c3537 | ||
|
|
8afc96e1ad | ||
|
|
55d2c9e49c | ||
|
|
9baabee3fd | ||
|
|
ad20cb6644 | ||
|
|
04d2d92524 | ||
|
|
6630a8c2a5 | ||
|
|
67ee86eaeb | ||
|
|
2fcfbc2e1a | ||
|
|
2bb1162adf | ||
|
|
f5e0b67305 | ||
|
|
0b25fb5771 | ||
|
|
27ff29329f | ||
|
|
b52cfbb602 | ||
|
|
c5a1c64a35 | ||
|
|
cbedd9bec5 | ||
|
|
7a90844970 | ||
|
|
45dcb72178 | ||
|
|
d23b5bb58b | ||
|
|
bf7de99182 | ||
|
|
8ddfab4b47 | ||
|
|
57c2dc2d65 | ||
|
|
62236a38f3 | ||
|
|
25ab7bba02 | ||
|
|
fe14f3ee0e | ||
|
|
425120de94 | ||
|
|
2520c8d173 | ||
|
|
7b4ee1c44b | ||
|
|
58a1dcd141 | ||
|
|
3b4f44f276 | ||
|
|
ebcc06686c | ||
|
|
45b3a7dbcd | ||
|
|
16f04f2255 | ||
|
|
a23fcbd095 | ||
|
|
7491c0f7c4 | ||
|
|
83da75a5e5 | ||
|
|
2474c32f60 | ||
|
|
6910f1f0b7 | ||
|
|
c426aeac6a | ||
|
|
0e2716ba31 | ||
|
|
011239d45c | ||
|
|
5bb3d1a9e1 | ||
|
|
43766c7ab9 | ||
|
|
e12eeed65d | ||
|
|
711ecb4025 | ||
|
|
88957699c5 | ||
|
|
fcd6c51d55 | ||
|
|
adda02dd0d | ||
|
|
ab1cff2a7d | ||
|
|
0716a743d8 | ||
|
|
d0e17fde77 | ||
|
|
d6c0aa8a80 | ||
|
|
815bf9b390 | ||
|
|
0aa6e0a8b2 | ||
|
|
8b1aff33fe | ||
|
|
fdc9464576 | ||
|
|
dc6c1a0fe1 | ||
|
|
78a73ac15f | ||
|
|
48891ed7c7 | ||
|
|
d3fd5ba9ac | ||
|
|
2b6f575802 | ||
|
|
f604460d56 | ||
|
|
7472893e8e | ||
|
|
eff074faae | ||
|
|
07c04b40b1 | ||
|
|
754adb545e | ||
|
|
5fc04277c1 | ||
|
|
78f5fd3f71 | ||
|
|
0277c6b9bd | ||
|
|
e34b4b8ae7 | ||
|
|
c0de18f3aa | ||
|
|
4b78918347 | ||
|
|
6606a883c5 | ||
|
|
30c1a64d31 | ||
|
|
91dbcc40aa | ||
|
|
b0f5119ec0 | ||
|
|
ed9aba18b8 | ||
|
|
d507325378 | ||
|
|
0a0546168b | ||
|
|
5abbbe80d1 | ||
|
|
4a6413f654 | ||
|
|
6c60244b26 | ||
|
|
a384f0e6e9 | ||
|
|
2a56410543 | ||
|
|
7ef22fc1e0 | ||
|
|
5051d698c0 | ||
|
|
1a87c08bc2 | ||
|
|
ed0c5908ce | ||
|
|
f571ced9c5 | ||
|
|
3110181a9f | ||
|
|
fcb7966f70 | ||
|
|
be2945a16f | ||
|
|
6b3326ad42 | ||
|
|
3e81a03087 | ||
|
|
3778430ead | ||
|
|
31bd251f37 | ||
|
|
f49f01ec85 | ||
|
|
1bd6721af9 | ||
|
|
4a069266d8 | ||
|
|
d10d7f3f02 | ||
|
|
05adbb1325 | ||
|
|
ca8719b42b | ||
|
|
ec80850e76 | ||
|
|
ab75a8b3e5 | ||
|
|
d00c8119fa | ||
|
|
2b7d188677 | ||
|
|
12c09693bd | ||
|
|
87793b3dc3 | ||
|
|
7ce8c0b966 | ||
|
|
a831944b14 | ||
|
|
17533d2c61 | ||
|
|
bee1d6beed | ||
|
|
a49ae076a5 | ||
|
|
4856503a33 | ||
|
|
0d4560f54e | ||
|
|
c5f7c2ace7 | ||
|
|
f8c03fa48c | ||
|
|
8b6b34d7c0 | ||
|
|
1fd7001e0c | ||
|
|
2631550c2f | ||
|
|
01734fadcf | ||
|
|
33cead0b03 | ||
|
|
08f86cbcf9 | ||
|
|
a83b96c74d | ||
|
|
7cf0ddc81b | ||
|
|
41640b5215 | ||
|
|
e1abedbfa4 | ||
|
|
a1482b9781 | ||
|
|
8a6d6ae771 | ||
|
|
a67e8314af | ||
|
|
f5e7497913 | ||
|
|
e4c7c601d7 |
2
AUTHORS
2
AUTHORS
@@ -1,4 +1,4 @@
|
||||
nzbget:
|
||||
Sven Henkel <sidddy@users.sourceforge.net> (versions 0.1.0 - ?)
|
||||
Bo Cordes Petersen <placebodk@users.sourceforge.net> (versions ? - 0.2.3)
|
||||
Andrei Prygounkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)
|
||||
Andrey Prygunkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
@@ -110,17 +110,35 @@ void ArticleDownloader::SetInfoName(const char * v)
|
||||
m_szInfoName = strdup(v);
|
||||
}
|
||||
|
||||
void ArticleDownloader::SetStatus(EStatus eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
Notify(NULL);
|
||||
}
|
||||
/*
|
||||
* How server management (for one particular article) works:
|
||||
- there is a list of failed servers which is initially empty;
|
||||
- level is initially 0;
|
||||
|
||||
<loop>
|
||||
- request a connection from server pool for current level;
|
||||
Exception: this step is skipped for the very first download attempt, because a
|
||||
level-0 connection is initially passed from queue manager;
|
||||
- try to download from server;
|
||||
- if connection to server cannot be established or download fails due to interrupted connection,
|
||||
try again (as many times as needed without limit) the same server until connection is OK;
|
||||
- if download fails with error "Not-Found" (article or group not found) or with CRC error,
|
||||
add the server to failed server list;
|
||||
- if download fails with general failure error (article incomplete, other unknown error
|
||||
codes), try the same server again as many times as defined by option <Retries>; if all attempts
|
||||
fail, add the server to failed server list;
|
||||
- if all servers from current level were tried, increase level;
|
||||
- if all servers from all levels were tried, break the loop with failure status.
|
||||
<end-loop>
|
||||
*/
|
||||
void ArticleDownloader::Run()
|
||||
{
|
||||
debug("Entering ArticleDownloader-loop");
|
||||
|
||||
SetStatus(adRunning);
|
||||
|
||||
BuildOutputFilename();
|
||||
|
||||
m_szResultFilename = m_pArticleInfo->GetResultFilename();
|
||||
|
||||
if (g_pOptions->GetContinuePartial())
|
||||
@@ -129,59 +147,44 @@ void ArticleDownloader::Run()
|
||||
{
|
||||
// file exists from previous program's start
|
||||
detail("Article %s already downloaded, skipping", m_szInfoName);
|
||||
SetStatus(adFinished);
|
||||
FreeConnection(true);
|
||||
SetStatus(adFinished);
|
||||
Notify(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int iRemainedDownloadRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
|
||||
|
||||
#ifdef THREADCONNECT_WORKAROUND
|
||||
// NOTE: about iRemainedConnectRetries:
|
||||
// Sometimes connections just do not want to work in a particular thread,
|
||||
// regardless of retry count. However they work in other threads.
|
||||
// If ArticleDownloader can't start download after many attempts, it terminates
|
||||
// and let QueueCoordinator retry the article in a new thread.
|
||||
// It wasn't confirmed that this workaround actually helps.
|
||||
// Therefore it is disabled by default. Define symbol "THREADCONNECT_WORKAROUND"
|
||||
// to activate the workaround.
|
||||
int iRemainedConnectRetries = iRemainedDownloadRetries > 5 ? iRemainedDownloadRetries * 2 : 10;
|
||||
#endif
|
||||
|
||||
EStatus Status = adFailed;
|
||||
int iMaxLevel = g_pServerPool->GetMaxLevel();
|
||||
int* LevelStatus = (int*)malloc((iMaxLevel + 1) * sizeof(int));
|
||||
for (int i = 0; i <= iMaxLevel; i++)
|
||||
{
|
||||
LevelStatus[i] = 0;
|
||||
}
|
||||
int level = 0;
|
||||
|
||||
while (!IsStopped() && iRemainedDownloadRetries > 0)
|
||||
{
|
||||
SetLastUpdateTimeNow();
|
||||
int iRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
|
||||
int iRemainedRetries = iRetries;
|
||||
ServerPool::Servers failedServers;
|
||||
failedServers.reserve(g_pServerPool->GetServers()->size());
|
||||
NewsServer* pWantServer = NULL;
|
||||
NewsServer* pLastServer = NULL;
|
||||
int iLevel = 0;
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
|
||||
SetStatus(adWaiting);
|
||||
while (!IsStopped() && !m_pConnection)
|
||||
{
|
||||
m_pConnection = g_pServerPool->GetConnection(level);
|
||||
m_pConnection = g_pServerPool->GetConnection(iLevel, pWantServer, &failedServers);
|
||||
usleep(5 * 1000);
|
||||
}
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
pLastServer = m_pConnection->GetNewsServer();
|
||||
|
||||
m_pConnection->SetSuppressErrors(false);
|
||||
|
||||
// test connection
|
||||
@@ -189,7 +192,8 @@ void ArticleDownloader::Run()
|
||||
if (bConnected && !IsStopped())
|
||||
{
|
||||
// Okay, we got a Connection. Now start downloading.
|
||||
detail("Downloading %s @ %s", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
detail("Downloading %s @ server%i (%s)", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
Status = Download();
|
||||
}
|
||||
|
||||
@@ -200,9 +204,6 @@ void ArticleDownloader::Run()
|
||||
m_pConnection->Disconnect();
|
||||
bConnected = false;
|
||||
Status = adFailed;
|
||||
#ifdef THREADCONNECT_WORKAROUND
|
||||
iRemainedConnectRetries--;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -212,89 +213,103 @@ void ArticleDownloader::Run()
|
||||
// free the connection, to prevent starting of thousands of threads
|
||||
// (cause each of them will also free it's connection after the
|
||||
// same connect-error).
|
||||
FreeConnection(Status == adFinished);
|
||||
FreeConnection(Status == adFinished || Status == adNotFound);
|
||||
}
|
||||
}
|
||||
#ifdef THREADCONNECT_WORKAROUND
|
||||
else
|
||||
{
|
||||
iRemainedConnectRetries--;
|
||||
}
|
||||
|
||||
if (iRemainedConnectRetries == 0)
|
||||
if (Status == adFinished || Status == adFatalError)
|
||||
{
|
||||
debug("Can't connect from this thread, retry later from another");
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
if (((Status == adFailed) || (Status == adCrcError && g_pOptions->GetRetryOnCrcError())) &&
|
||||
(iRemainedDownloadRetries > 1 || !bConnected) && !IsStopped())
|
||||
pWantServer = NULL;
|
||||
|
||||
if (bConnected && Status == adFailed)
|
||||
{
|
||||
iRemainedRetries--;
|
||||
}
|
||||
|
||||
if (!bConnected || (Status == adFailed && iRemainedRetries > 0))
|
||||
{
|
||||
pWantServer = pLastServer;
|
||||
}
|
||||
|
||||
if (pWantServer && !IsStopped() &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
SetStatus(adWaiting);
|
||||
int msec = 0;
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000))
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
}
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Status == adFinished) || (Status == adFatalError) ||
|
||||
(Status == adCrcError && !g_pOptions->GetRetryOnCrcError()))
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
LevelStatus[level] = Status;
|
||||
if (!pWantServer)
|
||||
{
|
||||
failedServers.push_back(pLastServer);
|
||||
|
||||
bool bAllLevelNotFound = true;
|
||||
for (int lev = 0; lev <= iMaxLevel; lev++)
|
||||
{
|
||||
if (LevelStatus[lev] != adNotFound)
|
||||
{
|
||||
bAllLevelNotFound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bAllLevelNotFound)
|
||||
{
|
||||
if (iMaxLevel > 0)
|
||||
{
|
||||
warn("Article %s @ all servers failed: Article not found", m_szInfoName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// if all servers from current level were tried, increase level
|
||||
// if all servers from all levels were tried, break the loop with failure status
|
||||
|
||||
// do not count connect-errors, only article- and group-errors
|
||||
if (bConnected)
|
||||
{
|
||||
level++;
|
||||
if (level > iMaxLevel)
|
||||
bool bAllServersOnLevelFailed = true;
|
||||
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
level = 0;
|
||||
NewsServer* pCandidateServer = *it;
|
||||
if (pCandidateServer->GetLevel() == iLevel)
|
||||
{
|
||||
bool bServerFailed = false;
|
||||
for (ServerPool::Servers::iterator it = failedServers.begin(); it != failedServers.end(); it++)
|
||||
{
|
||||
NewsServer* pIgnoreServer = *it;
|
||||
if (pIgnoreServer == pCandidateServer ||
|
||||
(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
|
||||
pIgnoreServer->GetLevel() == pCandidateServer->GetLevel()))
|
||||
{
|
||||
bServerFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bServerFailed)
|
||||
{
|
||||
bAllServersOnLevelFailed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iRemainedDownloadRetries--;
|
||||
|
||||
if (bAllServersOnLevelFailed)
|
||||
{
|
||||
if (iLevel < g_pServerPool->GetMaxLevel())
|
||||
{
|
||||
detail("Article %s @ all level %i servers failed, increasing level", m_szInfoName, iLevel);
|
||||
iLevel++;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Article %s @ all servers failed", m_szInfoName);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iRemainedRetries = iRetries;
|
||||
}
|
||||
}
|
||||
|
||||
FreeConnection(Status == adFinished);
|
||||
|
||||
free(LevelStatus);
|
||||
|
||||
if (m_bDuplicate)
|
||||
{
|
||||
Status = adFinished;
|
||||
@@ -305,19 +320,19 @@ void ArticleDownloader::Run()
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
Status = adRetry;
|
||||
}
|
||||
|
||||
if (Status == adFailed)
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Download %s failed", m_szInfoName);
|
||||
}
|
||||
warn("Download %s failed", m_szInfoName);
|
||||
}
|
||||
|
||||
SetStatus(Status);
|
||||
Notify(NULL);
|
||||
|
||||
debug("Exiting ArticleDownloader-loop");
|
||||
}
|
||||
@@ -354,7 +369,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
for (int retry = 3; retry > 0; retry--)
|
||||
{
|
||||
szResponse = m_pConnection->Request(tmp);
|
||||
if (szResponse && !strncmp(szResponse, "2", 1))
|
||||
if ((szResponse && !strncmp(szResponse, "2", 1)) || m_pConnection->GetAuthError())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -405,7 +420,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed: Unexpected end of article", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
warn("Article %s @ server%i (%s) failed: Unexpected end of article", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
@@ -439,7 +455,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
if (strncmp(p, m_pArticleInfo->GetMessageID(), strlen(m_pArticleInfo->GetMessageID())))
|
||||
{
|
||||
if (char* e = strrchr(p, '\r')) *e = '\0'; // remove trailing CR-character
|
||||
warn("Article %s @ %s failed: Wrong message-id, expected %s, returned %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
warn("Article %s @ server%i (%s) failed: Wrong message-id, expected %s, returned %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
@@ -467,7 +484,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
|
||||
if (!bEnd && Status == adRunning && !IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed: article incomplete", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
warn("Article %s @ server%i (%s) failed: article incomplete", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
@@ -494,18 +512,21 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: Connection closed by remote host", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment);
|
||||
warn("Article %s @ server%i (%s) failed, %s: Connection closed by remote host", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment);
|
||||
}
|
||||
return adConnectError;
|
||||
}
|
||||
else if (m_pConnection->GetAuthError() || !strncmp(szResponse, "400", 3) || !strncmp(szResponse, "499", 3))
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adConnectError;
|
||||
}
|
||||
else if (!strncmp(szResponse, "41", 2) || !strncmp(szResponse, "42", 2) || !strncmp(szResponse, "43", 2))
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szResponse, "2", 1))
|
||||
@@ -516,7 +537,8 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
else
|
||||
{
|
||||
// unknown error, no special handling
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
@@ -569,7 +591,8 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
if (g_pOptions->GetDupeCheck())
|
||||
{
|
||||
m_pFileInfo->LockOutputFile();
|
||||
if (!m_pFileInfo->GetOutputInitialized())
|
||||
bool bOutputInitialized = m_pFileInfo->GetOutputInitialized();
|
||||
if (!bOutputInitialized)
|
||||
{
|
||||
char* pb = strstr(szLine, " name=");
|
||||
if (pb)
|
||||
@@ -583,11 +606,6 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
strncpy(m_szArticleFilename, pb, pe - pb);
|
||||
m_szArticleFilename[pe - pb] = '\0';
|
||||
}
|
||||
if (m_pFileInfo->IsDupe(m_szArticleFilename))
|
||||
{
|
||||
m_bDuplicate = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!g_pOptions->GetDirectWrite())
|
||||
@@ -595,6 +613,11 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
m_pFileInfo->SetOutputInitialized(true);
|
||||
}
|
||||
m_pFileInfo->UnlockOutputFile();
|
||||
if (!bOutputInitialized && m_szArticleFilename && m_pFileInfo->IsDupe(m_szArticleFilename))
|
||||
{
|
||||
m_bDuplicate = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
@@ -607,9 +630,9 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
{
|
||||
pb += 6; //=strlen(" size=")
|
||||
long iArticleFilesize = atol(pb);
|
||||
if (!Util::SetFileSize(m_szOutputFilename, iArticleFilesize))
|
||||
if (!CreateOutputFile(iArticleFilesize))
|
||||
{
|
||||
error("Could not create file %s!", m_szOutputFilename);
|
||||
m_pFileInfo->UnlockOutputFile();
|
||||
return false;
|
||||
}
|
||||
m_pFileInfo->SetOutputInitialized(true);
|
||||
@@ -652,6 +675,77 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* creates output file and subdirectores */
|
||||
bool ArticleDownloader::CreateOutputFile(int iSize)
|
||||
{
|
||||
if (g_pOptions->GetDirectWrite() && Util::FileExists(m_szOutputFilename) &&
|
||||
Util::FileSize(m_szOutputFilename) == iSize)
|
||||
{
|
||||
// keep existing old file from previous program session
|
||||
return true;
|
||||
}
|
||||
|
||||
// delete eventually existing old file from previous program session
|
||||
remove(m_szOutputFilename);
|
||||
|
||||
// ensure the directory exist
|
||||
char szDestDir[1024];
|
||||
int iMaxlen = Util::BaseFileName(m_szOutputFilename) - m_szOutputFilename;
|
||||
if (iMaxlen > 1024-1) iMaxlen = 1024-1;
|
||||
strncpy(szDestDir, m_szOutputFilename, iMaxlen);
|
||||
szDestDir[iMaxlen] = '\0';
|
||||
char szErrBuf[1024];
|
||||
|
||||
if (!Util::ForceDirectories(szDestDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", szDestDir, szErrBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Util::CreateSparseFile(m_szOutputFilename, iSize))
|
||||
{
|
||||
error("Could not create file %s", m_szOutputFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArticleDownloader::BuildOutputFilename()
|
||||
{
|
||||
char szFilename[1024];
|
||||
|
||||
snprintf(szFilename, 1024, "%s%i.%03i", g_pOptions->GetTempDir(), m_pFileInfo->GetID(), m_pArticleInfo->GetPartNumber());
|
||||
szFilename[1024-1] = '\0';
|
||||
m_pArticleInfo->SetResultFilename(szFilename);
|
||||
|
||||
char tmpname[1024];
|
||||
snprintf(tmpname, 1024, "%s.tmp", szFilename);
|
||||
tmpname[1024-1] = '\0';
|
||||
SetTempFilename(tmpname);
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
{
|
||||
m_pFileInfo->LockOutputFile();
|
||||
|
||||
if (m_pFileInfo->GetOutputFilename())
|
||||
{
|
||||
strncpy(szFilename, m_pFileInfo->GetOutputFilename(), 1024);
|
||||
szFilename[1024-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szFilename, 1024, "%s%c%i.out.tmp", m_pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetID());
|
||||
szFilename[1024-1] = '\0';
|
||||
m_pFileInfo->SetOutputFilename(szFilename);
|
||||
}
|
||||
|
||||
m_pFileInfo->UnlockOutputFile();
|
||||
|
||||
SetOutputFilename(szFilename);
|
||||
}
|
||||
}
|
||||
|
||||
ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
{
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
|
||||
@@ -673,7 +767,7 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
else
|
||||
{
|
||||
warn("Decoding %s failed: no binary data or unsupported encoding format", m_szInfoName);
|
||||
return adFatalError;
|
||||
return adFailed;
|
||||
}
|
||||
|
||||
Decoder::EStatus eStatus = pDecoder->Check();
|
||||
@@ -823,11 +917,18 @@ void ArticleDownloader::CompleteFileParts()
|
||||
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_pFileInfo->GetOutputInitialized();
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
m_pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
char szNZBName[1024];
|
||||
char szNZBDestDir[1024];
|
||||
// the locking is needed for accessing the memebers of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
strncpy(szNZBName, m_pFileInfo->GetNZBInfo()->GetName(), 1024);
|
||||
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
szNZBName[1024-1] = '\0';
|
||||
szNZBDestDir[1024-1] = '\0';
|
||||
|
||||
char InfoFilename[1024];
|
||||
snprintf(InfoFilename, 1024, "%s%c%s", szNZBNiceName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
snprintf(InfoFilename, 1024, "%s%c%s", szNZBName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
InfoFilename[1024-1] = '\0';
|
||||
|
||||
if (!g_pOptions->GetDecode())
|
||||
@@ -843,17 +944,11 @@ void ArticleDownloader::CompleteFileParts()
|
||||
detail("Joining articles for %s", InfoFilename);
|
||||
}
|
||||
|
||||
char szNZBDestDir[1024];
|
||||
// the locking is needed for accessing the memebers of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
szNZBDestDir[1024-1] = '\0';
|
||||
|
||||
// Ensure the DstDir is created
|
||||
if (!Util::ForceDirectories(szNZBDestDir))
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(szNZBDestDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s! Errcode: %i", szNZBDestDir, errno);
|
||||
error("Could not create directory %s: %s", szNZBDestDir, szErrBuf);
|
||||
SetStatus(adJoined);
|
||||
return;
|
||||
}
|
||||
@@ -983,6 +1078,24 @@ void ArticleDownloader::CompleteFileParts()
|
||||
{
|
||||
error("Could not move file %s to %s! Errcode: %i", m_szOutputFilename, ofn, errno);
|
||||
}
|
||||
|
||||
// if destination directory was changed delete the old directory (if empty)
|
||||
int iLen = strlen(szNZBDestDir);
|
||||
if (!(!strncmp(szNZBDestDir, m_szOutputFilename, iLen) &&
|
||||
(m_szOutputFilename[iLen] == PATH_SEPARATOR || m_szOutputFilename[iLen] == ALT_PATH_SEPARATOR)))
|
||||
{
|
||||
debug("Checking old dir for: %s", m_szOutputFilename);
|
||||
char szOldDestDir[1024];
|
||||
int iMaxlen = Util::BaseFileName(m_szOutputFilename) - m_szOutputFilename;
|
||||
if (iMaxlen > 1024-1) iMaxlen = 1024-1;
|
||||
strncpy(szOldDestDir, m_szOutputFilename, iMaxlen);
|
||||
szOldDestDir[iMaxlen] = '\0';
|
||||
if (Util::DirEmpty(szOldDestDir))
|
||||
{
|
||||
debug("Deleting old dir: %s", szOldDestDir);
|
||||
rmdir(szOldDestDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDirectWrite || g_pOptions->GetContinuePartial())
|
||||
@@ -1002,27 +1115,6 @@ void ArticleDownloader::CompleteFileParts()
|
||||
{
|
||||
warn("%i of %i article downloads failed for \"%s\"", iBrokenCount, m_pFileInfo->GetArticles()->size(), InfoFilename);
|
||||
|
||||
if (g_pOptions->GetRenameBroken())
|
||||
{
|
||||
char brokenfn[1024];
|
||||
snprintf(brokenfn, 1024, "%s_broken", ofn);
|
||||
brokenfn[1024-1] = '\0';
|
||||
if (Util::MoveFile(ofn, brokenfn))
|
||||
{
|
||||
detail("Renaming broken file from %s to %s", ofn, brokenfn);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Renaming broken file from %s to %s failed", ofn, brokenfn);
|
||||
}
|
||||
strncpy(ofn, brokenfn, 1024);
|
||||
ofn[1024-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("Not renaming broken file %s", ofn);
|
||||
}
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
@@ -1055,9 +1147,10 @@ bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldD
|
||||
}
|
||||
|
||||
// Ensure the DstDir is created
|
||||
if (!Util::ForceDirectories(pNZBInfo->GetDestDir()))
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(pNZBInfo->GetDestDir(), szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s! Errcode: %i", pNZBInfo->GetDestDir(), errno);
|
||||
error("Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -42,10 +42,10 @@ public:
|
||||
{
|
||||
adUndefined,
|
||||
adRunning,
|
||||
adWaiting,
|
||||
adFinished,
|
||||
adFailed,
|
||||
adRetry,
|
||||
adDecodeError,
|
||||
adCrcError,
|
||||
adDecoding,
|
||||
adJoining,
|
||||
@@ -76,9 +76,15 @@ private:
|
||||
EStatus Download();
|
||||
bool Write(char* szLine, int iLen);
|
||||
bool PrepareFile(char* szLine);
|
||||
bool CreateOutputFile(int iSize);
|
||||
void BuildOutputFilename();
|
||||
EStatus DecodeCheck();
|
||||
void FreeConnection(bool bKeepConnected);
|
||||
EStatus CheckResponse(const char* szResponse, const char* szComment);
|
||||
void SetStatus(EStatus eStatus) { m_eStatus = eStatus; }
|
||||
const char* GetTempFilename() { return m_szTempFilename; }
|
||||
void SetTempFilename(const char* v);
|
||||
void SetOutputFilename(const char* v);
|
||||
|
||||
public:
|
||||
ArticleDownloader();
|
||||
@@ -87,16 +93,12 @@ public:
|
||||
FileInfo* GetFileInfo() { return m_pFileInfo; }
|
||||
void SetArticleInfo(ArticleInfo* pArticleInfo) { m_pArticleInfo = pArticleInfo; }
|
||||
ArticleInfo* GetArticleInfo() { return m_pArticleInfo; }
|
||||
void SetStatus(EStatus eStatus);
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
bool Terminate();
|
||||
time_t GetLastUpdateTime() { return m_tLastUpdateTime; }
|
||||
void SetLastUpdateTimeNow() { m_tLastUpdateTime = ::time(NULL); }
|
||||
const char* GetTempFilename() { return m_szTempFilename; }
|
||||
void SetTempFilename(const char* v);
|
||||
void SetOutputFilename(const char* v);
|
||||
const char* GetArticleFilename() { return m_szArticleFilename; }
|
||||
void SetInfoName(const char* v);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
@@ -111,7 +113,7 @@ class DownloadSpeedMeter
|
||||
{
|
||||
public:
|
||||
virtual ~DownloadSpeedMeter() {};
|
||||
virtual float CalcCurrentDownloadSpeed() = 0;
|
||||
virtual int CalcCurrentDownloadSpeed() = 0;
|
||||
virtual void AddSpeedReading(int iBytes) = 0;
|
||||
};
|
||||
|
||||
|
||||
527
BinRpc.cpp
527
BinRpc.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -34,8 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -48,19 +47,25 @@
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "UrlCoordinator.h"
|
||||
#include "QueueEditor.h"
|
||||
#include "PrePostProcessor.h"
|
||||
#include "Util.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Scanner.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern UrlCoordinator* g_pUrlCoordinator;
|
||||
extern PrePostProcessor* g_pPrePostProcessor;
|
||||
extern Scanner* g_pScanner;
|
||||
extern void ExitProc();
|
||||
extern void Reload();
|
||||
|
||||
const char* g_szMessageRequestNames[] =
|
||||
{ "N/A", "Download", "Pause/Unpause", "List", "Set download rate", "Dump debug",
|
||||
"Edit queue", "Log", "Quit", "Version", "Post-queue", "Write log", "Scan",
|
||||
"Pause/Unpause postprocessor", "History" };
|
||||
"Edit queue", "Log", "Quit", "Reload", "Version", "Post-queue", "Write log", "Scan",
|
||||
"Pause/Unpause postprocessor", "History", "Download URL", "URL-queue" };
|
||||
|
||||
const unsigned int g_iMessageRequestSizes[] =
|
||||
{ 0,
|
||||
@@ -72,39 +77,41 @@ const unsigned int g_iMessageRequestSizes[] =
|
||||
sizeof(SNZBEditQueueRequest),
|
||||
sizeof(SNZBLogRequest),
|
||||
sizeof(SNZBShutdownRequest),
|
||||
sizeof(SNZBReloadRequest),
|
||||
sizeof(SNZBVersionRequest),
|
||||
sizeof(SNZBPostQueueRequest),
|
||||
sizeof(SNZBWriteLogRequest),
|
||||
sizeof(SNZBScanRequest),
|
||||
sizeof(SNZBHistoryRequest)
|
||||
sizeof(SNZBHistoryRequest),
|
||||
sizeof(SNZBDownloadUrlRequest),
|
||||
sizeof(SNZBUrlQueueRequest)
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// BinProcessor
|
||||
|
||||
BinRpcProcessor::BinRpcProcessor()
|
||||
{
|
||||
m_MessageBase.m_iSignature = (int)NZBMESSAGE_SIGNATURE;
|
||||
}
|
||||
|
||||
void BinRpcProcessor::Execute()
|
||||
{
|
||||
// Read the first package which needs to be a request
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)&m_MessageBase) + sizeof(m_MessageBase.m_iSignature), sizeof(m_MessageBase) - sizeof(m_MessageBase.m_iSignature), 0);
|
||||
if (iBytesReceived < 0)
|
||||
if (!m_pConnection->Recv(((char*)&m_MessageBase) + sizeof(m_MessageBase.m_iSignature), sizeof(m_MessageBase) - sizeof(m_MessageBase.m_iSignature)))
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure this is a nzbget request from a client
|
||||
if ((int)ntohl(m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE)
|
||||
if ((strlen(g_pOptions->GetControlUsername()) > 0 && strcmp(m_MessageBase.m_szUsername, g_pOptions->GetControlUsername())) ||
|
||||
strcmp(m_MessageBase.m_szPassword, g_pOptions->GetControlPassword()))
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetServerPort(), m_szClientIP);
|
||||
warn("nzbget request received on port %i from %s, but username or password invalid", g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetServerPassword()))
|
||||
{
|
||||
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetServerPort(), m_szClientIP);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_szClientIP);
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_pConnection->GetRemoteAddr());
|
||||
|
||||
Dispatch();
|
||||
}
|
||||
@@ -156,6 +163,10 @@ void BinRpcProcessor::Dispatch()
|
||||
command = new ShutdownBinCommand();
|
||||
break;
|
||||
|
||||
case eRemoteRequestReload:
|
||||
command = new ReloadBinCommand();
|
||||
break;
|
||||
|
||||
case eRemoteRequestVersion:
|
||||
command = new VersionBinCommand();
|
||||
break;
|
||||
@@ -176,6 +187,14 @@ void BinRpcProcessor::Dispatch()
|
||||
command = new HistoryBinCommand();
|
||||
break;
|
||||
|
||||
case eRemoteRequestDownloadUrl:
|
||||
command = new DownloadUrlBinCommand();
|
||||
break;
|
||||
|
||||
case eRemoteRequestUrlQueue:
|
||||
command = new UrlQueueBinCommand();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
|
||||
break;
|
||||
@@ -183,7 +202,7 @@ void BinRpcProcessor::Dispatch()
|
||||
|
||||
if (command)
|
||||
{
|
||||
command->SetSocket(m_iSocket);
|
||||
command->SetConnection(m_pConnection);
|
||||
command->SetMessageBase(&m_MessageBase);
|
||||
command->Execute();
|
||||
delete command;
|
||||
@@ -205,8 +224,8 @@ void BinCommand::SendBoolResponse(bool bSuccess, const char* szText)
|
||||
BoolResponse.m_iTrailingDataLength = htonl(iTextLen);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &BoolResponse, sizeof(BoolResponse), 0);
|
||||
send(m_iSocket, (char*)szText, iTextLen, 0);
|
||||
m_pConnection->Send((char*) &BoolResponse, sizeof(BoolResponse));
|
||||
m_pConnection->Send((char*)szText, iTextLen);
|
||||
}
|
||||
|
||||
bool BinCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
@@ -215,8 +234,7 @@ bool BinCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
iSize -= sizeof(SNZBRequestBase);
|
||||
if (iSize > 0)
|
||||
{
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)pBuffer) + sizeof(SNZBRequestBase), iSize, 0);
|
||||
if (iBytesReceived != iSize)
|
||||
if (!m_pConnection->Recv(((char*)pBuffer) + sizeof(SNZBRequestBase), iSize))
|
||||
{
|
||||
error("invalid request");
|
||||
return false;
|
||||
@@ -233,6 +251,8 @@ void PauseUnpauseBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetResumeTime(0);
|
||||
|
||||
switch (ntohl(PauseUnpauseRequest.m_iAction))
|
||||
{
|
||||
case eRemotePauseUnpauseActionDownload:
|
||||
@@ -263,7 +283,7 @@ void SetDownloadRateBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate) / 1024.0f);
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate));
|
||||
SendBoolResponse(true, "Rate-Command completed successfully");
|
||||
}
|
||||
|
||||
@@ -276,6 +296,7 @@ void DumpDebugBinCommand::Execute()
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->LogDebugInfo();
|
||||
g_pUrlCoordinator->LogDebugInfo();
|
||||
SendBoolResponse(true, "Debug-Command completed successfully");
|
||||
}
|
||||
|
||||
@@ -291,6 +312,18 @@ void ShutdownBinCommand::Execute()
|
||||
ExitProc();
|
||||
}
|
||||
|
||||
void ReloadBinCommand::Execute()
|
||||
{
|
||||
SNZBReloadRequest ReloadRequest;
|
||||
if (!ReceiveRequest(&ReloadRequest, sizeof(ReloadRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendBoolResponse(true, "Reloading server");
|
||||
Reload();
|
||||
}
|
||||
|
||||
void VersionBinCommand::Execute()
|
||||
{
|
||||
SNZBVersionRequest VersionRequest;
|
||||
@@ -310,48 +343,29 @@ void DownloadBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(DownloadRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
int iBufLen = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
char* pRecvBuffer = (char*)malloc(iBufLen);
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
while (NeedBytes > 0)
|
||||
if (!m_pConnection->Recv(pRecvBuffer, iBufLen))
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
error("invalid request");
|
||||
free(pRecvBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
int iPriority = ntohl(DownloadRequest.m_iPriority);
|
||||
bool bAddPaused = ntohl(DownloadRequest.m_bAddPaused);
|
||||
bool bAddTop = ntohl(DownloadRequest.m_bAddFirst);
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
||||
bool bOK = g_pScanner->AddExternalFile(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory,
|
||||
iPriority, NULL, bAddTop, bAddPaused, NULL, pRecvBuffer, iBufLen, true);
|
||||
|
||||
if (pNZBFile)
|
||||
{
|
||||
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, ntohl(DownloadRequest.m_bAddFirst));
|
||||
delete pNZBFile;
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, bOK ? "Collection %s added to queue" : "Download Request failed for %s",
|
||||
Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Collection %s added to queue", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Download Request failed for %s", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(false, tmp);
|
||||
}
|
||||
}
|
||||
SendBoolResponse(bOK, tmp);
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
@@ -369,12 +383,24 @@ void ListBinCommand::Execute()
|
||||
ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse));
|
||||
ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseFileEntry));
|
||||
ListResponse.m_bRegExValid = 0;
|
||||
|
||||
char* buf = NULL;
|
||||
int bufsize = 0;
|
||||
|
||||
if (ntohl(ListRequest.m_bFileList))
|
||||
{
|
||||
eRemoteMatchMode eMatchMode = (eRemoteMatchMode)ntohl(ListRequest.m_iMatchMode);
|
||||
bool bMatchGroup = ntohl(ListRequest.m_bMatchGroup);
|
||||
const char* szPattern = ListRequest.m_szPattern;
|
||||
|
||||
RegEx *pRegEx = NULL;
|
||||
if (eMatchMode == eRemoteMatchModeRegEx)
|
||||
{
|
||||
pRegEx = new RegEx(szPattern);
|
||||
ListResponse.m_bRegExValid = pRegEx->IsValid();
|
||||
}
|
||||
|
||||
// Make a data structure and copy all the elements of the list into it
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
@@ -386,6 +412,7 @@ void ListBinCommand::Execute()
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
bufsize += strlen(pNZBInfo->GetFilename()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetName()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetDestDir()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetCategory()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetQueuedFilename()) + 1;
|
||||
@@ -429,13 +456,17 @@ void ListBinCommand::Execute()
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_bMatch = htonl(bMatchGroup && (!pRegEx || pRegEx->Match(pNZBInfo->GetName())));
|
||||
pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1);
|
||||
pListAnswer->m_iNameLen = htonl(strlen(pNZBInfo->GetName()) + 1);
|
||||
pListAnswer->m_iDestDirLen = htonl(strlen(pNZBInfo->GetDestDir()) + 1);
|
||||
pListAnswer->m_iCategoryLen = htonl(strlen(pNZBInfo->GetCategory()) + 1);
|
||||
pListAnswer->m_iQueuedFilenameLen = htonl(strlen(pNZBInfo->GetQueuedFilename()) + 1);
|
||||
bufptr += sizeof(SNZBListResponseNZBEntry);
|
||||
strcpy(bufptr, pNZBInfo->GetFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iFilenameLen);
|
||||
strcpy(bufptr, pNZBInfo->GetName());
|
||||
bufptr += ntohl(pListAnswer->m_iNameLen);
|
||||
strcpy(bufptr, pNZBInfo->GetDestDir());
|
||||
bufptr += ntohl(pListAnswer->m_iDestDirLen);
|
||||
strcpy(bufptr, pNZBInfo->GetCategory());
|
||||
@@ -484,7 +515,7 @@ void ListBinCommand::Execute()
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
FileInfo* pFileInfo = *it;
|
||||
SNZBListResponseFileEntry* pListAnswer = (SNZBListResponseFileEntry*) bufptr;
|
||||
pListAnswer->m_iID = htonl(pFileInfo->GetID());
|
||||
pListAnswer->m_iID = htonl(pFileInfo->GetID());
|
||||
|
||||
int iNZBIndex = 0;
|
||||
for (unsigned int i = 0; i < pDownloadQueue->GetNZBInfoList()->size(); i++)
|
||||
@@ -497,6 +528,13 @@ void ListBinCommand::Execute()
|
||||
}
|
||||
pListAnswer->m_iNZBIndex = htonl(iNZBIndex);
|
||||
|
||||
if (pRegEx && !bMatchGroup)
|
||||
{
|
||||
char szFilename[MAX_PATH];
|
||||
snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename()));
|
||||
pListAnswer->m_bMatch = htonl(pRegEx->Match(szFilename));
|
||||
}
|
||||
|
||||
Util::SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
|
||||
@@ -505,6 +543,8 @@ void ListBinCommand::Execute()
|
||||
pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed());
|
||||
pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused());
|
||||
pListAnswer->m_iActiveDownloads = htonl(pFileInfo->GetActiveDownloads());
|
||||
pListAnswer->m_iPriority = htonl(pFileInfo->GetPriority());
|
||||
pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
|
||||
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
|
||||
bufptr += sizeof(SNZBListResponseFileEntry);
|
||||
@@ -523,6 +563,11 @@ void ListBinCommand::Execute()
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (pRegEx)
|
||||
{
|
||||
delete pRegEx;
|
||||
}
|
||||
|
||||
ListResponse.m_iNrTrailingNZBEntries = htonl(iNrNZBEntries);
|
||||
ListResponse.m_iNrTrailingPPPEntries = htonl(iNrPPPEntries);
|
||||
ListResponse.m_iNrTrailingFileEntries = htonl(iNrFileEntries);
|
||||
@@ -532,11 +577,11 @@ void ListBinCommand::Execute()
|
||||
if (htonl(ListRequest.m_bServerState))
|
||||
{
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024));
|
||||
ListResponse.m_iDownloadRate = htonl(g_pQueueCoordinator->CalcCurrentDownloadSpeed());
|
||||
Util::SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024));
|
||||
ListResponse.m_iDownloadLimit = htonl(g_pOptions->GetDownloadRate());
|
||||
ListResponse.m_bDownloadPaused = htonl(g_pOptions->GetPauseDownload());
|
||||
ListResponse.m_bDownload2Paused = htonl(g_pOptions->GetPauseDownload2());
|
||||
ListResponse.m_bPostPaused = htonl(g_pOptions->GetPausePostProcess());
|
||||
@@ -559,12 +604,12 @@ void ListBinCommand::Execute()
|
||||
}
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0);
|
||||
m_pConnection->Send((char*) &ListResponse, sizeof(ListResponse));
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
@@ -650,12 +695,12 @@ void LogBinCommand::Execute()
|
||||
LogResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &LogResponse, sizeof(LogResponse), 0);
|
||||
m_pConnection->Send((char*) &LogResponse, sizeof(LogResponse));
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -669,67 +714,75 @@ void EditQueueBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
int iNrEntries = ntohl(EditQueueRequest.m_iNrTrailingEntries);
|
||||
int iNrIDEntries = ntohl(EditQueueRequest.m_iNrTrailingIDEntries);
|
||||
int iNrNameEntries = ntohl(EditQueueRequest.m_iNrTrailingNameEntries);
|
||||
int iNameEntriesLen = ntohl(EditQueueRequest.m_iTrailingNameEntriesLen);
|
||||
int iAction = ntohl(EditQueueRequest.m_iAction);
|
||||
int iMatchMode = ntohl(EditQueueRequest.m_iMatchMode);
|
||||
int iOffset = ntohl(EditQueueRequest.m_iOffset);
|
||||
int iTextLen = ntohl(EditQueueRequest.m_iTextLen);
|
||||
bool bSmartOrder = ntohl(EditQueueRequest.m_bSmartOrder);
|
||||
unsigned int iBufLength = ntohl(EditQueueRequest.m_iTrailingDataLength);
|
||||
|
||||
if (iNrEntries * sizeof(int32_t) + iTextLen != iBufLength)
|
||||
if (iNrIDEntries * sizeof(int32_t) + iTextLen + iNameEntriesLen != iBufLength)
|
||||
{
|
||||
error("Invalid struct size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (iNrEntries <= 0)
|
||||
char* pBuf = (char*)malloc(iBufLength);
|
||||
|
||||
if (!m_pConnection->Recv(pBuf, iBufLength))
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed: no IDs specified");
|
||||
error("invalid request");
|
||||
free(pBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
char* pBuf = (char*)malloc(iBufLength);
|
||||
char* szText = NULL;
|
||||
int32_t* pIDs = NULL;
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
char* pBufPtr = pBuf;
|
||||
int NeedBytes = iBufLength;
|
||||
int iResult = 0;
|
||||
while (NeedBytes > 0)
|
||||
if (iNrIDEntries <= 0 && iNrNameEntries <= 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
SendBoolResponse(false, "Edit-Command failed: no IDs/Names specified");
|
||||
return;
|
||||
}
|
||||
bool bOK = NeedBytes == 0;
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
szText = iTextLen > 0 ? pBuf : NULL;
|
||||
pIDs = (int32_t*)(pBuf + iTextLen);
|
||||
}
|
||||
char* szText = iTextLen > 0 ? pBuf : NULL;
|
||||
int32_t* pIDs = (int32_t*)(pBuf + iTextLen);
|
||||
char* pNames = (pBuf + iTextLen + iNrIDEntries * sizeof(int32_t));
|
||||
|
||||
IDList cIDList;
|
||||
cIDList.reserve(iNrEntries);
|
||||
for (int i = 0; i < iNrEntries; i++)
|
||||
NameList cNameList;
|
||||
|
||||
if (iNrIDEntries > 0)
|
||||
{
|
||||
cIDList.push_back(ntohl(pIDs[i]));
|
||||
cIDList.reserve(iNrIDEntries);
|
||||
for (int i = 0; i < iNrIDEntries; i++)
|
||||
{
|
||||
cIDList.push_back(ntohl(pIDs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (iNrNameEntries > 0)
|
||||
{
|
||||
cNameList.reserve(iNrNameEntries);
|
||||
for (int i = 0; i < iNrNameEntries; i++)
|
||||
{
|
||||
cNameList.push_back(pNames);
|
||||
pNames += strlen(pNames) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool bOK = false;
|
||||
|
||||
if (iAction < eRemoteEditActionPostMoveOffset)
|
||||
{
|
||||
bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(&cIDList, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset, szText);
|
||||
bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(
|
||||
iNrIDEntries > 0 ? &cIDList : NULL,
|
||||
iNrNameEntries > 0 ? &cNameList : NULL,
|
||||
(QueueEditor::EMatchMode)iMatchMode, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset, szText);
|
||||
}
|
||||
else
|
||||
{
|
||||
bOK = g_pPrePostProcessor->QueueEditList(&cIDList, (PrePostProcessor::EEditAction)iAction, iOffset);
|
||||
bOK = g_pPrePostProcessor->QueueEditList(&cIDList, (PrePostProcessor::EEditAction)iAction, iOffset, szText);
|
||||
}
|
||||
|
||||
free(pBuf);
|
||||
@@ -740,6 +793,13 @@ void EditQueueBinCommand::Execute()
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef HAVE_REGEX_H
|
||||
if ((QueueEditor::EMatchMode)iMatchMode == QueueEditor::mmRegEx)
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed: the program was compiled without RegEx-support");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SendBoolResponse(false, "Edit-Command failed");
|
||||
}
|
||||
}
|
||||
@@ -772,7 +832,6 @@ void PostQueueBinCommand::Execute()
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
bufsize += strlen(pPostInfo->GetNZBInfo()->GetFilename()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetParFilename()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetInfoName()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetNZBInfo()->GetDestDir()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetProgressLabel()) + 1;
|
||||
@@ -795,15 +854,12 @@ void PostQueueBinCommand::Execute()
|
||||
pPostQueueAnswer->m_iTotalTimeSec = htonl((int)(pPostInfo->GetStartTime() ? tCurTime - pPostInfo->GetStartTime() : 0));
|
||||
pPostQueueAnswer->m_iStageTimeSec = htonl((int)(pPostInfo->GetStageTime() ? tCurTime - pPostInfo->GetStageTime() : 0));
|
||||
pPostQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pPostInfo->GetNZBInfo()->GetFilename()) + 1);
|
||||
pPostQueueAnswer->m_iParFilename = htonl(strlen(pPostInfo->GetParFilename()) + 1);
|
||||
pPostQueueAnswer->m_iInfoNameLen = htonl(strlen(pPostInfo->GetInfoName()) + 1);
|
||||
pPostQueueAnswer->m_iDestDirLen = htonl(strlen(pPostInfo->GetNZBInfo()->GetDestDir()) + 1);
|
||||
pPostQueueAnswer->m_iProgressLabelLen = htonl(strlen(pPostInfo->GetProgressLabel()) + 1);
|
||||
bufptr += sizeof(SNZBPostQueueResponseEntry);
|
||||
strcpy(bufptr, pPostInfo->GetNZBInfo()->GetFilename());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iNZBFilenameLen);
|
||||
strcpy(bufptr, pPostInfo->GetParFilename());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iParFilename);
|
||||
strcpy(bufptr, pPostInfo->GetInfoName());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iInfoNameLen);
|
||||
strcpy(bufptr, pPostInfo->GetNZBInfo()->GetDestDir());
|
||||
@@ -825,12 +881,12 @@ void PostQueueBinCommand::Execute()
|
||||
PostQueueResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &PostQueueResponse, sizeof(PostQueueResponse), 0);
|
||||
m_pConnection->Send((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -845,50 +901,36 @@ void WriteLogBinCommand::Execute()
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(WriteLogRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(WriteLogRequest.m_iTrailingDataLength);
|
||||
pRecvBuffer[NeedBytes] = '\0';
|
||||
while (NeedBytes > 0)
|
||||
|
||||
if (!m_pConnection->Recv(pRecvBuffer, ntohl(WriteLogRequest.m_iTrailingDataLength)))
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
error("invalid request");
|
||||
free(pRecvBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
bool OK = true;
|
||||
switch ((Message::EKind)ntohl(WriteLogRequest.m_iKind))
|
||||
{
|
||||
case Message::mkDetail:
|
||||
detail(pRecvBuffer);
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
bool OK = true;
|
||||
switch ((Message::EKind)ntohl(WriteLogRequest.m_iKind))
|
||||
{
|
||||
case Message::mkDetail:
|
||||
detail(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkInfo:
|
||||
info(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkWarning:
|
||||
warn(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkError:
|
||||
error(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkDebug:
|
||||
debug(pRecvBuffer);
|
||||
break;
|
||||
default:
|
||||
OK = false;
|
||||
}
|
||||
SendBoolResponse(OK, OK ? "Message added to log" : "Invalid message-kind");
|
||||
case Message::mkInfo:
|
||||
info(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkWarning:
|
||||
warn(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkError:
|
||||
error(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkDebug:
|
||||
debug(pRecvBuffer);
|
||||
break;
|
||||
default:
|
||||
OK = false;
|
||||
}
|
||||
SendBoolResponse(OK, OK ? "Message added to log" : "Invalid message-kind");
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
@@ -901,8 +943,10 @@ void ScanBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pPrePostProcessor->ScanNZBDir();
|
||||
SendBoolResponse(true, "Scan-Command scheduled successfully");
|
||||
bool bSyncMode = ntohl(ScanRequest.m_bSyncMode);
|
||||
|
||||
g_pScanner->ScanNZBDir(bSyncMode);
|
||||
SendBoolResponse(true, bSyncMode ? "Scan-Command completed" : "Scan-Command scheduled successfully");
|
||||
}
|
||||
|
||||
void HistoryBinCommand::Execute()
|
||||
@@ -926,15 +970,14 @@ void HistoryBinCommand::Execute()
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
// calculate required buffer size for nzbs
|
||||
int iNrNZBEntries = pDownloadQueue->GetHistoryList()->size();
|
||||
bufsize += iNrNZBEntries * sizeof(SNZBHistoryResponseEntry);
|
||||
int iNrEntries = pDownloadQueue->GetHistoryList()->size();
|
||||
bufsize += iNrEntries * sizeof(SNZBHistoryResponseEntry);
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
bufsize += strlen(pNZBInfo->GetFilename()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetDestDir()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetCategory()) + 1;
|
||||
bufsize += strlen(pNZBInfo->GetQueuedFilename()) + 1;
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
bufsize += strlen(szNicename) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
@@ -943,36 +986,42 @@ void HistoryBinCommand::Execute()
|
||||
char* bufptr = buf;
|
||||
|
||||
// write nzb entries
|
||||
for (NZBInfoList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) bufptr;
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iID = htonl(pNZBInfo->GetID());
|
||||
pListAnswer->m_tTime = htonl((int)pNZBInfo->GetHistoryTime());
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
|
||||
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
|
||||
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatus());
|
||||
pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1);
|
||||
pListAnswer->m_iDestDirLen = htonl(strlen(pNZBInfo->GetDestDir()) + 1);
|
||||
pListAnswer->m_iCategoryLen = htonl(strlen(pNZBInfo->GetCategory()) + 1);
|
||||
pListAnswer->m_iQueuedFilenameLen = htonl(strlen(pNZBInfo->GetQueuedFilename()) + 1);
|
||||
pListAnswer->m_iID = htonl(pHistoryInfo->GetID());
|
||||
pListAnswer->m_iKind = htonl((int)pHistoryInfo->GetKind());
|
||||
pListAnswer->m_tTime = htonl((int)pHistoryInfo->GetTime());
|
||||
|
||||
char szNicename[1024];
|
||||
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
|
||||
pListAnswer->m_iNicenameLen = htonl(strlen(szNicename) + 1);
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
|
||||
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
|
||||
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatuses()->CalcTotalStatus());
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
|
||||
{
|
||||
UrlInfo* pUrlInfo = pHistoryInfo->GetUrlInfo();
|
||||
pListAnswer->m_iUrlStatus = htonl(pUrlInfo->GetStatus());
|
||||
}
|
||||
|
||||
bufptr += sizeof(SNZBHistoryResponseEntry);
|
||||
strcpy(bufptr, pNZBInfo->GetFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iFilenameLen);
|
||||
strcpy(bufptr, pNZBInfo->GetDestDir());
|
||||
bufptr += ntohl(pListAnswer->m_iDestDirLen);
|
||||
strcpy(bufptr, pNZBInfo->GetCategory());
|
||||
bufptr += ntohl(pListAnswer->m_iCategoryLen);
|
||||
strcpy(bufptr, pNZBInfo->GetQueuedFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iQueuedFilenameLen);
|
||||
strcpy(bufptr, szNicename);
|
||||
bufptr += ntohl(pListAnswer->m_iNicenameLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pListAnswer->m_iQueuedFilenameLen = htonl(ntohl(pListAnswer->m_iQueuedFilenameLen) + 4 - (size_t)bufptr % 4);
|
||||
pListAnswer->m_iNicenameLen = htonl(ntohl(pListAnswer->m_iNicenameLen) + 4 - (size_t)bufptr % 4);
|
||||
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
@@ -980,16 +1029,126 @@ void HistoryBinCommand::Execute()
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
HistoryResponse.m_iNrTrailingEntries = htonl(iNrNZBEntries);
|
||||
HistoryResponse.m_iNrTrailingEntries = htonl(iNrEntries);
|
||||
HistoryResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &HistoryResponse, sizeof(HistoryResponse), 0);
|
||||
m_pConnection->Send((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void DownloadUrlBinCommand::Execute()
|
||||
{
|
||||
SNZBDownloadUrlRequest DownloadUrlRequest;
|
||||
if (!ReceiveRequest(&DownloadUrlRequest, sizeof(DownloadUrlRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
URL url(DownloadUrlRequest.m_szURL);
|
||||
if (!url.IsValid())
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Url %s is not valid", DownloadUrlRequest.m_szURL);
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
UrlInfo* pUrlInfo = new UrlInfo();
|
||||
pUrlInfo->SetURL(DownloadUrlRequest.m_szURL);
|
||||
pUrlInfo->SetNZBFilename(DownloadUrlRequest.m_szNZBFilename);
|
||||
pUrlInfo->SetCategory(DownloadUrlRequest.m_szCategory);
|
||||
pUrlInfo->SetPriority(ntohl(DownloadUrlRequest.m_iPriority));
|
||||
pUrlInfo->SetAddTop(ntohl(DownloadUrlRequest.m_bAddFirst));
|
||||
pUrlInfo->SetAddPaused(ntohl(DownloadUrlRequest.m_bAddPaused));
|
||||
|
||||
g_pUrlCoordinator->AddUrlToQueue(pUrlInfo, ntohl(DownloadUrlRequest.m_bAddFirst));
|
||||
|
||||
info("Request: Queue url %s", DownloadUrlRequest.m_szURL);
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Url %s added to queue", DownloadUrlRequest.m_szURL);
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
}
|
||||
|
||||
void UrlQueueBinCommand::Execute()
|
||||
{
|
||||
SNZBUrlQueueRequest UrlQueueRequest;
|
||||
if (!ReceiveRequest(&UrlQueueRequest, sizeof(UrlQueueRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SNZBUrlQueueResponse UrlQueueResponse;
|
||||
memset(&UrlQueueResponse, 0, sizeof(UrlQueueResponse));
|
||||
UrlQueueResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
UrlQueueResponse.m_MessageBase.m_iStructSize = htonl(sizeof(UrlQueueResponse));
|
||||
UrlQueueResponse.m_iEntrySize = htonl(sizeof(SNZBUrlQueueResponseEntry));
|
||||
|
||||
char* buf = NULL;
|
||||
int bufsize = 0;
|
||||
|
||||
// Make a data structure and copy all the elements of the list into it
|
||||
UrlQueue* pUrlQueue = g_pQueueCoordinator->LockQueue()->GetUrlQueue();
|
||||
|
||||
int NrEntries = pUrlQueue->size();
|
||||
|
||||
// calculate required buffer size
|
||||
bufsize = NrEntries * sizeof(SNZBUrlQueueResponseEntry);
|
||||
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
|
||||
{
|
||||
UrlInfo* pUrlInfo = *it;
|
||||
bufsize += strlen(pUrlInfo->GetURL()) + 1;
|
||||
bufsize += strlen(pUrlInfo->GetNZBFilename()) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
|
||||
buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
|
||||
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
|
||||
{
|
||||
UrlInfo* pUrlInfo = *it;
|
||||
SNZBUrlQueueResponseEntry* pUrlQueueAnswer = (SNZBUrlQueueResponseEntry*) bufptr;
|
||||
pUrlQueueAnswer->m_iID = htonl(pUrlInfo->GetID());
|
||||
pUrlQueueAnswer->m_iURLLen = htonl(strlen(pUrlInfo->GetURL()) + 1);
|
||||
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pUrlInfo->GetNZBFilename()) + 1);
|
||||
bufptr += sizeof(SNZBUrlQueueResponseEntry);
|
||||
strcpy(bufptr, pUrlInfo->GetURL());
|
||||
bufptr += ntohl(pUrlQueueAnswer->m_iURLLen);
|
||||
strcpy(bufptr, pUrlInfo->GetNZBFilename());
|
||||
bufptr += ntohl(pUrlQueueAnswer->m_iNZBFilenameLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(ntohl(pUrlQueueAnswer->m_iNZBFilenameLen) + 4 - (size_t)bufptr % 4);
|
||||
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
UrlQueueResponse.m_iNrTrailingEntries = htonl(NrEntries);
|
||||
UrlQueueResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
34
BinRpc.h
34
BinRpc.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -33,23 +33,21 @@
|
||||
class BinRpcProcessor
|
||||
{
|
||||
private:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase m_MessageBase;
|
||||
const char* m_szClientIP;
|
||||
Connection* m_pConnection;
|
||||
|
||||
void Dispatch();
|
||||
|
||||
public:
|
||||
BinRpcProcessor();
|
||||
void Execute();
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetSignature(int iSignature) { m_MessageBase.m_iSignature = iSignature; }
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
};
|
||||
|
||||
class BinCommand
|
||||
{
|
||||
protected:
|
||||
SOCKET m_iSocket;
|
||||
Connection* m_pConnection;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
@@ -58,7 +56,7 @@ protected:
|
||||
public:
|
||||
virtual ~BinCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; }
|
||||
};
|
||||
|
||||
@@ -110,6 +108,12 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ReloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
@@ -140,4 +144,16 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DownloadUrlBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UrlQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
564
ChangeLog
564
ChangeLog
@@ -1,3 +1,567 @@
|
||||
nzbget-11.0:
|
||||
- reworked concept of post-processing scripts:
|
||||
- multiple scripts can be assigned to each nzb-file;
|
||||
- all assigned scripts are executed after the nzb-file is
|
||||
downloaded and internally processed (unpack, repair);
|
||||
- option <PostProcess> is obsolete;
|
||||
- new option <ScriptDir> sets directory where all pp-scripts must
|
||||
be stored;
|
||||
- new option <DefScript> sets the default list of pp-scripts to
|
||||
be assigned to nzb-file when it's added to queue;
|
||||
- new option <CategoryX.DefScript> to set the default list of
|
||||
pp-scripts on a category basis;
|
||||
- the execution order of pp-scripts can be set using new option
|
||||
<ScriptOrder>;
|
||||
- there are no separate configuration files for pp-scripts;
|
||||
- configuration options and pp-parameters are defined in the
|
||||
pp-scripts;
|
||||
- script configuration options are saved in nzbget configuration
|
||||
file (nzbget.conf);
|
||||
- changed parameters list of RPC-methods <loadconfig> and
|
||||
<saveconfig>;
|
||||
- new RPC-method <configtemplates> returns configuration
|
||||
descriptions for the program and for all pp-scripts;
|
||||
- configuration of all scripts can be done in web-interface;
|
||||
- the pp-scripts assigned to a particular nzb-file can be viewed
|
||||
and changed in web-interface on page <pp-parameters> in the
|
||||
edit download dialog;
|
||||
- option <PostPauseQueue> renamed to <ScriptPauseQueue> (the old
|
||||
name is still recognized);
|
||||
- new option <ConfigTemplate> to define the location of template
|
||||
configuration file (in previous versions it must be always
|
||||
stored in <WebDir>);
|
||||
- history dialog shows status of every script;
|
||||
- the old example post-processing script replaced with two new scripts:
|
||||
- EMail.py - sends E-Mail notification;
|
||||
- Logger.py - saves the full post-processing log of the job into
|
||||
file _postprocesslog.txt;
|
||||
- both pp-scripts are written in python and work on Windows too
|
||||
(in addition to Linux, Mac, etc.);
|
||||
- added possibility to set post-processing parameters for history items:
|
||||
- pp-parameters can now be viewed and changed in history dialog
|
||||
in web-interface;
|
||||
- useful before post-processing again;
|
||||
- new action <HistorySetParameter> in RPC-method <editqueue>;
|
||||
- new action <O> in remote command <--edit/-E> for history items
|
||||
(subcommand <H>);
|
||||
- added new feature <split download> which creates new download from
|
||||
selected files of source download;
|
||||
- new command <Split> in web-interface in edit download dialog
|
||||
on page <Files>;
|
||||
- new action <S> in remote command <--edit/-E>;
|
||||
- new action <FileSplit> in JSON-/XML-RPC method <editqueue>;
|
||||
- added support for manual par-check:
|
||||
- if option <ParCheck> is set to <Manual> and a damaged download
|
||||
is detected the program downloads all par2-files but doesn't
|
||||
perform par-check; the user must perform par-check/repair
|
||||
manually then (possibly on another, faster computer);
|
||||
- old values <yes/no> of option <ParCheck> renamed to <Force>
|
||||
and <Auto> respectively;
|
||||
- when set to <Force> all par2-files are always downloaded;
|
||||
- removed option <LoadPars> since its functionality is now
|
||||
covered by option <ParCheck>;
|
||||
- result of par-check can now have new value <Manual repair
|
||||
necessary>;
|
||||
- field <ParStatus> in RPC-method <history> can have new value
|
||||
<MANUAL>;
|
||||
- parameter <NZBPP_PARSTATUS> for pp-script can have new value
|
||||
<4 = manual repair necessary>;
|
||||
- when download is resumed in web-interface the option <ParCheck=Force>
|
||||
is respected and all par2-files are resumed (not only main par2-file);
|
||||
- automatic deletion of backup-source files after successful par-repair;
|
||||
important when repairing renamed rar-files since this could cause
|
||||
failure during unpack;
|
||||
- par-checker and renamer now add messages into the log of pp-item
|
||||
(like unpack- and pp-scripts-messages); these message now appear in
|
||||
the log created by scripts Logger.py and EMail.py;
|
||||
- when a nzb-file is added via web-interface or via remote call the
|
||||
file is now put into incoming nzb-directory (option "NzbDir") and
|
||||
then scanned; this has two advantages over the old behavior when the
|
||||
file was parsed directly in memory:
|
||||
- the file serves as a backup for troubleshootings;
|
||||
- the file is processed by nzbprocess-script (if defined in
|
||||
option "NzbProcess") making the pre-processing much easier;
|
||||
- new env-var parameters are passed to NzbProcess-script: NZBNP_NZBNAME,
|
||||
NZBNP_CATEGORY, NZBNP_PRIORITY, NZBNP_TOP, NZBNP_PAUSED;
|
||||
- new commands for use in NzbProcess-scripts: "[NZB] TOP=1" to add nzb
|
||||
to the top of queue and "[NZB] PAUSED=1" to add nzb-file in paused state;
|
||||
- reworked post-processor queue:
|
||||
- only one job is created for each nzb-file; no more separate
|
||||
jobs are created for par-collections within one nzb-file;
|
||||
- option <AllowReProcess> removed; a post-processing script is
|
||||
called only once per nzb-file, this behavior cannot be altered
|
||||
anymore;
|
||||
- with a new feature <Split> individual par-collections can be
|
||||
processed separately in a more effective way than before
|
||||
- improved unicode (utf8) support:
|
||||
- non-ascii characters are now correctly transferred via JSON-RPC;
|
||||
- correct displaying of nzb-names and paths in web-interface;
|
||||
- it is now possible to use non-ascii characters on settings page
|
||||
for option values (such as paths or category names);
|
||||
- improved unicode support in XML-RPC and JSON-RPC;
|
||||
- if username and password are defined for a news-server the
|
||||
authentication is now forced (in previous versions the authentication
|
||||
was performed only if requested by server); needed for servers
|
||||
supporting both anonymous (restricted) and authorized (full access)
|
||||
accounts;
|
||||
- added option <ExtCleanupDisk> to automatically delete unwanted files
|
||||
(with specified extensions or names) after successful par-check or unpack;
|
||||
- improvement in JSON-/XML-RPC:
|
||||
- all ID fields including NZBID are now persistent and remain
|
||||
their values after restart;
|
||||
- this allows for third-party software to identify nzb-files by
|
||||
ID;
|
||||
- method <history> now returns ID of NZB-file in the field
|
||||
<NZBID>;
|
||||
- in versions up to 0.8.0 the field <NZBID> was used to identify
|
||||
history items in the edit-commands <HistoryDelete>,
|
||||
<HistoryReturn>, <HistoryProcess>; since version 9 field <ID>
|
||||
is used for this purpose; in versions 9-10 field <NZBID> still
|
||||
existed and had the same value as field <ID> for compatibility
|
||||
with version 0.8.0; the compatibility is not provided anymore;
|
||||
this change was needed to provide a consistent using of field
|
||||
<NZBID> across all RPC-methods;
|
||||
- added support for rar-files with non-standard extensions (such as
|
||||
.001, etc.);
|
||||
- added functions to backup and restore settings from web-interface;
|
||||
when restoring it's possible to choose what sections to restore
|
||||
(for example only news servers settings or only settings of a
|
||||
certain pp-script) or restore the whole configuration;
|
||||
- new option "ControlUsername" to define login user name (if you don't
|
||||
like default username "nzbget");
|
||||
- if a communication error occurs in web-interface, it retries multiple
|
||||
times before giving up with an error message;
|
||||
- the maximum number of download threads are now managed automatically
|
||||
taking into account the number of allowed connections to news servers;
|
||||
removed option <ThreadLimit>;
|
||||
- pp-scripts terminated with unknown status are now considered failed
|
||||
(status=FAILURE instead of status=UNKNOWN);
|
||||
- new parameter (env. var) <NZBPP_NZBID> is passed to pp_scripts and
|
||||
contains an internal ID of NZB-file;
|
||||
- improved thread synchronisation to avoid (short-time) lockings of
|
||||
the program during creation of destination files;
|
||||
- more detailed error message if a directory could not be created
|
||||
(<DstDir>, <NzbDir>, etc.); the message includes error text reported
|
||||
by OS such as <permission denied> or similar;
|
||||
- when unpacking the unpack start time is now measured after receiving
|
||||
of unrar copyright message; this provides better unpack time
|
||||
estimation in a case when user uses unpack-script to do some things
|
||||
before executing unrar (for example sending Wake-On-Lan message to
|
||||
the destination NAS); it works with unrar only, it's not possible
|
||||
with 7-Zip because it buffers printed messages;
|
||||
- when the program is reloaded, a message with version number is
|
||||
printed like on start;
|
||||
- configuration can now be saved in web-interface even if there were
|
||||
no changes made but if obsolete or invalid options were detected in
|
||||
the config file; the saving removes invalid entries from config file;
|
||||
- option <ControlPassword> can now be set to en empty value to disable
|
||||
authentication; useful if nzbget works behind other web-server with
|
||||
its own authentication;
|
||||
- when deleting downloads via web-interface a proper hint regarding
|
||||
deleting of already downloaded files from disk depending on option
|
||||
<DeleteCleanupDisk> is displayed;
|
||||
- if a news-server returns empty or bad article (this may be caused
|
||||
by errors on the news server), the program tries again from the same
|
||||
or other servers (in previous versions the article was marked as
|
||||
failed without other download attempts);
|
||||
- when a nzb-file whose name ends with ".queued" is added via web-
|
||||
interface the ".queued"-part is automatically removed;
|
||||
- small improvement in multithread synchronization of download queue;
|
||||
- added link to catalog of pp-scripts to web-interface;
|
||||
- updated forum URL in about dialog in web-interface;
|
||||
- small correction in a log-message: removed <Request:> from message
|
||||
<Request: Queue collection...>;
|
||||
- removed option "ProcessLogKind"; scripts should use prefixes ([INFO],
|
||||
[DETAIL], etc); messages printed without prefixes are added as [INFO];
|
||||
- removed option "AppendNzbDir"; if it was disabled that caused problems
|
||||
in par-checker and unpacker; the option is now assumed always active;
|
||||
- removed option "RenameBroken"; it caused problems in par-checker
|
||||
(the option existed since early program versions before the par-check
|
||||
was added);
|
||||
- configure-script now defines "SIGCHLD_HANDLER" by default on all
|
||||
systems including BSD; this eliminates the need of configure-
|
||||
parameter "--enable-sigchld-handler" on 64-Bit BSD; the trade-off:
|
||||
32-Bit BSD now requires "--disable-sigchld-handler";
|
||||
- improved configure-script: defining of symbol "FILE_OFFSET_BITS=64",
|
||||
required on some systems, is not necessary anymore;
|
||||
- fixed: in the option "NzbAddedProcess" the env-var parameter with
|
||||
nzb-name was passed in "NZBNA_NAME", should be "NZBNA_NZBNAME";
|
||||
the old parameter name "NZBNA_NAME" is still supported for
|
||||
compatibility;
|
||||
- fixed: download time in statistics were incorrect if the computer
|
||||
was put into standby (thanks Frank Kuypers for the patch);
|
||||
- fixed: when option <InterDir> was active and the download after
|
||||
unpack contained rar-file with the same name as one of original
|
||||
files (sometimes happen with included subtitles) the original
|
||||
rar-file was kept with name <.rar_duplicate1> even if the option
|
||||
<UnpackCleanupDisk> was active;
|
||||
- fixed: failed to read download queue from disk if post-processing
|
||||
queue was not empty;
|
||||
- fixed: when a duplicate file was detected during download the
|
||||
program could hang;
|
||||
- fixed: symbol <DISABLE_TLS> must be defined in project settings;
|
||||
defining it in <win32.h> didn't work properly (Windows only);
|
||||
- fixed: crash when adding malformed nzb-files with certain
|
||||
structure (Windows only);
|
||||
- fixed: by deleting of a partially downloaded nzb-file from queue,
|
||||
when the option <DeleteCleanupDisk> was active, the file
|
||||
<_brokenlog.txt> was not deleted preventing the directory from
|
||||
automatic deletion;
|
||||
- fixed: if an error occurs when a RPC-client or web-browser
|
||||
communicates with nzbget the program could crash;
|
||||
- fixed: if the last file of collection was detected as duplicate
|
||||
after the download of the first article the file was deleted from
|
||||
queue (that's OK) but the post-processing was not triggered
|
||||
(that's a bug);
|
||||
- fixed: support for splitted files (.001, .002, etc.) were broken.
|
||||
|
||||
nzbget-10.2:
|
||||
- fixed potential segfault which could happen with file paths longer
|
||||
than 1024 characters;
|
||||
- fixed: when options <DirectWrite> and <ContinuePartial> were both
|
||||
active, a restart or reload of the program during download may cause
|
||||
damaged files in the active download;
|
||||
- increased width of speed indication ui-element to avoid layout
|
||||
breaking on some linux-browsers;
|
||||
- fixed a race condition in unpacker which could lead to a segfault
|
||||
(although the chances were low because the code wasn't executed often).
|
||||
|
||||
nzbget-10.1:
|
||||
- fixed: articles with decoding errors (incomplete or damaged posts)
|
||||
caused infinite retry-loop in downloader.
|
||||
|
||||
nzbget-10.0:
|
||||
- added built-in unpack:
|
||||
- rar and 7-zip formats are supported (via external Unrar and
|
||||
7-Zip executables);
|
||||
- new options <Unpack>, <UnpackPauseQueue>, <UnpackCleanupDisk>,
|
||||
<UnrarCmd>, <SevenZipCmd>;
|
||||
- web-interface now shows progress and estimated time during
|
||||
unpack (rar only; for 7-Zip progress is not available due to
|
||||
limitations of 7-Zip);
|
||||
- when built-in unpack is enabled, the post-processing script is
|
||||
called after unpack and possibly par-check/repair (if needed);
|
||||
- for nzb-files containing multiple collections (par-sets) the
|
||||
post-processing script is called only once, after the last
|
||||
par-set;
|
||||
- new parameter <NZBPP_UNPACKSTATUS> passed to post-processing
|
||||
script;
|
||||
- if the option <AllowReProcess> is enabled the post-processing-
|
||||
script is called after each par-set (as in previous versions);
|
||||
- example post-processing script updated: removed unrar-code,
|
||||
added check for unpack status;
|
||||
- new field <UnpackStatus> in result of RPC-method <history>;
|
||||
- history-dialog in web-interface shows three status: par-status,
|
||||
unpack-status, script-status;
|
||||
- with two built-in special post-processing parameters <*Unpack:>
|
||||
and <*Unpack:Password> the unpack can be disabled for individual
|
||||
nzb-file or the password can be set;
|
||||
- built-in special post-processing parameters can be set via web-
|
||||
interface on page <PP-Parameters> (when built-in unpack is
|
||||
enabled);
|
||||
- added support for HTTPS to the built-in web-server (web-interface and
|
||||
XML/JSON-RPC):
|
||||
- new options <SecureControl>, <SecurePort>, <SecureCert> and
|
||||
<SecureKey>;
|
||||
- module <TLS.c/h> completely rewritten with support for server-
|
||||
side sockets, newer versions of GnuTLS, proper thread lockings
|
||||
in OpenSSL;
|
||||
- improved the automatic par-scan (option <ParScan=auto>) to
|
||||
significantly reduce the verify-time in some common cases with renamed
|
||||
rar-files:
|
||||
- the extra files are scanned in an optimized order;
|
||||
- the scan stops when all missings files are found;
|
||||
- added fast renaming of intentionally misnamed (rar-) files:
|
||||
- the new renaming algorithm doesn't require full par-scan and
|
||||
restores original filenames in just a few seconds, even on very
|
||||
slow computers (NAS, media players, etc.);
|
||||
- the fast renaming is performed automatically when requested by
|
||||
the built-in unpacker (option <Unpack> must be active);
|
||||
- added new option <InterDir> to put intermediate files during download
|
||||
into a separate directory (instead of storing them directly in
|
||||
destination directory (option <DestDir>):
|
||||
- when nzb-file is completely (successfully) downloaded, repaired
|
||||
(if neccessary) and unpacked the files are moved to destination
|
||||
directory (option <DestDir> or <CategoryX.DestDir>);
|
||||
- intermediate directory can significantly improve unpack
|
||||
performance if it is located on a separate physical hard drive;
|
||||
- added new option <ServerX.Cipher> to manually select cipher for
|
||||
encrypted communication with news server:
|
||||
- manually choosing a faster cipher (such as <RC4>) can
|
||||
significantly improve performance (if CPU is a limiting factor);
|
||||
- major improvements in news-server/connection management (main and fill
|
||||
servers):
|
||||
- if download of article fails, the program tries all servers of
|
||||
the same level before trying higher level servers;
|
||||
- this ensures that fill servers are used only if all main servers
|
||||
fail;
|
||||
- this makes the configuring of multiple servers much easier than
|
||||
before: in most cases the simple configuration of level 0 for
|
||||
all main servers and level 1 for all fill servers suffices;
|
||||
- in previous versions the level was increased immediately after
|
||||
the first tried server of the level failed; to make sure all
|
||||
main servers were tried before downloading from fill servers it
|
||||
was required to create complex server configurations with
|
||||
duplicates; these configurations were still not as effective as
|
||||
now;
|
||||
- do not reconnect on <article/group not found> errors since this
|
||||
doesn't help but unnecessary increases CPU load and network
|
||||
traffic;
|
||||
- removed option <RetryOnCrcError>; it's not required anymore;
|
||||
- new option <ServerX.Group> allows more flexible configuration
|
||||
of news servers when using multiple accounts on the same server;
|
||||
with this option it's also possible to imitate the old server
|
||||
management behavior regarding levels;
|
||||
- news servers configuration is now less error-prone:
|
||||
- the option <ServerX.Level> is not required to start from <0> and
|
||||
when several news servers are configured the Levels can be any
|
||||
integers - the program sorts the servers and corrects the Levels
|
||||
to 0,1,2,etc. automatically if needed;
|
||||
- when option <ServerX.Connections> is set to <0> the server is
|
||||
ignored (in previous version such a server could cause hanging
|
||||
when the program was trying to go to the next level);
|
||||
- if no news servers are defined (or all definitions are invalid)
|
||||
a warning is printed to inform that the download is not
|
||||
possible;
|
||||
- categories can now have their own destination directories; new option
|
||||
<CategoryX.DestDir>;
|
||||
- new feature <Pause for X Minutes> in web-interface; new XML-/JSON-RPC
|
||||
method <scheduleresume>;
|
||||
- improved the handling of hanging connections: if a connection hangs
|
||||
longer than defined by option <ConnectionTimeout> the program tries to
|
||||
gracefully close connection first (this is new); if it still hangs
|
||||
after <TerminateTimeout> the download thread is terminated as a last
|
||||
resort (as in previous versions);
|
||||
- added automatic speed meter recalibration to recover after possible
|
||||
synchronization errors which can occur when the option <AccurateRate>
|
||||
is not active; this makes the default (less accurate but fast) speed
|
||||
meter almost as good as the accurate one; important when speed
|
||||
throttling is active;
|
||||
- when the par-checked requests more par-files, they get an extra
|
||||
priority and are downloaded before other files regardless of their
|
||||
priorities; this is needed to avoid hanging of par-checker-job if a
|
||||
file with a higher priority gets added to queue during par-check;
|
||||
- when post-processing-parameters are passed to the post-processing
|
||||
script a second version of each parameter with a normalized parameter-
|
||||
name is passed in addition to the original parameter name; in the
|
||||
normalized name the special characters <*> and <:> are replaced with
|
||||
<_> and all characters are passed in upper case; this is important for
|
||||
internal post-processing-parameters (*Unpack:=yes/no) which include
|
||||
special characters;
|
||||
- warning <Non-nzbget request received> now is not printed when the
|
||||
connection was aborted before the request signature was read;
|
||||
- changed formatting of remaining time for post-processing to short
|
||||
format (as used for remaining download time);
|
||||
- added link to article <Performance tips> to settings tab on web-
|
||||
interface;
|
||||
- removed hint <Post-processing script may have moved files elsewhere>
|
||||
from history dialog since it caused more questions than helped;
|
||||
- changed default value for option <ServerX.JoinGroup> to <no>; most
|
||||
news servers nowadays do not require joining the group and many
|
||||
servers do not keep headers for many groups making the join-command
|
||||
fail even if the articles still can be successfully downloaded;
|
||||
- small change in example post-processing script: message <Deleting
|
||||
source ts-files> are now printed only if ts-files really existed;
|
||||
- improved configure-script:
|
||||
- libs which are added via pkgconfig are now put into LIBS instead
|
||||
of LDFLAGS - improves compatibility with newer Linux linkers;
|
||||
- OpenSSL libs/includes are now added using pkgconfig to better
|
||||
handle dependencies;
|
||||
- additional check for libcrypto (part of OpenSSL) ensures the
|
||||
library is added to linker command even if pkgconfig is not
|
||||
used;
|
||||
- adding of local files via web-interface now works in IE10;
|
||||
- if an obsolete option is found in the config file a warning is printed
|
||||
instead of an error and the program is not paused anymore;
|
||||
- fixed: the reported line numbers for configuration errors were
|
||||
sometimes inaccurate;
|
||||
- fixed warning <file glyphicons-halflings.png not found>;
|
||||
- fixed: some XML-/JSON-RPC methods may return negative values for file
|
||||
sizes between 2-4GB; this had also influence on web-interface.
|
||||
- fixed: if an external program (unrar, pp-script, etc.) could not be
|
||||
started, the execute-function has returned code 255 although the code
|
||||
-1 were expected in this case; this could break designed post-
|
||||
processing flow;
|
||||
- fixed: some characters with codes below 32 were not properly encoded
|
||||
in JSON-RPC; sometimes output from unrar contained such characters
|
||||
and could break web-interface;
|
||||
- fixed: special characters (quotation marks, etc.) in unpack password
|
||||
and in configuration options were not displayed properly and could be
|
||||
discarded on saving;
|
||||
|
||||
nzbget-9.0:
|
||||
- changed version naming scheme by removing the leading zero: current
|
||||
version is now called 9.0 instead of 0.9.0 (it's really the 9th major
|
||||
version of the program);
|
||||
- added built-in web-interface:
|
||||
- completely new designed and written from scratch;
|
||||
- doesn't require a separate web-server;
|
||||
- doesn't require PHP;
|
||||
- 100% Javascript application; the built-in web-server hosts only
|
||||
static files; the javascript app communicates with NZBGet via
|
||||
JSON-RPC;
|
||||
- very efficient usage of server resources (CPU and memory);
|
||||
- easy installation. Since neither a separate web-server nor PHP
|
||||
are needed the installation of new web-interface is very easy.
|
||||
Actually it is performed automatically when you "make install"
|
||||
or "ipkg install nzbget";
|
||||
- modern look: better layout, popup dialogs, nice animations,
|
||||
hi-def icons;
|
||||
- built-in phone-theme (activates automatically);
|
||||
- combined view for "currently downloading", "queued", "currently
|
||||
processing" and "queued for processing";
|
||||
- renaming of nzb-files;
|
||||
- multiselect with multiedit or merge of downloads;
|
||||
- fast paging in the lists (downloads, history, messages);
|
||||
- search box for filtering in the lists (downloads, history, messages)
|
||||
and in settings;
|
||||
- adding nzb-files to download queue was improved in several ways:
|
||||
- add multiple files at once. The "select files dialog" allows
|
||||
to select multiple files;
|
||||
- add files using drag and drop. Just drop the files from your
|
||||
file manager directly into the web-browser;
|
||||
- add files via URLs. Put the URL and NZBGet downloads the
|
||||
nzb-file and adds it to download queue automatically;
|
||||
- the priority of nzb-file can now be set when adding local-files
|
||||
or URLs;
|
||||
- the history can be cleared completely or selected items can be removed;
|
||||
- file mode is now nzb-file related;
|
||||
- added the ability to queue URLs:
|
||||
- the program automatically downloads nzb-files from given URLs
|
||||
and put them to download queue.
|
||||
- when multiple URLs are added in a short time, they are put
|
||||
into a special URL-queue.
|
||||
- the number of simultaneous URL-downloads are controlled via
|
||||
new option UrlConnections.
|
||||
- with the new option ReloadUrlQueue can be controlled if the URL-queue
|
||||
should be reloaded after the program is restarted (if the URL-queue
|
||||
was not empty).
|
||||
- new switch <-U> for remote-command <--append/-A> to queue an URL.
|
||||
- new subcommand <-U> in the remote command <--list/-L> prints the
|
||||
current URL-queue.
|
||||
- if URL-download fails, the URL is moved into history.
|
||||
- with subcommand <-R> of command <--edit> the failed URL can be
|
||||
returned to URL-queue for redownload.
|
||||
- the remote command <--list/-L> for history can now print the infos
|
||||
for URL history items.
|
||||
- new XML/JSON-RPC command <appendurl> to add an URL or multiple
|
||||
URLs for download.
|
||||
- new XML/JSON-RPC command <urlqueue> returns the items from the
|
||||
URL-queue.
|
||||
- the XML/JSON-RPC command <history> was extended to provide
|
||||
infos about URL history items.
|
||||
- the URL-queue obeys the pause-state of download queue.
|
||||
- the URL-downloads support HTTP and HTTPS protocols;
|
||||
- added new field <name> to nzb-info-object.
|
||||
- it is initially set to the cleaned up name of the nzb-file.
|
||||
- the renaming of the group changes this field.
|
||||
- all RPC-methods related to nzb-object return the new field, the
|
||||
old field <NZBNicename> is now deprecated.
|
||||
- the option <MergeNZB> now checks the <name>-field instead of
|
||||
<nzbfilename> (the latter is not changed when the nzb is renamed).
|
||||
- new env-var-parameter <NZBPP_NZBNAME> for post-processing script;
|
||||
- added options <GN> and <FN> for remote command <--edit/-E>. With these
|
||||
options the name of group or file can be used in edit-command instead
|
||||
of file ID;
|
||||
- added support for regular expressions (POSIX ERE Syntax) in remote
|
||||
commands <--list/-L> and <--edit/-E> using new subcommands <GR> and <FR>;
|
||||
- improved performance of RPC-command <listgroups>;
|
||||
- added new command <FileReorder> to RPC-method <editqueue> to set the
|
||||
order of individual files in the group;
|
||||
- added gzip-support to built-in web-server (including RPC);
|
||||
- added processing of http-request <OPTIONS> in RPC-server for better
|
||||
support of cross domain requests;
|
||||
- renamed example configuration file and postprocessing script to make
|
||||
the installation easier;
|
||||
- improved the automatic installation (<make install>) to install all
|
||||
necessary files (not only the binary as it was before);
|
||||
- improved handling of configuration errors: the program now does not
|
||||
terminate on errors but rather logs all of them and uses default option values;
|
||||
- added new XML/JSON-RPC methods <config>, <loadconfig> and <saveconfig>;
|
||||
- with active option <AllowReProcess> the NZB considered completed even if
|
||||
there are paused non-par-files (the paused non-par-files are treated the
|
||||
same way as paused par-files): as a result the reprocessable script is called;
|
||||
- added subcommand <W> to remote command <-S/--scan> to scan synchronously
|
||||
(wait until scan completed);
|
||||
- added parameter <SyncMode> to XML/JSON-RPC method <scan>;
|
||||
- the command <Scan> in web-interface now waits for completing of scan
|
||||
before reporting the status;
|
||||
- added remote command <--reload/-O> and JSON/XML-RPC method <reload> to
|
||||
reload configuration from disk and reintialize the program; the reload
|
||||
can be performed from web-interface;
|
||||
- JSON/XML-RPC method <append> extended with parameter <priority>;
|
||||
- categories available in web-interface are now configured in program
|
||||
configuration file (nzbget.conf) and can be managed via web-interface
|
||||
on settings page;
|
||||
- updated descriptions in example configuration file;
|
||||
- changes in configuration file:
|
||||
- renamed options <ServerIP>, <ServerPort> and <ServerPassword> to
|
||||
<ControlIP>, <ControlPort> and <ControlPassword> to avoid confusion
|
||||
with news-server options <ServerX.Host>, <ServerX.Port> and
|
||||
<ServerX.Password>;
|
||||
- the old option names are still recognized and are automatically
|
||||
renamed when the configuration is saved from web-interface;
|
||||
- also renamed option <$MAINDIR> to <MainDir>;
|
||||
- extended remote command <--append/-A> with optional parameters:
|
||||
- <T> - adds the file/URL to the top of queue;
|
||||
- <P> - pauses added files;
|
||||
- <C category-name> - sets category for added nzb-file/URL;
|
||||
- <N nzb-name> - sets nzb filename for added URL;
|
||||
- the old switches <--category/-K> and <--top/-T> are deprecated
|
||||
but still supported for compatibility;
|
||||
- renamed subcommand <K> of command <--edit/-E> to <C> (the old
|
||||
subcommand is still supported for compatibility);
|
||||
- added new option <NzbAddedProcess> to setup a script called after
|
||||
a nzb-file is added to queue;
|
||||
- added debug messages for speed meter;
|
||||
- improved the startup script <nzbgetd> so it can be directly used in
|
||||
</etc/init.d> without modifications;
|
||||
- fixed: after renaming of a group, the new name was not displayed
|
||||
by remote commands <-L G> and <-C in curses mode>;
|
||||
- fixed incompatibility with OpenSLL 1.0 (thanks to OpenWRT team
|
||||
for the patch);
|
||||
- fixed: RPC-method <log(0, IdFrom)> could return wrong results if
|
||||
the log was filtered with options <XXXTarget>;
|
||||
- fixed: free disk space calculated incorrectly on some OSes;
|
||||
- fixed: unrar failure was not always properly detected causing the
|
||||
post-processing to delete not yet unpacked rar-files;
|
||||
- fixed compilation error on recent linux versions;
|
||||
- fixed compilation error on older systems;
|
||||
|
||||
nzbget-0.8.0:
|
||||
- added priorities; new action <I> for remote command <--edit/-E> to set
|
||||
priorities for groups or individual files; new actions <SetGroupPriority>
|
||||
and <SetFilePriority> of RPC-command <editqueue>; remote command
|
||||
<--list/-L> prints priorities and indicates files or groups being
|
||||
downloaded; ncurses-frontend prints priorities and indicates files or
|
||||
groups being download; new command <PRIORITY> to set priority of nzb-file
|
||||
from nzbprocess-script; RPC-commands <listgroups> and <listfiles> return
|
||||
priorities and indicate files or groups being downloaded;
|
||||
- added renaming of groups; new subcommand <N> for command <--edit/-E>; new
|
||||
action <SetName> for RPC-method <editqueue>;
|
||||
- added new option <AccurateRate>, which enables syncronisation in speed
|
||||
meter; that makes the indicated speed more accurate by eliminating
|
||||
measurement errors possible due thread conflicts; thanks to anonymous
|
||||
nzbget user for the patch;
|
||||
- improved the parsing of filename from article subject;
|
||||
- option <DirectWrite> now efficiently works on Windows with NTFS partitions;
|
||||
- added URL-based-authentication as alternative to HTTP-header authentication
|
||||
for XML- and JSON-RPC;
|
||||
- fixed: nzb-files containing umlauts and other special characters could not
|
||||
be parsed - replaced XML-Reader with SAX-Parser - only on POSIX (not on
|
||||
Windows);
|
||||
- fixed incorrect displaying of group sizes bigger than 4GB on many 64-bit
|
||||
OSes;
|
||||
- fixed a bug causing error on decoding of input data in JSON-RPC;
|
||||
- fixed a compilation error on some windows versions;
|
||||
- fixed: par-repair could fail when the filenames were not correctly parsed
|
||||
from article subjects;
|
||||
- fixed a compatibility issue with OpenBSD (and possibly other BSD based
|
||||
systems); added the automatic configuring of required signal handling logic
|
||||
to better support BSD without breaking the compatibility with certain Linux
|
||||
systems;
|
||||
- corrected the address of Free Software Foundation in copyright notice.
|
||||
|
||||
nzbget-0.7.0:
|
||||
- added history: new option <KeepHistory>, new remote subcommand <H> for
|
||||
commands <L> (list history entries) and <E> (delete history entries,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -74,11 +74,11 @@ void ColoredFrontend::PrintStatus()
|
||||
char tmp[1024];
|
||||
char timeString[100];
|
||||
timeString[0] = '\0';
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
|
||||
if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = m_lRemainingSize / ((long long)(fCurrentDownloadSpeed * 1024));
|
||||
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
@@ -86,9 +86,9 @@ void ColoredFrontend::PrintStatus()
|
||||
}
|
||||
|
||||
char szDownloadLimit[128];
|
||||
if (m_fDownloadLimit > 0.0f)
|
||||
if (m_iDownloadLimit > 0)
|
||||
{
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", m_fDownloadLimit);
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -113,7 +113,7 @@ void ColoredFrontend::PrintStatus()
|
||||
#endif
|
||||
|
||||
snprintf(tmp, 1024, " %d threads, %.*f KB/s, %.2f MB remaining%s%s%s%s%s\n",
|
||||
m_iThreadCount, (fCurrentDownloadSpeed >= 10 ? 0 : 1), fCurrentDownloadSpeed,
|
||||
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_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
|
||||
szDownloadLimit, szControlSeq);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
673
Connection.cpp
673
Connection.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -54,19 +54,16 @@
|
||||
#include "nzbget.h"
|
||||
#include "Connection.h"
|
||||
#include "Log.h"
|
||||
#include "TLS.h"
|
||||
|
||||
static const int CONNECTION_READBUFFER_SIZE = 1024;
|
||||
#ifndef DISABLE_TLS
|
||||
bool Connection::bTLSLibInitialized = false;
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
Mutex* Connection::m_pMutexGetHostByName = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void Connection::Init(bool bTLS)
|
||||
|
||||
void Connection::Init()
|
||||
{
|
||||
debug("Initializing global connection data");
|
||||
|
||||
@@ -87,21 +84,7 @@ void Connection::Init(bool bTLS)
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (bTLS)
|
||||
{
|
||||
debug("Initializing TLS library");
|
||||
char* szErrStr;
|
||||
int iRes = tls_lib_init(&szErrStr);
|
||||
bTLSLibInitialized = iRes == TLS_EOK;
|
||||
if (!bTLSLibInitialized)
|
||||
{
|
||||
error("Could not initialize TLS library: %s", szErrStr ? szErrStr : "unknown error");
|
||||
if (szErrStr)
|
||||
{
|
||||
free(szErrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
TLSSocket::Init();
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -120,11 +103,7 @@ void Connection::Final()
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (bTLSLibInitialized)
|
||||
{
|
||||
debug("Finalizing TLS library");
|
||||
tls_lib_deinit();
|
||||
}
|
||||
TLSSocket::Final();
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -134,38 +113,48 @@ void Connection::Final()
|
||||
#endif
|
||||
}
|
||||
|
||||
Connection::Connection(NetAddress* pNetAddress)
|
||||
Connection::Connection(const char* szHost, int iPort, bool bTLS)
|
||||
{
|
||||
debug("Creating Connection");
|
||||
|
||||
m_pNetAddress = pNetAddress;
|
||||
m_szHost = NULL;
|
||||
m_iPort = iPort;
|
||||
m_bTLS = bTLS;
|
||||
m_szCipher = NULL;
|
||||
m_eStatus = csDisconnected;
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
m_iBufAvail = 0;
|
||||
m_iTimeout = 60;
|
||||
m_bSuppressErrors = true;
|
||||
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
|
||||
m_bAutoClose = true;
|
||||
#ifndef DISABLE_TLS
|
||||
m_pTLS = NULL;
|
||||
m_pTLSSocket = NULL;
|
||||
m_bTLSError = false;
|
||||
#endif
|
||||
|
||||
if (szHost)
|
||||
{
|
||||
m_szHost = strdup(szHost);
|
||||
}
|
||||
}
|
||||
|
||||
Connection::Connection(SOCKET iSocket, bool bAutoClose)
|
||||
Connection::Connection(SOCKET iSocket, bool bTLS)
|
||||
{
|
||||
debug("Creating Connection");
|
||||
|
||||
m_pNetAddress = NULL;
|
||||
m_szHost = NULL;
|
||||
m_iPort = 0;
|
||||
m_bTLS = bTLS;
|
||||
m_szCipher = NULL;
|
||||
m_eStatus = csConnected;
|
||||
m_iSocket = iSocket;
|
||||
m_iBufAvail = 0;
|
||||
m_iTimeout = 60;
|
||||
m_bSuppressErrors = true;
|
||||
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
|
||||
m_bAutoClose = bAutoClose;
|
||||
#ifndef DISABLE_TLS
|
||||
m_pTLS = NULL;
|
||||
m_pTLSSocket = NULL;
|
||||
m_bTLSError = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -173,32 +162,65 @@ Connection::~Connection()
|
||||
{
|
||||
debug("Destroying Connection");
|
||||
|
||||
if (m_eStatus == csConnected && m_bAutoClose)
|
||||
Disconnect();
|
||||
|
||||
if (m_szHost)
|
||||
{
|
||||
Disconnect();
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
|
||||
free(m_szReadBuf);
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_pTLS)
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
free(m_pTLS);
|
||||
delete m_pTLSSocket;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Connection::SetSuppressErrors(bool bSuppressErrors)
|
||||
{
|
||||
m_bSuppressErrors = bSuppressErrors;
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
m_pTLSSocket->SetSuppressErrors(bSuppressErrors);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Connection::SetCipher(const char* szCipher)
|
||||
{
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
m_szCipher = szCipher ? strdup(szCipher) : NULL;
|
||||
}
|
||||
|
||||
bool Connection::Connect()
|
||||
{
|
||||
debug("Connecting");
|
||||
|
||||
if (m_eStatus == csConnected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bRes = DoConnect();
|
||||
|
||||
if (bRes)
|
||||
{
|
||||
m_eStatus = csConnected;
|
||||
}
|
||||
else
|
||||
Connection::DoDisconnect();
|
||||
{
|
||||
DoDisconnect();
|
||||
}
|
||||
|
||||
return bRes;
|
||||
}
|
||||
@@ -208,7 +230,9 @@ bool Connection::Disconnect()
|
||||
debug("Disconnecting");
|
||||
|
||||
if (m_eStatus == csDisconnected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bRes = DoDisconnect();
|
||||
|
||||
@@ -219,51 +243,145 @@ bool Connection::Disconnect()
|
||||
return bRes;
|
||||
}
|
||||
|
||||
int Connection::Bind()
|
||||
bool Connection::Bind()
|
||||
{
|
||||
debug("Binding");
|
||||
|
||||
if (m_eStatus == csListening)
|
||||
{
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int iRes = DoBind();
|
||||
|
||||
if (iRes == 0)
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo addr_hints, *addr_list, *addr;
|
||||
char iPortStr[sizeof(int) * 4 + 1]; // is enough to hold any converted int
|
||||
|
||||
memset(&addr_hints, 0, sizeof(addr_hints));
|
||||
addr_hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
|
||||
addr_hints.ai_socktype = SOCK_STREAM,
|
||||
addr_hints.ai_flags = AI_PASSIVE; // For wildcard IP address
|
||||
|
||||
sprintf(iPortStr, "%d", m_iPort);
|
||||
|
||||
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
|
||||
if (res != 0)
|
||||
{
|
||||
m_eStatus = csListening;
|
||||
error("Could not resolve hostname %s", m_szHost);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
int opt = 1;
|
||||
setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
|
||||
res = bind(m_iSocket, addr->ai_addr, addr->ai_addrlen);
|
||||
if (res != -1)
|
||||
{
|
||||
// Connection established
|
||||
break;
|
||||
}
|
||||
// Connection failed
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(addr_list);
|
||||
|
||||
#else
|
||||
|
||||
struct sockaddr_in sSocketAddress;
|
||||
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
|
||||
sSocketAddress.sin_family = AF_INET;
|
||||
if (!m_szHost || strlen(m_szHost) == 0)
|
||||
{
|
||||
sSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
else
|
||||
{
|
||||
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_szHost);
|
||||
if (sSocketAddress.sin_addr.s_addr == (unsigned int)-1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sSocketAddress.sin_port = htons(m_iPort);
|
||||
|
||||
m_iSocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
|
||||
|
||||
int res = bind(m_iSocket, (struct sockaddr *) &sSocketAddress, sizeof(sSocketAddress));
|
||||
if (res == -1)
|
||||
{
|
||||
// Connection failed
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Binding socket failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(m_iSocket, 100) < 0)
|
||||
{
|
||||
ReportError("Listen on socket failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_eStatus = csListening;
|
||||
|
||||
return iRes;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Connection::WriteLine(const char* pBuffer)
|
||||
{
|
||||
//debug("Connection::write(char* line)");
|
||||
//debug("Connection::WriteLine");
|
||||
|
||||
if (m_eStatus != csConnected)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int iRes = DoWriteLine(pBuffer);
|
||||
int iRes = send(m_iSocket, pBuffer, strlen(pBuffer), 0);
|
||||
|
||||
return iRes;
|
||||
}
|
||||
|
||||
int Connection::Send(const char* pBuffer, int iSize)
|
||||
bool Connection::Send(const char* pBuffer, int iSize)
|
||||
{
|
||||
debug("Sending data");
|
||||
|
||||
if (m_eStatus != csConnected)
|
||||
{
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
int iRes = send(m_iSocket, pBuffer, iSize, 0);
|
||||
int iBytesSent = 0;
|
||||
while (iBytesSent < iSize)
|
||||
{
|
||||
int iRes = send(m_iSocket, pBuffer + iBytesSent, iSize-iBytesSent, 0);
|
||||
if (iRes <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
iBytesSent += iRes;
|
||||
}
|
||||
|
||||
return iRes;
|
||||
return true;
|
||||
}
|
||||
|
||||
char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
@@ -273,26 +391,100 @@ char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* res = DoReadLine(pBuffer, iSize, pBytesRead);
|
||||
|
||||
return res;
|
||||
char* pBufPtr = pBuffer;
|
||||
iSize--; // for trailing '0'
|
||||
int iBytesRead = 0;
|
||||
int iBufAvail = m_iBufAvail; // local variable is faster
|
||||
char* szBufPtr = m_szBufPtr; // local variable is faster
|
||||
while (iSize)
|
||||
{
|
||||
if (!iBufAvail)
|
||||
{
|
||||
iBufAvail = recv(m_iSocket, m_szReadBuf, CONNECTION_READBUFFER_SIZE, 0);
|
||||
if (iBufAvail < 0)
|
||||
{
|
||||
ReportError("Could not receive data on socket", NULL, true, 0);
|
||||
break;
|
||||
}
|
||||
else if (iBufAvail == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
szBufPtr = m_szReadBuf;
|
||||
m_szReadBuf[iBufAvail] = '\0';
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
char* p = (char*)memchr(szBufPtr, '\n', iBufAvail);
|
||||
if (p)
|
||||
{
|
||||
len = (int)(p - szBufPtr + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = iBufAvail;
|
||||
}
|
||||
|
||||
if (len > iSize)
|
||||
{
|
||||
len = iSize;
|
||||
}
|
||||
|
||||
memcpy(pBufPtr, szBufPtr, len);
|
||||
pBufPtr += len;
|
||||
szBufPtr += len;
|
||||
iBufAvail -= len;
|
||||
iBytesRead += len;
|
||||
iSize -= len;
|
||||
|
||||
if (p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pBufPtr = '\0';
|
||||
|
||||
m_iBufAvail = iBufAvail > 0 ? iBufAvail : 0; // copy back to member
|
||||
m_szBufPtr = szBufPtr; // copy back to member
|
||||
|
||||
if (pBytesRead)
|
||||
{
|
||||
*pBytesRead = iBytesRead;
|
||||
}
|
||||
|
||||
if (pBufPtr == pBuffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
SOCKET Connection::Accept()
|
||||
Connection* Connection::Accept()
|
||||
{
|
||||
debug("Accepting connection");
|
||||
|
||||
if (m_eStatus != csListening)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SOCKET iRes = DoAccept();
|
||||
SOCKET iSocket = accept(m_iSocket, NULL, NULL);
|
||||
if (iSocket == INVALID_SOCKET && m_eStatus != csCancelled)
|
||||
{
|
||||
ReportError("Could not accept connection", NULL, true, 0);
|
||||
}
|
||||
if (iSocket == INVALID_SOCKET)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Connection* pCon = new Connection(iSocket, m_bTLS);
|
||||
|
||||
return iRes;
|
||||
return pCon;
|
||||
}
|
||||
|
||||
int Connection::Recv(char* pBuffer, int iSize)
|
||||
int Connection::TryRecv(char* pBuffer, int iSize)
|
||||
{
|
||||
debug("Receiving data");
|
||||
|
||||
@@ -308,7 +500,7 @@ int Connection::Recv(char* pBuffer, int iSize)
|
||||
return iReceived;
|
||||
}
|
||||
|
||||
bool Connection::RecvAll(char * pBuffer, int iSize)
|
||||
bool Connection::Recv(char * pBuffer, int iSize)
|
||||
{
|
||||
debug("Receiving data (full buffer)");
|
||||
|
||||
@@ -357,17 +549,18 @@ bool Connection::DoConnect()
|
||||
addr_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
addr_hints.ai_socktype = SOCK_STREAM,
|
||||
|
||||
sprintf(iPortStr, "%d", m_pNetAddress->GetPort());
|
||||
sprintf(iPortStr, "%d", m_iPort);
|
||||
|
||||
int res = getaddrinfo(m_pNetAddress->GetHost(), iPortStr, &addr_hints, &addr_list);
|
||||
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
|
||||
if (res != 0)
|
||||
{
|
||||
ReportError("Could not resolve hostname %s", m_pNetAddress->GetHost(), true, 0);
|
||||
ReportError("Could not resolve hostname %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
bool bLastAddr = !addr->ai_next;
|
||||
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
@@ -378,20 +571,33 @@ bool Connection::DoConnect()
|
||||
break;
|
||||
}
|
||||
// Connection failed
|
||||
if (bLastAddr)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
}
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
else if (bLastAddr)
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_szHost, true, 0);
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(addr_list);
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
struct sockaddr_in sSocketAddress;
|
||||
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
|
||||
sSocketAddress.sin_family = AF_INET;
|
||||
sSocketAddress.sin_port = htons(m_pNetAddress->GetPort());
|
||||
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_pNetAddress->GetHost());
|
||||
sSocketAddress.sin_port = htons(m_iPort);
|
||||
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_szHost);
|
||||
if (sSocketAddress.sin_addr.s_addr == (unsigned int)-1)
|
||||
{
|
||||
return false;
|
||||
@@ -400,25 +606,20 @@ bool Connection::DoConnect()
|
||||
m_iSocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_pNetAddress->GetHost(), true, 0);
|
||||
ReportError("Socket creation failed for %s", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int res = connect(m_iSocket , (struct sockaddr *) & sSocketAddress, sizeof(sSocketAddress));
|
||||
if (res == -1)
|
||||
{
|
||||
// Connection failed
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_pNetAddress->GetHost(), true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int MSecVal = m_iTimeout * 1000;
|
||||
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&MSecVal, sizeof(MSecVal));
|
||||
@@ -430,9 +631,16 @@ bool Connection::DoConnect()
|
||||
#endif
|
||||
if (err != 0)
|
||||
{
|
||||
ReportError("setsockopt failed", NULL, true, 0);
|
||||
ReportError("Socket initialization failed for %s", m_szHost, true, 0);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_bTLS && !StartTLS(true, NULL, NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -442,205 +650,23 @@ bool Connection::DoDisconnect()
|
||||
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
#ifndef DISABLE_TLS
|
||||
CloseTLS();
|
||||
#endif
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_pTLS)
|
||||
{
|
||||
CloseTLS();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
m_eStatus = csDisconnected;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Connection::DoWriteLine(const char* pBuffer)
|
||||
void Connection::ReadBuffer(char** pBuffer, int *iBufLen)
|
||||
{
|
||||
//debug("Connection::doWrite()");
|
||||
return send(m_iSocket, pBuffer, strlen(pBuffer), 0);
|
||||
}
|
||||
|
||||
char* Connection::DoReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
{
|
||||
//debug( "Connection::DoReadLine()" );
|
||||
char* pBufPtr = pBuffer;
|
||||
iSize--; // for trailing '0'
|
||||
int iBytesRead = 0;
|
||||
int iBufAvail = m_iBufAvail; // local variable is faster
|
||||
char* szBufPtr = m_szBufPtr; // local variable is faster
|
||||
while (iSize)
|
||||
{
|
||||
if (!iBufAvail)
|
||||
{
|
||||
iBufAvail = recv(m_iSocket, m_szReadBuf, CONNECTION_READBUFFER_SIZE, 0);
|
||||
if (iBufAvail < 0)
|
||||
{
|
||||
ReportError("Could not receive data on socket", NULL, true, 0);
|
||||
break;
|
||||
}
|
||||
else if (iBufAvail == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
szBufPtr = m_szReadBuf;
|
||||
m_szReadBuf[iBufAvail] = '\0';
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
char* p = (char*)memchr(szBufPtr, '\n', iBufAvail);
|
||||
if (p)
|
||||
{
|
||||
len = (int)(p - szBufPtr + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = iBufAvail;
|
||||
}
|
||||
|
||||
if (len > iSize)
|
||||
{
|
||||
len = iSize;
|
||||
}
|
||||
|
||||
memcpy(pBufPtr, szBufPtr, len);
|
||||
pBufPtr += len;
|
||||
szBufPtr += len;
|
||||
iBufAvail -= len;
|
||||
iBytesRead += len;
|
||||
iSize -= len;
|
||||
|
||||
if (p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pBufPtr = '\0';
|
||||
|
||||
m_iBufAvail = iBufAvail > 0 ? iBufAvail : 0; // copy back to member
|
||||
m_szBufPtr = szBufPtr; // copy back to member
|
||||
|
||||
if (pBytesRead)
|
||||
{
|
||||
*pBytesRead = iBytesRead;
|
||||
}
|
||||
|
||||
if (pBufPtr == pBuffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
int Connection::DoBind()
|
||||
{
|
||||
debug("Do binding");
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo addr_hints, *addr_list, *addr;
|
||||
char iPortStr[sizeof(int) * 4 + 1]; // is enough to hold any converted int
|
||||
|
||||
memset(&addr_hints, 0, sizeof(addr_hints));
|
||||
addr_hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
|
||||
addr_hints.ai_socktype = SOCK_STREAM,
|
||||
addr_hints.ai_flags = AI_PASSIVE; // For wildcard IP address
|
||||
|
||||
sprintf(iPortStr, "%d", m_pNetAddress->GetPort());
|
||||
|
||||
int res = getaddrinfo(m_pNetAddress->GetHost(), iPortStr, &addr_hints, &addr_list);
|
||||
if (res != 0)
|
||||
{
|
||||
error( "Could not resolve hostname %s", m_pNetAddress->GetHost() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
|
||||
{
|
||||
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (m_iSocket != INVALID_SOCKET)
|
||||
{
|
||||
int opt = 1;
|
||||
setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
|
||||
res = bind(m_iSocket, addr->ai_addr, addr->ai_addrlen);
|
||||
if (res != -1)
|
||||
{
|
||||
// Connection established
|
||||
break;
|
||||
}
|
||||
// Connection failed
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(addr_list);
|
||||
|
||||
#else
|
||||
|
||||
struct sockaddr_in sSocketAddress;
|
||||
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
|
||||
sSocketAddress.sin_family = AF_INET;
|
||||
if (!m_pNetAddress->GetHost() || strlen(m_pNetAddress->GetHost()) == 0)
|
||||
{
|
||||
sSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
else
|
||||
{
|
||||
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_pNetAddress->GetHost());
|
||||
if (sSocketAddress.sin_addr.s_addr == (unsigned int)-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sSocketAddress.sin_port = htons(m_pNetAddress->GetPort());
|
||||
|
||||
m_iSocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Socket creation failed for %s", m_pNetAddress->GetHost(), true, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
|
||||
|
||||
int res = bind(m_iSocket, (struct sockaddr *) &sSocketAddress, sizeof(sSocketAddress));
|
||||
if (res == -1)
|
||||
{
|
||||
// Connection failed
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Binding socket failed for %s", m_pNetAddress->GetHost(), true, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(m_iSocket, 10) < 0)
|
||||
{
|
||||
ReportError("Listen on socket failed for %s", m_pNetAddress->GetHost(), true, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SOCKET Connection::DoAccept()
|
||||
{
|
||||
SOCKET iSocket = accept(GetSocket(), NULL, NULL);
|
||||
|
||||
if (iSocket == INVALID_SOCKET && m_eStatus != csCancelled)
|
||||
{
|
||||
ReportError("Could not accept connection", NULL, true, 0);
|
||||
}
|
||||
|
||||
return iSocket;
|
||||
}
|
||||
*iBufLen = m_iBufAvail;
|
||||
*pBuffer = m_szBufPtr;
|
||||
m_iBufAvail = 0;
|
||||
};
|
||||
|
||||
void Connection::Cancel()
|
||||
{
|
||||
@@ -675,14 +701,9 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
{
|
||||
#ifdef WIN32
|
||||
int ErrCode = WSAGetLastError();
|
||||
if (m_bSuppressErrors)
|
||||
{
|
||||
debug("%s: ErrNo %i", szErrPrefix, ErrCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s: ErrNo %i", szErrPrefix, ErrCode);
|
||||
}
|
||||
char szErrMsg[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrCode, 0, szErrMsg, 1024, NULL);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
#else
|
||||
const char *szErrMsg = NULL;
|
||||
int ErrCode = herrno;
|
||||
@@ -695,7 +716,7 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
{
|
||||
szErrMsg = hstrerror(ErrCode);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (m_bSuppressErrors)
|
||||
{
|
||||
debug("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
|
||||
@@ -704,7 +725,6 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
{
|
||||
error("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -720,71 +740,40 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
bool Connection::CheckTLSResult(int iResultCode, char* szErrStr, const char* szErrMsgPrefix)
|
||||
{
|
||||
bool bOK = iResultCode == TLS_EOK;
|
||||
if (!bOK)
|
||||
{
|
||||
ReportError(szErrMsgPrefix, szErrStr ? szErrStr : "unknown error", false, 0);
|
||||
if (szErrStr)
|
||||
{
|
||||
free(szErrStr);
|
||||
}
|
||||
}
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool Connection::StartTLS()
|
||||
bool Connection::StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile)
|
||||
{
|
||||
debug("Starting TLS");
|
||||
|
||||
if (m_pTLS)
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
free(m_pTLS);
|
||||
delete m_pTLSSocket;
|
||||
}
|
||||
|
||||
m_pTLS = malloc(sizeof(tls_t));
|
||||
tls_t* pTLS = (tls_t*)m_pTLS;
|
||||
memset(pTLS, 0, sizeof(tls_t));
|
||||
tls_clear(pTLS);
|
||||
m_pTLSSocket = new TLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher);
|
||||
m_pTLSSocket->SetSuppressErrors(m_bSuppressErrors);
|
||||
|
||||
char* szErrStr;
|
||||
int iRes;
|
||||
|
||||
iRes = tls_init(pTLS, NULL, NULL, NULL, 0, &szErrStr);
|
||||
if (!CheckTLSResult(iRes, szErrStr, "Could not initialize TLS-object: %s"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("tls_start...");
|
||||
iRes = tls_start(pTLS, (int)m_iSocket, NULL, 1, NULL, &szErrStr);
|
||||
debug("tls_start...%i", iRes);
|
||||
if (!CheckTLSResult(iRes, szErrStr, "Could not establish secure connection: %s"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_pTLSSocket->Start();
|
||||
}
|
||||
|
||||
void Connection::CloseTLS()
|
||||
{
|
||||
tls_close((tls_t*)m_pTLS);
|
||||
free(m_pTLS);
|
||||
m_pTLS = NULL;
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
m_pTLSSocket->Close();
|
||||
delete m_pTLSSocket;
|
||||
m_pTLSSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int Connection::recv(SOCKET s, char* buf, int len, int flags)
|
||||
{
|
||||
size_t iReceived = 0;
|
||||
int iReceived = 0;
|
||||
|
||||
if (m_pTLS)
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
m_bTLSError = false;
|
||||
char* szErrStr;
|
||||
int iRes = tls_getbuf((tls_t*)m_pTLS, buf, len, &iReceived, &szErrStr);
|
||||
if (!CheckTLSResult(iRes, szErrStr, "Could not read from TLS-socket: %s"))
|
||||
iReceived = m_pTLSSocket->Recv(buf, len);
|
||||
if (iReceived < 0)
|
||||
{
|
||||
m_bTLSError = true;
|
||||
return -1;
|
||||
@@ -799,22 +788,23 @@ int Connection::recv(SOCKET s, char* buf, int len, int flags)
|
||||
|
||||
int Connection::send(SOCKET s, const char* buf, int len, int flags)
|
||||
{
|
||||
if (m_pTLS)
|
||||
int iSent = 0;
|
||||
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
m_bTLSError = false;
|
||||
char* szErrStr;
|
||||
int iRes = tls_putbuf((tls_t*)m_pTLS, buf, len, &szErrStr);
|
||||
if (!CheckTLSResult(iRes, szErrStr, "Could not send to TLS-socket: %s"))
|
||||
iSent = m_pTLSSocket->Send(buf, len);
|
||||
if (iSent < 0)
|
||||
{
|
||||
m_bTLSError = true;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return iSent;
|
||||
}
|
||||
else
|
||||
{
|
||||
int iRet = ::send(s, buf, len, flags);
|
||||
return iRet;
|
||||
iSent = ::send(s, buf, len, flags);
|
||||
return iSent;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -868,3 +858,20 @@ unsigned int Connection::ResolveHostAddr(const char* szHost)
|
||||
return uaddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* Connection::GetRemoteAddr()
|
||||
{
|
||||
struct sockaddr_in PeerName;
|
||||
int iPeerNameLength = sizeof(PeerName);
|
||||
if (getpeername(m_iSocket, (struct sockaddr*)&PeerName, (SOCKLEN_T*) &iPeerNameLength) >= 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
strncpy(m_szRemoteAddr, inet_ntoa(PeerName.sin_addr), sizeof(m_szRemoteAddr));
|
||||
#else
|
||||
inet_ntop(AF_INET, &PeerName.sin_addr, m_szRemoteAddr, sizeof(m_szRemoteAddr));
|
||||
#endif
|
||||
}
|
||||
m_szRemoteAddr[sizeof(m_szRemoteAddr)-1] = '\0';
|
||||
|
||||
return m_szRemoteAddr;
|
||||
}
|
||||
|
||||
62
Connection.h
62
Connection.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -27,12 +27,14 @@
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include "NetAddress.h"
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
#include "Thread.h"
|
||||
#endif
|
||||
#endif
|
||||
#ifndef DISABLE_TLS
|
||||
#include "TLS.h"
|
||||
#endif
|
||||
|
||||
class Connection
|
||||
{
|
||||
@@ -44,20 +46,22 @@ public:
|
||||
csListening,
|
||||
csCancelled
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
NetAddress* m_pNetAddress;
|
||||
char* m_szHost;
|
||||
int m_iPort;
|
||||
SOCKET m_iSocket;
|
||||
bool m_bTLS;
|
||||
char* m_szCipher;
|
||||
char* m_szReadBuf;
|
||||
int m_iBufAvail;
|
||||
char* m_szBufPtr;
|
||||
EStatus m_eStatus;
|
||||
int m_iTimeout;
|
||||
bool m_bSuppressErrors;
|
||||
bool m_bAutoClose;
|
||||
char m_szRemoteAddr[20];
|
||||
#ifndef DISABLE_TLS
|
||||
void* m_pTLS;
|
||||
static bool bTLSLibInitialized;
|
||||
TLSSocket* m_pTLSSocket;
|
||||
bool m_bTLSError;
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -66,47 +70,47 @@ protected:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Connection(SOCKET iSocket, bool bTLS);
|
||||
void ReportError(const char* szMsgPrefix, const char* szMsgArg, bool PrintErrCode, int herrno);
|
||||
virtual bool DoConnect();
|
||||
virtual bool DoDisconnect();
|
||||
int DoBind();
|
||||
int DoWriteLine(const char* pBuffer);
|
||||
char* DoReadLine(char* pBuffer, int iSize, int* pBytesRead);
|
||||
SOCKET DoAccept();
|
||||
bool DoConnect();
|
||||
bool DoDisconnect();
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
unsigned int ResolveHostAddr(const char* szHost);
|
||||
#endif
|
||||
#ifndef DISABLE_TLS
|
||||
bool CheckTLSResult(int iResultCode, char* szErrStr, const char* szErrMsgPrefix);
|
||||
int recv(SOCKET s, char* buf, int len, int flags);
|
||||
int send(SOCKET s, const char* buf, int len, int flags);
|
||||
void CloseTLS();
|
||||
#endif
|
||||
|
||||
public:
|
||||
Connection(NetAddress* pNetAddress);
|
||||
Connection(SOCKET iSocket, bool bAutoClose);
|
||||
Connection(const char* szHost, int iPort, bool bTLS);
|
||||
virtual ~Connection();
|
||||
static void Init(bool bTLS);
|
||||
static void Init();
|
||||
static void Final();
|
||||
bool Connect();
|
||||
bool Disconnect();
|
||||
int Bind();
|
||||
int Send(const char* pBuffer, int iSize);
|
||||
int Recv(char* pBuffer, int iSize);
|
||||
bool RecvAll(char* pBuffer, int iSize);
|
||||
virtual bool Connect();
|
||||
virtual bool Disconnect();
|
||||
bool Bind();
|
||||
bool Send(const char* pBuffer, int iSize);
|
||||
bool Recv(char* pBuffer, int iSize);
|
||||
int TryRecv(char* pBuffer, int iSize);
|
||||
char* ReadLine(char* pBuffer, int iSize, int* pBytesRead);
|
||||
void ReadBuffer(char** pBuffer, int *iBufLen);
|
||||
int WriteLine(const char* pBuffer);
|
||||
SOCKET Accept();
|
||||
Connection* Accept();
|
||||
void Cancel();
|
||||
NetAddress* GetServer() { return m_pNetAddress; }
|
||||
SOCKET GetSocket() { return m_iSocket; }
|
||||
const char* GetHost() { return m_szHost; }
|
||||
int GetPort() { return m_iPort; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
const char* GetCipher() { return m_szCipher; }
|
||||
void SetCipher(const char* szCipher);
|
||||
void SetTimeout(int iTimeout) { m_iTimeout = iTimeout; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetSuppressErrors(bool bSuppressErrors) { m_bSuppressErrors = bSuppressErrors; }
|
||||
void SetSuppressErrors(bool bSuppressErrors);
|
||||
bool GetSuppressErrors() { return m_bSuppressErrors; }
|
||||
const char* GetRemoteAddr();
|
||||
#ifndef DISABLE_TLS
|
||||
bool StartTLS();
|
||||
bool StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
483
DiskState.cpp
483
DiskState.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -77,12 +77,12 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s", fileName);
|
||||
error("Error saving diskstate: Could not create file %s", fileName);
|
||||
perror(fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 12);
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 25);
|
||||
|
||||
// save nzb-infos
|
||||
SaveNZBList(pDownloadQueue, outfile);
|
||||
@@ -93,6 +93,9 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
// save post-queue
|
||||
SavePostQueue(pDownloadQueue, outfile);
|
||||
|
||||
// save url-queue
|
||||
SaveUrlQueue(pDownloadQueue, outfile);
|
||||
|
||||
// save history
|
||||
SaveHistory(pDownloadQueue, outfile);
|
||||
|
||||
@@ -102,6 +105,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
fclose(outfile);
|
||||
|
||||
if (pDownloadQueue->GetFileQueue()->empty() &&
|
||||
pDownloadQueue->GetUrlQueue()->empty() &&
|
||||
pDownloadQueue->GetPostQueue()->empty() &&
|
||||
pDownloadQueue->GetHistoryList()->empty())
|
||||
{
|
||||
@@ -125,14 +129,14 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
|
||||
if (!infile)
|
||||
{
|
||||
error("Could not open file %s", fileName);
|
||||
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 || iFormatVersion > 12)
|
||||
if (iFormatVersion < 3 || iFormatVersion > 25)
|
||||
{
|
||||
error("Could not load diskstate due to file version mismatch");
|
||||
fclose(infile);
|
||||
@@ -148,7 +152,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
if (iFormatVersion >= 7)
|
||||
{
|
||||
// load post-queue
|
||||
if (!LoadPostQueue(pDownloadQueue, infile)) goto error;
|
||||
if (!LoadPostQueue(pDownloadQueue, infile, iFormatVersion)) goto error;
|
||||
}
|
||||
else if (iFormatVersion < 7 && g_pOptions->GetReloadPostQueue())
|
||||
{
|
||||
@@ -156,10 +160,16 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
LoadOldPostQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 15)
|
||||
{
|
||||
// load url-queue
|
||||
if (!LoadUrlQueue(pDownloadQueue, infile, iFormatVersion)) goto error;
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 9)
|
||||
{
|
||||
// load history
|
||||
if (!LoadHistory(pDownloadQueue, infile)) goto error;
|
||||
if (!LoadHistory(pDownloadQueue, infile, iFormatVersion)) goto error;
|
||||
|
||||
// load parked file-infos
|
||||
if (!LoadFileQueue(pDownloadQueue, pDownloadQueue->GetParkedFiles(), infile, iFormatVersion)) goto error;
|
||||
@@ -188,13 +198,15 @@ void DiskState::SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetID());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetFilename());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetDestDir());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetQueuedFilename());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetName());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetCategory());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetPostProcess() ? 1 : 0);
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetParStatus());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetScriptStatus());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetPostProcess());
|
||||
fprintf(outfile, "%i,%i,%i,%i\n", (int)pNZBInfo->GetParStatus(), (int)pNZBInfo->GetUnpackStatus(), (int)pNZBInfo->GetMoveStatus(), (int)pNZBInfo->GetRenameStatus());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetUnpackCleanedUpDisk());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetFileCount());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetParkedFileCount());
|
||||
|
||||
@@ -228,6 +240,13 @@ void DiskState::SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
fprintf(outfile, "%s=%s\n", pParameter->GetName(), pParameter->GetValue());
|
||||
}
|
||||
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetScriptStatuses()->size());
|
||||
for (ScriptStatusList::iterator it = pNZBInfo->GetScriptStatuses()->begin(); it != pNZBInfo->GetScriptStatuses()->end(); it++)
|
||||
{
|
||||
ScriptStatus* pScriptStatus = *it;
|
||||
fprintf(outfile, "%i,%s\n", pScriptStatus->GetStatus(), pScriptStatus->GetName());
|
||||
}
|
||||
|
||||
NZBInfo::Messages* pMessages = pNZBInfo->LockMessages();
|
||||
fprintf(outfile, "%i\n", pMessages->size());
|
||||
for (NZBInfo::Messages::iterator it = pMessages->begin(); it != pMessages->end(); it++)
|
||||
@@ -254,6 +273,13 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
pNZBInfo->AddReference();
|
||||
pDownloadQueue->GetNZBInfoList()->Add(pNZBInfo);
|
||||
|
||||
if (iFormatVersion >= 24)
|
||||
{
|
||||
int iID;
|
||||
if (fscanf(infile, "%i\n", &iID) != 1) goto error;
|
||||
pNZBInfo->SetID(iID);
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pNZBInfo->SetFilename(buf);
|
||||
@@ -269,6 +295,16 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
pNZBInfo->SetQueuedFilename(buf);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 13)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (strlen(buf) > 0)
|
||||
{
|
||||
pNZBInfo->SetName(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 4)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
@@ -277,23 +313,61 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
|
||||
int iPostProcess;
|
||||
if (fscanf(infile, "%i\n", &iPostProcess) != 1) goto error;
|
||||
pNZBInfo->SetPostProcess(iPostProcess == 1);
|
||||
pNZBInfo->SetPostProcess((bool)iPostProcess);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 8)
|
||||
if (iFormatVersion >= 8 && iFormatVersion < 18)
|
||||
{
|
||||
int iParStatus;
|
||||
if (fscanf(infile, "%i\n", &iParStatus) != 1) goto error;
|
||||
pNZBInfo->SetParStatus((NZBInfo::EParStatus)iParStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 9)
|
||||
if (iFormatVersion >= 9 && iFormatVersion < 18)
|
||||
{
|
||||
int iScriptStatus;
|
||||
if (fscanf(infile, "%i\n", &iScriptStatus) != 1) goto error;
|
||||
pNZBInfo->SetScriptStatus((NZBInfo::EScriptStatus)iScriptStatus);
|
||||
if (iScriptStatus > 1) iScriptStatus--;
|
||||
pNZBInfo->GetScriptStatuses()->Add("SCRIPT", (ScriptStatus::EStatus)iScriptStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 18)
|
||||
{
|
||||
int iParStatus, iUnpackStatus, iScriptStatus, iMoveStatus = 0, iRenameStatus = 0;
|
||||
if (iFormatVersion >= 23)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iMoveStatus, &iRenameStatus) != 4) goto error;
|
||||
}
|
||||
else if (iFormatVersion >= 21)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iScriptStatus, &iMoveStatus, &iRenameStatus) != 5) goto error;
|
||||
}
|
||||
else if (iFormatVersion >= 20)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iScriptStatus, &iMoveStatus) != 4) goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iScriptStatus) != 3) goto error;
|
||||
}
|
||||
pNZBInfo->SetParStatus((NZBInfo::EParStatus)iParStatus);
|
||||
pNZBInfo->SetUnpackStatus((NZBInfo::EUnpackStatus)iUnpackStatus);
|
||||
pNZBInfo->SetMoveStatus((NZBInfo::EMoveStatus)iMoveStatus);
|
||||
pNZBInfo->SetRenameStatus((NZBInfo::ERenameStatus)iRenameStatus);
|
||||
if (iFormatVersion < 23)
|
||||
{
|
||||
if (iScriptStatus > 1) iScriptStatus--;
|
||||
pNZBInfo->GetScriptStatuses()->Add("SCRIPT", (ScriptStatus::EStatus)iScriptStatus);
|
||||
}
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 19)
|
||||
{
|
||||
int iUnpackCleanedUpDisk;
|
||||
if (fscanf(infile, "%i\n", &iUnpackCleanedUpDisk) != 1) goto error;
|
||||
pNZBInfo->SetUnpackCleanedUpDisk((bool)iUnpackCleanedUpDisk);
|
||||
}
|
||||
|
||||
int iFileCount;
|
||||
if (fscanf(infile, "%i\n", &iFileCount) != 1) goto error;
|
||||
pNZBInfo->SetFileCount(iFileCount);
|
||||
@@ -349,6 +423,26 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
}
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 23)
|
||||
{
|
||||
int iScriptCount;
|
||||
if (fscanf(infile, "%i\n", &iScriptCount) != 1) goto error;
|
||||
for (int i = 0; i < iScriptCount; i++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
|
||||
char* szScriptName = strchr(buf, ',');
|
||||
if (szScriptName)
|
||||
{
|
||||
szScriptName++;
|
||||
int iStatus = atoi(buf);
|
||||
if (iStatus > 1 && iFormatVersion < 25) iStatus--;
|
||||
pNZBInfo->GetScriptStatuses()->Add(szScriptName, (ScriptStatus::EStatus)iStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 11)
|
||||
{
|
||||
int iLogCount;
|
||||
@@ -388,7 +482,8 @@ void DiskState::SaveFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
if (!pFileInfo->GetDeleted())
|
||||
{
|
||||
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pFileInfo->GetNZBInfo());
|
||||
fprintf(outfile, "%i,%i,%i,%i\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused(), (int)pFileInfo->GetTime());
|
||||
fprintf(outfile, "%i,%i,%i,%i,%i,%i\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused(),
|
||||
(int)pFileInfo->GetTime(), pFileInfo->GetPriority(), (int)pFileInfo->GetExtraPriority());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,17 +496,26 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
unsigned int id, iNZBIndex, paused, iTime;
|
||||
if (iFormatVersion >= 12)
|
||||
unsigned int id, iNZBIndex, paused;
|
||||
unsigned int iTime = 0;
|
||||
int iPriority = 0, iExtraPriority = 0;
|
||||
if (iFormatVersion >= 17)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime, &iPriority, &iExtraPriority) != 6) goto error;
|
||||
}
|
||||
else if (iFormatVersion >= 14)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime, &iPriority) != 5) goto error;
|
||||
}
|
||||
else if (iFormatVersion >= 12)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime) != 4) goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i\n", &id, &iNZBIndex, &paused) != 3) goto error;
|
||||
iTime = 0;
|
||||
}
|
||||
if (iNZBIndex < 0 || iNZBIndex > pDownloadQueue->GetNZBInfoList()->size()) goto error;
|
||||
if (iNZBIndex > pDownloadQueue->GetNZBInfoList()->size()) goto error;
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
@@ -423,12 +527,13 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
pFileInfo->SetID(id);
|
||||
pFileInfo->SetPaused(paused);
|
||||
pFileInfo->SetTime(iTime);
|
||||
pFileInfo->SetPriority(iPriority);
|
||||
pFileInfo->SetExtraPriority(iExtraPriority != 0);
|
||||
pFileInfo->SetNZBInfo(pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1));
|
||||
pFileQueue->push_back(pFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Could not load diskstate for file %s", fileName);
|
||||
delete pFileInfo;
|
||||
}
|
||||
}
|
||||
@@ -456,7 +561,7 @@ bool DiskState::SaveFileInfo(FileInfo* pFileInfo, const char* szFilename)
|
||||
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s", szFilename);
|
||||
error("Error saving diskstate: could not create file %s", szFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -501,7 +606,7 @@ bool DiskState::LoadFileInfo(FileInfo* pFileInfo, const char * szFilename, bool
|
||||
|
||||
if (!infile)
|
||||
{
|
||||
error("Could not open file %s", szFilename);
|
||||
error("Error reading diskstate: could not open file %s", szFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -570,14 +675,12 @@ void DiskState::SavePostQueue(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pPostInfo->GetNZBInfo());
|
||||
fprintf(outfile, "%i,%i,%i,%i\n", iNZBIndex, (int)pPostInfo->GetParCheck(),
|
||||
(int)pPostInfo->GetParStatus(), (int)pPostInfo->GetStage());
|
||||
fprintf(outfile, "%i,%i\n", iNZBIndex, (int)pPostInfo->GetStage());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetInfoName());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetParFilename());
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
|
||||
{
|
||||
debug("Loading post-queue from disk");
|
||||
|
||||
@@ -590,15 +693,27 @@ bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
PostInfo* pPostInfo = NULL;
|
||||
unsigned int iNZBIndex, iParCheck, iParStatus, iStage;
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iParCheck, &iParStatus, &iStage) != 4) goto error;
|
||||
unsigned int iNZBIndex, iStage, iDummy;
|
||||
if (iFormatVersion < 19)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iDummy, &iDummy, &iStage) != 4) goto error;
|
||||
}
|
||||
else if (iFormatVersion < 22)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iDummy, &iDummy, &iStage) != 4) goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fscanf(infile, "%i,%i\n", &iNZBIndex, &iStage) != 2) goto error;
|
||||
}
|
||||
if (iFormatVersion < 18 && iStage > (int)PostInfo::ptVerifyingRepaired) iStage++;
|
||||
if (iFormatVersion < 21 && iStage > (int)PostInfo::ptVerifyingRepaired) iStage++;
|
||||
if (iFormatVersion < 20 && iStage > (int)PostInfo::ptUnpacking) iStage++;
|
||||
|
||||
if (!bSkipPostQueue)
|
||||
{
|
||||
pPostInfo = new PostInfo();
|
||||
pPostInfo->SetNZBInfo(pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1));
|
||||
pPostInfo->SetParCheck(iParCheck);
|
||||
pPostInfo->SetParStatus((PostInfo::EParStatus)iParStatus);
|
||||
pPostInfo->SetStage((PostInfo::EStage)iStage);
|
||||
}
|
||||
|
||||
@@ -606,9 +721,11 @@ bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (!bSkipPostQueue) pPostInfo->SetInfoName(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (!bSkipPostQueue) pPostInfo->SetParFilename(buf);
|
||||
if (iFormatVersion < 22)
|
||||
{
|
||||
// ParFilename, ignore
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
}
|
||||
|
||||
if (!bSkipPostQueue)
|
||||
{
|
||||
@@ -644,7 +761,7 @@ bool DiskState::LoadOldPostQueue(DownloadQueue* pDownloadQueue)
|
||||
|
||||
if (!infile)
|
||||
{
|
||||
error("Could not open file %s", fileName);
|
||||
error("Error reading diskstate: could not open file %s", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -701,9 +818,8 @@ bool DiskState::LoadOldPostQueue(DownloadQueue* pDownloadQueue)
|
||||
pNZBInfo->SetDestDir(buf);
|
||||
}
|
||||
|
||||
// ParFilename, ignore
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pPostInfo->SetParFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
@@ -743,11 +859,11 @@ bool DiskState::LoadOldPostQueue(DownloadQueue* pDownloadQueue)
|
||||
}
|
||||
}
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParCheck(iIntValue);
|
||||
int iParCheck;
|
||||
if (fscanf(infile, "%i\n", &iParCheck) != 1) goto error; // ParCheck
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParStatus((PostInfo::EParStatus)iIntValue);
|
||||
pNZBInfo->SetParStatus(iParCheck ? (NZBInfo::EParStatus)iIntValue : NZBInfo::psSkipped);
|
||||
|
||||
if (iFormatVersion < 7)
|
||||
{
|
||||
@@ -792,6 +908,102 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
void DiskState::SaveUrlQueue(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
{
|
||||
debug("Saving url-queue to disk");
|
||||
|
||||
fprintf(outfile, "%i\n", pDownloadQueue->GetUrlQueue()->size());
|
||||
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
|
||||
{
|
||||
UrlInfo* pUrlInfo = *it;
|
||||
SaveUrlInfo(pUrlInfo, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskState::LoadUrlQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
|
||||
{
|
||||
debug("Loading url-queue from disk");
|
||||
|
||||
bool bSkipUrlQueue = !g_pOptions->GetReloadUrlQueue();
|
||||
int size;
|
||||
|
||||
// load url-infos
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
UrlInfo* pUrlInfo = NULL;
|
||||
if (!bSkipUrlQueue)
|
||||
{
|
||||
pUrlInfo = new UrlInfo();
|
||||
}
|
||||
|
||||
if (!LoadUrlInfo(pUrlInfo, infile, iFormatVersion)) goto error;
|
||||
|
||||
if (!bSkipUrlQueue)
|
||||
{
|
||||
pDownloadQueue->GetUrlQueue()->push_back(pUrlInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
error("Error reading diskstate for url-queue");
|
||||
return false;
|
||||
}
|
||||
|
||||
void DiskState::SaveUrlInfo(UrlInfo* pUrlInfo, FILE* outfile)
|
||||
{
|
||||
fprintf(outfile, "%i\n", pUrlInfo->GetID());
|
||||
fprintf(outfile, "%i,%i\n", (int)pUrlInfo->GetStatus(), pUrlInfo->GetPriority());
|
||||
fprintf(outfile, "%i,%i\n", (int)pUrlInfo->GetAddTop(), pUrlInfo->GetAddPaused());
|
||||
fprintf(outfile, "%s\n", pUrlInfo->GetURL());
|
||||
fprintf(outfile, "%s\n", pUrlInfo->GetNZBFilename());
|
||||
fprintf(outfile, "%s\n", pUrlInfo->GetCategory());
|
||||
}
|
||||
|
||||
bool DiskState::LoadUrlInfo(UrlInfo* pUrlInfo, FILE* infile, int iFormatVersion)
|
||||
{
|
||||
char buf[10240];
|
||||
|
||||
if (iFormatVersion >= 24)
|
||||
{
|
||||
int iID;
|
||||
if (fscanf(infile, "%i\n", &iID) != 1) goto error;
|
||||
pUrlInfo->SetID(iID);
|
||||
}
|
||||
|
||||
int iStatus, iPriority;
|
||||
if (fscanf(infile, "%i,%i\n", &iStatus, &iPriority) != 2) goto error;
|
||||
if (pUrlInfo) pUrlInfo->SetStatus((UrlInfo::EStatus)iStatus);
|
||||
if (pUrlInfo) pUrlInfo->SetPriority(iPriority);
|
||||
|
||||
if (iFormatVersion >= 16)
|
||||
{
|
||||
int iAddTop, iAddPaused;
|
||||
if (fscanf(infile, "%i,%i\n", &iAddTop, &iAddPaused) != 2) goto error;
|
||||
if (pUrlInfo) pUrlInfo->SetAddTop(iAddTop);
|
||||
if (pUrlInfo) pUrlInfo->SetAddPaused(iAddPaused);
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (pUrlInfo) pUrlInfo->SetURL(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (pUrlInfo) pUrlInfo->SetNZBFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (pUrlInfo) pUrlInfo->SetCategory(buf);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
return false;
|
||||
}
|
||||
|
||||
void DiskState::SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
{
|
||||
debug("Saving history to disk");
|
||||
@@ -799,14 +1011,26 @@ void DiskState::SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
fprintf(outfile, "%i\n", pDownloadQueue->GetHistoryList()->size());
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pNZBInfo);
|
||||
fprintf(outfile, "%i\n", iNZBIndex);
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetHistoryTime());
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
|
||||
fprintf(outfile, "%i\n", pHistoryInfo->GetID());
|
||||
fprintf(outfile, "%i\n", (int)pHistoryInfo->GetKind());
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pHistoryInfo->GetNZBInfo());
|
||||
fprintf(outfile, "%i\n", iNZBIndex);
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
|
||||
{
|
||||
SaveUrlInfo(pHistoryInfo->GetUrlInfo(), outfile);
|
||||
}
|
||||
|
||||
fprintf(outfile, "%i\n", (int)pHistoryInfo->GetTime());
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
|
||||
{
|
||||
debug("Loading history from disk");
|
||||
|
||||
@@ -814,23 +1038,53 @@ bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
unsigned int iNZBIndex;
|
||||
if (fscanf(infile, "%i\n", &iNZBIndex) != 1) goto error;
|
||||
HistoryInfo* pHistoryInfo = NULL;
|
||||
int iID = 0;
|
||||
|
||||
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1);
|
||||
if (iFormatVersion >= 24)
|
||||
{
|
||||
if (fscanf(infile, "%i\n", &iID) != 1) goto error;
|
||||
}
|
||||
|
||||
HistoryInfo::EKind eKind = HistoryInfo::hkNZBInfo;
|
||||
|
||||
if (iFormatVersion >= 15)
|
||||
{
|
||||
int iKind = 0;
|
||||
if (fscanf(infile, "%i\n", &iKind) != 1) goto error;
|
||||
eKind = (HistoryInfo::EKind)iKind;
|
||||
}
|
||||
|
||||
if (eKind == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
unsigned int iNZBIndex;
|
||||
if (fscanf(infile, "%i\n", &iNZBIndex) != 1) goto error;
|
||||
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1);
|
||||
pHistoryInfo = new HistoryInfo(pNZBInfo);
|
||||
}
|
||||
else if (eKind == HistoryInfo::hkUrlInfo)
|
||||
{
|
||||
UrlInfo* pUrlInfo = new UrlInfo();
|
||||
if (!LoadUrlInfo(pUrlInfo, infile, iFormatVersion)) goto error;
|
||||
pHistoryInfo = new HistoryInfo(pUrlInfo);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 24)
|
||||
{
|
||||
pHistoryInfo->SetID(iID);
|
||||
}
|
||||
|
||||
int iTime;
|
||||
if (fscanf(infile, "%i\n", &iTime) != 1) goto error;
|
||||
pNZBInfo->SetHistoryTime((time_t)iTime);
|
||||
pHistoryInfo->SetTime((time_t)iTime);
|
||||
|
||||
pNZBInfo->AddReference();
|
||||
pDownloadQueue->GetHistoryList()->push_back(pNZBInfo);
|
||||
pDownloadQueue->GetHistoryList()->push_back(pHistoryInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
error("Error reading diskstate for post-processor queue");
|
||||
error("Error reading diskstate for history");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -850,124 +1104,37 @@ int DiskState::FindNZBInfoIndex(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all files from Queue.
|
||||
* Returns true if successful, false if not
|
||||
* Deletes whole download queue including history.
|
||||
*/
|
||||
bool DiskState::DiscardDownloadQueue()
|
||||
void DiskState::DiscardDownloadQueue()
|
||||
{
|
||||
debug("Discarding queue");
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
|
||||
fileName[1024-1] = '\0';
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
|
||||
szFullFilename[1024-1] = '\0';
|
||||
remove(szFullFilename);
|
||||
|
||||
FILE* infile = fopen(fileName, "rb");
|
||||
|
||||
if (!infile)
|
||||
DirBrowser dir(g_pOptions->GetQueueDir());
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
error("Could not open file %s", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
int iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (3 <= iFormatVersion && iFormatVersion <= 12)
|
||||
{
|
||||
// skip nzb-infos
|
||||
int size = 0;
|
||||
char buf[1024];
|
||||
fscanf(infile, "%i\n", &size);
|
||||
for (int i = 0; i < size; i++)
|
||||
// delete all files whose names have only characters '0'..'9'
|
||||
bool bOnlyNums = true;
|
||||
for (const char* p = filename; *p != '\0'; p++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // filename
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // destdir
|
||||
if (iFormatVersion >= 5)
|
||||
if (!('0' <= *p && *p <= '9'))
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // localfile
|
||||
}
|
||||
if (iFormatVersion >= 4)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // category
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // postprocess
|
||||
}
|
||||
if (iFormatVersion >= 8)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ParStatus
|
||||
}
|
||||
if (iFormatVersion >= 9)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ScriptStatus
|
||||
}
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // file count
|
||||
if (iFormatVersion >= 10)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // parked file count
|
||||
}
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // file size
|
||||
if (iFormatVersion >= 4)
|
||||
{
|
||||
// completed files
|
||||
int iFileCount;
|
||||
if (fscanf(infile, "%i\n", &iFileCount) != 1) break;
|
||||
for (int i = 0; i < iFileCount; i++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // filename
|
||||
}
|
||||
}
|
||||
if (iFormatVersion >= 6)
|
||||
{
|
||||
// postprocess-parameters
|
||||
int iParameterCount;
|
||||
if (fscanf(infile, "%i\n", &iParameterCount) != 1) break;
|
||||
for (int i = 0; i < iParameterCount; i++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 11)
|
||||
{
|
||||
// log-messages
|
||||
int iLogCount;
|
||||
if (fscanf(infile, "%i\n", &iLogCount) != 1) break;
|
||||
for (int i = 0; i < iLogCount; i++)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
}
|
||||
bOnlyNums = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// file-infos
|
||||
fscanf(infile, "%i\n", &size);
|
||||
for (int i = 0; i < size; i++)
|
||||
if (bOnlyNums)
|
||||
{
|
||||
int id;
|
||||
char tr[100];
|
||||
if (fscanf(infile, "%i,%s\n", &id, &tr) == 2)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
}
|
||||
snprintf(szFullFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
remove(szFullFilename);
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not discard diskstate due to file version mismatch");
|
||||
res = false;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
if (res)
|
||||
{
|
||||
remove(fileName);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DiskState::DownloadQueueExists()
|
||||
|
||||
14
DiskState.h
14
DiskState.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -39,10 +39,14 @@ private:
|
||||
void SaveFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQueue, FILE* outfile);
|
||||
bool LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQueue, FILE* infile, int iFormatVersion);
|
||||
void SavePostQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile);
|
||||
bool LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
bool LoadOldPostQueue(DownloadQueue* pDownloadQueue);
|
||||
void SaveUrlQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadUrlQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
void SaveUrlInfo(UrlInfo* pUrlInfo, FILE* outfile);
|
||||
bool LoadUrlInfo(UrlInfo* pUrlInfo, FILE* infile, int iFormatVersion);
|
||||
void SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile);
|
||||
bool LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
int FindNZBInfoIndex(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
|
||||
public:
|
||||
@@ -52,7 +56,7 @@ public:
|
||||
bool LoadDownloadQueue(DownloadQueue* pDownloadQueue);
|
||||
bool SaveFile(FileInfo* pFileInfo);
|
||||
bool LoadArticles(FileInfo* pFileInfo);
|
||||
bool DiscardDownloadQueue();
|
||||
void DiscardDownloadQueue();
|
||||
bool DiscardFile(FileInfo* pFileInfo);
|
||||
void CleanupTempDir(DownloadQueue* pDownloadQueue);
|
||||
};
|
||||
|
||||
472
DownloadInfo.cpp
472
DownloadInfo.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -34,9 +34,10 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <map>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "DownloadInfo.h"
|
||||
@@ -49,6 +50,8 @@ extern Options* g_pOptions;
|
||||
int FileInfo::m_iIDGen = 0;
|
||||
int NZBInfo::m_iIDGen = 0;
|
||||
int PostInfo::m_iIDGen = 0;
|
||||
int UrlInfo::m_iIDGen = 0;
|
||||
int HistoryInfo::m_iIDGen = 0;
|
||||
|
||||
NZBParameter::NZBParameter(const char* szName)
|
||||
{
|
||||
@@ -114,6 +117,59 @@ void NZBParameterList::SetParameter(const char* szName, const char* szValue)
|
||||
}
|
||||
|
||||
|
||||
ScriptStatus::ScriptStatus(const char* szName, EStatus eStatus)
|
||||
{
|
||||
m_szName = strdup(szName);
|
||||
m_eStatus = eStatus;
|
||||
}
|
||||
|
||||
ScriptStatus::~ScriptStatus()
|
||||
{
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScriptStatusList::~ScriptStatusList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void ScriptStatusList::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
void ScriptStatusList::Add(const char* szScriptName, ScriptStatus::EStatus eStatus)
|
||||
{
|
||||
push_back(new ScriptStatus(szScriptName, eStatus));
|
||||
}
|
||||
|
||||
ScriptStatus::EStatus ScriptStatusList::CalcTotalStatus()
|
||||
{
|
||||
ScriptStatus::EStatus eStatus = ScriptStatus::srNone;
|
||||
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
ScriptStatus* pScriptStatus = *it;
|
||||
// Failure-Status overrides Success-Status
|
||||
if ((pScriptStatus->GetStatus() == ScriptStatus::srSuccess && eStatus == ScriptStatus::srNone) ||
|
||||
(pScriptStatus->GetStatus() == ScriptStatus::srFailure))
|
||||
{
|
||||
eStatus = pScriptStatus->GetStatus();
|
||||
}
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
|
||||
NZBInfo::NZBInfo()
|
||||
{
|
||||
debug("Creating NZBInfo");
|
||||
@@ -121,18 +177,22 @@ NZBInfo::NZBInfo()
|
||||
m_szFilename = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_szCategory = strdup("");
|
||||
m_szName = NULL;
|
||||
m_iFileCount = 0;
|
||||
m_iParkedFileCount = 0;
|
||||
m_lSize = 0;
|
||||
m_iRefCount = 0;
|
||||
m_bPostProcess = false;
|
||||
m_eParStatus = prNone;
|
||||
m_eScriptStatus = srNone;
|
||||
m_eRenameStatus = rsNone;
|
||||
m_eParStatus = psNone;
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eCleanupStatus = csNone;
|
||||
m_eMoveStatus = msNone;
|
||||
m_bDeleted = false;
|
||||
m_bParCleanup = false;
|
||||
m_bCleanupDisk = false;
|
||||
m_bUnpackCleanedUpDisk = false;
|
||||
m_szQueuedFilename = strdup("");
|
||||
m_tHistoryTime = 0;
|
||||
m_Owner = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDMessageGen = 0;
|
||||
@@ -156,6 +216,10 @@ NZBInfo::~NZBInfo()
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
if (m_szQueuedFilename)
|
||||
{
|
||||
free(m_szQueuedFilename);
|
||||
@@ -195,6 +259,15 @@ void NZBInfo::Release()
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::ClearCompletedFiles()
|
||||
{
|
||||
for (Files::iterator it = m_completedFiles.begin(); it != m_completedFiles.end(); it++)
|
||||
@@ -220,6 +293,23 @@ void NZBInfo::SetFilename(const char * szFilename)
|
||||
free(m_szFilename);
|
||||
}
|
||||
m_szFilename = strdup(szFilename);
|
||||
|
||||
if (!m_szName)
|
||||
{
|
||||
char szNZBNicename[1024];
|
||||
MakeNiceNZBName(m_szFilename, szNZBNicename, sizeof(szNZBNicename), true);
|
||||
szNZBNicename[1024-1] = '\0';
|
||||
SetName(szNZBNicename);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::SetName(const char* szName)
|
||||
{
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
m_szName = szName ? strdup(szName) : NULL;
|
||||
}
|
||||
|
||||
void NZBInfo::SetCategory(const char* szCategory)
|
||||
@@ -240,96 +330,78 @@ void NZBInfo::SetQueuedFilename(const char * szQueuedFilename)
|
||||
m_szQueuedFilename = strdup(szQueuedFilename);
|
||||
}
|
||||
|
||||
void NZBInfo::GetNiceNZBName(char* szBuffer, int iSize)
|
||||
{
|
||||
MakeNiceNZBName(m_szFilename, szBuffer, iSize);
|
||||
}
|
||||
|
||||
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize)
|
||||
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize, bool bRemoveExt)
|
||||
{
|
||||
char postname[1024];
|
||||
const char* szBaseName = Util::BaseFileName(szNZBFilename);
|
||||
|
||||
// if .nzb file has a certain structure, try to strip out certain elements
|
||||
if (sscanf(szBaseName, "msgid_%*d_%1023s", postname) == 1)
|
||||
{
|
||||
// OK, using stripped name
|
||||
}
|
||||
else
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
}
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
if (bRemoveExt)
|
||||
{
|
||||
// wipe out ".nzb"
|
||||
char* p = strrchr(postname, '.');
|
||||
if (p && !strcasecmp(p, ".nzb")) *p = '\0';
|
||||
}
|
||||
|
||||
Util::MakeValidFilename(postname, '_', false);
|
||||
|
||||
// if the resulting name is empty, use basename without cleaning up "msgid_"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
|
||||
Util::MakeValidFilename(postname, '_', false);
|
||||
|
||||
// if the resulting name is STILL empty, use "noname"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
strncpy(postname, "noname", 1024);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(szBuffer, postname, iSize);
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
|
||||
void NZBInfo::BuildDestDirName()
|
||||
{
|
||||
char szBuffer[1024];
|
||||
char szCategory[1024];
|
||||
bool bHasCategory = m_szCategory && m_szCategory[0] != '\0';
|
||||
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
|
||||
{
|
||||
strncpy(szCategory, m_szCategory, 1024);
|
||||
szCategory[1024 - 1] = '\0';
|
||||
Util::MakeValidFilename(szCategory, '_', true);
|
||||
}
|
||||
char szDestDir[1024];
|
||||
|
||||
if (g_pOptions->GetAppendNZBDir())
|
||||
if (strlen(g_pOptions->GetInterDir()) == 0)
|
||||
{
|
||||
char szNiceNZBName[1024];
|
||||
GetNiceNZBName(szNiceNZBName, 1024);
|
||||
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s%c%s", g_pOptions->GetDestDir(), szCategory, PATH_SEPARATOR, szNiceNZBName);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s", g_pOptions->GetDestDir(), szNiceNZBName);
|
||||
}
|
||||
szBuffer[1024-1] = '\0';
|
||||
BuildFinalDirName(szDestDir, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s", g_pOptions->GetDestDir(), szCategory);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(szBuffer, g_pOptions->GetDestDir(), 1024);
|
||||
}
|
||||
szBuffer[1024-1] = '\0'; // trim the last slash, always returned by GetDestDir()
|
||||
snprintf(szDestDir, 1024, "%s%s", g_pOptions->GetInterDir(), GetName());
|
||||
szDestDir[1024-1] = '\0';
|
||||
}
|
||||
|
||||
SetDestDir(szBuffer);
|
||||
SetDestDir(szDestDir);
|
||||
}
|
||||
|
||||
void NZBInfo::BuildFinalDirName(char* szFinalDirBuf, int iBufSize)
|
||||
{
|
||||
char szBuffer[1024];
|
||||
bool bUseCategory = m_szCategory && m_szCategory[0] != '\0';
|
||||
|
||||
snprintf(szFinalDirBuf, iBufSize, "%s", g_pOptions->GetDestDir());
|
||||
szFinalDirBuf[iBufSize-1] = '\0';
|
||||
|
||||
if (bUseCategory)
|
||||
{
|
||||
Options::Category *pCategory = g_pOptions->FindCategory(m_szCategory);
|
||||
if (pCategory && pCategory->GetDestDir() && pCategory->GetDestDir()[0] != '\0')
|
||||
{
|
||||
snprintf(szFinalDirBuf, iBufSize, "%s", pCategory->GetDestDir());
|
||||
szFinalDirBuf[iBufSize-1] = '\0';
|
||||
bUseCategory = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pOptions->GetAppendCategoryDir() && bUseCategory)
|
||||
{
|
||||
char szCategoryDir[1024];
|
||||
strncpy(szCategoryDir, m_szCategory, 1024);
|
||||
szCategoryDir[1024 - 1] = '\0';
|
||||
Util::MakeValidFilename(szCategoryDir, '_', true);
|
||||
|
||||
snprintf(szBuffer, 1024, "%s%s%c", szFinalDirBuf, szCategoryDir, PATH_SEPARATOR);
|
||||
szBuffer[1024-1] = '\0';
|
||||
strncpy(szFinalDirBuf, szBuffer, iBufSize);
|
||||
}
|
||||
|
||||
snprintf(szBuffer, 1024, "%s%s", szFinalDirBuf, GetName());
|
||||
szBuffer[1024-1] = '\0';
|
||||
strncpy(szFinalDirBuf, szBuffer, iBufSize);
|
||||
}
|
||||
|
||||
void NZBInfo::SetParameter(const char* szName, const char* szValue)
|
||||
@@ -355,9 +427,8 @@ void NZBInfo::AppendMessage(Message::EKind eKind, time_t tTime, const char * szT
|
||||
tTime = time(NULL);
|
||||
}
|
||||
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
@@ -447,6 +518,8 @@ FileInfo::FileInfo()
|
||||
m_Groups.clear();
|
||||
m_szSubject = NULL;
|
||||
m_szFilename = NULL;
|
||||
m_szOutputFilename = NULL;
|
||||
m_pMutexOutputFile = NULL;
|
||||
m_bFilenameConfirmed = false;
|
||||
m_lSize = 0;
|
||||
m_lRemainingSize = 0;
|
||||
@@ -456,6 +529,10 @@ FileInfo::FileInfo()
|
||||
m_iCompleted = 0;
|
||||
m_bOutputInitialized = false;
|
||||
m_pNZBInfo = NULL;
|
||||
m_iPriority = 0;
|
||||
m_bExtraPriority = false;
|
||||
m_iActiveDownloads = 0;
|
||||
m_bAutoDeleted = false;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
@@ -472,6 +549,14 @@ FileInfo::~ FileInfo()
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
if (m_pMutexOutputFile)
|
||||
{
|
||||
delete m_pMutexOutputFile;
|
||||
}
|
||||
|
||||
for (Groups::iterator it = m_Groups.begin(); it != m_Groups.end() ;it++)
|
||||
{
|
||||
@@ -496,9 +581,9 @@ void FileInfo::ClearArticles()
|
||||
m_Articles.clear();
|
||||
}
|
||||
|
||||
void FileInfo::SetID(int s)
|
||||
void FileInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = s;
|
||||
m_iID = iID;
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDGen = m_iID;
|
||||
@@ -536,12 +621,36 @@ void FileInfo::MakeValidFilename()
|
||||
|
||||
void FileInfo::LockOutputFile()
|
||||
{
|
||||
m_mutexOutputFile.Lock();
|
||||
m_pMutexOutputFile->Lock();
|
||||
}
|
||||
|
||||
void FileInfo::UnlockOutputFile()
|
||||
{
|
||||
m_mutexOutputFile.Unlock();
|
||||
m_pMutexOutputFile->Unlock();
|
||||
}
|
||||
|
||||
void FileInfo::SetOutputFilename(const char* szOutputFilename)
|
||||
{
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
m_szOutputFilename = strdup(szOutputFilename);
|
||||
}
|
||||
|
||||
void FileInfo::SetActiveDownloads(int iActiveDownloads)
|
||||
{
|
||||
m_iActiveDownloads = iActiveDownloads;
|
||||
|
||||
if (m_iActiveDownloads > 0 && !m_pMutexOutputFile)
|
||||
{
|
||||
m_pMutexOutputFile = new Mutex();
|
||||
}
|
||||
else if (m_iActiveDownloads == 0 && m_pMutexOutputFile)
|
||||
{
|
||||
delete m_pMutexOutputFile;
|
||||
m_pMutexOutputFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileInfo::IsDupe(const char* szFilename)
|
||||
@@ -574,6 +683,9 @@ GroupInfo::GroupInfo()
|
||||
m_iRemainingParCount = 0;
|
||||
m_tMinTime = 0;
|
||||
m_tMaxTime = 0;
|
||||
m_iMinPriority = 0;
|
||||
m_iMaxPriority = 0;
|
||||
m_iActiveDownloads = 0;
|
||||
}
|
||||
|
||||
GroupInfo::~GroupInfo()
|
||||
@@ -589,21 +701,18 @@ PostInfo::PostInfo()
|
||||
debug("Creating PostInfo");
|
||||
|
||||
m_pNZBInfo = NULL;
|
||||
m_szParFilename = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_bWorking = false;
|
||||
m_bDeleted = false;
|
||||
m_bParCheck = false;
|
||||
m_eParStatus = psNone;
|
||||
m_eRequestParCheck = rpNone;
|
||||
m_eScriptStatus = srNone;
|
||||
m_bRequestParCheck = false;
|
||||
m_bRequestParRename = false;
|
||||
m_szProgressLabel = strdup("");
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_tStartTime = 0;
|
||||
m_tStageTime = 0;
|
||||
m_eStage = ptQueued;
|
||||
m_pScriptThread = NULL;
|
||||
m_pPostThread = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDMessageGen = 0;
|
||||
m_iIDGen++;
|
||||
@@ -614,10 +723,6 @@ PostInfo::~ PostInfo()
|
||||
{
|
||||
debug("Destroying PostInfo");
|
||||
|
||||
if (m_szParFilename)
|
||||
{
|
||||
free(m_szParFilename);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
@@ -649,11 +754,6 @@ void PostInfo::SetNZBInfo(NZBInfo* pNZBInfo)
|
||||
m_pNZBInfo->AddReference();
|
||||
}
|
||||
|
||||
void PostInfo::SetParFilename(const char* szParFilename)
|
||||
{
|
||||
m_szParFilename = strdup(szParFilename);
|
||||
}
|
||||
|
||||
void PostInfo::SetInfoName(const char* szInfoName)
|
||||
{
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
@@ -681,9 +781,8 @@ void PostInfo::UnlockMessages()
|
||||
|
||||
void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
@@ -697,19 +796,12 @@ void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
|
||||
void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
{
|
||||
std::map<int, GroupInfo*> groupMap;
|
||||
|
||||
for (FileQueue::iterator it = GetFileQueue()->begin(); it != GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
GroupInfo* pGroupInfo = NULL;
|
||||
for (GroupQueue::iterator itg = pGroupQueue->begin(); itg != pGroupQueue->end(); itg++)
|
||||
{
|
||||
GroupInfo* pGroupInfo1 = *itg;
|
||||
if (pGroupInfo1->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
pGroupInfo = pGroupInfo1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
GroupInfo *&pGroupInfo = groupMap[pFileInfo->GetNZBInfo()->GetID()];
|
||||
if (!pGroupInfo)
|
||||
{
|
||||
pGroupInfo = new GroupInfo();
|
||||
@@ -719,6 +811,8 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
pGroupInfo->m_iLastID = pFileInfo->GetID();
|
||||
pGroupInfo->m_tMinTime = pFileInfo->GetTime();
|
||||
pGroupInfo->m_tMaxTime = pFileInfo->GetTime();
|
||||
pGroupInfo->m_iMinPriority = pFileInfo->GetPriority();
|
||||
pGroupInfo->m_iMaxPriority = pFileInfo->GetPriority();
|
||||
pGroupQueue->push_back(pGroupInfo);
|
||||
}
|
||||
if (pFileInfo->GetID() < pGroupInfo->GetFirstID())
|
||||
@@ -740,6 +834,16 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
pGroupInfo->m_tMaxTime = pFileInfo->GetTime();
|
||||
}
|
||||
}
|
||||
if (pFileInfo->GetPriority() < pGroupInfo->GetMinPriority())
|
||||
{
|
||||
pGroupInfo->m_iMinPriority = pFileInfo->GetPriority();
|
||||
}
|
||||
if (pFileInfo->GetPriority() > pGroupInfo->GetMaxPriority())
|
||||
{
|
||||
pGroupInfo->m_iMaxPriority = pFileInfo->GetPriority();
|
||||
}
|
||||
|
||||
pGroupInfo->m_iActiveDownloads += pFileInfo->GetActiveDownloads();
|
||||
pGroupInfo->m_iRemainingFileCount++;
|
||||
pGroupInfo->m_lRemainingSize += pFileInfo->GetRemainingSize();
|
||||
if (pFileInfo->GetPaused())
|
||||
@@ -758,3 +862,151 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UrlInfo::UrlInfo()
|
||||
{
|
||||
//debug("Creating ArticleInfo");
|
||||
m_szURL = NULL;
|
||||
m_szNZBFilename = strdup("");
|
||||
m_szCategory = strdup("");
|
||||
m_iPriority = 0;
|
||||
m_bAddTop = false;
|
||||
m_bAddPaused = false;
|
||||
m_eStatus = aiUndefined;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
UrlInfo::~ UrlInfo()
|
||||
{
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
}
|
||||
|
||||
void UrlInfo::SetURL(const char* szURL)
|
||||
{
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
m_szURL = strdup(szURL);
|
||||
}
|
||||
|
||||
void UrlInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void UrlInfo::SetNZBFilename(const char* szNZBFilename)
|
||||
{
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
m_szNZBFilename = strdup(szNZBFilename);
|
||||
}
|
||||
|
||||
void UrlInfo::SetCategory(const char* szCategory)
|
||||
{
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
m_szCategory = strdup(szCategory);
|
||||
}
|
||||
|
||||
void UrlInfo::GetName(char* szBuffer, int iSize)
|
||||
{
|
||||
MakeNiceName(m_szURL, m_szNZBFilename, szBuffer, iSize);
|
||||
}
|
||||
|
||||
void UrlInfo::MakeNiceName(const char* szURL, const char* szNZBFilename, char* szBuffer, int iSize)
|
||||
{
|
||||
URL url(szURL);
|
||||
|
||||
if (strlen(szNZBFilename) > 0)
|
||||
{
|
||||
char szNZBNicename[1024];
|
||||
NZBInfo::MakeNiceNZBName(szNZBFilename, szNZBNicename, sizeof(szNZBNicename), true);
|
||||
snprintf(szBuffer, iSize, "%s @ %s", szNZBNicename, url.GetHost());
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szBuffer, iSize, "%s%s", url.GetHost(), url.GetResource());
|
||||
}
|
||||
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
|
||||
|
||||
HistoryInfo::HistoryInfo(NZBInfo* pNZBInfo)
|
||||
{
|
||||
m_eKind = hkNZBInfo;
|
||||
m_pInfo = pNZBInfo;
|
||||
pNZBInfo->AddReference();
|
||||
m_tTime = 0;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
HistoryInfo::HistoryInfo(UrlInfo* pUrlInfo)
|
||||
{
|
||||
m_eKind = hkUrlInfo;
|
||||
m_pInfo = pUrlInfo;
|
||||
m_tTime = 0;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
HistoryInfo::~HistoryInfo()
|
||||
{
|
||||
if (m_eKind == hkNZBInfo && m_pInfo)
|
||||
{
|
||||
((NZBInfo*)m_pInfo)->Release();
|
||||
}
|
||||
else if (m_eKind == hkUrlInfo && m_pInfo)
|
||||
{
|
||||
delete (UrlInfo*)m_pInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInfo::GetName(char* szBuffer, int iSize)
|
||||
{
|
||||
if (m_eKind == hkNZBInfo)
|
||||
{
|
||||
strncpy(szBuffer, GetNZBInfo()->GetName(), iSize);
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
else if (m_eKind == hkUrlInfo)
|
||||
{
|
||||
GetUrlInfo()->GetName(szBuffer, iSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(szBuffer, "<unknown>", iSize);
|
||||
}
|
||||
}
|
||||
|
||||
280
DownloadInfo.h
280
DownloadInfo.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -91,7 +91,12 @@ private:
|
||||
bool m_bFilenameConfirmed;
|
||||
int m_iCompleted;
|
||||
bool m_bOutputInitialized;
|
||||
Mutex m_mutexOutputFile;
|
||||
char* m_szOutputFilename;
|
||||
Mutex* m_pMutexOutputFile;
|
||||
int m_iPriority;
|
||||
bool m_bExtraPriority;
|
||||
int m_iActiveDownloads;
|
||||
bool m_bAutoDeleted;
|
||||
|
||||
static int m_iIDGen;
|
||||
|
||||
@@ -99,7 +104,7 @@ public:
|
||||
FileInfo();
|
||||
~FileInfo();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int s);
|
||||
void SetID(int iID);
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
void SetNZBInfo(NZBInfo* pNZBInfo);
|
||||
Articles* GetArticles() { return &m_Articles; }
|
||||
@@ -126,9 +131,19 @@ public:
|
||||
void ClearArticles();
|
||||
void LockOutputFile();
|
||||
void UnlockOutputFile();
|
||||
const char* GetOutputFilename() { return m_szOutputFilename; }
|
||||
void SetOutputFilename(const char* szOutputFilename);
|
||||
bool GetOutputInitialized() { return m_bOutputInitialized; }
|
||||
void SetOutputInitialized(bool bOutputInitialized) { m_bOutputInitialized = bOutputInitialized; }
|
||||
bool IsDupe(const char* szFilename);
|
||||
int GetPriority() { return m_iPriority; }
|
||||
void SetPriority(int iPriority) { m_iPriority = iPriority; }
|
||||
bool GetExtraPriority() { return m_bExtraPriority; }
|
||||
void SetExtraPriority(bool bExtraPriority) { m_bExtraPriority = bExtraPriority; };
|
||||
int GetActiveDownloads() { return m_iActiveDownloads; }
|
||||
void SetActiveDownloads(int iActiveDownloads);
|
||||
bool GetAutoDeleted() { return m_bAutoDeleted; }
|
||||
void SetAutoDeleted(bool bAutoDeleted) { m_bAutoDeleted = bAutoDeleted; }
|
||||
};
|
||||
|
||||
typedef std::deque<FileInfo*> FileQueue;
|
||||
@@ -146,6 +161,9 @@ private:
|
||||
int m_iRemainingParCount;
|
||||
time_t m_tMinTime;
|
||||
time_t m_tMaxTime;
|
||||
int m_iMinPriority;
|
||||
int m_iMaxPriority;
|
||||
int m_iActiveDownloads;
|
||||
|
||||
friend class DownloadQueue;
|
||||
|
||||
@@ -162,6 +180,9 @@ public:
|
||||
int GetRemainingParCount() { return m_iRemainingParCount; }
|
||||
time_t GetMinTime() { return m_tMinTime; }
|
||||
time_t GetMaxTime() { return m_tMaxTime; }
|
||||
int GetMinPriority() { return m_iMinPriority; }
|
||||
int GetMaxPriority() { return m_iMaxPriority; }
|
||||
int GetActiveDownloads() { return m_iActiveDownloads; }
|
||||
};
|
||||
|
||||
typedef std::deque<GroupInfo*> GroupQueue;
|
||||
@@ -191,25 +212,83 @@ public:
|
||||
void SetParameter(const char* szName, const char* szValue);
|
||||
};
|
||||
|
||||
class ScriptStatus
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
srNone,
|
||||
srFailure,
|
||||
srSuccess
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szName;
|
||||
EStatus m_eStatus;
|
||||
|
||||
friend class ScriptStatusList;
|
||||
|
||||
public:
|
||||
ScriptStatus(const char* szName, EStatus eStatus);
|
||||
~ScriptStatus();
|
||||
const char* GetName() { return m_szName; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
};
|
||||
|
||||
typedef std::deque<ScriptStatus*> ScriptStatusListBase;
|
||||
|
||||
class ScriptStatusList : public ScriptStatusListBase
|
||||
{
|
||||
public:
|
||||
~ScriptStatusList();
|
||||
void Add(const char* szScriptName, ScriptStatus::EStatus eStatus);
|
||||
void Clear();
|
||||
ScriptStatus::EStatus CalcTotalStatus();
|
||||
};
|
||||
|
||||
class NZBInfoList;
|
||||
|
||||
class NZBInfo
|
||||
{
|
||||
public:
|
||||
enum EParStatus
|
||||
enum ERenameStatus
|
||||
{
|
||||
prNone,
|
||||
prFailure,
|
||||
prRepairPossible,
|
||||
prSuccess
|
||||
rsNone,
|
||||
rsSkipped,
|
||||
rsFailure,
|
||||
rsSuccess
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
enum EParStatus
|
||||
{
|
||||
srNone,
|
||||
srUnknown,
|
||||
srFailure,
|
||||
srSuccess
|
||||
psNone,
|
||||
psSkipped,
|
||||
psFailure,
|
||||
psSuccess,
|
||||
psRepairPossible,
|
||||
psManual
|
||||
};
|
||||
|
||||
enum EUnpackStatus
|
||||
{
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess
|
||||
};
|
||||
|
||||
enum ECleanupStatus
|
||||
{
|
||||
csNone,
|
||||
csFailure,
|
||||
csSuccess
|
||||
};
|
||||
|
||||
enum EMoveStatus
|
||||
{
|
||||
msNone,
|
||||
msFailure,
|
||||
msSuccess
|
||||
};
|
||||
|
||||
typedef std::vector<char*> Files;
|
||||
@@ -219,6 +298,7 @@ private:
|
||||
int m_iID;
|
||||
int m_iRefCount;
|
||||
char* m_szFilename;
|
||||
char* m_szName;
|
||||
char* m_szDestDir;
|
||||
char* m_szCategory;
|
||||
int m_iFileCount;
|
||||
@@ -226,15 +306,20 @@ private:
|
||||
long long m_lSize;
|
||||
Files m_completedFiles;
|
||||
bool m_bPostProcess;
|
||||
ERenameStatus m_eRenameStatus;
|
||||
EParStatus m_eParStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
ECleanupStatus m_eCleanupStatus;
|
||||
EMoveStatus m_eMoveStatus;
|
||||
char* m_szQueuedFilename;
|
||||
bool m_bDeleted;
|
||||
bool m_bParCleanup;
|
||||
bool m_bParManual;
|
||||
bool m_bCleanupDisk;
|
||||
time_t m_tHistoryTime;
|
||||
bool m_bUnpackCleanedUpDisk;
|
||||
NZBInfoList* m_Owner;
|
||||
NZBParameterList m_ppParameters;
|
||||
ScriptStatusList m_scriptStatuses;
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
int m_iIDMessageGen;
|
||||
@@ -249,14 +334,16 @@ public:
|
||||
void AddReference();
|
||||
void Release();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int iID);
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
void SetFilename(const char* szFilename);
|
||||
void GetNiceNZBName(char* szBuffer, int iSize);
|
||||
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize);
|
||||
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize, bool bRemoveExt);
|
||||
const char* GetDestDir() { return m_szDestDir; } // needs locking (for shared objects)
|
||||
void SetDestDir(const char* szDestDir); // needs locking (for shared objects)
|
||||
const char* GetCategory() { return m_szCategory; } // needs locking (for shared objects)
|
||||
void SetCategory(const char* szCategory); // needs locking (for shared objects)
|
||||
const char* GetName() { return m_szName; } // needs locking (for shared objects)
|
||||
void SetName(const char* szName); // needs locking (for shared objects)
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; }
|
||||
int GetFileCount() { return m_iFileCount; }
|
||||
@@ -264,14 +351,21 @@ public:
|
||||
int GetParkedFileCount() { return m_iParkedFileCount; }
|
||||
void SetParkedFileCount(int iParkedFileCount) { m_iParkedFileCount = iParkedFileCount; }
|
||||
void BuildDestDirName();
|
||||
void BuildFinalDirName(char* szFinalDirBuf, int iBufSize);
|
||||
Files* GetCompletedFiles() { return &m_completedFiles; } // needs locking (for shared objects)
|
||||
void ClearCompletedFiles();
|
||||
bool GetPostProcess() { return m_bPostProcess; }
|
||||
void SetPostProcess(bool bPostProcess) { m_bPostProcess = bPostProcess; }
|
||||
ERenameStatus GetRenameStatus() { return m_eRenameStatus; }
|
||||
void SetRenameStatus(ERenameStatus eRenameStatus) { m_eRenameStatus = eRenameStatus; }
|
||||
EParStatus GetParStatus() { return m_eParStatus; }
|
||||
void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
void SetScriptStatus(EScriptStatus eScriptStatus) { m_eScriptStatus = eScriptStatus; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; }
|
||||
void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; }
|
||||
ECleanupStatus GetCleanupStatus() { return m_eCleanupStatus; }
|
||||
void SetCleanupStatus(ECleanupStatus eCleanupStatus) { m_eCleanupStatus = eCleanupStatus; }
|
||||
EMoveStatus GetMoveStatus() { return m_eMoveStatus; }
|
||||
void SetMoveStatus(EMoveStatus eMoveStatus) { m_eMoveStatus = eMoveStatus; }
|
||||
const char* GetQueuedFilename() { return m_szQueuedFilename; }
|
||||
void SetQueuedFilename(const char* szQueuedFilename);
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
@@ -280,10 +374,11 @@ public:
|
||||
void SetParCleanup(bool bParCleanup) { m_bParCleanup = bParCleanup; }
|
||||
bool GetCleanupDisk() { return m_bCleanupDisk; }
|
||||
void SetCleanupDisk(bool bCleanupDisk) { m_bCleanupDisk = bCleanupDisk; }
|
||||
time_t GetHistoryTime() { return m_tHistoryTime; }
|
||||
void SetHistoryTime(time_t tHistoryTime) { m_tHistoryTime = tHistoryTime; }
|
||||
bool GetUnpackCleanedUpDisk() { return m_bUnpackCleanedUpDisk; }
|
||||
void SetUnpackCleanedUpDisk(bool bUnpackCleanedUpDisk) { m_bUnpackCleanedUpDisk = bUnpackCleanedUpDisk; }
|
||||
NZBParameterList* GetParameters() { return &m_ppParameters; } // needs locking (for shared objects)
|
||||
void SetParameter(const char* szName, const char* szValue); // needs locking (for shared objects)
|
||||
ScriptStatusList* GetScriptStatuses() { return &m_scriptStatuses; } // needs locking (for shared objects)
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
@@ -309,53 +404,30 @@ public:
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
ptRenaming,
|
||||
ptUnpacking,
|
||||
ptMoving,
|
||||
ptExecutingScript,
|
||||
ptFinished
|
||||
};
|
||||
|
||||
enum EParStatus
|
||||
{
|
||||
psNone,
|
||||
psFailure,
|
||||
psSuccess,
|
||||
psRepairPossible
|
||||
};
|
||||
|
||||
enum ERequestParCheck
|
||||
{
|
||||
rpNone,
|
||||
rpCurrent,
|
||||
rpAll
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
{
|
||||
srNone,
|
||||
srUnknown,
|
||||
srFailure,
|
||||
srSuccess
|
||||
};
|
||||
|
||||
typedef std::deque<Message*> Messages;
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
NZBInfo* m_pNZBInfo;
|
||||
char* m_szParFilename;
|
||||
char* m_szInfoName;
|
||||
bool m_bWorking;
|
||||
bool m_bDeleted;
|
||||
bool m_bParCheck;
|
||||
EParStatus m_eParStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
ERequestParCheck m_eRequestParCheck;
|
||||
bool m_bRequestParCheck;
|
||||
bool m_bRequestParRename;
|
||||
EStage m_eStage;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
int m_iStageProgress;
|
||||
time_t m_tStartTime;
|
||||
time_t m_tStageTime;
|
||||
Thread* m_pScriptThread;
|
||||
Thread* m_pPostThread;
|
||||
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
@@ -369,8 +441,6 @@ public:
|
||||
int GetID() { return m_iID; }
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
void SetNZBInfo(NZBInfo* pNZBInfo);
|
||||
const char* GetParFilename() { return m_szParFilename; }
|
||||
void SetParFilename(const char* szParFilename);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetInfoName(const char* szInfoName);
|
||||
EStage GetStage() { return m_eStage; }
|
||||
@@ -389,17 +459,13 @@ public:
|
||||
void SetWorking(bool bWorking) { m_bWorking = bWorking; }
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
|
||||
bool GetParCheck() { return m_bParCheck; }
|
||||
void SetParCheck(bool bParCheck) { m_bParCheck = bParCheck; }
|
||||
EParStatus GetParStatus() { return m_eParStatus; }
|
||||
void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; }
|
||||
ERequestParCheck GetRequestParCheck() { return m_eRequestParCheck; }
|
||||
void SetRequestParCheck(ERequestParCheck eRequestParCheck) { m_eRequestParCheck = eRequestParCheck; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
void SetScriptStatus(EScriptStatus eScriptStatus) { m_eScriptStatus = eScriptStatus; }
|
||||
bool GetRequestParCheck() { return m_bRequestParCheck; }
|
||||
void SetRequestParCheck(bool bRequestParCheck) { m_bRequestParCheck = bRequestParCheck; }
|
||||
bool GetRequestParRename() { return m_bRequestParRename; }
|
||||
void SetRequestParRename(bool bRequestParRename) { m_bRequestParRename = bRequestParRename; }
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
Thread* GetScriptThread() { return m_pScriptThread; }
|
||||
void SetScriptThread(Thread* pScriptThread) { m_pScriptThread = pScriptThread; }
|
||||
Thread* GetPostThread() { return m_pPostThread; }
|
||||
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
};
|
||||
@@ -408,7 +474,91 @@ typedef std::deque<PostInfo*> PostQueue;
|
||||
|
||||
typedef std::vector<int> IDList;
|
||||
|
||||
typedef std::deque<NZBInfo*> HistoryList;
|
||||
typedef std::vector<char*> NameList;
|
||||
|
||||
class UrlInfo
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
aiUndefined,
|
||||
aiRunning,
|
||||
aiFinished,
|
||||
aiFailed,
|
||||
aiRetry
|
||||
};
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
char* m_szURL;
|
||||
char* m_szNZBFilename;
|
||||
char* m_szCategory;
|
||||
int m_iPriority;
|
||||
bool m_bAddTop;
|
||||
bool m_bAddPaused;
|
||||
EStatus m_eStatus;
|
||||
|
||||
static int m_iIDGen;
|
||||
|
||||
public:
|
||||
UrlInfo();
|
||||
~UrlInfo();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int iID);
|
||||
const char* GetURL() { return m_szURL; } // needs locking (for shared objects)
|
||||
void SetURL(const char* szURL); // needs locking (for shared objects)
|
||||
const char* GetNZBFilename() { return m_szNZBFilename; } // needs locking (for shared objects)
|
||||
void SetNZBFilename(const char* szNZBFilename); // needs locking (for shared objects)
|
||||
const char* GetCategory() { return m_szCategory; } // needs locking (for shared objects)
|
||||
void SetCategory(const char* szCategory); // needs locking (for shared objects)
|
||||
int GetPriority() { return m_iPriority; }
|
||||
void SetPriority(int iPriority) { m_iPriority = iPriority; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
void SetAddTop(bool bAddTop) { m_bAddTop = bAddTop; }
|
||||
bool GetAddPaused() { return m_bAddPaused; }
|
||||
void SetAddPaused(bool bAddPaused) { m_bAddPaused = bAddPaused; }
|
||||
void GetName(char* szBuffer, int iSize); // needs locking (for shared objects)
|
||||
static void MakeNiceName(const char* szURL, const char* szNZBFilename, char* szBuffer, int iSize);
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetStatus(EStatus Status) { m_eStatus = Status; }
|
||||
};
|
||||
|
||||
typedef std::deque<UrlInfo*> UrlQueue;
|
||||
|
||||
class HistoryInfo
|
||||
{
|
||||
public:
|
||||
enum EKind
|
||||
{
|
||||
hkUnknown,
|
||||
hkNZBInfo,
|
||||
hkUrlInfo
|
||||
};
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
EKind m_eKind;
|
||||
void* m_pInfo;
|
||||
time_t m_tTime;
|
||||
|
||||
static int m_iIDGen;
|
||||
|
||||
public:
|
||||
HistoryInfo(NZBInfo* pNZBInfo);
|
||||
HistoryInfo(UrlInfo* pUrlInfo);
|
||||
~HistoryInfo();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int iID);
|
||||
EKind GetKind() { return m_eKind; }
|
||||
NZBInfo* GetNZBInfo() { return (NZBInfo*)m_pInfo; }
|
||||
UrlInfo* GetUrlInfo() { return (UrlInfo*)m_pInfo; }
|
||||
void DiscardUrlInfo() { m_pInfo = NULL; }
|
||||
time_t GetTime() { return m_tTime; }
|
||||
void SetTime(time_t tTime) { m_tTime = tTime; }
|
||||
void GetName(char* szBuffer, int iSize); // needs locking (for shared objects)
|
||||
};
|
||||
|
||||
typedef std::deque<HistoryInfo*> HistoryList;
|
||||
|
||||
class DownloadQueue
|
||||
{
|
||||
@@ -418,6 +568,7 @@ protected:
|
||||
PostQueue m_PostQueue;
|
||||
HistoryList m_HistoryList;
|
||||
FileQueue m_ParkedFiles;
|
||||
UrlQueue m_UrlQueue;
|
||||
|
||||
public:
|
||||
NZBInfoList* GetNZBInfoList() { return &m_NZBInfoList; }
|
||||
@@ -425,6 +576,7 @@ public:
|
||||
PostQueue* GetPostQueue() { return &m_PostQueue; }
|
||||
HistoryList* GetHistoryList() { return &m_HistoryList; }
|
||||
FileQueue* GetParkedFiles() { return &m_ParkedFiles; }
|
||||
UrlQueue* GetUrlQueue() { return &m_UrlQueue; }
|
||||
void BuildGroups(GroupQueue* pGroupQueue);
|
||||
};
|
||||
|
||||
|
||||
62
Frontend.cpp
62
Frontend.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -34,8 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -63,11 +62,11 @@ Frontend::Frontend()
|
||||
m_iNeededLogEntries = 0;
|
||||
m_bSummary = false;
|
||||
m_bFileList = false;
|
||||
m_fCurrentDownloadSpeed = 0;
|
||||
m_iCurrentDownloadSpeed = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_bPauseDownload = false;
|
||||
m_bPauseDownload2 = false;
|
||||
m_fDownloadLimit = 0;
|
||||
m_iDownloadLimit = 0;
|
||||
m_iThreadCount = 0;
|
||||
m_iPostJobCount = 0;
|
||||
m_iUpTimeSec = 0;
|
||||
@@ -87,7 +86,7 @@ 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->GetServerIP(), g_pOptions->GetServerPort());
|
||||
printf("\nUnable to send request to nzbget-server at %s (port %i) \n", g_pOptions->GetControlIP(), g_pOptions->GetControlPort());
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
@@ -96,11 +95,11 @@ bool Frontend::PrepareData()
|
||||
{
|
||||
if (m_bSummary)
|
||||
{
|
||||
m_fCurrentDownloadSpeed = g_pQueueCoordinator->CalcCurrentDownloadSpeed();
|
||||
m_iCurrentDownloadSpeed = g_pQueueCoordinator->CalcCurrentDownloadSpeed();
|
||||
m_lRemainingSize = g_pQueueCoordinator->CalcRemainingSize();
|
||||
m_bPauseDownload = g_pOptions->GetPauseDownload();
|
||||
m_bPauseDownload2 = g_pOptions->GetPauseDownload2();
|
||||
m_fDownloadLimit = g_pOptions->GetDownloadRate();
|
||||
m_iDownloadLimit = g_pOptions->GetDownloadRate();
|
||||
m_iThreadCount = Thread::GetThreadCount();
|
||||
PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue();
|
||||
m_iPostJobCount = pPostQueue->size();
|
||||
@@ -182,6 +181,7 @@ void Frontend::ServerPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pOptions->SetResumeTime(0);
|
||||
if (bSecondRegister)
|
||||
{
|
||||
g_pOptions->SetPauseDownload2(bPause);
|
||||
@@ -193,15 +193,15 @@ void Frontend::ServerPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
}
|
||||
}
|
||||
|
||||
void Frontend::ServerSetDownloadRate(float fRate)
|
||||
void Frontend::ServerSetDownloadRate(int iRate)
|
||||
{
|
||||
if (IsRemoteMode())
|
||||
{
|
||||
RequestSetDownloadRate(fRate);
|
||||
RequestSetDownloadRate(iRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pOptions->SetDownloadRate(fRate);
|
||||
g_pOptions->SetDownloadRate(iRate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,14 +235,17 @@ void Frontend::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest, int
|
||||
pMessageBase->m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
pMessageBase->m_iType = htonl(iRequest);
|
||||
pMessageBase->m_iStructSize = htonl(iSize);
|
||||
strncpy(pMessageBase->m_szPassword, g_pOptions->GetServerPassword(), NZBREQUESTPASSWORDSIZE);
|
||||
|
||||
strncpy(pMessageBase->m_szUsername, g_pOptions->GetControlUsername(), NZBREQUESTPASSWORDSIZE - 1);
|
||||
pMessageBase->m_szUsername[NZBREQUESTPASSWORDSIZE - 1] = '\0';
|
||||
|
||||
strncpy(pMessageBase->m_szPassword, g_pOptions->GetControlPassword(), NZBREQUESTPASSWORDSIZE);
|
||||
pMessageBase->m_szPassword[NZBREQUESTPASSWORDSIZE - 1] = '\0';
|
||||
}
|
||||
|
||||
bool Frontend::RequestMessages()
|
||||
{
|
||||
NetAddress netAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
||||
Connection connection(&netAddress);
|
||||
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
|
||||
|
||||
bool OK = connection.Connect();
|
||||
if (!OK)
|
||||
@@ -262,15 +265,15 @@ bool Frontend::RequestMessages()
|
||||
LogRequest.m_iIDFrom = 0;
|
||||
}
|
||||
|
||||
if (connection.Send((char*)(&LogRequest), sizeof(LogRequest)) < 0)
|
||||
if (!connection.Send((char*)(&LogRequest), sizeof(LogRequest)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now listen for the returned log
|
||||
SNZBLogResponse LogResponse;
|
||||
int iResponseLen = connection.Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (iResponseLen != sizeof(LogResponse) ||
|
||||
bool bRead = connection.Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(LogResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(LogResponse.m_MessageBase.m_iStructSize) != sizeof(LogResponse))
|
||||
{
|
||||
@@ -281,7 +284,7 @@ bool Frontend::RequestMessages()
|
||||
if (ntohl(LogResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(LogResponse.m_iTrailingDataLength));
|
||||
if (!connection.RecvAll(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
if (!connection.Recv(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -313,8 +316,7 @@ bool Frontend::RequestMessages()
|
||||
|
||||
bool Frontend::RequestFileList()
|
||||
{
|
||||
NetAddress netAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
||||
Connection connection(&netAddress);
|
||||
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
|
||||
|
||||
bool OK = connection.Connect();
|
||||
if (!OK)
|
||||
@@ -327,15 +329,15 @@ bool Frontend::RequestFileList()
|
||||
ListRequest.m_bFileList = htonl(m_bFileList);
|
||||
ListRequest.m_bServerState = htonl(m_bSummary);
|
||||
|
||||
if (connection.Send((char*)(&ListRequest), sizeof(ListRequest)) < 0)
|
||||
if (!connection.Send((char*)(&ListRequest), sizeof(ListRequest)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBListResponse ListResponse;
|
||||
int iResponseLen = connection.Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (iResponseLen != sizeof(ListResponse) ||
|
||||
bool bRead = connection.Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(ListResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(ListResponse.m_MessageBase.m_iStructSize) != sizeof(ListResponse))
|
||||
{
|
||||
@@ -346,7 +348,7 @@ bool Frontend::RequestFileList()
|
||||
if (ntohl(ListResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(ListResponse.m_iTrailingDataLength));
|
||||
if (!connection.RecvAll(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
if (!connection.Recv(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -360,8 +362,8 @@ bool Frontend::RequestFileList()
|
||||
m_bPauseDownload = ntohl(ListResponse.m_bDownloadPaused);
|
||||
m_bPauseDownload2 = ntohl(ListResponse.m_bDownload2Paused);
|
||||
m_lRemainingSize = Util::JoinInt64(ntohl(ListResponse.m_iRemainingSizeHi), ntohl(ListResponse.m_iRemainingSizeLo));
|
||||
m_fCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate) / 1024.0f;
|
||||
m_fDownloadLimit = ntohl(ListResponse.m_iDownloadLimit) / 1024.0f;
|
||||
m_iCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate);
|
||||
m_iDownloadLimit = ntohl(ListResponse.m_iDownloadLimit);
|
||||
m_iThreadCount = ntohl(ListResponse.m_iThreadCount);
|
||||
m_iPostJobCount = ntohl(ListResponse.m_iPostJobCount);
|
||||
m_iUpTimeSec = ntohl(ListResponse.m_iUpTimeSec);
|
||||
@@ -392,11 +394,11 @@ bool Frontend::RequestPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
return client.RequestServerPauseUnpause(bPause, bSecondRegister ? eRemotePauseUnpauseActionDownload2 : eRemotePauseUnpauseActionDownload);
|
||||
}
|
||||
|
||||
bool Frontend::RequestSetDownloadRate(float fRate)
|
||||
bool Frontend::RequestSetDownloadRate(int iRate)
|
||||
{
|
||||
RemoteClient client;
|
||||
client.SetVerbose(false);
|
||||
return client.RequestServerSetDownloadRate(fRate);
|
||||
return client.RequestServerSetDownloadRate(iRate);
|
||||
}
|
||||
|
||||
bool Frontend::RequestDumpDebug()
|
||||
@@ -410,5 +412,5 @@ bool Frontend::RequestEditQueue(eRemoteEditAction iAction, int iOffset, int iID)
|
||||
{
|
||||
RemoteClient client;
|
||||
client.SetVerbose(false);
|
||||
return client.RequestServerEditQueue(iAction, iOffset, NULL, &iID, 1, false);
|
||||
return client.RequestServerEditQueue(iAction, iOffset, NULL, &iID, 1, NULL, eRemoteMatchModeID, false);
|
||||
}
|
||||
|
||||
12
Frontend.h
12
Frontend.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -50,11 +50,11 @@ protected:
|
||||
int m_iUpdateInterval;
|
||||
|
||||
// summary
|
||||
float m_fCurrentDownloadSpeed;
|
||||
int m_iCurrentDownloadSpeed;
|
||||
long long m_lRemainingSize;
|
||||
bool m_bPauseDownload;
|
||||
bool m_bPauseDownload2;
|
||||
float m_fDownloadLimit;
|
||||
int m_iDownloadLimit;
|
||||
int m_iThreadCount;
|
||||
int m_iPostJobCount;
|
||||
int m_iUpTimeSec;
|
||||
@@ -72,8 +72,8 @@ protected:
|
||||
void InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest, int iSize);
|
||||
void ServerPauseUnpause(bool bPause, bool bSecondRegister);
|
||||
bool RequestPauseUnpause(bool bPause, bool bSecondRegister);
|
||||
void ServerSetDownloadRate(float fRate);
|
||||
bool RequestSetDownloadRate(float fRate);
|
||||
void ServerSetDownloadRate(int iRate);
|
||||
bool RequestSetDownloadRate(int iRate);
|
||||
void ServerDumpDebug();
|
||||
bool RequestDumpDebug();
|
||||
bool ServerEditQueue(QueueEditor::EEditAction eAction, int iOffset, int iEntry);
|
||||
|
||||
29
Log.cpp
29
Log.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Options.h"
|
||||
@@ -59,11 +59,7 @@ Log::Log()
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
Clear();
|
||||
if (m_szLogFilename)
|
||||
{
|
||||
free(m_szLogFilename);
|
||||
@@ -315,6 +311,17 @@ Message::~ Message()
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Clear()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void Log::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
Message* pMessage = new Message(++m_iIDGen, eKind, time(NULL), szText);
|
||||
@@ -351,9 +358,10 @@ void Log::ResetLog()
|
||||
* During intializing stage (when options were not read yet) all messages
|
||||
* are saved in screen log, even if they shouldn't (according to options).
|
||||
* Method "InitOptions()" check all messages added to screen log during
|
||||
* intializing stage and does two things:
|
||||
* intializing stage and does three things:
|
||||
* 1) save the messages to log-file (if they should according to options);
|
||||
* 2) delete messages from screen log (if they should not be saved in screen log).
|
||||
* 3) renumerate IDs
|
||||
*/
|
||||
void Log::InitOptions()
|
||||
{
|
||||
@@ -364,6 +372,8 @@ void Log::InitOptions()
|
||||
m_szLogFilename = strdup(g_pOptions->GetLogFile());
|
||||
}
|
||||
|
||||
m_iIDGen = 0;
|
||||
|
||||
for (unsigned int i = 0; i < m_Messages.size(); )
|
||||
{
|
||||
Message* pMessage = m_Messages.at(i);
|
||||
@@ -399,6 +409,7 @@ void Log::InitOptions()
|
||||
}
|
||||
else
|
||||
{
|
||||
pMessage->m_iID = ++m_iIDGen;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
11
Log.h
11
Log.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -64,9 +64,11 @@ private:
|
||||
time_t m_tTime;
|
||||
char* m_szText;
|
||||
|
||||
friend class Log;
|
||||
|
||||
public:
|
||||
Message(unsigned int iID, EKind eKind, time_t tTime, const char* szText);
|
||||
~Message();
|
||||
Message(unsigned int iID, EKind eKind, time_t tTime, const char* szText);
|
||||
~Message();
|
||||
unsigned int GetID() { return m_iID; }
|
||||
EKind GetKind() { return m_eKind; }
|
||||
time_t GetTime() { return m_tTime; }
|
||||
@@ -108,6 +110,7 @@ public:
|
||||
~Log();
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
void Clear();
|
||||
void ResetLog();
|
||||
void InitOptions();
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
129
Makefile.am
129
Makefile.am
@@ -1,23 +1,119 @@
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Copyright (C) 2008-2013 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.
|
||||
#
|
||||
#
|
||||
|
||||
bin_PROGRAMS = nzbget
|
||||
nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
|
||||
nzbget_SOURCES = \
|
||||
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
|
||||
NZBFile.h NetAddress.cpp NetAddress.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h \
|
||||
PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
NZBFile.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h ParRenamer.cpp ParRenamer.h \
|
||||
ParCoordinator.cpp ParCoordinator.h PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp RemoteClient.h \
|
||||
RemoteServer.cpp RemoteServer.h Scanner.cpp Scanner.h Scheduler.cpp Scheduler.h ScriptController.cpp \
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h Util.cpp \
|
||||
Util.h XmlRpc.cpp XmlRpc.h nzbget.cpp nzbget.h
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h \
|
||||
Util.cpp Util.h XmlRpc.cpp XmlRpc.h WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = nzbget.conf.example postprocess-example.sh postprocess-example.conf \
|
||||
win32.h NTService.cpp NTService.h \
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd \
|
||||
$(patches_FILES) $(windows_FILES)
|
||||
|
||||
patches_FILES = \
|
||||
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
|
||||
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch \
|
||||
Makefile.cvs nzbget.kdevelop nzbget.sln nzbget.vcproj \
|
||||
nzbgetd nzbget-shell.bat
|
||||
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch
|
||||
|
||||
windows_FILES = \
|
||||
win32.h NTService.cpp NTService.h nzbget.sln nzbget.vcproj nzbget-shell.bat
|
||||
|
||||
doc_FILES = \
|
||||
README ChangeLog COPYING
|
||||
|
||||
exampleconf_FILES = \
|
||||
nzbget.conf
|
||||
|
||||
webui_FILES = \
|
||||
webui/index.html webui/index.js webui/downloads.js webui/edit.js webui/fasttable.js \
|
||||
webui/history.js webui/messages.js webui/status.js webui/style.css webui/upload.js \
|
||||
webui/util.js webui/config.js \
|
||||
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
|
||||
webui/lib/jquery.js webui/lib/jquery.min.js \
|
||||
webui/img/icons.png webui/img/icons-2x.png \
|
||||
webui/img/transmit.gif webui/img/transmit-file.gif webui/img/favicon.ico \
|
||||
webui/img/download-anim-green-2x.png webui/img/download-anim-orange-2x.png \
|
||||
webui/img/transmit-reload-2x.gif
|
||||
|
||||
ppscripts_FILES = \
|
||||
ppscripts/EMail.py ppscripts/Logger.py
|
||||
|
||||
# Install
|
||||
sbin_SCRIPTS = nzbgetd
|
||||
dist_doc_DATA = $(doc_FILES)
|
||||
exampleconfdir = $(datadir)/nzbget
|
||||
dist_exampleconf_DATA = $(exampleconf_FILES)
|
||||
webuidir = $(datadir)/nzbget
|
||||
nobase_dist_webui_DATA = $(webui_FILES)
|
||||
ppscriptsdir = $(datadir)/nzbget
|
||||
nobase_dist_ppscripts_SCRIPTS = $(ppscripts_FILES)
|
||||
|
||||
# Note about "sed":
|
||||
# We need to make some changes in installed files.
|
||||
# On Linux "sed" has option "-i" for in-place-edit. Unfortunateley the BSD version of "sed"
|
||||
# has incompatible syntax. To solve the problem we perform in-place-edit in three steps:
|
||||
# 1) copy the original file to original.temp (delete existing original.temp, if any);
|
||||
# 2) sed < original.temp > original
|
||||
# 3) delete original.temp
|
||||
# These steps ensure that the output file has the same permissions as the original file.
|
||||
|
||||
# Configure installed script
|
||||
install-exec-hook:
|
||||
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
|
||||
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
|
||||
# Prepare example configuration file
|
||||
install-data-hook:
|
||||
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:^ConfigTemplate=:ConfigTemplate=$(exampleconfdir)/nzbget.conf:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
sed 's:configuration file (typically installed:configuration file (installed:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:/usr/local/share/nzbget/nzbget.conf):$(exampleconfdir)/nzbget.conf):' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
sed 's:^WebDir=:WebDir=$(webuidir)/webui:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:typically installed to /usr/local/share/nzbget/ppscripts:installed to $(ppscriptsdir)/ppscripts:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
rm "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
|
||||
# Install configuration files into /etc
|
||||
# (only if they do not exist there to prevent override by update)
|
||||
install-conf:
|
||||
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; then \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
|
||||
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
|
||||
fi
|
||||
|
||||
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)
|
||||
@@ -56,4 +152,15 @@ svn_version.cpp: FORCE
|
||||
fi
|
||||
FORCE:
|
||||
|
||||
# Ignore "svn_version.cpp" in distcleancheck
|
||||
distcleancheck_listfiles = \
|
||||
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
|
||||
sh '{}' ';'
|
||||
|
||||
clean-bak: rm *~
|
||||
|
||||
# Fix premissions
|
||||
dist-hook:
|
||||
chmod -x $(distdir)/*.cpp $(distdir)/*.h
|
||||
find $(distdir)/webui -type f -print -exec chmod -x {} \;
|
||||
|
||||
|
||||
321
Makefile.in
321
Makefile.in
@@ -14,6 +14,29 @@
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Copyright (C) 2008-2013 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.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
@@ -36,8 +59,11 @@ PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
bin_PROGRAMS = nzbget$(EXEEXT)
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
|
||||
$(dist_exampleconf_DATA) $(nobase_dist_ppscripts_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
|
||||
@@ -51,7 +77,9 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(ppscriptsdir)" \
|
||||
"$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" \
|
||||
"$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"
|
||||
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
|
||||
PROGRAMS = $(bin_PROGRAMS)
|
||||
am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
@@ -59,16 +87,28 @@ am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
Decoder.$(OBJEXT) DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
|
||||
Frontend.$(OBJEXT) Log.$(OBJEXT) LoggableFrontend.$(OBJEXT) \
|
||||
NCursesFrontend.$(OBJEXT) NNTPConnection.$(OBJEXT) \
|
||||
NZBFile.$(OBJEXT) NetAddress.$(OBJEXT) NewsServer.$(OBJEXT) \
|
||||
Observer.$(OBJEXT) Options.$(OBJEXT) ParChecker.$(OBJEXT) \
|
||||
PrePostProcessor.$(OBJEXT) QueueCoordinator.$(OBJEXT) \
|
||||
QueueEditor.$(OBJEXT) RemoteClient.$(OBJEXT) \
|
||||
RemoteServer.$(OBJEXT) Scanner.$(OBJEXT) Scheduler.$(OBJEXT) \
|
||||
NZBFile.$(OBJEXT) NewsServer.$(OBJEXT) Observer.$(OBJEXT) \
|
||||
Options.$(OBJEXT) ParChecker.$(OBJEXT) ParRenamer.$(OBJEXT) \
|
||||
ParCoordinator.$(OBJEXT) PrePostProcessor.$(OBJEXT) \
|
||||
QueueCoordinator.$(OBJEXT) QueueEditor.$(OBJEXT) \
|
||||
RemoteClient.$(OBJEXT) RemoteServer.$(OBJEXT) \
|
||||
Scanner.$(OBJEXT) Scheduler.$(OBJEXT) \
|
||||
ScriptController.$(OBJEXT) ServerPool.$(OBJEXT) \
|
||||
svn_version.$(OBJEXT) TLS.$(OBJEXT) Thread.$(OBJEXT) \
|
||||
Util.$(OBJEXT) XmlRpc.$(OBJEXT) nzbget.$(OBJEXT)
|
||||
Util.$(OBJEXT) XmlRpc.$(OBJEXT) WebDownloader.$(OBJEXT) \
|
||||
WebServer.$(OBJEXT) UrlCoordinator.$(OBJEXT) Unpack.$(OBJEXT) \
|
||||
nzbget.$(OBJEXT)
|
||||
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
|
||||
nzbget_LDADD = $(LDADD)
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||
nobase_dist_ppscriptsSCRIPT_INSTALL = $(install_sh_SCRIPT)
|
||||
sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
|
||||
SCRIPTS = $(nobase_dist_ppscripts_SCRIPTS) $(sbin_SCRIPTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
@@ -83,6 +123,11 @@ CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(nzbget_SOURCES)
|
||||
DIST_SOURCES = $(nzbget_SOURCES)
|
||||
dist_docDATA_INSTALL = $(INSTALL_DATA)
|
||||
dist_exampleconfDATA_INSTALL = $(INSTALL_DATA)
|
||||
nobase_dist_webuiDATA_INSTALL = $(install_sh_DATA)
|
||||
DATA = $(dist_doc_DATA) $(dist_exampleconf_DATA) \
|
||||
$(nobase_dist_webui_DATA)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
@@ -95,18 +140,14 @@ am__remove_distdir = \
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
ADDSRCS = @ADDSRCS@
|
||||
AMDEP_FALSE = @AMDEP_FALSE@
|
||||
AMDEP_TRUE = @AMDEP_TRUE@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
@@ -184,6 +225,8 @@ localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
openssl_CFLAGS = @openssl_CFLAGS@
|
||||
openssl_LIBS = @openssl_LIBS@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
@@ -191,26 +234,72 @@ psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
nzbget_SOURCES = \
|
||||
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
|
||||
NZBFile.h NetAddress.cpp NetAddress.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h \
|
||||
PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
NZBFile.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h ParRenamer.cpp ParRenamer.h \
|
||||
ParCoordinator.cpp ParCoordinator.h PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp RemoteClient.h \
|
||||
RemoteServer.cpp RemoteServer.h Scanner.cpp Scanner.h Scheduler.cpp Scheduler.h ScriptController.cpp \
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h Util.cpp \
|
||||
Util.h XmlRpc.cpp XmlRpc.h nzbget.cpp nzbget.h
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h \
|
||||
Util.cpp Util.h XmlRpc.cpp XmlRpc.h WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = nzbget.conf.example postprocess-example.sh postprocess-example.conf \
|
||||
win32.h NTService.cpp NTService.h \
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd \
|
||||
$(patches_FILES) $(windows_FILES)
|
||||
|
||||
patches_FILES = \
|
||||
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
|
||||
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch \
|
||||
Makefile.cvs nzbget.kdevelop nzbget.sln nzbget.vcproj \
|
||||
nzbgetd nzbget-shell.bat
|
||||
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch
|
||||
|
||||
windows_FILES = \
|
||||
win32.h NTService.cpp NTService.h nzbget.sln nzbget.vcproj nzbget-shell.bat
|
||||
|
||||
doc_FILES = \
|
||||
README ChangeLog COPYING
|
||||
|
||||
exampleconf_FILES = \
|
||||
nzbget.conf
|
||||
|
||||
webui_FILES = \
|
||||
webui/index.html webui/index.js webui/downloads.js webui/edit.js webui/fasttable.js \
|
||||
webui/history.js webui/messages.js webui/status.js webui/style.css webui/upload.js \
|
||||
webui/util.js webui/config.js \
|
||||
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
|
||||
webui/lib/jquery.js webui/lib/jquery.min.js \
|
||||
webui/img/icons.png webui/img/icons-2x.png \
|
||||
webui/img/transmit.gif webui/img/transmit-file.gif webui/img/favicon.ico \
|
||||
webui/img/download-anim-green-2x.png webui/img/download-anim-orange-2x.png \
|
||||
webui/img/transmit-reload-2x.gif
|
||||
|
||||
ppscripts_FILES = \
|
||||
ppscripts/EMail.py ppscripts/Logger.py
|
||||
|
||||
|
||||
# Install
|
||||
sbin_SCRIPTS = nzbgetd
|
||||
dist_doc_DATA = $(doc_FILES)
|
||||
exampleconfdir = $(datadir)/nzbget
|
||||
dist_exampleconf_DATA = $(exampleconf_FILES)
|
||||
webuidir = $(datadir)/nzbget
|
||||
nobase_dist_webui_DATA = $(webui_FILES)
|
||||
ppscriptsdir = $(datadir)/nzbget
|
||||
nobase_dist_ppscripts_SCRIPTS = $(ppscripts_FILES)
|
||||
|
||||
# Ignore "svn_version.cpp" in distcleancheck
|
||||
distcleancheck_listfiles = \
|
||||
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
|
||||
sh '{}' ';'
|
||||
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
@@ -293,6 +382,50 @@ clean-binPROGRAMS:
|
||||
nzbget$(EXEEXT): $(nzbget_OBJECTS) $(nzbget_DEPENDENCIES)
|
||||
@rm -f nzbget$(EXEEXT)
|
||||
$(CXXLINK) $(nzbget_LDFLAGS) $(nzbget_OBJECTS) $(nzbget_LDADD) $(LIBS)
|
||||
install-nobase_dist_ppscriptsSCRIPTS: $(nobase_dist_ppscripts_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(ppscriptsdir)" || $(mkdir_p) "$(DESTDIR)$(ppscriptsdir)"
|
||||
@$(am__vpath_adj_setup) \
|
||||
list='$(nobase_dist_ppscripts_SCRIPTS)'; for p in $$list; do \
|
||||
$(am__vpath_adj) p=$$f; \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f $$d$$p; then \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
f=`echo "$$p" | sed 's|[^/]*$$||'`"$$f"; \
|
||||
echo " $(nobase_dist_ppscriptsSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(ppscriptsdir)/$$f'"; \
|
||||
$(nobase_dist_ppscriptsSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(ppscriptsdir)/$$f"; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-nobase_dist_ppscriptsSCRIPTS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@$(am__vpath_adj_setup) \
|
||||
list='$(nobase_dist_ppscripts_SCRIPTS)'; for p in $$list; do \
|
||||
$(am__vpath_adj) p=$$f; \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
f=`echo "$$p" | sed 's|[^/]*$$||'`"$$f"; \
|
||||
echo " rm -f '$(DESTDIR)$(ppscriptsdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(ppscriptsdir)/$$f"; \
|
||||
done
|
||||
install-sbinSCRIPTS: $(sbin_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
|
||||
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f $$d$$p; then \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
echo " $(sbinSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
|
||||
$(sbinSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(sbindir)/$$f"; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-sbinSCRIPTS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
|
||||
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
|
||||
echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(sbindir)/$$f"; \
|
||||
done
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
@@ -313,11 +446,12 @@ 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)/NetAddress.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NewsServer.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)/ParChecker.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParRenamer.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@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueEditor.Po@am__quote@
|
||||
@@ -329,7 +463,11 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TLS.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)/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)/nzbget.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svn_version.Po@am__quote@
|
||||
@@ -348,6 +486,59 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
uninstall-info-am:
|
||||
install-dist_docDATA: $(dist_doc_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)"
|
||||
@list='$(dist_doc_DATA)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \
|
||||
$(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-dist_docDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_doc_DATA)'; for p in $$list; do \
|
||||
f=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(docdir)/$$f"; \
|
||||
done
|
||||
install-dist_exampleconfDATA: $(dist_exampleconf_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(exampleconfdir)" || $(mkdir_p) "$(DESTDIR)$(exampleconfdir)"
|
||||
@list='$(dist_exampleconf_DATA)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(dist_exampleconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(exampleconfdir)/$$f'"; \
|
||||
$(dist_exampleconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(exampleconfdir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-dist_exampleconfDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_exampleconf_DATA)'; for p in $$list; do \
|
||||
f=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(exampleconfdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(exampleconfdir)/$$f"; \
|
||||
done
|
||||
install-nobase_dist_webuiDATA: $(nobase_dist_webui_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(webuidir)" || $(mkdir_p) "$(DESTDIR)$(webuidir)"
|
||||
@$(am__vpath_adj_setup) \
|
||||
list='$(nobase_dist_webui_DATA)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
$(am__vpath_adj) \
|
||||
echo " $(nobase_dist_webuiDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(webuidir)/$$f'"; \
|
||||
$(nobase_dist_webuiDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(webuidir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-nobase_dist_webuiDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@$(am__vpath_adj_setup) \
|
||||
list='$(nobase_dist_webui_DATA)'; for p in $$list; do \
|
||||
$(am__vpath_adj) \
|
||||
echo " rm -f '$(DESTDIR)$(webuidir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(webuidir)/$$f"; \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
@@ -400,6 +591,7 @@ distclean-tags:
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(mkdir_p) $(distdir)/ppscripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
@@ -426,6 +618,9 @@ distdir: $(DISTFILES)
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$(top_distdir)" distdir="$(distdir)" \
|
||||
dist-hook
|
||||
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
@@ -525,9 +720,9 @@ distcleancheck: distclean
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS) config.h
|
||||
all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) config.h
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(bindir)"; do \
|
||||
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(ppscriptsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"; do \
|
||||
test -z "$$dir" || $(mkdir_p) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
@@ -575,9 +770,15 @@ info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
install-data-am: install-dist_docDATA install-dist_exampleconfDATA \
|
||||
install-nobase_dist_ppscriptsSCRIPTS \
|
||||
install-nobase_dist_webuiDATA
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-data-hook
|
||||
|
||||
install-exec-am: install-binPROGRAMS
|
||||
install-exec-am: install-binPROGRAMS install-sbinSCRIPTS
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
@@ -604,23 +805,70 @@ ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-binPROGRAMS uninstall-info-am
|
||||
uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
|
||||
uninstall-dist_exampleconfDATA uninstall-info-am \
|
||||
uninstall-nobase_dist_ppscriptsSCRIPTS \
|
||||
uninstall-nobase_dist_webuiDATA uninstall-sbinSCRIPTS
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
|
||||
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
|
||||
distclean-compile distclean-generic distclean-hdr \
|
||||
dist-gzip dist-hook dist-shar dist-tarZ dist-zip distcheck \
|
||||
distclean distclean-compile distclean-generic distclean-hdr \
|
||||
distclean-tags distcleancheck distdir distuninstallcheck dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-binPROGRAMS install-data install-data-am install-exec \
|
||||
install-exec-am install-info install-info-am install-man \
|
||||
install-binPROGRAMS install-data install-data-am \
|
||||
install-data-hook install-dist_docDATA \
|
||||
install-dist_exampleconfDATA install-exec install-exec-am \
|
||||
install-exec-hook install-info install-info-am install-man \
|
||||
install-nobase_dist_ppscriptsSCRIPTS \
|
||||
install-nobase_dist_webuiDATA install-sbinSCRIPTS \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-binPROGRAMS \
|
||||
uninstall-info-am
|
||||
uninstall-dist_docDATA uninstall-dist_exampleconfDATA \
|
||||
uninstall-info-am uninstall-nobase_dist_ppscriptsSCRIPTS \
|
||||
uninstall-nobase_dist_webuiDATA uninstall-sbinSCRIPTS
|
||||
|
||||
|
||||
# Note about "sed":
|
||||
# We need to make some changes in installed files.
|
||||
# On Linux "sed" has option "-i" for in-place-edit. Unfortunateley the BSD version of "sed"
|
||||
# has incompatible syntax. To solve the problem we perform in-place-edit in three steps:
|
||||
# 1) copy the original file to original.temp (delete existing original.temp, if any);
|
||||
# 2) sed < original.temp > original
|
||||
# 3) delete original.temp
|
||||
# These steps ensure that the output file has the same permissions as the original file.
|
||||
|
||||
# Configure installed script
|
||||
install-exec-hook:
|
||||
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
|
||||
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
|
||||
|
||||
# Prepare example configuration file
|
||||
install-data-hook:
|
||||
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:^ConfigTemplate=:ConfigTemplate=$(exampleconfdir)/nzbget.conf:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
sed 's:configuration file (typically installed:configuration file (installed:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:/usr/local/share/nzbget/nzbget.conf):$(exampleconfdir)/nzbget.conf):' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
sed 's:^WebDir=:WebDir=$(webuidir)/webui:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
sed 's:typically installed to /usr/local/share/nzbget/ppscripts:installed to $(ppscriptsdir)/ppscripts:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
|
||||
rm "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
|
||||
|
||||
# Install configuration files into /etc
|
||||
# (only if they do not exist there to prevent override by update)
|
||||
install-conf:
|
||||
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; then \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
|
||||
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
|
||||
fi
|
||||
|
||||
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)
|
||||
# File is recreated only if revision number was changed.
|
||||
@@ -659,6 +907,11 @@ svn_version.cpp: FORCE
|
||||
FORCE:
|
||||
|
||||
clean-bak: rm *~
|
||||
|
||||
# Fix premissions
|
||||
dist-hook:
|
||||
chmod -x $(distdir)/*.cpp $(distdir)/*.h
|
||||
find $(distdir)/webui -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:
|
||||
|
||||
148
MessageBase.h
148
MessageBase.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef MESSAGEBASE_H
|
||||
#define MESSAGEBASE_H
|
||||
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6208; // = "nzb8" (protocol version)
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6217; // = "nzb-XX" (protocol version)
|
||||
static const int NZBREQUESTFILENAMESIZE = 512;
|
||||
static const int NZBREQUESTPASSWORDSIZE = 32;
|
||||
|
||||
@@ -56,11 +56,14 @@ enum eRemoteRequest
|
||||
eRemoteRequestEditQueue,
|
||||
eRemoteRequestLog,
|
||||
eRemoteRequestShutdown,
|
||||
eRemoteRequestReload,
|
||||
eRemoteRequestVersion,
|
||||
eRemoteRequestPostQueue,
|
||||
eRemoteRequestWriteLog,
|
||||
eRemoteRequestScan,
|
||||
eRemoteRequestHistory
|
||||
eRemoteRequestHistory,
|
||||
eRemoteRequestDownloadUrl,
|
||||
eRemoteRequestUrlQueue
|
||||
};
|
||||
|
||||
// Possible values for field "m_iAction" of struct "SNZBEditQueueRequest":
|
||||
@@ -76,6 +79,9 @@ enum eRemoteEditAction
|
||||
eRemoteEditActionFileDelete, // delete files
|
||||
eRemoteEditActionFilePauseAllPars, // pause only (all) pars (does not affect other files)
|
||||
eRemoteEditActionFilePauseExtraPars, // pause only (almost all) pars, except main par-file (does not affect other files)
|
||||
eRemoteEditActionFileSetPriority, // set priority for files
|
||||
eRemoteEditActionFileReorder, // (not supported)
|
||||
eRemoteEditActionFileSplit, // split - create new group from selected files
|
||||
eRemoteEditActionGroupMoveOffset, // move group to m_iOffset relative to the current position in download-queue
|
||||
eRemoteEditActionGroupMoveTop, // move group to the top of download-queue
|
||||
eRemoteEditActionGroupMoveBottom, // move group to the bottom of download-queue
|
||||
@@ -84,16 +90,19 @@ enum eRemoteEditAction
|
||||
eRemoteEditActionGroupDelete, // delete group
|
||||
eRemoteEditActionGroupPauseAllPars, // pause only (all) pars (does not affect other files) in group
|
||||
eRemoteEditActionGroupPauseExtraPars, // pause only (almost all) pars in group, except main par-file (does not affect other files)
|
||||
eRemoteEditActionGroupSetPriority, // set priority for groups
|
||||
eRemoteEditActionGroupSetCategory, // set or change category for a group
|
||||
eRemoteEditActionGroupMerge, // merge group
|
||||
eRemoteEditActionGroupSetParameter, // set post-process parameter for group
|
||||
eRemoteEditActionGroupSetName, // set group name (rename group)
|
||||
eRemoteEditActionPostMoveOffset = 51, // move post-job to m_iOffset relative to the current position in post-queue
|
||||
eRemoteEditActionPostMoveTop, // move post-job to the top of post-queue
|
||||
eRemoteEditActionPostMoveBottom, // move post-job to the bottom of post-queue
|
||||
eRemoteEditActionPostDelete, // delete post-job
|
||||
eRemoteEditActionHistoryDelete, // delete history-item
|
||||
eRemoteEditActionHistoryReturn, // move history-item back to download queue
|
||||
eRemoteEditActionHistoryProcess // move history-item back to download queue and start postprocessing
|
||||
eRemoteEditActionHistoryProcess, // move history-item back to download queue and start postprocessing
|
||||
eRemoteEditActionHistorySetParameter // set post-process parameter for history-item
|
||||
};
|
||||
|
||||
// Possible values for field "m_iAction" of struct "SNZBPauseUnpauseRequest":
|
||||
@@ -105,13 +114,22 @@ enum eRemotePauseUnpauseAction
|
||||
eRemotePauseUnpauseActionScan // pause/unpause scan of incoming nzb-directory
|
||||
};
|
||||
|
||||
// Possible values for field "m_iMatchMode" of struct "SNZBEditQueueRequest":
|
||||
enum eRemoteMatchMode
|
||||
{
|
||||
eRemoteMatchModeID = 1, // ID
|
||||
eRemoteMatchModeName, // Name
|
||||
eRemoteMatchModeRegEx, // RegEx
|
||||
};
|
||||
|
||||
// The basic SNZBRequestBase struct, used in all requests
|
||||
struct SNZBRequestBase
|
||||
{
|
||||
int32_t m_iSignature; // Signature must be NZBMESSAGE_SIGNATURE in integer-value
|
||||
int32_t m_iStructSize; // Size of the entire struct
|
||||
int32_t m_iType; // Message type, see enum in NZBMessageRequest-namespace
|
||||
char m_szPassword[NZBREQUESTPASSWORDSIZE]; // Password needs to be in every request
|
||||
char m_szUsername[NZBREQUESTPASSWORDSIZE]; // User name
|
||||
char m_szPassword[NZBREQUESTPASSWORDSIZE]; // Password
|
||||
};
|
||||
|
||||
// The basic SNZBResposneBase struct, used in all responses
|
||||
@@ -126,8 +144,10 @@ struct SNZBDownloadRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
char m_szFilename[NZBREQUESTFILENAMESIZE]; // Name of nzb-file, may contain full path (local path on client) or only filename
|
||||
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, be empty
|
||||
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
|
||||
int32_t m_bAddFirst; // 1 - add file to the top of download queue
|
||||
int32_t m_bAddPaused; // 1 - pause added files
|
||||
int32_t m_iPriority; // Priority for files (0 - default)
|
||||
int32_t m_iTrailingDataLength; // Length of nzb-file in bytes
|
||||
//char m_szContent[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
@@ -147,6 +167,9 @@ struct SNZBListRequest
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bFileList; // 1 - return file list
|
||||
int32_t m_bServerState; // 1 - return server state
|
||||
int32_t m_iMatchMode; // File/Group match mode, see enum eRemoteMatchMode (only values eRemoteMatchModeID (no filter) and eRemoteMatchModeRegEx are allowed)
|
||||
int32_t m_bMatchGroup; // 0 - match files; 1 - match nzbs (when m_iMatchMode == eRemoteMatchModeRegEx)
|
||||
char m_szPattern[NZBREQUESTFILENAMESIZE]; // RegEx Pattern (when m_iMatchMode == eRemoteMatchModeRegEx)
|
||||
};
|
||||
|
||||
// A list response
|
||||
@@ -169,6 +192,7 @@ struct SNZBListResponse
|
||||
int32_t m_iDownloadTimeSec; // Server download time in seconds (up_time - standby_time)
|
||||
int32_t m_iDownloadedBytesLo; // Amount of data downloaded since server start, Low 32-bits of 64-bit value
|
||||
int32_t m_iDownloadedBytesHi; // Amount of data downloaded since server start, High 32-bits of 64-bit value
|
||||
int32_t m_bRegExValid; // 0 - error in RegEx-pattern, 1 - RegEx-pattern is valid (only when Request has eRemoteMatchModeRegEx)
|
||||
int32_t m_iNrTrailingNZBEntries; // Number of List-NZB-entries, following to this structure
|
||||
int32_t m_iNrTrailingPPPEntries; // Number of List-PPP-entries, following to this structure
|
||||
int32_t m_iNrTrailingFileEntries; // Number of List-File-entries, following to this structure
|
||||
@@ -183,11 +207,14 @@ struct SNZBListResponseNZBEntry
|
||||
{
|
||||
int32_t m_iSizeLo; // Size of all files in bytes, Low 32-bits of 64-bit value
|
||||
int32_t m_iSizeHi; // Size of all files in bytes, High 32-bits of 64-bit value
|
||||
int32_t m_bMatch; // 1 - group matches the pattern (only when Request has eRemoteMatchModeRegEx)
|
||||
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
|
||||
int32_t m_iNameLen; // Length of Name-string (m_szName), following to this record
|
||||
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
|
||||
int32_t m_iCategoryLen; // Length of Category-string (m_szCategory), following to this record
|
||||
int32_t m_iQueuedFilenameLen; // Length of queued file name (m_szQueuedFilename), following to this record
|
||||
//char m_szFilename[m_iFilenameLen]; // variable sized
|
||||
//char m_szName[m_iNameLen]; // variable sized
|
||||
//char m_szDestDir[m_iDestDirLen]; // variable sized
|
||||
//char m_szCategory[m_iCategoryLen]; // variable sized
|
||||
//char m_szQueuedFilename[m_iQueuedFilenameLen]; // variable sized
|
||||
@@ -214,6 +241,9 @@ struct SNZBListResponseFileEntry
|
||||
int32_t m_iRemainingSizeHi; // Remaining size in bytes, High 32-bits of 64-bit value
|
||||
int32_t m_bPaused; // 1 - file is paused
|
||||
int32_t m_bFilenameConfirmed; // 1 - Filename confirmed (read from article body), 0 - Filename parsed from subject (can be changed after reading of article)
|
||||
int32_t m_iPriority; // Download priority
|
||||
int32_t m_iActiveDownloads; // Number of active downloads for this file
|
||||
int32_t m_bMatch; // 1 - file matches the pattern (only when Request has eRemoteMatchModeRegEx)
|
||||
int32_t m_iSubjectLen; // Length of Subject-string (m_szSubject), following to this record
|
||||
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
|
||||
//char m_szSubject[m_iSubjectLen]; // variable sized
|
||||
@@ -281,7 +311,7 @@ struct SNZBSetDownloadRateResponse
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
// An edit queue request
|
||||
// edit queue request
|
||||
struct SNZBEditQueueRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
@@ -289,11 +319,15 @@ struct SNZBEditQueueRequest
|
||||
int32_t m_iOffset; // Offset to move (for m_iAction = 0)
|
||||
int32_t m_bSmartOrder; // For Move-Actions: 0 - execute action for each ID in order they are placed in array;
|
||||
// 1 - smart execute to ensure that the relative order of all affected IDs are not changed.
|
||||
int32_t m_iNrTrailingEntries; // Number of ID-entries, following to this structure
|
||||
int32_t m_iTextLen; // Length of Text-string (m_szText), following to this record
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string and all ID-entries, following to this structure
|
||||
//char m_szText[m_iTextLen]; // variable sized
|
||||
//int32_t m_iIDs[m_iNrTrailingEntries]; // variable sized array of IDs. For File-Actions - ID of file, for Group-Actions - ID of any file belonging to group
|
||||
int32_t m_iMatchMode; // File/Group match mode, see enum eRemoteMatchMode
|
||||
int32_t m_iNrTrailingIDEntries; // Number of ID-entries, following to this structure
|
||||
int32_t m_iNrTrailingNameEntries; // Number of Name-entries, following to this structure
|
||||
int32_t m_iTrailingNameEntriesLen; // Length of all Name-entries, following to this structure
|
||||
int32_t m_iTextLen; // Length of Text-string (m_szText), following to this record
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string and all ID-entries, following to this structure
|
||||
//char m_szText[m_iTextLen]; // variable sized
|
||||
//int32_t m_iIDs[m_iNrTrailingIDEntries]; // variable sized array of IDs. For File-Actions - ID of file, for Group-Actions - ID of any file belonging to group
|
||||
//char* m_szNames[m_iNrTrailingNameEntries]; // variable sized array of strings. For File-Actions - name of file incl. nzb-name as path, for Group-Actions - name of group
|
||||
};
|
||||
|
||||
// An edit queue response
|
||||
@@ -335,6 +369,21 @@ struct SNZBShutdownResponse
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
// Reload server request
|
||||
struct SNZBReloadRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
};
|
||||
|
||||
// Reload server response
|
||||
struct SNZBReloadResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
// Server version request
|
||||
struct SNZBVersionRequest
|
||||
{
|
||||
@@ -376,12 +425,10 @@ struct SNZBPostQueueResponseEntry
|
||||
int32_t m_iTotalTimeSec; // Number of seconds this post-job is beeing processed (after it first changed the state from QUEUED).
|
||||
int32_t m_iStageTimeSec; // Number of seconds the current stage is beeing processed.
|
||||
int32_t m_iNZBFilenameLen; // Length of NZBFileName-string (m_szNZBFilename), following to this record
|
||||
int32_t m_iParFilename; // Length of ParFilename-string (m_szParFilename), following to this record
|
||||
int32_t m_iInfoNameLen; // Length of Filename-string (m_szFilename), following to this record
|
||||
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
|
||||
int32_t m_iProgressLabelLen; // Length of ProgressLabel-string (m_szProgressLabel), following to this record
|
||||
//char m_szNZBFilename[m_iNZBFilenameLen]; // variable sized, may contain full path (local path on client) or only filename
|
||||
//char m_szParFilename[m_iParFilename]; // variable sized
|
||||
//char m_szInfoName[m_iInfoNameLen]; // variable sized
|
||||
//char m_szDestDir[m_iDestDirLen]; // variable sized
|
||||
//char m_szProgressLabel[m_iProgressLabelLen]; // variable sized
|
||||
@@ -409,6 +456,7 @@ struct SNZBWriteLogResponse
|
||||
struct SNZBScanRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bSyncMode; // 0 - asynchronous Scan (the command returns immediately), 1 - synchronous Scan (the command returns when the scan is completed)
|
||||
};
|
||||
|
||||
// Scan nzb directory response
|
||||
@@ -426,34 +474,80 @@ struct SNZBHistoryRequest
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
};
|
||||
|
||||
// A history response
|
||||
// history response
|
||||
struct SNZBHistoryResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_iEntrySize; // Size of the SNZBHistoryResponseEntry-struct
|
||||
int32_t m_iNrTrailingEntries; // Number of History-entries, following to this structure
|
||||
int32_t m_iTrailingDataLength; // Length of all History-entries, following to this structure
|
||||
// SNZBHistoryResponseEntry m_NZBEntries[m_iNrTrailingNZBEntries] // variable sized
|
||||
// SNZBHistoryResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
|
||||
};
|
||||
|
||||
// A list response nzb entry
|
||||
// history entry
|
||||
struct SNZBHistoryResponseEntry
|
||||
{
|
||||
int32_t m_iID; // NZBID
|
||||
int32_t m_iID; // History-ID
|
||||
int32_t m_iKind; // Kind of Item: 1 - Collection (NZB), 2 - URL
|
||||
int32_t m_tTime; // When the item was added to history. time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
|
||||
int32_t m_iNicenameLen; // Length of Nicename-string (m_szNicename), following to this record
|
||||
// for Collection items (m_iKind = 1)
|
||||
int32_t m_iSizeLo; // Size of all files in bytes, Low 32-bits of 64-bit value
|
||||
int32_t m_iSizeHi; // Size of all files in bytes, High 32-bits of 64-bit value
|
||||
int32_t m_iFileCount; // Initial number of files included in NZB-file
|
||||
int32_t m_iParStatus; // See NZBInfo::EParStatus
|
||||
int32_t m_iScriptStatus; // See NZBInfo::EScriptStatus
|
||||
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
|
||||
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
|
||||
int32_t m_iCategoryLen; // Length of Category-string (m_szCategory), following to this record
|
||||
int32_t m_iQueuedFilenameLen; // Length of queued file name (m_szQueuedFilename), following to this record
|
||||
//char m_szFilename[m_iFilenameLen]; // variable sized
|
||||
//char m_szDestDir[m_iDestDirLen]; // variable sized
|
||||
//char m_szCategory[m_iCategoryLen]; // variable sized
|
||||
//char m_szQueuedFilename[m_iQueuedFilenameLen]; // variable sized
|
||||
// for URL items (m_iKind = 2)
|
||||
int32_t m_iUrlStatus; // See UrlInfo::EStatus
|
||||
// trailing data
|
||||
//char m_szNicename[m_iNicenameLen]; // variable sized
|
||||
};
|
||||
|
||||
// download url request
|
||||
struct SNZBDownloadUrlRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
char m_szURL[NZBREQUESTFILENAMESIZE]; // url to nzb-file
|
||||
char m_szNZBFilename[NZBREQUESTFILENAMESIZE];// Name of nzb-file. Can be empty, then the filename is read from URL download response
|
||||
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
|
||||
int32_t m_bAddFirst; // 1 - add url to the top of download queue
|
||||
int32_t m_bAddPaused; // 1 - pause added files
|
||||
int32_t m_iPriority; // Priority for files (0 - default)
|
||||
};
|
||||
|
||||
// download url response
|
||||
struct SNZBDownloadUrlResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
// UrlQueue request
|
||||
struct SNZBUrlQueueRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
};
|
||||
|
||||
// UrlQueue response
|
||||
struct SNZBUrlQueueResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_iEntrySize; // Size of the SNZBUrlQueueResponseEntry-struct
|
||||
int32_t m_iNrTrailingEntries; // Number of UrlQueue-entries, following to this structure
|
||||
int32_t m_iTrailingDataLength; // Length of all UrlQueue-entries, following to this structure
|
||||
// SNZBUrlQueueResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
|
||||
};
|
||||
|
||||
// UrlQueue response entry
|
||||
struct SNZBUrlQueueResponseEntry
|
||||
{
|
||||
int32_t m_iID; // ID of Url-entry
|
||||
int32_t m_iURLLen; // Length of URL-string (m_szURL), following to this record
|
||||
int32_t m_iNZBFilenameLen; // Length of NZBFilename-string (m_szNZBFilename), following to this record
|
||||
//char m_szURL[m_iURLLen]; // variable sized
|
||||
//char m_szNZBFilename[m_iNZBFilenameLen]; // variable sized
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2011 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -613,10 +613,10 @@ void NCursesFrontend::PrintStatus()
|
||||
char timeString[100];
|
||||
timeString[0] = '\0';
|
||||
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = (long long)(m_lRemainingSize / (fCurrentDownloadSpeed * 1024));
|
||||
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
@@ -624,9 +624,9 @@ void NCursesFrontend::PrintStatus()
|
||||
}
|
||||
|
||||
char szDownloadLimit[128];
|
||||
if (m_fDownloadLimit > 0.0f)
|
||||
if (m_iDownloadLimit > 0)
|
||||
{
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", m_fDownloadLimit);
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -646,7 +646,7 @@ void NCursesFrontend::PrintStatus()
|
||||
float fAverageSpeed = (float)(Util::Int64ToFloat(m_iDnTimeSec > 0 ? m_iAllBytes / m_iDnTimeSec : 0) / 1024.0);
|
||||
|
||||
snprintf(tmp, MAX_SCREEN_WIDTH, " %d threads, %.*f KB/s, %.2f MB remaining%s%s%s%s%s, Avg. %.*f KB/s",
|
||||
m_iThreadCount, (fCurrentDownloadSpeed >= 10 ? 0 : 1), fCurrentDownloadSpeed,
|
||||
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_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
|
||||
m_bPauseDownload || m_bPauseDownload2 ?
|
||||
@@ -819,6 +819,19 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
|
||||
color = NCURSES_COLORPAIR_TEXT;
|
||||
}
|
||||
|
||||
const char* szDownloading = "";
|
||||
if (pFileInfo->GetActiveDownloads() > 0)
|
||||
{
|
||||
szDownloading = " *";
|
||||
}
|
||||
|
||||
char szPriority[100];
|
||||
szPriority[0] = '\0';
|
||||
if (pFileInfo->GetPriority() != 0)
|
||||
{
|
||||
sprintf(szPriority, " [%+i]", pFileInfo->GetPriority());
|
||||
}
|
||||
|
||||
char szCompleted[20];
|
||||
szCompleted[0] = '\0';
|
||||
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
|
||||
@@ -829,7 +842,7 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
|
||||
char szNZBNiceName[1024];
|
||||
if (m_bShowNZBname)
|
||||
{
|
||||
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
strncpy(szNZBNiceName, pFileInfo->GetNZBInfo()->GetName(), 1023);
|
||||
int len = strlen(szNZBNiceName);
|
||||
szNZBNiceName[len] = PATH_SEPARATOR;
|
||||
szNZBNiceName[len + 1] = '\0';
|
||||
@@ -840,8 +853,9 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
|
||||
}
|
||||
|
||||
char szBuffer[MAX_SCREEN_WIDTH];
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(),
|
||||
Brace2, szNZBNiceName, pFileInfo->GetFilename(), (float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
|
||||
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),
|
||||
szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
|
||||
@@ -912,6 +926,7 @@ void NCursesFrontend::PrintGroupQueue()
|
||||
{
|
||||
int iLineNr = m_iQueueWinTop;
|
||||
|
||||
LockQueue();
|
||||
GroupQueue* pGroupQueue = &m_groupQueue;
|
||||
if (pGroupQueue->empty())
|
||||
{
|
||||
@@ -966,6 +981,7 @@ void NCursesFrontend::PrintGroupQueue()
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
PrintTopHeader(szBuffer, m_iQueueWinTop, false);
|
||||
}
|
||||
UnlockQueue();
|
||||
}
|
||||
|
||||
void NCursesFrontend::ResetColWidths()
|
||||
@@ -977,21 +993,23 @@ void NCursesFrontend::ResetColWidths()
|
||||
|
||||
void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSelected, bool bCalcColWidth)
|
||||
{
|
||||
int color = 0;
|
||||
const char* Brace1 = "[";
|
||||
const char* Brace2 = "]";
|
||||
int color = NCURSES_COLORPAIR_TEXT;
|
||||
char chBrace1 = '[';
|
||||
char chBrace2 = ']';
|
||||
if (m_eInputMode == eEditQueue && bSelected)
|
||||
{
|
||||
color = NCURSES_COLORPAIR_TEXTHIGHL;
|
||||
if (!m_bUseColor)
|
||||
{
|
||||
Brace1 = "<";
|
||||
Brace2 = ">";
|
||||
chBrace1 = '<';
|
||||
chBrace2 = '>';
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
const char* szDownloading = "";
|
||||
if (pGroupInfo->GetActiveDownloads() > 0)
|
||||
{
|
||||
color = NCURSES_COLORPAIR_TEXT;
|
||||
szDownloading = " *";
|
||||
}
|
||||
|
||||
long long lUnpausedRemainingSize = pGroupInfo->GetRemainingSize() - pGroupInfo->GetPausedSize();
|
||||
@@ -999,8 +1017,19 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
|
||||
char szRemaining[20];
|
||||
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
pGroupInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
char szPriority[100];
|
||||
szPriority[0] = '\0';
|
||||
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
|
||||
{
|
||||
if (pGroupInfo->GetMinPriority() == pGroupInfo->GetMaxPriority())
|
||||
{
|
||||
sprintf(szPriority, " [%+i]", pGroupInfo->GetMinPriority());
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(szPriority, " [%+i..%+i]", pGroupInfo->GetMinPriority(), pGroupInfo->GetMaxPriority());
|
||||
}
|
||||
}
|
||||
|
||||
char szBuffer[MAX_SCREEN_WIDTH];
|
||||
|
||||
@@ -1030,20 +1059,21 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
|
||||
Util::FormatFileSize(szTotal, sizeof(szTotal), pGroupInfo->GetNZBInfo()->GetSize());
|
||||
|
||||
char szNameWithIds[1024];
|
||||
snprintf(szNameWithIds, 1024, "%s%i-%i%s %s", Brace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), Brace2, szNZBNiceName);
|
||||
snprintf(szNameWithIds, 1024, "%c%i-%i%c%s%s %s", chBrace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), chBrace2,
|
||||
szPriority, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
|
||||
szNameWithIds[iNameLen] = '\0';
|
||||
|
||||
char szTime[100];
|
||||
szTime[0] = '\0';
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
if (pGroupInfo->GetPausedSize() > 0 && lUnpausedRemainingSize == 0)
|
||||
{
|
||||
snprintf(szTime, 100, "[paused]");
|
||||
Util::FormatFileSize(szRemaining, sizeof(szRemaining), pGroupInfo->GetRemainingSize());
|
||||
}
|
||||
else if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
else if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = (long long)(lUnpausedRemainingSize / (fCurrentDownloadSpeed * 1024));
|
||||
long long remain_sec = (long long)(lUnpausedRemainingSize / iCurrentDownloadSpeed);
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
@@ -1075,7 +1105,8 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i-%i%s %s", Brace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), Brace2, szNZBNiceName);
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%c%i-%i%c%s %s", chBrace1, pGroupInfo->GetFirstID(),
|
||||
pGroupInfo->GetLastID(), chBrace2, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
|
||||
}
|
||||
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
@@ -1417,7 +1448,7 @@ void NCursesFrontend::UpdateInput(int initialKey)
|
||||
// Enter
|
||||
else if (iKey == 10 || iKey == 13)
|
||||
{
|
||||
ServerSetDownloadRate((float)m_iInputValue);
|
||||
ServerSetDownloadRate(m_iInputValue * 1024);
|
||||
m_eInputMode = eNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Log.h"
|
||||
@@ -44,11 +44,13 @@
|
||||
|
||||
static const int CONNECTION_LINEBUFFER_SIZE = 1024*10;
|
||||
|
||||
NNTPConnection::NNTPConnection(NewsServer* server) : Connection(server)
|
||||
NNTPConnection::NNTPConnection(NewsServer* pNewsServer) : Connection(pNewsServer->GetHost(), pNewsServer->GetPort(), pNewsServer->GetTLS())
|
||||
{
|
||||
m_pNewsServer = pNewsServer;
|
||||
m_szActiveGroup = NULL;
|
||||
m_szLineBuf = (char*)malloc(CONNECTION_LINEBUFFER_SIZE);
|
||||
m_bAuthError = false;
|
||||
SetCipher(pNewsServer->GetCipher());
|
||||
}
|
||||
|
||||
NNTPConnection::~NNTPConnection()
|
||||
@@ -81,19 +83,16 @@ const char* NNTPConnection::Request(const char* req)
|
||||
|
||||
if (!strncmp(answer, "480", 3))
|
||||
{
|
||||
debug("%s requested authorization", m_pNetAddress->GetHost());
|
||||
debug("%s requested authorization", GetHost());
|
||||
|
||||
//authentication required!
|
||||
if (!Authenticate())
|
||||
{
|
||||
m_bAuthError = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//try again
|
||||
WriteLine(req);
|
||||
answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
return answer;
|
||||
}
|
||||
|
||||
return answer;
|
||||
@@ -101,13 +100,16 @@ const char* NNTPConnection::Request(const char* req)
|
||||
|
||||
bool NNTPConnection::Authenticate()
|
||||
{
|
||||
if (!((NewsServer*)m_pNetAddress)->GetUser() ||
|
||||
!((NewsServer*)m_pNetAddress)->GetPassword())
|
||||
if (!m_pNewsServer->GetUser() || strlen(m_pNewsServer->GetUser()) == 0 ||
|
||||
!m_pNewsServer->GetPassword() || strlen(m_pNewsServer->GetPassword()) == 0)
|
||||
{
|
||||
return true;
|
||||
error("Server%i (%s) requested authorization but username/password are not set in settings", m_pNewsServer->GetID(), m_pNewsServer->GetHost());
|
||||
m_bAuthError = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return AuthInfoUser();
|
||||
m_bAuthError = !AuthInfoUser(0);
|
||||
return !m_bAuthError;
|
||||
}
|
||||
|
||||
bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
@@ -118,7 +120,7 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
}
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "AUTHINFO USER %s\r\n", ((NewsServer*)m_pNetAddress)->GetUser());
|
||||
snprintf(tmp, 1024, "AUTHINFO USER %s\r\n", m_pNewsServer->GetUser());
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
WriteLine(tmp);
|
||||
@@ -126,13 +128,13 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
if (!answer)
|
||||
{
|
||||
ReportError("Authorization for %s failed: Connection closed by remote host.", m_pNetAddress->GetHost(), true, 0);
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strncmp(answer, "281", 3))
|
||||
{
|
||||
debug("Authorization for %s successful", m_pNetAddress->GetHost());
|
||||
debug("Authorization for %s successful", GetHost());
|
||||
return true;
|
||||
}
|
||||
else if (!strncmp(answer, "381", 3))
|
||||
@@ -148,7 +150,7 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
|
||||
|
||||
if (GetStatus() != csCancelled)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for %s failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed (Answer: %s)", answer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -161,7 +163,7 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
}
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "AUTHINFO PASS %s\r\n", ((NewsServer*)m_pNetAddress)->GetPassword());
|
||||
snprintf(tmp, 1024, "AUTHINFO PASS %s\r\n", m_pNewsServer->GetPassword());
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
WriteLine(tmp);
|
||||
@@ -169,12 +171,12 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
if (!answer)
|
||||
{
|
||||
ReportError("Authorization for %s failed: Connection closed by remote host.", m_pNetAddress->GetHost(), true, 0);
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
return false;
|
||||
}
|
||||
else if (!strncmp(answer, "2", 1))
|
||||
{
|
||||
debug("Authorization for %s successful", m_pNetAddress->GetHost());
|
||||
debug("Authorization for %s successful", GetHost());
|
||||
return true;
|
||||
}
|
||||
else if (!strncmp(answer, "381", 3))
|
||||
@@ -186,7 +188,7 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
|
||||
if (GetStatus() != csCancelled)
|
||||
{
|
||||
ReportErrorAnswer("Authorization for %s failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Authorization for server%i (%s) failed (Answer: %s)", answer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -205,14 +207,10 @@ const char* NNTPConnection::JoinGroup(const char* grp)
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
const char* answer = Request(tmp);
|
||||
if (m_bAuthError)
|
||||
{
|
||||
return answer;
|
||||
}
|
||||
|
||||
if (answer && !strncmp(answer, "2", 1))
|
||||
{
|
||||
debug("Changed group to %s on %s", grp, GetServer()->GetHost());
|
||||
debug("Changed group to %s on %s", grp, GetHost());
|
||||
|
||||
if (m_szActiveGroup)
|
||||
{
|
||||
@@ -222,52 +220,55 @@ const char* NNTPConnection::JoinGroup(const char* grp)
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Error changing group on %s to %s: %s.",
|
||||
GetServer()->GetHost(), grp, answer);
|
||||
debug("Error changing group on %s to %s: %s.", GetHost(), grp, answer);
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
bool NNTPConnection::DoConnect()
|
||||
bool NNTPConnection::Connect()
|
||||
{
|
||||
debug("Opening connection to %s", GetServer()->GetHost());
|
||||
bool res = Connection::DoConnect();
|
||||
if (!res)
|
||||
debug("Opening connection to %s", GetHost());
|
||||
|
||||
if (m_eStatus == csConnected)
|
||||
{
|
||||
return res;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (GetNewsServer()->GetTLS())
|
||||
if (!Connection::Connect())
|
||||
{
|
||||
if (!StartTLS())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* answer = DoReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
|
||||
|
||||
if (!answer)
|
||||
{
|
||||
ReportError("Connection to %s failed: Connection closed by remote host.", m_pNetAddress->GetHost(), true, 0);
|
||||
ReportErrorAnswer("Connection to server%i (%s) failed: Connection closed by remote host", NULL);
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(answer, "2", 1))
|
||||
{
|
||||
ReportErrorAnswer("Connection to %s failed (Answer: %s)", answer);
|
||||
ReportErrorAnswer("Connection to server%i (%s) failed (Answer: %s)", answer);
|
||||
Disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("Connection to %s established", GetServer()->GetHost());
|
||||
if ((m_pNewsServer->GetUser() && strlen(m_pNewsServer->GetUser()) > 0 &&
|
||||
m_pNewsServer->GetPassword() && strlen(m_pNewsServer->GetPassword()) > 0) &&
|
||||
!Authenticate())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("Connection to %s established", GetHost());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NNTPConnection::DoDisconnect()
|
||||
bool NNTPConnection::Disconnect()
|
||||
{
|
||||
if (m_eStatus == csConnected)
|
||||
{
|
||||
@@ -278,13 +279,13 @@ bool NNTPConnection::DoDisconnect()
|
||||
m_szActiveGroup = NULL;
|
||||
}
|
||||
}
|
||||
return Connection::DoDisconnect();
|
||||
return Connection::Disconnect();
|
||||
}
|
||||
|
||||
void NNTPConnection::ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer)
|
||||
{
|
||||
char szErrStr[1024];
|
||||
snprintf(szErrStr, 1024, szMsgPrefix, m_pNetAddress->GetHost(), szAnswer);
|
||||
snprintf(szErrStr, 1024, szMsgPrefix, m_pNewsServer->GetID(), m_pNewsServer->GetHost(), szAnswer);
|
||||
szErrStr[1024-1] = '\0';
|
||||
|
||||
ReportError(szErrStr, NULL, false, 0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -33,27 +33,27 @@
|
||||
class NNTPConnection : public Connection
|
||||
{
|
||||
private:
|
||||
char* m_szActiveGroup;
|
||||
char* m_szLineBuf;
|
||||
bool m_bAuthError;
|
||||
NewsServer* m_pNewsServer;
|
||||
char* m_szActiveGroup;
|
||||
char* m_szLineBuf;
|
||||
bool m_bAuthError;
|
||||
|
||||
virtual bool DoConnect();
|
||||
virtual bool DoDisconnect();
|
||||
void Clear();
|
||||
void ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer);
|
||||
void Clear();
|
||||
void ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer);
|
||||
bool Authenticate();
|
||||
bool AuthInfoUser(int iRecur);
|
||||
bool AuthInfoPass(int iRecur);
|
||||
|
||||
public:
|
||||
NNTPConnection(NewsServer* server);
|
||||
virtual ~NNTPConnection();
|
||||
NewsServer* GetNewsServer() { return(NewsServer*)m_pNetAddress; }
|
||||
const char* Request(const char* req);
|
||||
bool Authenticate();
|
||||
bool AuthInfoUser(int iRecur = 0);
|
||||
bool AuthInfoPass(int iRecur = 0);
|
||||
const char* JoinGroup(const char* grp);
|
||||
bool GetAuthError() { return m_bAuthError; }
|
||||
NNTPConnection(NewsServer* pNewsServer);
|
||||
virtual ~NNTPConnection();
|
||||
virtual bool Connect();
|
||||
virtual bool Disconnect();
|
||||
NewsServer* GetNewsServer() { return m_pNewsServer; }
|
||||
const char* Request(const char* req);
|
||||
const char* JoinGroup(const char* grp);
|
||||
bool GetAuthError() { return m_bAuthError; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
542
NZBFile.cpp
542
NZBFile.cpp
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -36,12 +36,13 @@
|
||||
#include <list>
|
||||
#ifdef WIN32
|
||||
#include <comutil.h>
|
||||
#import "MSXML.dll" named_guids
|
||||
#import <msxml.tlb> named_guids
|
||||
using namespace MSXML;
|
||||
#else
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlerror.h>
|
||||
#include <libxml/entities.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
@@ -55,23 +56,6 @@ using namespace MSXML;
|
||||
extern Options* g_pOptions;
|
||||
extern DiskState* g_pDiskState;
|
||||
|
||||
#ifndef WIN32
|
||||
static void libxml_errorhandler(void *ebuf, const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
char szErrMsg[1024];
|
||||
vsnprintf(szErrMsg, sizeof(szErrMsg), fmt, argp);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
va_end(argp);
|
||||
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
NZBFile::NZBFile(const char* szFileName, const char* szCategory)
|
||||
{
|
||||
debug("Creating NZBFile");
|
||||
@@ -83,6 +67,13 @@ NZBFile::NZBFile(const char* szFileName, const char* szCategory)
|
||||
m_pNZBInfo->SetCategory(szCategory);
|
||||
m_pNZBInfo->BuildDestDirName();
|
||||
|
||||
#ifndef WIN32
|
||||
m_pFileInfo = NULL;
|
||||
m_pArticle = NULL;
|
||||
m_szTagContent = NULL;
|
||||
m_iTagContentLen = 0;
|
||||
#endif
|
||||
|
||||
m_FileInfos.clear();
|
||||
}
|
||||
|
||||
@@ -106,6 +97,18 @@ NZBFile::~NZBFile()
|
||||
{
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (m_pFileInfo)
|
||||
{
|
||||
delete m_pFileInfo;
|
||||
}
|
||||
|
||||
if (m_szTagContent)
|
||||
{
|
||||
free(m_szTagContent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void NZBFile::LogDebugInfo()
|
||||
@@ -118,16 +121,6 @@ void NZBFile::DetachFileInfos()
|
||||
m_FileInfos.clear();
|
||||
}
|
||||
|
||||
NZBFile* NZBFile::CreateFromBuffer(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize)
|
||||
{
|
||||
return Create(szFileName, szCategory, szBuffer, iSize, true);
|
||||
}
|
||||
|
||||
NZBFile* NZBFile::CreateFromFile(const char* szFileName, const char* szCategory)
|
||||
{
|
||||
return Create(szFileName, szCategory, NULL, 0, false);
|
||||
}
|
||||
|
||||
void NZBFile::AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo)
|
||||
{
|
||||
// make Article-List big enough
|
||||
@@ -158,17 +151,10 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
|
||||
|
||||
if (!pArticles->empty())
|
||||
{
|
||||
ParseSubject(pFileInfo);
|
||||
m_FileInfos.push_back(pFileInfo);
|
||||
pFileInfo->SetNZBInfo(m_pNZBInfo);
|
||||
m_pNZBInfo->SetSize(m_pNZBInfo->GetSize() + pFileInfo->GetSize());
|
||||
m_pNZBInfo->SetFileCount(m_pNZBInfo->GetFileCount() + 1);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveFile(pFileInfo);
|
||||
pFileInfo->ClearArticles();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -176,8 +162,34 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void NZBFile::ParseSubject(FileInfo* pFileInfo)
|
||||
void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
|
||||
{
|
||||
if (TryQuotes)
|
||||
{
|
||||
// try to use the filename in quatation marks
|
||||
char* p = (char*)pFileInfo->GetSubject();
|
||||
char* start = strchr(p, '\"');
|
||||
if (start)
|
||||
{
|
||||
start++;
|
||||
char* end = strchr(start + 1, '\"');
|
||||
if (end)
|
||||
{
|
||||
int len = (int)(end - start);
|
||||
char* point = strchr(start + 1, '.');
|
||||
if (point && point < end)
|
||||
{
|
||||
char* filename = (char*)malloc(len + 1);
|
||||
strncpy(filename, start, len);
|
||||
filename[len] = '\0';
|
||||
pFileInfo->SetFilename(filename);
|
||||
free(filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tokenize subject, considering spaces as separators and quotation
|
||||
// marks as non separatable token delimiters.
|
||||
// then take the last token containing dot (".") as a filename
|
||||
@@ -260,19 +272,14 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo)
|
||||
debug("Could not extract Filename from Subject: %s. Using Subject as Filename", pFileInfo->GetSubject());
|
||||
pFileInfo->SetFilename(pFileInfo->GetSubject());
|
||||
}
|
||||
|
||||
pFileInfo->MakeValidFilename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the parsing of subject was correct
|
||||
*/
|
||||
void NZBFile::CheckFilenames()
|
||||
bool NZBFile::HasDuplicateFilenames()
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo1 = *it;
|
||||
int iDupe = 0;
|
||||
int iDupe = 1;
|
||||
for (FileInfos::iterator it2 = it + 1; it2 != m_FileInfos.end(); it2++)
|
||||
{
|
||||
FileInfo* pFileInfo2 = *it2;
|
||||
@@ -291,25 +298,56 @@ void NZBFile::CheckFilenames()
|
||||
// an often case by posting-errors to repost bad files
|
||||
if (iDupe > 2 || (iDupe == 2 && m_FileInfos.size() == 2))
|
||||
{
|
||||
for (FileInfos::iterator it2 = it; it2 != m_FileInfos.end(); it2++)
|
||||
{
|
||||
FileInfo* pFileInfo2 = *it2;
|
||||
pFileInfo2->SetFilename(pFileInfo2->GetSubject());
|
||||
pFileInfo2->MakeValidFilename();
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->LoadArticles(pFileInfo2);
|
||||
g_pDiskState->SaveFile(pFileInfo2);
|
||||
pFileInfo2->ClearArticles();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate filenames from subjects and check if the parsing of subject was correct
|
||||
*/
|
||||
void NZBFile::ProcessFilenames()
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
ParseSubject(pFileInfo, true);
|
||||
}
|
||||
|
||||
if (HasDuplicateFilenames())
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
ParseSubject(pFileInfo, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDuplicateFilenames())
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->SetFilename(pFileInfo->GetSubject());
|
||||
}
|
||||
}
|
||||
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->MakeValidFilename();
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveFile(pFileInfo);
|
||||
pFileInfo->ClearArticles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize, bool bFromBuffer)
|
||||
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
{
|
||||
CoInitialize(NULL);
|
||||
|
||||
@@ -326,21 +364,15 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const c
|
||||
doc->put_resolveExternals(VARIANT_FALSE);
|
||||
doc->put_validateOnParse(VARIANT_FALSE);
|
||||
doc->put_async(VARIANT_FALSE);
|
||||
VARIANT_BOOL success;
|
||||
if (bFromBuffer)
|
||||
{
|
||||
success = doc->loadXML(szBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// filename needs to be properly encoded
|
||||
char* szURL = (char*)malloc(strlen(szFileName)*3 + 1);
|
||||
EncodeURL(szFileName, szURL);
|
||||
debug("url=\"%s\"", szURL);
|
||||
_variant_t v(szURL);
|
||||
free(szURL);
|
||||
success = doc->load(v);
|
||||
}
|
||||
|
||||
// filename needs to be properly encoded
|
||||
char* szURL = (char*)malloc(strlen(szFileName)*3 + 1);
|
||||
EncodeURL(szFileName, szURL);
|
||||
debug("url=\"%s\"", szURL);
|
||||
_variant_t v(szURL);
|
||||
free(szURL);
|
||||
|
||||
VARIANT_BOOL success = doc->load(v);
|
||||
if (success == VARIANT_FALSE)
|
||||
{
|
||||
_bstr_t r(doc->GetparseError()->reason);
|
||||
@@ -352,7 +384,7 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const c
|
||||
NZBFile* pFile = new NZBFile(szFileName, szCategory);
|
||||
if (pFile->ParseNZB(doc))
|
||||
{
|
||||
pFile->CheckFilenames();
|
||||
pFile->ProcessFilenames();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -434,11 +466,14 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
|
||||
int partNumber = atoi(number);
|
||||
int lsize = atoi(bytes);
|
||||
|
||||
ArticleInfo* pArticle = new ArticleInfo();
|
||||
pArticle->SetPartNumber(partNumber);
|
||||
pArticle->SetMessageID(szId);
|
||||
pArticle->SetSize(lsize);
|
||||
AddArticle(pFileInfo, pArticle);
|
||||
if (partNumber > 0)
|
||||
{
|
||||
ArticleInfo* pArticle = new ArticleInfo();
|
||||
pArticle->SetPartNumber(partNumber);
|
||||
pArticle->SetMessageID(szId);
|
||||
pArticle->SetSize(lsize);
|
||||
AddArticle(pFileInfo, pArticle);
|
||||
}
|
||||
|
||||
if (lsize > 0)
|
||||
{
|
||||
@@ -453,160 +488,229 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
|
||||
|
||||
#else
|
||||
|
||||
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize, bool bFromBuffer)
|
||||
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
{
|
||||
xmlSetGenericErrorFunc(NULL, libxml_errorhandler);
|
||||
|
||||
xmlTextReaderPtr doc;
|
||||
if (bFromBuffer)
|
||||
{
|
||||
doc = xmlReaderForMemory(szBuffer, iSize-1, "", NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
doc = xmlReaderForFile(szFileName, NULL, 0);
|
||||
}
|
||||
if (!doc)
|
||||
{
|
||||
error("Could not create XML-Reader");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NZBFile* pFile = new NZBFile(szFileName, szCategory);
|
||||
if (pFile->ParseNZB(doc))
|
||||
|
||||
xmlSAXHandler SAX_handler = {0};
|
||||
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
|
||||
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
|
||||
SAX_handler.characters = reinterpret_cast<charactersSAXFunc>(SAX_characters);
|
||||
SAX_handler.error = reinterpret_cast<errorSAXFunc>(SAX_error);
|
||||
SAX_handler.getEntity = reinterpret_cast<getEntitySAXFunc>(SAX_getEntity);
|
||||
|
||||
pFile->m_bIgnoreNextError = false;
|
||||
|
||||
int ret = xmlSAXUserParseFile(&SAX_handler, pFile, szFileName);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
pFile->CheckFilenames();
|
||||
pFile->ProcessFilenames();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Failed to parse nzb-file");
|
||||
delete pFile;
|
||||
pFile = NULL;
|
||||
}
|
||||
|
||||
xmlFreeTextReader(doc);
|
||||
|
||||
return pFile;
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
bool NZBFile::ParseNZB(void* nzb)
|
||||
void NZBFile::Parse_StartElement(const char *name, const char **atts)
|
||||
{
|
||||
FileInfo* pFileInfo = NULL;
|
||||
xmlTextReaderPtr node = (xmlTextReaderPtr)nzb;
|
||||
// walk through whole doc and search for segments-tags
|
||||
int ret = xmlTextReaderRead(node);
|
||||
while (ret == 1)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
xmlChar *name, *value;
|
||||
if (m_szTagContent)
|
||||
{
|
||||
free(m_szTagContent);
|
||||
m_szTagContent = NULL;
|
||||
m_iTagContentLen = 0;
|
||||
}
|
||||
|
||||
if (!strcmp("file", name))
|
||||
{
|
||||
m_pFileInfo = new FileInfo();
|
||||
m_pFileInfo->SetFilename(m_szFileName);
|
||||
|
||||
name = xmlTextReaderName(node);
|
||||
if (name == NULL)
|
||||
{
|
||||
name = xmlStrdup(BAD_CAST "--");
|
||||
}
|
||||
value = xmlTextReaderValue(node);
|
||||
for (int i = 0; atts[i]; i += 2)
|
||||
{
|
||||
const char* attrname = atts[i];
|
||||
const char* attrvalue = atts[i + 1];
|
||||
if (!strcmp("subject", attrname))
|
||||
{
|
||||
m_pFileInfo->SetSubject(attrvalue);
|
||||
}
|
||||
if (!strcmp("date", attrname))
|
||||
{
|
||||
m_pFileInfo->SetTime(atoi(attrvalue));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp("segment", name))
|
||||
{
|
||||
if (!m_pFileInfo)
|
||||
{
|
||||
// error: bad nzb-file
|
||||
return;
|
||||
}
|
||||
|
||||
long long lsize = -1;
|
||||
int partNumber = -1;
|
||||
|
||||
if (xmlTextReaderNodeType(node) == 1)
|
||||
{
|
||||
if (!strcmp("file", (char*)name))
|
||||
{
|
||||
pFileInfo = new FileInfo();
|
||||
pFileInfo->SetFilename(m_szFileName);
|
||||
for (int i = 0; atts[i]; i += 2)
|
||||
{
|
||||
const char* attrname = atts[i];
|
||||
const char* attrvalue = atts[i + 1];
|
||||
if (!strcmp("bytes", attrname))
|
||||
{
|
||||
lsize = atol(attrvalue);
|
||||
}
|
||||
if (!strcmp("number", attrname))
|
||||
{
|
||||
partNumber = atol(attrvalue);
|
||||
}
|
||||
}
|
||||
if (lsize > 0)
|
||||
{
|
||||
m_pFileInfo->SetSize(m_pFileInfo->GetSize() + lsize);
|
||||
}
|
||||
|
||||
while (xmlTextReaderMoveToNextAttribute(node))
|
||||
{
|
||||
xmlFree(name);
|
||||
name = xmlTextReaderName(node);
|
||||
if (!strcmp("subject",(char*)name))
|
||||
{
|
||||
xmlFree(value);
|
||||
value = xmlTextReaderValue(node);
|
||||
pFileInfo->SetSubject((char*)value);
|
||||
}
|
||||
if (!strcmp("date",(char*)name))
|
||||
{
|
||||
xmlFree(value);
|
||||
value = xmlTextReaderValue(node);
|
||||
pFileInfo->SetTime(atoi((char*)value));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp("segment",(char*)name))
|
||||
{
|
||||
long long lsize = -1;
|
||||
int partNumber = -1;
|
||||
if (partNumber > 0)
|
||||
{
|
||||
// new segment, add it!
|
||||
m_pArticle = new ArticleInfo();
|
||||
m_pArticle->SetPartNumber(partNumber);
|
||||
m_pArticle->SetSize(lsize);
|
||||
AddArticle(m_pFileInfo, m_pArticle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (xmlTextReaderMoveToNextAttribute(node))
|
||||
{
|
||||
xmlFree(name);
|
||||
name = xmlTextReaderName(node);
|
||||
xmlFree(value);
|
||||
value = xmlTextReaderValue(node);
|
||||
if (!strcmp("bytes",(char*)name))
|
||||
{
|
||||
lsize = atol((char*)value);
|
||||
}
|
||||
if (!strcmp("number",(char*)name))
|
||||
{
|
||||
partNumber = atol((char*)value);
|
||||
}
|
||||
}
|
||||
if (lsize > 0)
|
||||
{
|
||||
pFileInfo->SetSize(pFileInfo->GetSize() + lsize);
|
||||
}
|
||||
|
||||
/* Get the #text part */
|
||||
ret = xmlTextReaderRead(node);
|
||||
void NZBFile::Parse_EndElement(const char *name)
|
||||
{
|
||||
if (!strcmp("file", name))
|
||||
{
|
||||
// Close the file element, add the new file to file-list
|
||||
AddFileInfo(m_pFileInfo);
|
||||
m_pFileInfo = NULL;
|
||||
m_pArticle = NULL;
|
||||
}
|
||||
else if (!strcmp("group", name))
|
||||
{
|
||||
if (!m_pFileInfo)
|
||||
{
|
||||
// error: bad nzb-file
|
||||
return;
|
||||
}
|
||||
|
||||
m_pFileInfo->GetGroups()->push_back(m_szTagContent);
|
||||
m_szTagContent = NULL;
|
||||
m_iTagContentLen = 0;
|
||||
}
|
||||
else if (!strcmp("segment", name))
|
||||
{
|
||||
if (!m_pFileInfo || !m_pArticle)
|
||||
{
|
||||
// error: bad nzb-file
|
||||
return;
|
||||
}
|
||||
|
||||
if (partNumber > 0)
|
||||
{
|
||||
// new segment, add it!
|
||||
xmlFree(value);
|
||||
value = xmlTextReaderValue(node);
|
||||
char tmp[2048];
|
||||
snprintf(tmp, 2048, "<%s>", (char*)value);
|
||||
ArticleInfo* pArticle = new ArticleInfo();
|
||||
pArticle->SetPartNumber(partNumber);
|
||||
pArticle->SetMessageID(tmp);
|
||||
pArticle->SetSize(lsize);
|
||||
AddArticle(pFileInfo, pArticle);
|
||||
}
|
||||
}
|
||||
else if (!strcmp("group",(char*)name))
|
||||
{
|
||||
ret = xmlTextReaderRead(node);
|
||||
xmlFree(value);
|
||||
value = xmlTextReaderValue(node);
|
||||
if (!pFileInfo)
|
||||
{
|
||||
// error: bad nzb-file
|
||||
break;
|
||||
}
|
||||
pFileInfo->GetGroups()->push_back(strdup((char*)value));
|
||||
}
|
||||
}
|
||||
// Get the #text part
|
||||
char ID[2048];
|
||||
snprintf(ID, 2048, "<%s>", m_szTagContent);
|
||||
m_pArticle->SetMessageID(ID);
|
||||
m_pArticle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlTextReaderNodeType(node) == 15)
|
||||
{
|
||||
/* Close the file element, add the new file to file-list */
|
||||
if (!strcmp("file",(char*)name))
|
||||
{
|
||||
AddFileInfo(pFileInfo);
|
||||
}
|
||||
}
|
||||
void NZBFile::Parse_Content(const char *buf, int len)
|
||||
{
|
||||
m_szTagContent = (char*)realloc(m_szTagContent, m_iTagContentLen + len + 1);
|
||||
strncpy(m_szTagContent + m_iTagContentLen, buf, len);
|
||||
m_iTagContentLen += len;
|
||||
m_szTagContent[m_iTagContentLen] = '\0';
|
||||
}
|
||||
|
||||
xmlFree(name);
|
||||
xmlFree(value);
|
||||
}
|
||||
ret = xmlTextReaderRead(node);
|
||||
}
|
||||
if (ret != 0)
|
||||
{
|
||||
error("Failed to parse nzb-file");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
void NZBFile::SAX_StartElement(NZBFile* pFile, const char *name, const char **atts)
|
||||
{
|
||||
pFile->Parse_StartElement(name, atts);
|
||||
}
|
||||
|
||||
void NZBFile::SAX_EndElement(NZBFile* pFile, const char *name)
|
||||
{
|
||||
pFile->Parse_EndElement(name);
|
||||
}
|
||||
|
||||
void NZBFile::SAX_characters(NZBFile* pFile, const char * xmlstr, int len)
|
||||
{
|
||||
char* str = (char*)xmlstr;
|
||||
|
||||
// trim starting blanks
|
||||
int off = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char ch = str[i];
|
||||
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
|
||||
{
|
||||
off++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int newlen = len - off;
|
||||
|
||||
// trim ending blanks
|
||||
for (int i = len - 1; i >= off; i--)
|
||||
{
|
||||
char ch = str[i];
|
||||
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
|
||||
{
|
||||
newlen--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlen > 0)
|
||||
{
|
||||
// interpret tag content
|
||||
pFile->Parse_Content(str + off, newlen);
|
||||
}
|
||||
}
|
||||
|
||||
void* NZBFile::SAX_getEntity(NZBFile* pFile, const char * name)
|
||||
{
|
||||
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
|
||||
if (!e)
|
||||
{
|
||||
warn("entity not found");
|
||||
pFile->m_bIgnoreNextError = true;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void NZBFile::SAX_error(NZBFile* pFile, const char *msg, ...)
|
||||
{
|
||||
if (pFile->m_bIgnoreNextError)
|
||||
{
|
||||
pFile->m_bIgnoreNextError = false;
|
||||
return;
|
||||
}
|
||||
|
||||
va_list argp;
|
||||
va_start(argp, msg);
|
||||
char szErrMsg[1024];
|
||||
vsnprintf(szErrMsg, sizeof(szErrMsg), msg, argp);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
va_end(argp);
|
||||
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
30
NZBFile.h
30
NZBFile.h
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -44,20 +44,32 @@ private:
|
||||
NZBFile(const char* szFileName, const char* szCategory);
|
||||
void AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
|
||||
void AddFileInfo(FileInfo* pFileInfo);
|
||||
void ParseSubject(FileInfo* pFileInfo);
|
||||
void CheckFilenames();
|
||||
void ParseSubject(FileInfo* pFileInfo, bool TryQuotes);
|
||||
void ProcessFilenames();
|
||||
bool HasDuplicateFilenames();
|
||||
#ifdef WIN32
|
||||
bool ParseNZB(IUnknown* nzb);
|
||||
static void EncodeURL(const char* szFilename, char* szURL);
|
||||
#else
|
||||
bool ParseNZB(void* nzb);
|
||||
FileInfo* m_pFileInfo;
|
||||
ArticleInfo* m_pArticle;
|
||||
char* m_szTagContent;
|
||||
int m_iTagContentLen;
|
||||
bool m_bIgnoreNextError;
|
||||
|
||||
static void SAX_StartElement(NZBFile* pFile, const char *name, const char **atts);
|
||||
static void SAX_EndElement(NZBFile* pFile, const char *name);
|
||||
static void SAX_characters(NZBFile* pFile, const char * xmlstr, int len);
|
||||
static void* SAX_getEntity(NZBFile* pFile, const char * name);
|
||||
static void SAX_error(NZBFile* pFile, const char *msg, ...);
|
||||
void Parse_StartElement(const char *name, const char **atts);
|
||||
void Parse_EndElement(const char *name);
|
||||
void Parse_Content(const char *buf, int len);
|
||||
#endif
|
||||
static NZBFile* Create(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize, bool bFromBuffer);
|
||||
|
||||
public:
|
||||
virtual ~NZBFile();
|
||||
static NZBFile* CreateFromBuffer(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize);
|
||||
static NZBFile* CreateFromFile(const char* szFileName, const char* szCategory);
|
||||
static NZBFile* Create(const char* szFileName, const char* szCategory);
|
||||
const char* GetFileName() const { return m_szFileName; }
|
||||
FileInfos* GetFileInfos() { return &m_FileInfos; }
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NetAddress.h"
|
||||
|
||||
NetAddress::NetAddress(const char* szHost, int iPort)
|
||||
{
|
||||
m_szHost = NULL;
|
||||
m_iPort = iPort;
|
||||
if (szHost)
|
||||
m_szHost = strdup(szHost);
|
||||
}
|
||||
|
||||
NetAddress::~NetAddress()
|
||||
{
|
||||
if (m_szHost)
|
||||
free(m_szHost);
|
||||
m_szHost = NULL;
|
||||
}
|
||||
44
NetAddress.h
44
NetAddress.h
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NETADDRESS_H
|
||||
#define NETADDRESS_H
|
||||
|
||||
class NetAddress
|
||||
{
|
||||
private:
|
||||
char* m_szHost;
|
||||
int m_iPort;
|
||||
|
||||
public:
|
||||
NetAddress(const char* szHost, int iPort);
|
||||
virtual ~NetAddress();
|
||||
const char* GetHost() { return m_szHost; }
|
||||
int GetPort() { return m_iPort; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -37,29 +37,32 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NewsServer.h"
|
||||
#include "Log.h"
|
||||
|
||||
NewsServer::NewsServer(const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS, int iMaxConnections, int iLevel) : NetAddress(szHost, iPort)
|
||||
NewsServer::NewsServer(int iID, const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup)
|
||||
{
|
||||
m_iID = iID;
|
||||
m_szHost = NULL;
|
||||
m_iPort = iPort;
|
||||
m_szUser = NULL;
|
||||
m_szPassword = NULL;
|
||||
m_iLevel = iLevel;
|
||||
m_iGroup = iGroup;
|
||||
m_iMaxConnections = iMaxConnections;
|
||||
m_bJoinGroup = bJoinGroup;
|
||||
m_bTLS = bTLS;
|
||||
|
||||
if (szUser)
|
||||
{
|
||||
m_szUser = strdup(szUser);
|
||||
}
|
||||
if (szPass)
|
||||
{
|
||||
m_szPassword = strdup(szPass);
|
||||
}
|
||||
m_szHost = szHost ? strdup(szHost) : NULL;
|
||||
m_szUser = szUser ? strdup(szUser) : NULL;
|
||||
m_szPassword = szPass ? strdup(szPass) : NULL;
|
||||
m_szCipher = szCipher ? strdup(szCipher) : NULL;
|
||||
}
|
||||
|
||||
NewsServer::~NewsServer()
|
||||
{
|
||||
if (m_szHost)
|
||||
{
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szUser)
|
||||
{
|
||||
free(m_szUser);
|
||||
@@ -68,4 +71,8 @@ NewsServer::~NewsServer()
|
||||
{
|
||||
free(m_szPassword);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
}
|
||||
|
||||
24
NewsServer.h
24
NewsServer.h
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -27,27 +27,37 @@
|
||||
#ifndef NEWSSERVER_H
|
||||
#define NEWSSERVER_H
|
||||
|
||||
#include "NetAddress.h"
|
||||
|
||||
class NewsServer : public NetAddress
|
||||
class NewsServer
|
||||
{
|
||||
private:
|
||||
int m_iID;
|
||||
int m_iGroup;
|
||||
char* m_szHost;
|
||||
int m_iPort;
|
||||
char* m_szUser;
|
||||
char* m_szPassword;
|
||||
int m_iMaxConnections;
|
||||
int m_iLevel;
|
||||
bool m_bJoinGroup;
|
||||
bool m_bTLS;
|
||||
char* m_szCipher;
|
||||
|
||||
public:
|
||||
NewsServer(const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS, int iMaxConnections, int iLevel);
|
||||
virtual ~NewsServer();
|
||||
NewsServer(int iID, const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup);
|
||||
~NewsServer();
|
||||
int GetID() { return m_iID; }
|
||||
int GetGroup() { return m_iGroup; }
|
||||
const char* GetHost() { return m_szHost; }
|
||||
int GetPort() { return m_iPort; }
|
||||
const char* GetUser() { return m_szUser; }
|
||||
const char* GetPassword() { return m_szPassword; }
|
||||
int GetMaxConnections() { return m_iMaxConnections; }
|
||||
int GetLevel() { return m_iLevel; }
|
||||
void SetLevel(int iLevel) { m_iLevel = iLevel; }
|
||||
int GetJoinGroup() { return m_bJoinGroup; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
const char* GetCipher() { return m_szCipher; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
1986
Options.cpp
1986
Options.cpp
File diff suppressed because it is too large
Load Diff
267
Options.h
267
Options.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -28,7 +28,11 @@
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <time.h>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Util.h"
|
||||
|
||||
class Options
|
||||
{
|
||||
@@ -45,10 +49,12 @@ public:
|
||||
opClientRequestEditQueue,
|
||||
opClientRequestLog,
|
||||
opClientRequestShutdown,
|
||||
opClientRequestReload,
|
||||
opClientRequestVersion,
|
||||
opClientRequestPostQueue,
|
||||
opClientRequestWriteLog,
|
||||
opClientRequestScan,
|
||||
opClientRequestScanSync,
|
||||
opClientRequestScanAsync,
|
||||
opClientRequestDownloadPause,
|
||||
opClientRequestDownloadUnpause,
|
||||
opClientRequestDownload2Pause,
|
||||
@@ -57,7 +63,9 @@ public:
|
||||
opClientRequestPostUnpause,
|
||||
opClientRequestScanPause,
|
||||
opClientRequestScanUnpause,
|
||||
opClientRequestHistory
|
||||
opClientRequestHistory,
|
||||
opClientRequestDownloadUrl,
|
||||
opClientRequestUrlQueue
|
||||
};
|
||||
enum EMessageTarget
|
||||
{
|
||||
@@ -72,11 +80,17 @@ public:
|
||||
omColored,
|
||||
omNCurses
|
||||
};
|
||||
enum ELoadPars
|
||||
enum EParCheck
|
||||
{
|
||||
lpNone,
|
||||
lpOne,
|
||||
lpAll
|
||||
pcAuto,
|
||||
pcForce,
|
||||
pcManual
|
||||
};
|
||||
enum EParScan
|
||||
{
|
||||
psLimited,
|
||||
psFull,
|
||||
psAuto
|
||||
};
|
||||
enum EScriptLogKind
|
||||
{
|
||||
@@ -88,37 +102,140 @@ public:
|
||||
slDebug
|
||||
};
|
||||
|
||||
enum EMatchMode
|
||||
{
|
||||
mmID = 1,
|
||||
mmName,
|
||||
mmRegEx
|
||||
};
|
||||
|
||||
class OptEntry
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szValue;
|
||||
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;
|
||||
|
||||
public:
|
||||
OptEntry();
|
||||
OptEntry(const char* szName, const char* szValue);
|
||||
~OptEntry();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetValue() { return m_szValue; }
|
||||
const char* GetDefValue() { return m_szDefValue; }
|
||||
int GetLineNo() { return m_iLineNo; }
|
||||
};
|
||||
|
||||
typedef std::vector<OptEntry*> OptEntries;
|
||||
typedef std::vector<OptEntry*> OptEntriesBase;
|
||||
|
||||
class OptEntries: public OptEntriesBase
|
||||
{
|
||||
public:
|
||||
~OptEntries();
|
||||
OptEntry* FindOption(const char* szName);
|
||||
};
|
||||
|
||||
class ConfigTemplate
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szDisplayName;
|
||||
char* m_szTemplate;
|
||||
|
||||
friend class Options;
|
||||
|
||||
public:
|
||||
ConfigTemplate(const char* szName, const char* szDisplayName, const char* szTemplate);
|
||||
~ConfigTemplate();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetDisplayName() { return m_szDisplayName; }
|
||||
const char* GetTemplate() { return m_szTemplate; }
|
||||
};
|
||||
|
||||
typedef std::vector<ConfigTemplate*> ConfigTemplatesBase;
|
||||
|
||||
class ConfigTemplates: public ConfigTemplatesBase
|
||||
{
|
||||
public:
|
||||
~ConfigTemplates();
|
||||
};
|
||||
|
||||
typedef std::vector<char*> NameList;
|
||||
|
||||
class Category
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szDestDir;
|
||||
char* m_szDefScript;
|
||||
|
||||
public:
|
||||
Category(const char* szName, const char* szDestDir, const char* szDefScript);
|
||||
~Category();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
const char* GetDefScript() { return m_szDefScript; }
|
||||
};
|
||||
|
||||
typedef std::vector<Category*> CategoriesBase;
|
||||
|
||||
class Categories: public CategoriesBase
|
||||
{
|
||||
public:
|
||||
~Categories();
|
||||
Category* FindCategory(const char* szName);
|
||||
};
|
||||
|
||||
class Script
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szLocation;
|
||||
char* m_szDisplayName;
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
typedef std::list<Script*> ScriptListBase;
|
||||
|
||||
class ScriptList: public ScriptListBase
|
||||
{
|
||||
public:
|
||||
~ScriptList();
|
||||
Script* Find(const char* szName);
|
||||
};
|
||||
|
||||
private:
|
||||
OptEntries m_OptEntries;
|
||||
bool m_bConfigInitialized;
|
||||
Mutex m_mutexOptEntries;
|
||||
Categories m_Categories;
|
||||
|
||||
// Options
|
||||
bool m_bConfigErrors;
|
||||
int m_iConfigLine;
|
||||
char* m_szConfigFilename;
|
||||
char* m_szDestDir;
|
||||
char* m_szInterDir;
|
||||
char* m_szTempDir;
|
||||
char* m_szQueueDir;
|
||||
char* m_szNzbDir;
|
||||
char* m_szWebDir;
|
||||
char* m_szConfigTemplate;
|
||||
char* m_szScriptDir;
|
||||
EMessageTarget m_eInfoTarget;
|
||||
EMessageTarget m_eWarningTarget;
|
||||
EMessageTarget m_eErrorTarget;
|
||||
@@ -129,30 +246,37 @@ private:
|
||||
bool m_bResetLog;
|
||||
int m_iConnectionTimeout;
|
||||
int m_iTerminateTimeout;
|
||||
bool m_bAppendNZBDir;
|
||||
bool m_bAppendCategoryDir;
|
||||
bool m_bContinuePartial;
|
||||
bool m_bRenameBroken;
|
||||
int m_iRetries;
|
||||
int m_iRetryInterval;
|
||||
bool m_bSaveQueue;
|
||||
bool m_bDupeCheck;
|
||||
char* m_szServerIP;
|
||||
char* m_szServerPassword;
|
||||
int m_szServerPort;
|
||||
char* m_szControlIP;
|
||||
char* m_szControlUsername;
|
||||
char* m_szControlPassword;
|
||||
int m_iControlPort;
|
||||
bool m_bSecureControl;
|
||||
int m_iSecurePort;
|
||||
char* m_szSecureCert;
|
||||
char* m_szSecureKey;
|
||||
char* m_szLockFile;
|
||||
char* m_szDaemonUserName;
|
||||
char* m_szDaemonUsername;
|
||||
EOutputMode m_eOutputMode;
|
||||
bool m_bReloadQueue;
|
||||
bool m_bReloadUrlQueue;
|
||||
bool m_bReloadPostQueue;
|
||||
int m_iUrlConnections;
|
||||
int m_iLogBufferSize;
|
||||
bool m_bCreateLog;
|
||||
char* m_szLogFile;
|
||||
ELoadPars m_eLoadPars;
|
||||
bool m_bParCheck;
|
||||
EParCheck m_eParCheck;
|
||||
bool m_bParRepair;
|
||||
char* m_szPostProcess;
|
||||
EParScan m_eParScan;
|
||||
char* m_szDefScript;
|
||||
char* m_szScriptOrder;
|
||||
char* m_szNZBProcess;
|
||||
char* m_szNZBAddedProcess;
|
||||
bool m_bStrictParName;
|
||||
bool m_bNoConfig;
|
||||
int m_iUMask;
|
||||
@@ -161,25 +285,28 @@ private:
|
||||
bool m_bCursesTime;
|
||||
bool m_bCursesGroup;
|
||||
bool m_bCrcCheck;
|
||||
bool m_bRetryOnCrcError;
|
||||
int m_iThreadLimit;
|
||||
bool m_bDirectWrite;
|
||||
int m_iWriteBufferSize;
|
||||
int m_iNzbDirInterval;
|
||||
int m_iNzbDirFileAge;
|
||||
bool m_bParCleanupQueue;
|
||||
int m_iDiskSpace;
|
||||
EScriptLogKind m_eProcessLogKind;
|
||||
bool m_bAllowReProcess;
|
||||
bool m_bTLS;
|
||||
bool m_bDumpCore;
|
||||
bool m_bParPauseQueue;
|
||||
bool m_bPostPauseQueue;
|
||||
bool m_bScriptPauseQueue;
|
||||
bool m_bNzbCleanupDisk;
|
||||
bool m_bDeleteCleanupDisk;
|
||||
bool m_bMergeNzb;
|
||||
int m_iParTimeLimit;
|
||||
int m_iKeepHistory;
|
||||
bool m_bAccurateRate;
|
||||
bool m_bUnpack;
|
||||
bool m_bUnpackCleanupDisk;
|
||||
char* m_szUnrarCmd;
|
||||
char* m_szSevenZipCmd;
|
||||
bool m_bUnpackPauseQueue;
|
||||
char* m_szExtCleanupDisk;
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool m_bServerMode;
|
||||
@@ -189,13 +316,18 @@ private:
|
||||
int m_iEditQueueOffset;
|
||||
int* m_pEditQueueIDList;
|
||||
int m_iEditQueueIDCount;
|
||||
NameList m_EditQueueNameList;
|
||||
EMatchMode m_EMatchMode;
|
||||
char* m_szEditQueueText;
|
||||
char* m_szArgFilename;
|
||||
char* m_szCategory;
|
||||
char* m_szAddCategory;
|
||||
int m_iAddPriority;
|
||||
bool m_bAddPaused;
|
||||
char* m_szAddNZBFilename;
|
||||
char* m_szLastArg;
|
||||
bool m_bPrintOptions;
|
||||
bool m_bAddTop;
|
||||
float m_fSetRate;
|
||||
int m_iSetRate;
|
||||
int m_iLogLines;
|
||||
int m_iWriteLogKind;
|
||||
bool m_bTestBacktrace;
|
||||
@@ -205,8 +337,9 @@ private:
|
||||
bool m_bPauseDownload2;
|
||||
bool m_bPausePostProcess;
|
||||
bool m_bPauseScan;
|
||||
float m_fDownloadRate;
|
||||
int m_iDownloadRate;
|
||||
EClientOperation m_eClientOperation;
|
||||
time_t m_tResumeTime;
|
||||
|
||||
void InitDefault();
|
||||
void InitOptFile();
|
||||
@@ -214,33 +347,54 @@ private:
|
||||
void InitOptions();
|
||||
void InitFileArg(int argc, char* argv[]);
|
||||
void InitServers();
|
||||
void InitCategories();
|
||||
void InitScheduler();
|
||||
void CheckOptions();
|
||||
void PrintUsage(char* com);
|
||||
void Dump();
|
||||
int ParseOptionValue(const char* OptName, int argc, const char* argn[], const int argv[]);
|
||||
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 ValidateOptionName(const char* optname);
|
||||
void LoadConfig(const char* configfile);
|
||||
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty);
|
||||
void LoadConfigFile();
|
||||
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate);
|
||||
void ParseFileIDList(int argc, char* argv[], int optind);
|
||||
void ParseFileNameList(int argc, char* argv[], int optind);
|
||||
bool ParseTime(const char** pTime, 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(ScriptList* pScriptList, const char* szDirectory, bool bIsSubDir);
|
||||
void BuildScriptDisplayNames(ScriptList* pScriptList);
|
||||
|
||||
public:
|
||||
Options(int argc, char* argv[]);
|
||||
~Options();
|
||||
|
||||
bool LoadConfig(OptEntries* pOptEntries);
|
||||
bool SaveConfig(OptEntries* pOptEntries);
|
||||
bool LoadConfigTemplates(ConfigTemplates* pConfigTemplates);
|
||||
void LoadScriptList(ScriptList* pScriptList);
|
||||
|
||||
// Options
|
||||
OptEntries* LockOptEntries();
|
||||
void UnlockOptEntries();
|
||||
const char* GetConfigFilename() { return m_szConfigFilename; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
const char* GetInterDir() { return m_szInterDir; }
|
||||
const char* GetTempDir() { return m_szTempDir; }
|
||||
const char* GetQueueDir() { return m_szQueueDir; }
|
||||
const char* GetNzbDir() { return m_szNzbDir; }
|
||||
const char* GetWebDir() { return m_szWebDir; }
|
||||
const char* GetConfigTemplate() { return m_szConfigTemplate; }
|
||||
const char* GetScriptDir() { return m_szScriptDir; }
|
||||
bool GetCreateBrokenLog() const { return m_bCreateBrokenLog; }
|
||||
bool GetResetLog() const { return m_bResetLog; }
|
||||
EMessageTarget GetInfoTarget() const { return m_eInfoTarget; }
|
||||
@@ -251,30 +405,37 @@ public:
|
||||
int GetConnectionTimeout() { return m_iConnectionTimeout; }
|
||||
int GetTerminateTimeout() { return m_iTerminateTimeout; }
|
||||
bool GetDecode() { return m_bDecode; };
|
||||
bool GetAppendNZBDir() { return m_bAppendNZBDir; }
|
||||
bool GetAppendCategoryDir() { return m_bAppendCategoryDir; }
|
||||
bool GetContinuePartial() { return m_bContinuePartial; }
|
||||
bool GetRenameBroken() { return m_bRenameBroken; }
|
||||
int GetRetries() { return m_iRetries; }
|
||||
int GetRetryInterval() { return m_iRetryInterval; }
|
||||
bool GetSaveQueue() { return m_bSaveQueue; }
|
||||
bool GetDupeCheck() { return m_bDupeCheck; }
|
||||
const char* GetServerIP() { return m_szServerIP; }
|
||||
const char* GetServerPassword() { return m_szServerPassword; }
|
||||
int GetServerPort() { return m_szServerPort; }
|
||||
const char* GetControlIP() { return m_szControlIP; }
|
||||
const char* GetControlUsername() { return m_szControlUsername; }
|
||||
const char* GetControlPassword() { return m_szControlPassword; }
|
||||
int GetControlPort() { return m_iControlPort; }
|
||||
bool GetSecureControl() { return m_bSecureControl; }
|
||||
int GetSecurePort() { return m_iSecurePort; }
|
||||
const char* GetSecureCert() { return m_szSecureCert; }
|
||||
const char* GetSecureKey() { return m_szSecureKey; }
|
||||
const char* GetLockFile() { return m_szLockFile; }
|
||||
const char* GetDaemonUserName() { return m_szDaemonUserName; }
|
||||
const char* GetDaemonUsername() { return m_szDaemonUsername; }
|
||||
EOutputMode GetOutputMode() { return m_eOutputMode; }
|
||||
bool GetReloadQueue() { return m_bReloadQueue; }
|
||||
bool GetReloadUrlQueue() { return m_bReloadUrlQueue; }
|
||||
bool GetReloadPostQueue() { return m_bReloadPostQueue; }
|
||||
int GetUrlConnections() { return m_iUrlConnections; }
|
||||
int GetLogBufferSize() { return m_iLogBufferSize; }
|
||||
bool GetCreateLog() { return m_bCreateLog; }
|
||||
const char* GetLogFile() { return m_szLogFile; }
|
||||
ELoadPars GetLoadPars() { return m_eLoadPars; }
|
||||
bool GetParCheck() { return m_bParCheck; }
|
||||
EParCheck GetParCheck() { return m_eParCheck; }
|
||||
bool GetParRepair() { return m_bParRepair; }
|
||||
const char* GetPostProcess() { return m_szPostProcess; }
|
||||
EParScan GetParScan() { return m_eParScan; }
|
||||
const char* GetScriptOrder() { return m_szScriptOrder; }
|
||||
const char* GetDefScript() { return m_szDefScript; }
|
||||
const char* GetNZBProcess() { return m_szNZBProcess; }
|
||||
const char* GetNZBAddedProcess() { return m_szNZBAddedProcess; }
|
||||
bool GetStrictParName() { return m_bStrictParName; }
|
||||
int GetUMask() { return m_iUMask; }
|
||||
int GetUpdateInterval() {return m_iUpdateInterval; }
|
||||
@@ -282,25 +443,30 @@ public:
|
||||
bool GetCursesTime() { return m_bCursesTime; }
|
||||
bool GetCursesGroup() { return m_bCursesGroup; }
|
||||
bool GetCrcCheck() { return m_bCrcCheck; }
|
||||
bool GetRetryOnCrcError() { return m_bRetryOnCrcError; }
|
||||
int GetThreadLimit() { return m_iThreadLimit; }
|
||||
bool GetDirectWrite() { return m_bDirectWrite; }
|
||||
int GetWriteBufferSize() { return m_iWriteBufferSize; }
|
||||
int GetNzbDirInterval() { return m_iNzbDirInterval; }
|
||||
int GetNzbDirFileAge() { return m_iNzbDirFileAge; }
|
||||
bool GetParCleanupQueue() { return m_bParCleanupQueue; }
|
||||
int GetDiskSpace() { return m_iDiskSpace; }
|
||||
EScriptLogKind GetProcessLogKind() { return m_eProcessLogKind; }
|
||||
bool GetAllowReProcess() { return m_bAllowReProcess; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
bool GetDumpCore() { return m_bDumpCore; }
|
||||
bool GetParPauseQueue() { return m_bParPauseQueue; }
|
||||
bool GetPostPauseQueue() { return m_bPostPauseQueue; }
|
||||
bool GetScriptPauseQueue() { return m_bScriptPauseQueue; }
|
||||
bool GetNzbCleanupDisk() { return m_bNzbCleanupDisk; }
|
||||
bool GetDeleteCleanupDisk() { return m_bDeleteCleanupDisk; }
|
||||
bool GetMergeNzb() { return m_bMergeNzb; }
|
||||
int GetParTimeLimit() { return m_iParTimeLimit; }
|
||||
int GetKeepHistory() { return m_iKeepHistory; }
|
||||
bool GetAccurateRate() { return m_bAccurateRate; }
|
||||
bool GetUnpack() { return m_bUnpack; }
|
||||
bool GetUnpackCleanupDisk() { return m_bUnpackCleanupDisk; }
|
||||
const char* GetUnrarCmd() { return m_szUnrarCmd; }
|
||||
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
|
||||
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
|
||||
const char* GetExtCleanupDisk() { return m_szExtCleanupDisk; }
|
||||
|
||||
Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); }
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool GetServerMode() { return m_bServerMode; }
|
||||
@@ -311,12 +477,17 @@ public:
|
||||
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* GetCategory() { return m_szCategory; }
|
||||
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; }
|
||||
float GetSetRate() { return m_fSetRate; }
|
||||
int GetSetRate() { return m_iSetRate; }
|
||||
int GetLogLines() { return m_iLogLines; }
|
||||
int GetWriteLogKind() { return m_iWriteLogKind; }
|
||||
bool GetTestBacktrace() { return m_bTestBacktrace; }
|
||||
@@ -330,8 +501,10 @@ public:
|
||||
bool GetPausePostProcess() const { return m_bPausePostProcess; }
|
||||
void SetPauseScan(bool bPauseScan) { m_bPauseScan = bPauseScan; }
|
||||
bool GetPauseScan() const { return m_bPauseScan; }
|
||||
void SetDownloadRate(float fRate) { m_fDownloadRate = fRate; }
|
||||
float GetDownloadRate() const { return m_fDownloadRate; }
|
||||
void SetDownloadRate(int iRate) { m_iDownloadRate = iRate; }
|
||||
int GetDownloadRate() const { return m_iDownloadRate; }
|
||||
void SetResumeTime(time_t tResumeTime) { m_tResumeTime = tResumeTime; }
|
||||
time_t GetResumeTime() const { return m_tResumeTime; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
511
ParChecker.cpp
511
ParChecker.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -35,18 +35,21 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <fstream>
|
||||
#ifdef WIN32
|
||||
#include <par2cmdline.h>
|
||||
#include <par2repairer.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <libpar2/par2cmdline.h>
|
||||
#include <libpar2/par2repairer.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ParChecker.h"
|
||||
#include "ParCoordinator.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
@@ -66,15 +69,96 @@ const char* Par2CmdLineErrStr[] = { "OK",
|
||||
|
||||
class Repairer : public Par2Repairer
|
||||
{
|
||||
private:
|
||||
CommandLine commandLine;
|
||||
|
||||
public:
|
||||
Result PreProcess(const char *szParFilename);
|
||||
Result Process(bool dorepair);
|
||||
|
||||
friend class ParChecker;
|
||||
};
|
||||
|
||||
Result Repairer::PreProcess(const char *szParFilename)
|
||||
{
|
||||
#ifdef HAVE_PAR2_BUGFIXES_V2
|
||||
// Ensure linking against the patched version of libpar2
|
||||
BugfixesPatchVersion2();
|
||||
#endif
|
||||
|
||||
if (g_pOptions->GetParScan() == Options::psFull)
|
||||
{
|
||||
char szWildcardParam[1024];
|
||||
strncpy(szWildcardParam, szParFilename, 1024);
|
||||
szWildcardParam[1024-1] = '\0';
|
||||
char* szBasename = Util::BaseFileName(szWildcardParam);
|
||||
if (szBasename != szWildcardParam && strlen(szBasename) > 0)
|
||||
{
|
||||
szBasename[0] = '*';
|
||||
szBasename[1] = '\0';
|
||||
}
|
||||
|
||||
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename, szWildcardParam };
|
||||
if (!commandLine.Parse(6, (char**)argv))
|
||||
{
|
||||
return eInvalidCommandLineArguments;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename };
|
||||
if (!commandLine.Parse(5, (char**)argv))
|
||||
{
|
||||
return eInvalidCommandLineArguments;
|
||||
}
|
||||
}
|
||||
|
||||
return Par2Repairer::PreProcess(commandLine);
|
||||
}
|
||||
|
||||
Result Repairer::Process(bool dorepair)
|
||||
{
|
||||
return Par2Repairer::Process(commandLine, dorepair);
|
||||
}
|
||||
|
||||
|
||||
class MissingFilesComparator
|
||||
{
|
||||
private:
|
||||
const char* m_szBaseParFilename;
|
||||
public:
|
||||
MissingFilesComparator(const char* szBaseParFilename) : m_szBaseParFilename(szBaseParFilename) {}
|
||||
bool operator()(CommandLine::ExtraFile* pFirst, CommandLine::ExtraFile* pSecond) const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Files with the same name as in par-file (and a differnt extension) are
|
||||
* placed at the top of the list to be scanned first.
|
||||
*/
|
||||
bool MissingFilesComparator::operator()(CommandLine::ExtraFile* pFile1, CommandLine::ExtraFile* pFile2) const
|
||||
{
|
||||
char name1[1024];
|
||||
strncpy(name1, Util::BaseFileName(pFile1->FileName().c_str()), 1024);
|
||||
name1[1024-1] = '\0';
|
||||
if (char* ext = strrchr(name1, '.')) *ext = '\0'; // trim extension
|
||||
|
||||
char name2[1024];
|
||||
strncpy(name2, Util::BaseFileName(pFile2->FileName().c_str()), 1024);
|
||||
name2[1024-1] = '\0';
|
||||
if (char* ext = strrchr(name2, '.')) *ext = '\0'; // trim extension
|
||||
|
||||
return strcmp(name1, m_szBaseParFilename) == 0 && strcmp(name1, name2) != 0;
|
||||
}
|
||||
|
||||
|
||||
ParChecker::ParChecker()
|
||||
{
|
||||
debug("Creating ParChecker");
|
||||
|
||||
m_eStatus = psUndefined;
|
||||
m_eStatus = psFailed;
|
||||
m_szDestDir = NULL;
|
||||
m_szNZBName = NULL;
|
||||
m_szParFilename = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_szErrMsg = NULL;
|
||||
@@ -85,16 +169,19 @@ ParChecker::ParChecker()
|
||||
m_bVerifyingExtraFiles = false;
|
||||
m_bCancelled = false;
|
||||
m_eStage = ptLoadingPars;
|
||||
m_QueuedParFiles.clear();
|
||||
}
|
||||
|
||||
ParChecker::~ParChecker()
|
||||
{
|
||||
debug("Destroying ParChecker");
|
||||
|
||||
if (m_szParFilename)
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szParFilename);
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szNZBName)
|
||||
{
|
||||
free(m_szNZBName);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
@@ -106,20 +193,42 @@ ParChecker::~ParChecker()
|
||||
}
|
||||
free(m_szProgressLabel);
|
||||
|
||||
for (QueuedParFiles::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void ParChecker::Cleanup()
|
||||
{
|
||||
for (FileList::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_QueuedParFiles.clear();
|
||||
|
||||
for (FileList::iterator it = m_ProcessedFiles.begin(); it != m_ProcessedFiles.end() ;it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_ProcessedFiles.clear();
|
||||
|
||||
m_sourceFiles.clear();
|
||||
}
|
||||
|
||||
void ParChecker::SetParFilename(const char * szParFilename)
|
||||
void ParChecker::SetDestDir(const char * szDestDir)
|
||||
{
|
||||
if (m_szParFilename)
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szParFilename);
|
||||
free(m_szDestDir);
|
||||
}
|
||||
m_szParFilename = strdup(szParFilename);
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void ParChecker::SetNZBName(const char * szNZBName)
|
||||
{
|
||||
if (m_szNZBName)
|
||||
{
|
||||
free(m_szNZBName);
|
||||
}
|
||||
m_szNZBName = strdup(szNZBName);
|
||||
}
|
||||
|
||||
void ParChecker::SetInfoName(const char * szInfoName)
|
||||
@@ -131,34 +240,121 @@ void ParChecker::SetInfoName(const char * szInfoName)
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
}
|
||||
|
||||
void ParChecker::SetStatus(EStatus eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
Notify(NULL);
|
||||
}
|
||||
|
||||
void ParChecker::Run()
|
||||
{
|
||||
m_bRepairNotNeeded = false;
|
||||
ParCoordinator::FileList fileList;
|
||||
if (!ParCoordinator::FindMainPars(m_szDestDir, &fileList))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start par-check for %s. Could not find any par-files", m_szNZBName);
|
||||
m_eStatus = psFailed;
|
||||
Completed();
|
||||
return;
|
||||
}
|
||||
|
||||
m_eStatus = psRepairNotNeeded;
|
||||
m_bCancelled = false;
|
||||
|
||||
for (ParCoordinator::FileList::iterator it = fileList.begin(); it != fileList.end(); it++)
|
||||
{
|
||||
char* szParFilename = *it;
|
||||
debug("Found par: %s", szParFilename);
|
||||
|
||||
if (!IsStopped() && !m_bCancelled)
|
||||
{
|
||||
char szFullParFilename[1024];
|
||||
snprintf(szFullParFilename, 1024, "%s%c%s", m_szDestDir, (int)PATH_SEPARATOR, szParFilename);
|
||||
szFullParFilename[1024-1] = '\0';
|
||||
|
||||
char szInfoName[1024];
|
||||
int iBaseLen = 0;
|
||||
ParCoordinator::ParseParFilename(szParFilename, &iBaseLen, NULL);
|
||||
int maxlen = iBaseLen < 1024 ? iBaseLen : 1024 - 1;
|
||||
strncpy(szInfoName, szParFilename, maxlen);
|
||||
szInfoName[maxlen] = '\0';
|
||||
|
||||
char szParInfoName[1024];
|
||||
snprintf(szParInfoName, 1024, "%s%c%s", m_szNZBName, (int)PATH_SEPARATOR, szInfoName);
|
||||
szParInfoName[1024-1] = '\0';
|
||||
|
||||
SetInfoName(szParInfoName);
|
||||
|
||||
EStatus eStatus = RunParCheck(szFullParFilename);
|
||||
|
||||
// accumulate total status, the worst status has priority
|
||||
if (m_eStatus > eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
{
|
||||
WriteBrokenLog(eStatus);
|
||||
}
|
||||
}
|
||||
|
||||
free(szParFilename);
|
||||
}
|
||||
|
||||
Completed();
|
||||
}
|
||||
|
||||
void ParChecker::WriteBrokenLog(EStatus eStatus)
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", m_szDestDir, (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
|
||||
if (eStatus != psRepairNotNeeded || Util::FileExists(szBrokenLogName))
|
||||
{
|
||||
FILE* file = fopen(szBrokenLogName, "ab");
|
||||
if (file)
|
||||
{
|
||||
if (eStatus == psFailed)
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
fprintf(file, "Repair cancelled for %s\n", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "Repair failed for %s: %s\n", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
}
|
||||
}
|
||||
else if (eStatus == psRepairPossible)
|
||||
{
|
||||
fprintf(file, "Repair possible for %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepaired)
|
||||
{
|
||||
fprintf(file, "Successfully repaired %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepairNotNeeded)
|
||||
{
|
||||
fprintf(file, "Repair not needed for %s\n", m_szInfoName);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open file %s", szBrokenLogName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
{
|
||||
Cleanup();
|
||||
m_szParFilename = szParFilename;
|
||||
m_eStage = ptLoadingPars;
|
||||
m_iProcessedFiles = 0;
|
||||
m_iExtraFiles = 0;
|
||||
m_bVerifyingExtraFiles = false;
|
||||
m_bCancelled = false;
|
||||
EStatus eStatus = psFailed;
|
||||
|
||||
info("Verifying %s", m_szInfoName);
|
||||
SetStatus(psWorking);
|
||||
PrintMessage(Message::mkInfo, "Verifying %s", m_szInfoName);
|
||||
|
||||
debug("par: %s", m_szParFilename);
|
||||
CommandLine commandLine;
|
||||
const char* argv[] = { "par2", "r", "-v", "-v", m_szParFilename };
|
||||
if (!commandLine.Parse(5, (char**)argv))
|
||||
{
|
||||
error("Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
|
||||
SetStatus(psFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Result res;
|
||||
|
||||
Repairer* pRepairer = new Repairer();
|
||||
@@ -174,16 +370,24 @@ void ParChecker::Run()
|
||||
m_iStageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
res = pRepairer->PreProcess(commandLine);
|
||||
res = pRepairer->PreProcess(m_szParFilename);
|
||||
debug("ParChecker: PreProcess-result=%i", res);
|
||||
|
||||
if (res != eSuccess || IsStopped())
|
||||
{
|
||||
error("Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
|
||||
m_szErrMsg = strdup("par2-file could not be processed");
|
||||
SetStatus(psFailed);
|
||||
if (res == eInvalidCommandLineArguments)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
|
||||
m_szErrMsg = strdup("Command line could not be parsed");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
|
||||
m_szErrMsg = strdup("par2-file could not be processed");
|
||||
}
|
||||
delete pRepairer;
|
||||
return;
|
||||
Cleanup();
|
||||
return psFailed;
|
||||
}
|
||||
|
||||
char BufReason[1024];
|
||||
@@ -195,13 +399,19 @@ void ParChecker::Run()
|
||||
m_szErrMsg = NULL;
|
||||
|
||||
m_eStage = ptVerifyingSources;
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
|
||||
if (!IsStopped() && pRepairer->missingfilecount > 0 && g_pOptions->GetParScan() == Options::psAuto && AddMissingFiles())
|
||||
{
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
|
||||
if (!IsStopped() && res == eRepairNotPossible && CheckSplittedFragments())
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
|
||||
@@ -211,7 +421,7 @@ void ParChecker::Run()
|
||||
int missingblockcount = pRepairer->missingblockcount - pRepairer->recoverypacketmap.size();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
info("Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
@@ -266,29 +476,33 @@ void ParChecker::Run()
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
SetStatus(psFailed);
|
||||
delete pRepairer;
|
||||
return;
|
||||
Cleanup();
|
||||
return psFailed;
|
||||
}
|
||||
|
||||
eStatus = psFailed;
|
||||
|
||||
if (res == eSuccess)
|
||||
{
|
||||
info("Repair not needed for %s", m_szInfoName);
|
||||
m_bRepairNotNeeded = true;
|
||||
PrintMessage(Message::mkInfo, "Repair not needed for %s", m_szInfoName);
|
||||
eStatus = psRepairNotNeeded;
|
||||
}
|
||||
else if (res == eRepairPossible)
|
||||
{
|
||||
eStatus = psRepairPossible;
|
||||
if (g_pOptions->GetParRepair())
|
||||
{
|
||||
info("Repairing %s", m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Repairing %s", m_szInfoName);
|
||||
|
||||
SaveSourceList();
|
||||
snprintf(m_szProgressLabel, 1024, "Repairing %s", m_szInfoName);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
@@ -298,62 +512,69 @@ void ParChecker::Run()
|
||||
m_iFilesToRepair = pRepairer->damagedfilecount + pRepairer->missingfilecount;
|
||||
UpdateProgress();
|
||||
|
||||
res = pRepairer->Process(commandLine, true);
|
||||
res = pRepairer->Process(true);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
if (res == eSuccess)
|
||||
{
|
||||
info("Successfully repaired %s", m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Successfully repaired %s", m_szInfoName);
|
||||
eStatus = psRepaired;
|
||||
DeleteLeftovers();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Repair possible for %s", m_szInfoName);
|
||||
res = eSuccess;
|
||||
PrintMessage(Message::mkInfo, "Repair possible for %s", m_szInfoName);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bCancelled)
|
||||
{
|
||||
warn("Repair cancelled for %s", m_szInfoName);
|
||||
m_szErrMsg = strdup("repair cancelled");
|
||||
SetStatus(psFailed);
|
||||
if (m_eStage >= ptRepairing)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Repair cancelled for %s", m_szInfoName);
|
||||
m_szErrMsg = strdup("repair cancelled");
|
||||
eStatus = psRepairPossible;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Par-check cancelled for %s", m_szInfoName);
|
||||
m_szErrMsg = strdup("par-check cancelled");
|
||||
eStatus = psFailed;
|
||||
}
|
||||
}
|
||||
else if (res == eSuccess)
|
||||
{
|
||||
SetStatus(psFinished);
|
||||
}
|
||||
else
|
||||
else if (eStatus == psFailed)
|
||||
{
|
||||
if (!m_szErrMsg && (int)res >= 0 && (int)res <= 8)
|
||||
{
|
||||
m_szErrMsg = strdup(Par2CmdLineErrStr[res]);
|
||||
}
|
||||
error("Repair failed for %s: %s", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
SetStatus(psFailed);
|
||||
PrintMessage(Message::mkError, "Repair failed for %s: %s", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
}
|
||||
|
||||
delete pRepairer;
|
||||
Cleanup();
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
bool ParChecker::LoadMorePars()
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
QueuedParFiles moreFiles;
|
||||
FileList moreFiles;
|
||||
moreFiles.assign(m_QueuedParFiles.begin(), m_QueuedParFiles.end());
|
||||
m_QueuedParFiles.clear();
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
for (QueuedParFiles::iterator it = moreFiles.begin(); it != moreFiles.end() ;it++)
|
||||
for (FileList::iterator it = moreFiles.begin(); it != moreFiles.end() ;it++)
|
||||
{
|
||||
char* szParFilename = *it;
|
||||
bool loadedOK = ((Repairer*)m_pRepairer)->LoadPacketsFromFile(szParFilename);
|
||||
if (loadedOK)
|
||||
{
|
||||
info("File %s successfully loaded for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "File %s successfully loaded for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Could not load file %s for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Could not load file %s for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
}
|
||||
free(szParFilename);
|
||||
}
|
||||
@@ -380,11 +601,11 @@ bool ParChecker::CheckSplittedFragments()
|
||||
{
|
||||
bool bFragmentsAdded = false;
|
||||
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
if (!sourcefile->GetTargetExists() && AddSplittedFragments(sourcefile->TargetFileName().c_str()))
|
||||
if (AddSplittedFragments(sourcefile->TargetFileName().c_str()))
|
||||
{
|
||||
bFragmentsAdded = true;
|
||||
}
|
||||
@@ -407,7 +628,7 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
szBasename[-1] = '\0';
|
||||
int iBaseLen = strlen(szBasename);
|
||||
|
||||
list<CommandLine::ExtraFile> extrafiles;
|
||||
std::list<CommandLine::ExtraFile> extrafiles;
|
||||
|
||||
DirBrowser dir(szDirectory);
|
||||
while (const char* filename = dir.Next())
|
||||
@@ -437,7 +658,7 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
|
||||
if (!extrafiles.empty())
|
||||
{
|
||||
m_iExtraFiles = extrafiles.size();
|
||||
m_iExtraFiles += extrafiles.size();
|
||||
m_bVerifyingExtraFiles = true;
|
||||
bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
|
||||
m_bVerifyingExtraFiles = false;
|
||||
@@ -446,6 +667,93 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
return bFragmentsAdded;
|
||||
}
|
||||
|
||||
bool ParChecker::AddMissingFiles()
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Performing extra par-scan for %s", m_szInfoName);
|
||||
|
||||
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);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt"))
|
||||
{
|
||||
bool bAlreadyScanned = false;
|
||||
for (FileList::iterator it = m_ProcessedFiles.begin(); it != m_ProcessedFiles.end(); it++)
|
||||
{
|
||||
const char* szProcessedFilename = *it;
|
||||
if (!strcasecmp(Util::BaseFileName(szProcessedFilename), filename))
|
||||
{
|
||||
bAlreadyScanned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bAlreadyScanned)
|
||||
{
|
||||
char fullfilename[1024];
|
||||
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
|
||||
fullfilename[1024-1] = '\0';
|
||||
|
||||
extrafiles.push_back(new CommandLine::ExtraFile(fullfilename, Util::FileSize(fullfilename)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the list
|
||||
char* szBaseParFilename = strdup(Util::BaseFileName(m_szParFilename));
|
||||
if (char* ext = strrchr(szBaseParFilename, '.')) *ext = '\0'; // trim extension
|
||||
extrafiles.sort(MissingFilesComparator(szBaseParFilename));
|
||||
free(szBaseParFilename);
|
||||
|
||||
// Scan files
|
||||
bool bFilesAdded = false;
|
||||
if (!extrafiles.empty())
|
||||
{
|
||||
m_iExtraFiles += extrafiles.size();
|
||||
m_bVerifyingExtraFiles = true;
|
||||
|
||||
std::list<CommandLine::ExtraFile> extrafiles1;
|
||||
|
||||
// adding files one by one until all missing files are found
|
||||
|
||||
while (!IsStopped() && !m_bCancelled && extrafiles.size() > 0 && ((Repairer*)m_pRepairer)->missingfilecount > 0)
|
||||
{
|
||||
CommandLine::ExtraFile* pExtraFile = extrafiles.front();
|
||||
extrafiles.pop_front();
|
||||
|
||||
extrafiles1.clear();
|
||||
extrafiles1.push_back(*pExtraFile);
|
||||
|
||||
bFilesAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles1) || bFilesAdded;
|
||||
((Repairer*)m_pRepairer)->UpdateVerificationResults();
|
||||
|
||||
delete pExtraFile;
|
||||
}
|
||||
|
||||
m_bVerifyingExtraFiles = false;
|
||||
|
||||
// free any remaining objects
|
||||
for (std::list<CommandLine::ExtraFile*>::iterator it = extrafiles.begin(); it != extrafiles.end() ;it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
return bFilesAdded;
|
||||
}
|
||||
|
||||
void ParChecker::signal_filename(std::string str)
|
||||
{
|
||||
const char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
|
||||
@@ -455,7 +763,12 @@ void ParChecker::signal_filename(std::string str)
|
||||
m_eStage = ptVerifyingRepaired;
|
||||
}
|
||||
|
||||
info("%s %s", szStageMessage[m_eStage], str.c_str());
|
||||
PrintMessage(Message::mkInfo, "%s %s", szStageMessage[m_eStage], str.c_str());
|
||||
|
||||
if (m_eStage == ptLoadingPars || m_eStage == ptVerifyingSources)
|
||||
{
|
||||
m_ProcessedFiles.push_back(strdup(str.c_str()));
|
||||
}
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "%s %s", szStageMessage[m_eStage], str.c_str());
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
@@ -520,7 +833,7 @@ void ParChecker::signal_done(std::string str, int available, int total)
|
||||
{
|
||||
bool bFileExists = true;
|
||||
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
@@ -534,11 +847,11 @@ void ParChecker::signal_done(std::string str, int available, int total)
|
||||
|
||||
if (bFileExists)
|
||||
{
|
||||
warn("File %s has %i bad block(s) of total %i block(s)", str.c_str(), total - available, total);
|
||||
PrintMessage(Message::mkWarning, "File %s has %i bad block(s) of total %i block(s)", str.c_str(), total - available, total);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("File %s with %i block(s) is missing", str.c_str(), total);
|
||||
PrintMessage(Message::mkWarning, "File %s with %i block(s) is missing", str.c_str(), total);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,8 +863,60 @@ void ParChecker::Cancel()
|
||||
((Repairer*)m_pRepairer)->cancelled = true;
|
||||
m_bCancelled = true;
|
||||
#else
|
||||
error("Could not cancel par-repair. The used version of libpar2 does not support the cancelling of par-repair. Libpar2 needs to be patched for that feature to work.");
|
||||
PrintMessage(Message::mkError, "Could not cancel par-repair. The program was compiled using version of libpar2 which doesn't support cancelling of par-repair. Please apply libpar2-patches supplied with NZBGet and recompile libpar2 and NZBGet (see README for details).");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParChecker::SaveSourceList()
|
||||
{
|
||||
// Buliding a list of DiskFile-objects, marked as source-files
|
||||
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile* sourcefile = (Par2RepairerSourceFile*)*it;
|
||||
vector<DataBlock>::iterator it2 = sourcefile->SourceBlocks();
|
||||
for (int i = 0; i < (int)sourcefile->BlockCount(); i++, it2++)
|
||||
{
|
||||
DataBlock block = *it2;
|
||||
DiskFile* pSourceFile = block.GetDiskFile();
|
||||
if (pSourceFile &&
|
||||
std::find(m_sourceFiles.begin(), m_sourceFiles.end(), pSourceFile) == m_sourceFiles.end())
|
||||
{
|
||||
m_sourceFiles.push_back(pSourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParChecker::DeleteLeftovers()
|
||||
{
|
||||
// After repairing check if all DiskFile-objects saved by "SaveSourceList()" have
|
||||
// corresponding target-files. If not - the source file was replaced. In this case
|
||||
// the DiskFile-object points to the renamed bak-file, which we can delete.
|
||||
|
||||
for (SourceList::iterator it = m_sourceFiles.begin(); it != m_sourceFiles.end(); it++)
|
||||
{
|
||||
DiskFile* pSourceFile = (DiskFile*)*it;
|
||||
|
||||
bool bFound = false;
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it2 = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it2 != ((Repairer*)m_pRepairer)->sourcefiles.end(); it2++)
|
||||
{
|
||||
Par2RepairerSourceFile* sourcefile = *it2;
|
||||
if (sourcefile->GetTargetFile() == pSourceFile)
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFound)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", Util::BaseFileName(pSourceFile->FileName().c_str()));
|
||||
remove(pSourceFile->FileName().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
41
ParChecker.h
41
ParChecker.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -29,19 +29,20 @@
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Observer.h"
|
||||
#include "Log.h"
|
||||
|
||||
class ParChecker : public Thread, public Subject
|
||||
class ParChecker : public Thread
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
psUndefined,
|
||||
psWorking,
|
||||
psFailed,
|
||||
psFinished
|
||||
psRepairPossible,
|
||||
psRepaired,
|
||||
psRepairNotNeeded
|
||||
};
|
||||
|
||||
enum EStage
|
||||
@@ -52,19 +53,22 @@ public:
|
||||
ptVerifyingRepaired,
|
||||
};
|
||||
|
||||
typedef std::deque<char*> QueuedParFiles;
|
||||
typedef std::deque<char*> FileList;
|
||||
typedef std::deque<void*> SourceList;
|
||||
|
||||
private:
|
||||
char* m_szInfoName;
|
||||
char* m_szParFilename;
|
||||
char* m_szDestDir;
|
||||
char* m_szNZBName;
|
||||
const char* m_szParFilename;
|
||||
EStatus m_eStatus;
|
||||
EStage m_eStage;
|
||||
void* m_pRepairer; // declared as void* to prevent the including of libpar2-headers into this header-file
|
||||
char* m_szErrMsg;
|
||||
bool m_bRepairNotNeeded;
|
||||
QueuedParFiles m_QueuedParFiles;
|
||||
FileList m_QueuedParFiles;
|
||||
Mutex m_mutexQueuedParFiles;
|
||||
bool m_bQueuedParFilesChanged;
|
||||
FileList m_ProcessedFiles;
|
||||
int m_iProcessedFiles;
|
||||
int m_iFilesToRepair;
|
||||
int m_iExtraFiles;
|
||||
@@ -73,10 +77,17 @@ private:
|
||||
int m_iFileProgress;
|
||||
int m_iStageProgress;
|
||||
bool m_bCancelled;
|
||||
SourceList m_sourceFiles;
|
||||
|
||||
EStatus RunParCheck(const char* szParFilename);
|
||||
void WriteBrokenLog(EStatus eStatus);
|
||||
void Cleanup();
|
||||
bool LoadMorePars();
|
||||
bool CheckSplittedFragments();
|
||||
bool AddSplittedFragments(const char* szFilename);
|
||||
bool AddMissingFiles();
|
||||
void SaveSourceList();
|
||||
void DeleteLeftovers();
|
||||
void signal_filename(std::string str);
|
||||
void signal_progress(double progress);
|
||||
void signal_done(std::string str, int available, int total);
|
||||
@@ -89,6 +100,8 @@ protected:
|
||||
*/
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound) = 0;
|
||||
virtual void UpdateProgress() {}
|
||||
virtual void Completed() {}
|
||||
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
|
||||
EStage GetStage() { return m_eStage; }
|
||||
const char* GetProgressLabel() { return m_szProgressLabel; }
|
||||
int GetFileProgress() { return m_iFileProgress; }
|
||||
@@ -98,14 +111,12 @@ public:
|
||||
ParChecker();
|
||||
virtual ~ParChecker();
|
||||
virtual void Run();
|
||||
void SetDestDir(const char* szDestDir);
|
||||
const char* GetParFilename() { return m_szParFilename; }
|
||||
void SetParFilename(const char* szParFilename);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetInfoName(const char* szInfoName);
|
||||
void SetStatus(EStatus eStatus);
|
||||
void SetNZBName(const char* szNZBName);
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
const char* GetErrMsg() { return m_szErrMsg; }
|
||||
bool GetRepairNotNeeded() { return m_bRepairNotNeeded; }
|
||||
void AddParFile(const char* szParFilename);
|
||||
void QueueChanged();
|
||||
void Cancel();
|
||||
|
||||
726
ParCoordinator.cpp
Normal file
726
ParCoordinator.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 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>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ParCoordinator.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "DiskState.h"
|
||||
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern Options* g_pOptions;
|
||||
extern DiskState* g_pDiskState;
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
bool ParCoordinator::PostParChecker::RequestMorePars(int iBlockNeeded, int* pBlockFound)
|
||||
{
|
||||
return m_pOwner->RequestMorePars(m_pPostInfo->GetNZBInfo(), GetParFilename(), iBlockNeeded, pBlockFound);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::UpdateProgress()
|
||||
{
|
||||
m_pOwner->UpdateParCheckProgress();
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParChecker::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_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::UpdateProgress()
|
||||
{
|
||||
m_pOwner->UpdateParRenameProgress();
|
||||
}
|
||||
|
||||
void ParCoordinator::PostParRenamer::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_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
|
||||
}
|
||||
#endif
|
||||
|
||||
ParCoordinator::ParCoordinator()
|
||||
{
|
||||
debug("Creating ParCoordinator");
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_bStopped = false;
|
||||
m_ParChecker.m_pOwner = this;
|
||||
m_ParRenamer.m_pOwner = this;
|
||||
#endif
|
||||
}
|
||||
|
||||
ParCoordinator::~ParCoordinator()
|
||||
{
|
||||
debug("Destroying ParCoordinator");
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void ParCoordinator::Stop()
|
||||
{
|
||||
debug("Stopping ParCoordinator");
|
||||
|
||||
m_bStopped = true;
|
||||
|
||||
if (m_ParChecker.IsRunning())
|
||||
{
|
||||
m_ParChecker.Stop();
|
||||
int iMSecWait = 5000;
|
||||
while (m_ParChecker.IsRunning() && iMSecWait > 0)
|
||||
{
|
||||
usleep(50 * 1000);
|
||||
iMSecWait -= 50;
|
||||
}
|
||||
if (m_ParChecker.IsRunning())
|
||||
{
|
||||
warn("Terminating par-check for %s", m_ParChecker.GetInfoName());
|
||||
m_ParChecker.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ParCoordinator::PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
debug("ParCoordinator: Pausing pars");
|
||||
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo)
|
||||
{
|
||||
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false,
|
||||
QueueEditor::eaGroupPauseExtraPars, 0, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ParCoordinator::FindMainPars(const char* szPath, FileList* 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 (FileList::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 (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
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void ParCoordinator::StartParCheckJob(PostInfo* pPostInfo)
|
||||
{
|
||||
m_eCurrentJob = jkParCheck;
|
||||
m_ParChecker.SetPostInfo(pPostInfo);
|
||||
m_ParChecker.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
|
||||
m_ParChecker.SetNZBName(pPostInfo->GetNZBInfo()->GetName());
|
||||
m_ParChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", pPostInfo->GetInfoName());
|
||||
pPostInfo->SetWorking(true);
|
||||
m_ParChecker.Start();
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void ParCoordinator::StartParRenameJob(PostInfo* pPostInfo)
|
||||
{
|
||||
m_eCurrentJob = jkParRename;
|
||||
m_ParRenamer.SetPostInfo(pPostInfo);
|
||||
m_ParRenamer.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
|
||||
m_ParRenamer.SetInfoName(pPostInfo->GetNZBInfo()->GetName());
|
||||
m_ParRenamer.PrintMessage(Message::mkInfo, "Checking renamed files for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->SetWorking(true);
|
||||
m_ParRenamer.Start();
|
||||
}
|
||||
|
||||
bool ParCoordinator::Cancel()
|
||||
{
|
||||
if (m_eCurrentJob == jkParCheck)
|
||||
{
|
||||
#ifdef HAVE_PAR2_CANCEL
|
||||
if (!m_ParChecker.GetCancelled())
|
||||
{
|
||||
debug("Cancelling par-repair for %s", m_ParChecker.GetInfoName());
|
||||
m_ParChecker.Cancel();
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
warn("Cannot cancel par-repair for %s, used version of libpar2 does not support cancelling", m_ParChecker.GetInfoName());
|
||||
#endif
|
||||
}
|
||||
else if (m_eCurrentJob == jkParRename)
|
||||
{
|
||||
if (!m_ParRenamer.GetCancelled())
|
||||
{
|
||||
debug("Cancelling par-rename for %s", m_ParRenamer.GetInfoName());
|
||||
m_ParRenamer.Cancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
bool ParCoordinator::AddPar(FileInfo* pFileInfo, bool bDeleted)
|
||||
{
|
||||
bool bSameCollection = m_ParChecker.IsRunning() &&
|
||||
pFileInfo->GetNZBInfo() == m_ParChecker.GetPostInfo()->GetNZBInfo() &&
|
||||
SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(m_ParChecker.GetParFilename()));
|
||||
if (bSameCollection && !bDeleted)
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, pFileInfo->GetFilename());
|
||||
szFullFilename[1024-1] = '\0';
|
||||
m_ParChecker.AddParFile(szFullFilename);
|
||||
|
||||
if (g_pOptions->GetParPauseQueue())
|
||||
{
|
||||
PauseDownload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ParChecker.QueueChanged();
|
||||
}
|
||||
return bSameCollection;
|
||||
}
|
||||
|
||||
void ParCoordinator::ParCheckCompleted()
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
|
||||
|
||||
// Update ParStatus (accumulate result)
|
||||
if ((m_ParChecker.GetStatus() == ParChecker::psRepaired ||
|
||||
m_ParChecker.GetStatus() == ParChecker::psRepairNotNeeded) &&
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSuccess);
|
||||
}
|
||||
else if (m_ParChecker.GetStatus() == ParChecker::psRepairPossible &&
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psRepairPossible);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
|
||||
}
|
||||
|
||||
pPostInfo->SetWorking(false);
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound)
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
Blocks blocks;
|
||||
blocks.clear();
|
||||
int iBlockFound = 0;
|
||||
int iCurBlockFound = 0;
|
||||
|
||||
FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, true, true, &iCurBlockFound);
|
||||
iBlockFound += iCurBlockFound;
|
||||
if (iBlockFound < iBlockNeeded)
|
||||
{
|
||||
FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, true, false, &iCurBlockFound);
|
||||
iBlockFound += iCurBlockFound;
|
||||
}
|
||||
if (iBlockFound < iBlockNeeded && !g_pOptions->GetStrictParName())
|
||||
{
|
||||
FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, false, false, &iCurBlockFound);
|
||||
iBlockFound += iCurBlockFound;
|
||||
}
|
||||
|
||||
if (iBlockFound >= iBlockNeeded)
|
||||
{
|
||||
// 1. first unpause all files with par-blocks less or equal iBlockNeeded
|
||||
// starting from the file with max block count.
|
||||
// if par-collection was built exponentially and all par-files present,
|
||||
// this step selects par-files with exact number of blocks we need.
|
||||
while (iBlockNeeded > 0)
|
||||
{
|
||||
BlockInfo* pBestBlockInfo = NULL;
|
||||
for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
|
||||
{
|
||||
BlockInfo* pBlockInfo = *it;
|
||||
if (pBlockInfo->m_iBlockCount <= iBlockNeeded &&
|
||||
(!pBestBlockInfo || pBestBlockInfo->m_iBlockCount < pBlockInfo->m_iBlockCount))
|
||||
{
|
||||
pBestBlockInfo = pBlockInfo;
|
||||
}
|
||||
}
|
||||
if (pBestBlockInfo)
|
||||
{
|
||||
if (pBestBlockInfo->m_pFileInfo->GetPaused())
|
||||
{
|
||||
m_ParChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", pNZBInfo->GetName(), (int)PATH_SEPARATOR, pBestBlockInfo->m_pFileInfo->GetFilename());
|
||||
pBestBlockInfo->m_pFileInfo->SetPaused(false);
|
||||
pBestBlockInfo->m_pFileInfo->SetExtraPriority(true);
|
||||
}
|
||||
iBlockNeeded -= pBestBlockInfo->m_iBlockCount;
|
||||
blocks.remove(pBestBlockInfo);
|
||||
delete pBestBlockInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. then unpause other files
|
||||
// this step only needed if the par-collection was built not exponentially
|
||||
// or not all par-files present (or some of them were corrupted)
|
||||
// this step is not optimal, but we hope, that the first step will work good
|
||||
// in most cases and we will not need the second step often
|
||||
while (iBlockNeeded > 0)
|
||||
{
|
||||
BlockInfo* pBlockInfo = blocks.front();
|
||||
if (pBlockInfo->m_pFileInfo->GetPaused())
|
||||
{
|
||||
m_ParChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", pNZBInfo->GetName(), (int)PATH_SEPARATOR, pBlockInfo->m_pFileInfo->GetFilename());
|
||||
pBlockInfo->m_pFileInfo->SetPaused(false);
|
||||
pBlockInfo->m_pFileInfo->SetExtraPriority(true);
|
||||
}
|
||||
iBlockNeeded -= pBlockInfo->m_iBlockCount;
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (pBlockFound)
|
||||
{
|
||||
*pBlockFound = iBlockFound;
|
||||
}
|
||||
|
||||
for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
blocks.clear();
|
||||
|
||||
bool bOK = iBlockNeeded <= 0;
|
||||
|
||||
if (bOK && g_pOptions->GetParPauseQueue())
|
||||
{
|
||||
UnpauseDownload();
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szParFilename,
|
||||
Blocks* pBlocks, bool bStrictParName, bool bExactParName, int* pBlockFound)
|
||||
{
|
||||
*pBlockFound = 0;
|
||||
|
||||
// extract base name from m_szParFilename (trim .par2-extension and possible .vol-part)
|
||||
char* szBaseParFilename = Util::BaseFileName(szParFilename);
|
||||
char szMainBaseFilename[1024];
|
||||
int iMainBaseLen = 0;
|
||||
if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
|
||||
{
|
||||
// should not happen
|
||||
error("Internal error: could not parse filename %s", szBaseParFilename);
|
||||
return;
|
||||
}
|
||||
int maxlen = iMainBaseLen < 1024 ? iMainBaseLen : 1024 - 1;
|
||||
strncpy(szMainBaseFilename, szBaseParFilename, maxlen);
|
||||
szMainBaseFilename[maxlen] = '\0';
|
||||
for (char* p = szMainBaseFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
int iBlocks = 0;
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo &&
|
||||
ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
|
||||
iBlocks > 0)
|
||||
{
|
||||
bool bUseFile = true;
|
||||
|
||||
if (bExactParName)
|
||||
{
|
||||
bUseFile = SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(szParFilename));
|
||||
}
|
||||
else if (bStrictParName)
|
||||
{
|
||||
// the pFileInfo->GetFilename() may be not confirmed and may contain
|
||||
// additional texts if Subject could not be parsed correctly
|
||||
|
||||
char szLoFileName[1024];
|
||||
strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
|
||||
szLoFileName[1024-1] = '\0';
|
||||
for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
char szCandidateFileName[1024];
|
||||
snprintf(szCandidateFileName, 1024, "%s.par2", szMainBaseFilename);
|
||||
szCandidateFileName[1024-1] = '\0';
|
||||
if (!strstr(szLoFileName, szCandidateFileName))
|
||||
{
|
||||
snprintf(szCandidateFileName, 1024, "%s.vol", szMainBaseFilename);
|
||||
szCandidateFileName[1024-1] = '\0';
|
||||
bUseFile = strstr(szLoFileName, szCandidateFileName);
|
||||
}
|
||||
}
|
||||
|
||||
bool bAlreadyAdded = false;
|
||||
// check if file is not in the list already
|
||||
if (bUseFile)
|
||||
{
|
||||
for (Blocks::iterator it = pBlocks->begin(); it != pBlocks->end(); it++)
|
||||
{
|
||||
BlockInfo* pBlockInfo = *it;
|
||||
if (pBlockInfo->m_pFileInfo == pFileInfo)
|
||||
{
|
||||
bAlreadyAdded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it is a par2-file with blocks and it was from the same NZB-request
|
||||
// and it belongs to the same file collection (same base name),
|
||||
// then OK, we can use it
|
||||
if (bUseFile && !bAlreadyAdded)
|
||||
{
|
||||
BlockInfo* pBlockInfo = new BlockInfo();
|
||||
pBlockInfo->m_pFileInfo = pFileInfo;
|
||||
pBlockInfo->m_iBlockCount = iBlocks;
|
||||
pBlocks->push_back(pBlockInfo);
|
||||
*pBlockFound += iBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::UpdateParCheckProgress()
|
||||
{
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
|
||||
if (m_ParChecker.GetFileProgress() == 0)
|
||||
{
|
||||
pPostInfo->SetProgressLabel(m_ParChecker.GetProgressLabel());
|
||||
}
|
||||
pPostInfo->SetFileProgress(m_ParChecker.GetFileProgress());
|
||||
pPostInfo->SetStageProgress(m_ParChecker.GetStageProgress());
|
||||
PostInfo::EStage StageKind[] = { PostInfo::ptLoadingPars, PostInfo::ptVerifyingSources, PostInfo::ptRepairing, PostInfo::ptVerifyingRepaired };
|
||||
PostInfo::EStage eStage = StageKind[m_ParChecker.GetStage()];
|
||||
time_t tCurrent = time(NULL);
|
||||
|
||||
if (!pPostInfo->GetStartTime())
|
||||
{
|
||||
pPostInfo->SetStartTime(tCurrent);
|
||||
}
|
||||
|
||||
if (pPostInfo->GetStage() != eStage)
|
||||
{
|
||||
pPostInfo->SetStage(eStage);
|
||||
pPostInfo->SetStageTime(tCurrent);
|
||||
}
|
||||
|
||||
bool bParCancel = false;
|
||||
#ifdef HAVE_PAR2_CANCEL
|
||||
if (!m_ParChecker.GetCancelled())
|
||||
{
|
||||
if ((g_pOptions->GetParTimeLimit() > 0) &&
|
||||
m_ParChecker.GetStage() == ParChecker::ptRepairing &&
|
||||
((g_pOptions->GetParTimeLimit() > 5 && tCurrent - pPostInfo->GetStageTime() > 5 * 60) ||
|
||||
(g_pOptions->GetParTimeLimit() <= 5 && tCurrent - pPostInfo->GetStageTime() > 1 * 60)))
|
||||
{
|
||||
// first five (or one) minutes elapsed, now can check the estimated time
|
||||
int iEstimatedRepairTime = (int)((tCurrent - pPostInfo->GetStartTime()) * 1000 /
|
||||
(pPostInfo->GetStageProgress() > 0 ? pPostInfo->GetStageProgress() : 1));
|
||||
if (iEstimatedRepairTime > g_pOptions->GetParTimeLimit() * 60)
|
||||
{
|
||||
debug("Estimated repair time %i seconds", iEstimatedRepairTime);
|
||||
m_ParChecker.PrintMessage(Message::mkWarning, "Cancelling par-repair for %s, estimated repair time (%i minutes) exceeds allowed repair time", m_ParChecker.GetInfoName(), iEstimatedRepairTime / 60);
|
||||
bParCancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bParCancel)
|
||||
{
|
||||
m_ParChecker.Cancel();
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
CheckPauseState(pPostInfo);
|
||||
}
|
||||
|
||||
void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
|
||||
{
|
||||
if (g_pOptions->GetPausePostProcess())
|
||||
{
|
||||
time_t tStageTime = pPostInfo->GetStageTime();
|
||||
time_t tStartTime = pPostInfo->GetStartTime();
|
||||
time_t tWaitTime = time(NULL);
|
||||
|
||||
// wait until Post-processor is unpaused
|
||||
while (g_pOptions->GetPausePostProcess() && !m_bStopped)
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
|
||||
// update time stamps
|
||||
|
||||
time_t tDelta = time(NULL) - tWaitTime;
|
||||
|
||||
if (tStageTime > 0)
|
||||
{
|
||||
pPostInfo->SetStageTime(tStageTime + tDelta);
|
||||
}
|
||||
|
||||
if (tStartTime > 0)
|
||||
{
|
||||
pPostInfo->SetStartTime(tStartTime + tDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::ParRenameCompleted()
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
|
||||
pPostInfo->GetNZBInfo()->SetRenameStatus(m_ParRenamer.GetStatus() == ParRenamer::psSuccess ? NZBInfo::rsSuccess : NZBInfo::rsFailure);
|
||||
pPostInfo->SetWorking(false);
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
void ParCoordinator::UpdateParRenameProgress()
|
||||
{
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
|
||||
pPostInfo->SetProgressLabel(m_ParRenamer.GetProgressLabel());
|
||||
pPostInfo->SetStageProgress(m_ParRenamer.GetStageProgress());
|
||||
time_t tCurrent = time(NULL);
|
||||
|
||||
if (!pPostInfo->GetStartTime())
|
||||
{
|
||||
pPostInfo->SetStartTime(tCurrent);
|
||||
}
|
||||
|
||||
if (pPostInfo->GetStage() != PostInfo::ptRenaming)
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptRenaming);
|
||||
pPostInfo->SetStageTime(tCurrent);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
CheckPauseState(pPostInfo);
|
||||
}
|
||||
|
||||
void ParCoordinator::PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...)
|
||||
{
|
||||
char szText[1024];
|
||||
va_list args;
|
||||
va_start(args, szFormat);
|
||||
vsnprintf(szText, 1024, szFormat, args);
|
||||
va_end(args);
|
||||
szText[1024-1] = '\0';
|
||||
|
||||
pPostInfo->AppendMessage(eKind, szText);
|
||||
|
||||
switch (eKind)
|
||||
{
|
||||
case Message::mkDetail:
|
||||
detail("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkInfo:
|
||||
info("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkWarning:
|
||||
warn("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkError:
|
||||
error("%s", szText);
|
||||
break;
|
||||
|
||||
case Message::mkDebug:
|
||||
debug("%s", szText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
130
ParCoordinator.h
Normal file
130
ParCoordinator.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 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 PARCOORDINATOR_H
|
||||
#define PARCOORDINATOR_H
|
||||
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
#include "DownloadInfo.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
#include "ParRenamer.h"
|
||||
#endif
|
||||
|
||||
class ParCoordinator
|
||||
{
|
||||
private:
|
||||
#ifndef DISABLE_PARCHECK
|
||||
class PostParChecker: public ParChecker
|
||||
{
|
||||
private:
|
||||
ParCoordinator* m_pOwner;
|
||||
PostInfo* m_pPostInfo;
|
||||
protected:
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
virtual void UpdateProgress();
|
||||
virtual void Completed() { m_pOwner->ParCheckCompleted(); }
|
||||
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_pPostInfo; }
|
||||
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
|
||||
|
||||
friend class ParCoordinator;
|
||||
};
|
||||
|
||||
class PostParRenamer: public ParRenamer
|
||||
{
|
||||
private:
|
||||
ParCoordinator* m_pOwner;
|
||||
PostInfo* m_pPostInfo;
|
||||
protected:
|
||||
virtual void UpdateProgress();
|
||||
virtual void Completed() { m_pOwner->ParRenameCompleted(); }
|
||||
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_pPostInfo; }
|
||||
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
|
||||
|
||||
friend class ParCoordinator;
|
||||
};
|
||||
|
||||
struct BlockInfo
|
||||
{
|
||||
FileInfo* m_pFileInfo;
|
||||
int m_iBlockCount;
|
||||
};
|
||||
|
||||
typedef std::list<BlockInfo*> Blocks;
|
||||
|
||||
enum EJobKind
|
||||
{
|
||||
jkParCheck,
|
||||
jkParRename
|
||||
};
|
||||
|
||||
private:
|
||||
PostParChecker m_ParChecker;
|
||||
bool m_bStopped;
|
||||
PostParRenamer m_ParRenamer;
|
||||
EJobKind m_eCurrentJob;
|
||||
|
||||
protected:
|
||||
virtual bool PauseDownload() = 0;
|
||||
virtual bool UnpauseDownload() = 0;
|
||||
void UpdateParCheckProgress();
|
||||
void UpdateParRenameProgress();
|
||||
void ParCheckCompleted();
|
||||
void ParRenameCompleted();
|
||||
void CheckPauseState(PostInfo* pPostInfo);
|
||||
bool RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound);
|
||||
void PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...);
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
public:
|
||||
ParCoordinator();
|
||||
virtual ~ParCoordinator();
|
||||
static bool FindMainPars(const char* szPath, FileList* 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
|
||||
bool AddPar(FileInfo* pFileInfo, bool bDeleted);
|
||||
void FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szParFilename,
|
||||
Blocks* pBlocks, bool bStrictParName, bool bExactParName, int* pBlockFound);
|
||||
void StartParCheckJob(PostInfo* pPostInfo);
|
||||
void StartParRenameJob(PostInfo* pPostInfo);
|
||||
void Stop();
|
||||
bool Cancel();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
315
ParRenamer.cpp
Normal file
315
ParRenamer.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <par2cmdline.h>
|
||||
#include <par2repairer.h>
|
||||
#include <md5.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <libpar2/par2cmdline.h>
|
||||
#include <libpar2/par2repairer.h>
|
||||
#include <libpar2/md5.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ParRenamer.h"
|
||||
#include "ParCoordinator.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
class ParRenamerRepairer : public Par2Repairer
|
||||
{
|
||||
public:
|
||||
friend class ParRenamer;
|
||||
};
|
||||
|
||||
ParRenamer::FileHash::FileHash(const char* szFilename, const char* szHash)
|
||||
{
|
||||
m_szFilename = strdup(szFilename);
|
||||
m_szHash = strdup(szHash);
|
||||
}
|
||||
|
||||
ParRenamer::FileHash::~FileHash()
|
||||
{
|
||||
free(m_szFilename);
|
||||
free(m_szHash);
|
||||
}
|
||||
|
||||
ParRenamer::ParRenamer()
|
||||
{
|
||||
debug("Creating ParRenamer");
|
||||
|
||||
m_eStatus = psFailed;
|
||||
m_szDestDir = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_szProgressLabel = (char*)malloc(1024);
|
||||
m_iStageProgress = 0;
|
||||
m_bCancelled = false;
|
||||
}
|
||||
|
||||
ParRenamer::~ParRenamer()
|
||||
{
|
||||
debug("Destroying ParRenamer");
|
||||
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
free(m_szProgressLabel);
|
||||
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void ParRenamer::Cleanup()
|
||||
{
|
||||
for (FileHashList::iterator it = m_fileHashList.begin(); it != m_fileHashList.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_fileHashList.clear();
|
||||
}
|
||||
|
||||
void ParRenamer::SetDestDir(const char * szDestDir)
|
||||
{
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void ParRenamer::SetInfoName(const char * szInfoName)
|
||||
{
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
}
|
||||
|
||||
void ParRenamer::Cancel()
|
||||
{
|
||||
m_bCancelled = true;
|
||||
}
|
||||
|
||||
void ParRenamer::Run()
|
||||
{
|
||||
Cleanup();
|
||||
m_bCancelled = false;
|
||||
m_iRenamedCount = 0;
|
||||
m_eStatus = psFailed;
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "Checking renamed files for %s", m_szInfoName);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iStageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
LoadParFiles();
|
||||
CheckFiles();
|
||||
|
||||
if (m_bCancelled)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Renaming cancelled for %s", m_szInfoName);
|
||||
}
|
||||
else if (m_iRenamedCount > 0)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Successfully renamed %i file(s) for %s", m_iRenamedCount, m_szInfoName);
|
||||
m_eStatus = psSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "No renamed files found for %s", m_szInfoName);
|
||||
}
|
||||
|
||||
Cleanup();
|
||||
Completed();
|
||||
}
|
||||
|
||||
void ParRenamer::LoadParFiles()
|
||||
{
|
||||
ParCoordinator::FileList parFileList;
|
||||
ParCoordinator::FindMainPars(m_szDestDir, &parFileList);
|
||||
|
||||
for (ParCoordinator::FileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
|
||||
{
|
||||
char* szParFilename = *it;
|
||||
|
||||
char szFullParFilename[1024];
|
||||
snprintf(szFullParFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szParFilename);
|
||||
szFullParFilename[1024-1] = '\0';
|
||||
|
||||
LoadParFile(szFullParFilename);
|
||||
|
||||
free(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::LoadParFile(const char* szParFilename)
|
||||
{
|
||||
ParRenamerRepairer* pRepairer = new ParRenamerRepairer();
|
||||
|
||||
if (!pRepairer->LoadPacketsFromFile(szParFilename))
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Could not load par2-file %s", szParFilename);
|
||||
delete pRepairer;
|
||||
return;
|
||||
}
|
||||
|
||||
for (map<MD5Hash, Par2RepairerSourceFile*>::iterator it = pRepairer->sourcefilemap.begin(); it != pRepairer->sourcefilemap.end(); it++)
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Par2RepairerSourceFile* sourceFile = (*it).second;
|
||||
m_fileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(),
|
||||
sourceFile->GetDescriptionPacket()->Hash16k().print().c_str()));
|
||||
}
|
||||
|
||||
delete pRepairer;
|
||||
}
|
||||
|
||||
void ParRenamer::CheckFiles()
|
||||
{
|
||||
int iFileCount = 0;
|
||||
DirBrowser dir2(m_szDestDir);
|
||||
while (const char* filename = dir2.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !m_bCancelled)
|
||||
{
|
||||
iFileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int iCurFile = 0;
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !m_bCancelled)
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "Checking file %s", filename);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iStageProgress = iCurFile * 1000 / iFileCount;
|
||||
UpdateProgress();
|
||||
iCurFile++;
|
||||
|
||||
CheckFile(szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::CheckFile(const char* szFilename)
|
||||
{
|
||||
debug("Computing hash for %s", szFilename);
|
||||
|
||||
const int iBlockSize = 16*1024;
|
||||
|
||||
FILE* pFile = fopen(szFilename, "rb");
|
||||
if (!pFile)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open file %s", szFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
// load first 16K of the file into buffer
|
||||
|
||||
void* pBuffer = malloc(iBlockSize);
|
||||
|
||||
int iReadBytes = fread(pBuffer, 1, iBlockSize, pFile);
|
||||
int iError = ferror(pFile);
|
||||
if (iReadBytes != iBlockSize && iError)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not read file %s", szFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
MD5Hash hash16k;
|
||||
MD5Context context;
|
||||
context.Update(pBuffer, iReadBytes);
|
||||
context.Final(hash16k);
|
||||
|
||||
free(pBuffer);
|
||||
|
||||
debug("file: %s; hash16k: %s", Util::BaseFileName(szFilename), hash16k.print().c_str());
|
||||
|
||||
for (FileHashList::iterator it = m_fileHashList.begin(); it != m_fileHashList.end(); it++)
|
||||
{
|
||||
FileHash* pFileHash = *it;
|
||||
if (!strcmp(pFileHash->GetHash(), hash16k.print().c_str()))
|
||||
{
|
||||
debug("Found correct filename: %s", pFileHash->GetFilename());
|
||||
|
||||
char szDstFilename[1024];
|
||||
snprintf(szDstFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, pFileHash->GetFilename());
|
||||
szDstFilename[1024-1] = '\0';
|
||||
|
||||
if (!Util::FileExists(szDstFilename))
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szFilename), pFileHash->GetFilename());
|
||||
if (Util::MoveFile(szFilename, szDstFilename))
|
||||
{
|
||||
m_iRenamedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not rename %s to %s", szFilename, szDstFilename);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
98
ParRenamer.h
Normal file
98
ParRenamer.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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 PARRENAMER_H
|
||||
#define PARRENAMER_H
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Log.h"
|
||||
|
||||
class ParRenamer : public Thread
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
psFailed,
|
||||
psSuccess
|
||||
};
|
||||
|
||||
class FileHash
|
||||
{
|
||||
private:
|
||||
char* m_szFilename;
|
||||
char* m_szHash;
|
||||
|
||||
public:
|
||||
FileHash(const char* szFilename, const char* szHash);
|
||||
~FileHash();
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
const char* GetHash() { return m_szHash; }
|
||||
};
|
||||
|
||||
typedef std::deque<FileHash*> FileHashList;
|
||||
|
||||
private:
|
||||
char* m_szInfoName;
|
||||
char* m_szDestDir;
|
||||
EStatus m_eStatus;
|
||||
char* m_szProgressLabel;
|
||||
int m_iStageProgress;
|
||||
bool m_bCancelled;
|
||||
FileHashList m_fileHashList;
|
||||
int m_iRenamedCount;
|
||||
|
||||
void Cleanup();
|
||||
void LoadParFiles();
|
||||
void LoadParFile(const char* szParFilename);
|
||||
void CheckFiles();
|
||||
void CheckFile(const char* szFilename);
|
||||
|
||||
protected:
|
||||
virtual void UpdateProgress() {}
|
||||
virtual void Completed() {}
|
||||
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
|
||||
const char* GetProgressLabel() { return m_szProgressLabel; }
|
||||
int GetStageProgress() { return m_iStageProgress; }
|
||||
|
||||
public:
|
||||
ParRenamer();
|
||||
virtual ~ParRenamer();
|
||||
virtual void Run();
|
||||
void SetDestDir(const char* szDestDir);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetInfoName(const char* szInfoName);
|
||||
void SetStatus(EStatus eStatus);
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void Cancel();
|
||||
bool GetCancelled() { return m_bCancelled; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1361
PrePostProcessor.cpp
1361
PrePostProcessor.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -31,11 +31,7 @@
|
||||
#include "Thread.h"
|
||||
#include "Observer.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Scanner.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
#endif
|
||||
#include "ParCoordinator.h"
|
||||
|
||||
class PrePostProcessor : public Thread
|
||||
{
|
||||
@@ -48,103 +44,68 @@ public:
|
||||
eaPostDelete,
|
||||
eaHistoryDelete,
|
||||
eaHistoryReturn,
|
||||
eaHistoryProcess
|
||||
eaHistoryProcess,
|
||||
eaHistorySetParameter
|
||||
};
|
||||
|
||||
private:
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
class QueueCoordinatorObserver: public Observer
|
||||
{
|
||||
public:
|
||||
PrePostProcessor* owner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { owner->QueueCoordinatorUpdate(Caller, Aspect); }
|
||||
PrePostProcessor* m_pOwner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->QueueCoordinatorUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
class ParCheckerObserver: public Observer
|
||||
{
|
||||
public:
|
||||
PrePostProcessor* owner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { owner->ParCheckerUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
class PostParChecker: public ParChecker
|
||||
class PostParCoordinator: public ParCoordinator
|
||||
{
|
||||
private:
|
||||
PrePostProcessor* m_Owner;
|
||||
PostInfo* m_pPostInfo;
|
||||
PrePostProcessor* m_pOwner;
|
||||
protected:
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
virtual void UpdateProgress();
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_pPostInfo; }
|
||||
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
|
||||
virtual bool PauseDownload() { return m_pOwner->PauseDownload(); }
|
||||
virtual bool UnpauseDownload() { return m_pOwner->UnpauseDownload(); }
|
||||
|
||||
friend class PrePostProcessor;
|
||||
};
|
||||
|
||||
struct BlockInfo
|
||||
{
|
||||
FileInfo* m_pFileInfo;
|
||||
int m_iBlockCount;
|
||||
};
|
||||
|
||||
typedef std::list<BlockInfo*> Blocks;
|
||||
#endif
|
||||
|
||||
private:
|
||||
PostParCoordinator m_ParCoordinator;
|
||||
QueueCoordinatorObserver m_QueueCoordinatorObserver;
|
||||
bool m_bHasMoreJobs;
|
||||
bool m_bPostScript;
|
||||
bool m_bSchedulerPauseChanged;
|
||||
bool m_bSchedulerPause;
|
||||
bool m_bPostPause;
|
||||
Scanner m_Scanner;
|
||||
const char* m_szPauseReason;
|
||||
|
||||
bool IsNZBFileCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
|
||||
bool bIgnoreFirstInPostQueue, bool bIgnorePausedPars, bool bCheckPostQueue, bool bAllowOnlyOneDeleted);
|
||||
bool bIgnorePausedPars, bool bAllowOnlyOneDeleted);
|
||||
void CheckPostQueue();
|
||||
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartScriptJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void SaveQueue(DownloadQueue* pDownloadQueue);
|
||||
void SanitisePostQueue(PostQueue* pPostQueue);
|
||||
void CheckDiskSpace();
|
||||
void ApplySchedulerState();
|
||||
void CheckScheduledResume();
|
||||
void UpdatePauseState(bool bNeedPause, const char* szReason);
|
||||
bool PauseDownload();
|
||||
bool UnpauseDownload();
|
||||
void NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue);
|
||||
bool FindMainPars(const char* szPath, FileList* pFileList);
|
||||
bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
|
||||
bool SameParCollection(const char* szFilename1, const char* szFilename2);
|
||||
bool CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bParCheck, bool bPostScript, bool bAddTop);
|
||||
void DeleteQueuedFile(const char* szQueuedFile);
|
||||
void PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
NZBInfo* MergeGroups(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
bool PostQueueMove(IDList* pIDList, EEditAction eAction, int iOffset);
|
||||
bool PostQueueDelete(IDList* pIDList);
|
||||
bool HistoryDelete(IDList* pIDList);
|
||||
bool HistoryReturn(IDList* pIDList, bool bReprocess);
|
||||
bool HistoryEdit(IDList* pIDList, EEditAction eAction, int iOffset, const char* szText);
|
||||
void HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo);
|
||||
void HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bReprocess);
|
||||
void HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText);
|
||||
void Cleanup();
|
||||
FileInfo* GetQueueGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void CheckHistory();
|
||||
void DeletePostThread(PostInfo* pPostInfo);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
PostParChecker m_ParChecker;
|
||||
ParCheckerObserver m_ParCheckerObserver;
|
||||
|
||||
void ParCheckerUpdate(Subject* Caller, void* Aspect);
|
||||
bool AddPar(FileInfo* pFileInfo, bool bDeleted);
|
||||
bool RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound);
|
||||
void FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szParFilename,
|
||||
Blocks* pBlocks, bool bStrictParName, bool bExactParName, int* pBlockFound);
|
||||
void UpdateParProgress();
|
||||
void StartParJob(PostInfo* pPostInfo);
|
||||
#endif
|
||||
|
||||
public:
|
||||
PrePostProcessor();
|
||||
virtual ~PrePostProcessor();
|
||||
@@ -152,8 +113,7 @@ public:
|
||||
virtual void Stop();
|
||||
void QueueCoordinatorUpdate(Subject* Caller, void* Aspect);
|
||||
bool HasMoreJobs() { return m_bHasMoreJobs; }
|
||||
void ScanNZBDir();
|
||||
bool QueueEditList(IDList* pIDList, EEditAction eAction, int iOffset);
|
||||
bool QueueEditList(IDList* pIDList, EEditAction eAction, int iOffset, const char* szText);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
@@ -117,6 +117,17 @@ void QueueCoordinator::Run()
|
||||
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
|
||||
// compute maximum number of allowed download threads
|
||||
m_iDownloadsLimit = 2; // two extra threads for completing files (when connections are not needed)
|
||||
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (pNewsServer->GetLevel() == 0)
|
||||
{
|
||||
m_iDownloadsLimit += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
}
|
||||
|
||||
m_tStartServer = time(NULL);
|
||||
m_tLastCheck = m_tStartServer;
|
||||
bool bWasStandBy = true;
|
||||
@@ -127,27 +138,33 @@ void QueueCoordinator::Run()
|
||||
{
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
NNTPConnection* pConnection = g_pServerPool->GetConnection(0);
|
||||
NNTPConnection* pConnection = g_pServerPool->GetConnection(0, NULL, NULL);
|
||||
if (pConnection)
|
||||
{
|
||||
// start download for next article
|
||||
FileInfo* pFileInfo;
|
||||
ArticleInfo* pArticleInfo;
|
||||
|
||||
bool bFreeConnection = false;
|
||||
|
||||
m_mutexDownloadQueue.Lock();
|
||||
bool bHasMoreArticles = GetNextArticle(pFileInfo, pArticleInfo);
|
||||
bArticeDownloadsRunning = !m_ActiveDownloads.empty();
|
||||
m_bHasMoreJobs = bHasMoreArticles || bArticeDownloadsRunning;
|
||||
if (bHasMoreArticles && !IsStopped() && Thread::GetThreadCount() < g_pOptions->GetThreadLimit())
|
||||
if (bHasMoreArticles && !IsStopped() && (int)m_ActiveDownloads.size() < m_iDownloadsLimit)
|
||||
{
|
||||
StartArticleDownload(pFileInfo, pArticleInfo, pConnection);
|
||||
bArticeDownloadsRunning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pServerPool->FreeConnection(pConnection, false);
|
||||
bFreeConnection = true;
|
||||
}
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
|
||||
if (bFreeConnection)
|
||||
{
|
||||
g_pServerPool->FreeConnection(pConnection, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -168,9 +185,12 @@ void QueueCoordinator::Run()
|
||||
int iSleepInterval = bStandBy ? 100 : 5;
|
||||
usleep(iSleepInterval * 1000);
|
||||
|
||||
AddSpeedReading(0);
|
||||
if (!bStandBy)
|
||||
{
|
||||
AddSpeedReading(0);
|
||||
}
|
||||
|
||||
iResetCounter+= iSleepInterval;
|
||||
iResetCounter += iSleepInterval;
|
||||
if (iResetCounter >= 1000)
|
||||
{
|
||||
// this code should not be called too often, once per second is OK
|
||||
@@ -294,75 +314,99 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
/*
|
||||
* NOTE: see note to "AddSpeedReading"
|
||||
*/
|
||||
float QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
int QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
{
|
||||
if (m_bStandBy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
if (iTimeDiff == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
float fSpeed = m_iSpeedTotalBytes / 1024.0f / iTimeDiff;
|
||||
return fSpeed;
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
if (iTimeDiff == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_iSpeedTotalBytes / iTimeDiff;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: we should use mutex by access to m_iSpeedBytes and m_iSpeedBytesIndex,
|
||||
* but this would results in a big performance loss (the function
|
||||
* "AddSpeedReading" is called extremly often), so we better agree with calculation
|
||||
* errors possible because of simultaneuos access from several threads.
|
||||
* The used algorithm is able to recover after few seconds.
|
||||
* In any case the calculation errors can not result in fatal system
|
||||
* errors (segmentation faults).
|
||||
*/
|
||||
void QueueCoordinator::AddSpeedReading(int iBytes)
|
||||
{
|
||||
int iNowSlot = (int)time(NULL) / SPEEDMETER_SLOTSIZE;
|
||||
time_t tCurTime = time(NULL);
|
||||
int iNowSlot = (int)tCurTime / SPEEDMETER_SLOTSIZE;
|
||||
|
||||
if (iNowSlot > m_iSpeedTime[m_iSpeedBytesIndex])
|
||||
{
|
||||
//record bytes in next slot
|
||||
m_iSpeedBytesIndex++;
|
||||
if (m_iSpeedBytesIndex >= SPEEDMETER_SLOTS)
|
||||
{
|
||||
m_iSpeedBytesIndex = 0;
|
||||
}
|
||||
//Adjust counters with outging information.
|
||||
m_iSpeedTotalBytes -= m_iSpeedBytes[m_iSpeedBytesIndex];
|
||||
if (g_pOptions->GetAccurateRate())
|
||||
{
|
||||
#ifdef HAVE_SPINLOCK
|
||||
m_spinlockSpeed.Lock();
|
||||
#else
|
||||
m_mutexSpeed.Lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
//Note we should really use the start time of the next slot
|
||||
//but its easier to just use the outgoing slot time. This
|
||||
//will result in a small error.
|
||||
m_iSpeedStartTime = m_iSpeedTime[m_iSpeedBytesIndex];
|
||||
while (iNowSlot > m_iSpeedTime[m_iSpeedBytesIndex])
|
||||
{
|
||||
//record bytes in next slot
|
||||
m_iSpeedBytesIndex++;
|
||||
if (m_iSpeedBytesIndex >= SPEEDMETER_SLOTS)
|
||||
{
|
||||
m_iSpeedBytesIndex = 0;
|
||||
}
|
||||
//Adjust counters with outgoing information.
|
||||
m_iSpeedTotalBytes -= m_iSpeedBytes[m_iSpeedBytesIndex];
|
||||
|
||||
//Now reset.
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] = 0;
|
||||
m_iSpeedTime[m_iSpeedBytesIndex] = iNowSlot;
|
||||
}
|
||||
//Note we should really use the start time of the next slot
|
||||
//but its easier to just use the outgoing slot time. This
|
||||
//will result in a small error.
|
||||
m_iSpeedStartTime = m_iSpeedTime[m_iSpeedBytesIndex];
|
||||
|
||||
if (m_iSpeedTotalBytes == 0)
|
||||
{
|
||||
m_iSpeedStartTime = iNowSlot;
|
||||
}
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] += iBytes;
|
||||
m_iSpeedTotalBytes += iBytes;
|
||||
//Now reset.
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] = 0;
|
||||
m_iSpeedTime[m_iSpeedBytesIndex] = iNowSlot;
|
||||
}
|
||||
|
||||
// Once per second recalculate summary field "m_iSpeedTotalBytes" to recover from possible synchronisation errors
|
||||
if (tCurTime > m_tSpeedCorrection)
|
||||
{
|
||||
int iSpeedTotalBytes = 0;
|
||||
for (int i = 0; i < SPEEDMETER_SLOTS; i++)
|
||||
{
|
||||
iSpeedTotalBytes += m_iSpeedBytes[i];
|
||||
}
|
||||
m_iSpeedTotalBytes = iSpeedTotalBytes;
|
||||
m_tSpeedCorrection = tCurTime;
|
||||
}
|
||||
|
||||
if (m_iSpeedTotalBytes == 0)
|
||||
{
|
||||
m_iSpeedStartTime = iNowSlot;
|
||||
}
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] += iBytes;
|
||||
m_iSpeedTotalBytes += iBytes;
|
||||
m_iAllBytes += iBytes;
|
||||
|
||||
if (g_pOptions->GetAccurateRate())
|
||||
{
|
||||
#ifdef HAVE_SPINLOCK
|
||||
m_spinlockSpeed.Unlock();
|
||||
#else
|
||||
m_mutexSpeed.Unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void QueueCoordinator::ResetSpeedStat()
|
||||
{
|
||||
m_iSpeedStartTime = (int)time(NULL) / SPEEDMETER_SLOTSIZE;
|
||||
time_t tCurTime = time(NULL);
|
||||
m_iSpeedStartTime = (int)tCurTime / SPEEDMETER_SLOTSIZE;
|
||||
for (int i = 0; i < SPEEDMETER_SLOTS; i++)
|
||||
{
|
||||
m_iSpeedBytes[i] = 0;
|
||||
m_iSpeedTime[i] = m_iSpeedStartTime;
|
||||
m_iSpeedTime[i] = m_iSpeedStartTime;
|
||||
}
|
||||
m_iSpeedBytesIndex = 0;
|
||||
m_iSpeedTotalBytes = 0;
|
||||
m_iSpeedTotalBytes = 0;
|
||||
m_tSpeedCorrection = tCurTime;
|
||||
}
|
||||
|
||||
long long QueueCoordinator::CalcRemainingSize()
|
||||
@@ -425,31 +469,90 @@ void QueueCoordinator::Stop()
|
||||
debug("ArticleDownloads are notified");
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns next article for download.
|
||||
*/
|
||||
bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArticleInfo)
|
||||
{
|
||||
// find an unpaused file with the highest priority, then take the next article from the file.
|
||||
// if the file doesn't have any articles left for download, we store that fact and search again,
|
||||
// ignoring all files which were previously marked as not having any articles.
|
||||
|
||||
// special case: if the file has ExtraPriority-flag set, it has the highest priority and the
|
||||
// Paused-flag is ignored.
|
||||
|
||||
//debug("QueueCoordinator::GetNextArticle()");
|
||||
|
||||
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
|
||||
bool bOK = false;
|
||||
|
||||
// pCheckedFiles stores
|
||||
bool* pCheckedFiles = NULL;
|
||||
|
||||
while (!bOK)
|
||||
{
|
||||
pFileInfo = *it;
|
||||
if (!pFileInfo->GetPaused() && !pFileInfo->GetDeleted())
|
||||
//debug("QueueCoordinator::GetNextArticle() - in loop");
|
||||
|
||||
pFileInfo = NULL;
|
||||
int iNum = 0;
|
||||
int iFileNum = 0;
|
||||
|
||||
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
|
||||
{
|
||||
if (pFileInfo->GetArticles()->empty() && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
FileInfo* pFileInfo1 = *it;
|
||||
if ((!pCheckedFiles || !pCheckedFiles[iNum]) &&
|
||||
!pFileInfo1->GetPaused() && !pFileInfo1->GetDeleted() &&
|
||||
(!pFileInfo ||
|
||||
(pFileInfo1->GetExtraPriority() == pFileInfo->GetExtraPriority() &&
|
||||
pFileInfo1->GetPriority() > pFileInfo->GetPriority()) ||
|
||||
(pFileInfo1->GetExtraPriority() > pFileInfo->GetExtraPriority())))
|
||||
{
|
||||
g_pDiskState->LoadArticles(pFileInfo);
|
||||
pFileInfo = pFileInfo1;
|
||||
iFileNum = iNum;
|
||||
}
|
||||
for (FileInfo::Articles::iterator at = pFileInfo->GetArticles()->begin(); at != pFileInfo->GetArticles()->end(); at++)
|
||||
iNum++;
|
||||
}
|
||||
|
||||
if (!pFileInfo)
|
||||
{
|
||||
// there are no more files for download
|
||||
break;
|
||||
}
|
||||
|
||||
if (pFileInfo->GetArticles()->empty() && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->LoadArticles(pFileInfo);
|
||||
}
|
||||
|
||||
// check if the file has any articles left for download
|
||||
for (FileInfo::Articles::iterator at = pFileInfo->GetArticles()->begin(); at != pFileInfo->GetArticles()->end(); at++)
|
||||
{
|
||||
pArticleInfo = *at;
|
||||
if (pArticleInfo->GetStatus() == 0)
|
||||
{
|
||||
pArticleInfo = *at;
|
||||
if (pArticleInfo->GetStatus() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bOK = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bOK)
|
||||
{
|
||||
// the file doesn't have any articles left for download, we mark the file as such
|
||||
if (!pCheckedFiles)
|
||||
{
|
||||
int iArrSize = sizeof(bool) * m_DownloadQueue.GetFileQueue()->size();
|
||||
pCheckedFiles = (bool*)malloc(iArrSize);
|
||||
memset(pCheckedFiles, false, iArrSize);
|
||||
}
|
||||
pCheckedFiles[iFileNum] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (pCheckedFiles)
|
||||
{
|
||||
free(pCheckedFiles);
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void QueueCoordinator::StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pArticleInfo, NNTPConnection* pConnection)
|
||||
@@ -462,42 +565,19 @@ void QueueCoordinator::StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pA
|
||||
pArticleDownloader->SetFileInfo(pFileInfo);
|
||||
pArticleDownloader->SetArticleInfo(pArticleInfo);
|
||||
pArticleDownloader->SetConnection(pConnection);
|
||||
BuildArticleFilename(pArticleDownloader, pFileInfo, pArticleInfo);
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "%s%c%s [%i/%i]", pFileInfo->GetNZBInfo()->GetName(), (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
|
||||
szInfoName[1024-1] = '\0';
|
||||
pArticleDownloader->SetInfoName(szInfoName);
|
||||
|
||||
pArticleInfo->SetStatus(ArticleInfo::aiRunning);
|
||||
pFileInfo->SetActiveDownloads(pFileInfo->GetActiveDownloads() + 1);
|
||||
|
||||
m_ActiveDownloads.push_back(pArticleDownloader);
|
||||
pArticleDownloader->Start();
|
||||
}
|
||||
|
||||
void QueueCoordinator::BuildArticleFilename(ArticleDownloader* pArticleDownloader, FileInfo* pFileInfo, ArticleInfo* pArticleInfo)
|
||||
{
|
||||
char name[1024];
|
||||
|
||||
snprintf(name, 1024, "%s%i.%03i", g_pOptions->GetTempDir(), pFileInfo->GetID(), pArticleInfo->GetPartNumber());
|
||||
name[1024-1] = '\0';
|
||||
pArticleInfo->SetResultFilename(name);
|
||||
|
||||
char tmpname[1024];
|
||||
snprintf(tmpname, 1024, "%s.tmp", name);
|
||||
tmpname[1024-1] = '\0';
|
||||
pArticleDownloader->SetTempFilename(tmpname);
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
|
||||
snprintf(name, 1024, "%s%c%s [%i/%i]", szNZBNiceName, (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
|
||||
name[1024-1] = '\0';
|
||||
pArticleDownloader->SetInfoName(name);
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
{
|
||||
snprintf(name, 1024, "%s%i.out", g_pOptions->GetTempDir(), pFileInfo->GetID());
|
||||
name[1024-1] = '\0';
|
||||
pArticleDownloader->SetOutputFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
DownloadQueue* QueueCoordinator::LockQueue()
|
||||
{
|
||||
m_mutexDownloadQueue.Lock();
|
||||
@@ -564,6 +644,7 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
{
|
||||
warn("File \"%s\" seems to be duplicate, cancelling download and deleting file from queue", pFileInfo->GetFilename());
|
||||
fileCompleted = false;
|
||||
pFileInfo->SetAutoDeleted(true);
|
||||
DeleteQueueEntry(pFileInfo);
|
||||
}
|
||||
}
|
||||
@@ -607,6 +688,8 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
}
|
||||
}
|
||||
|
||||
pFileInfo->SetActiveDownloads(pFileInfo->GetActiveDownloads() - 1);
|
||||
|
||||
if (deleteFileObj)
|
||||
{
|
||||
bool fileDeleted = pFileInfo->GetDeleted();
|
||||
@@ -667,12 +750,9 @@ void QueueCoordinator::DiscardDiskFile(FileInfo* pFileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
if (g_pOptions->GetDirectWrite() && pFileInfo->GetOutputFilename())
|
||||
{
|
||||
char name[1024];
|
||||
snprintf(name, 1024, "%s%i.out", g_pOptions->GetTempDir(), pFileInfo->GetID());
|
||||
name[1024-1] = '\0';
|
||||
remove(name);
|
||||
remove(pFileInfo->GetOutputFilename());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,9 +784,25 @@ bool QueueCoordinator::IsDupe(FileInfo* pFileInfo)
|
||||
void QueueCoordinator::LogDebugInfo()
|
||||
{
|
||||
debug("--------------------------------------------");
|
||||
debug("Dumping debug info to log");
|
||||
debug("Dumping debug debug to log");
|
||||
debug("--------------------------------------------");
|
||||
|
||||
debug(" SpeedMeter");
|
||||
debug(" ----------");
|
||||
float fSpeed = (float)(CalcCurrentDownloadSpeed() / 1024.0);
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
debug(" Speed: %f", fSpeed);
|
||||
debug(" SpeedStartTime: %i", m_iSpeedStartTime);
|
||||
debug(" SpeedTotalBytes: %i", m_iSpeedTotalBytes);
|
||||
debug(" SpeedBytesIndex: %i", m_iSpeedBytesIndex);
|
||||
debug(" AllBytes: %i", m_iAllBytes);
|
||||
debug(" Time: %i", (int)time(NULL));
|
||||
debug(" TimeDiff: %i", iTimeDiff);
|
||||
for (int i=0; i < SPEEDMETER_SLOTS; i++)
|
||||
{
|
||||
debug(" Bytes[%i]: %i, Time[%i]: %i", i, m_iSpeedBytes[i], i, m_iSpeedTime[i]);
|
||||
}
|
||||
|
||||
debug(" QueueCoordinator");
|
||||
debug(" ----------------");
|
||||
|
||||
@@ -726,8 +822,7 @@ void QueueCoordinator::LogDebugInfo()
|
||||
|
||||
void QueueCoordinator::ResetHangingDownloads()
|
||||
{
|
||||
const int TimeOut = g_pOptions->GetTerminateTimeout();
|
||||
if (TimeOut == 0)
|
||||
if (g_pOptions->GetTerminateTimeout() == 0 && g_pOptions->GetConnectionTimeout() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -738,7 +833,15 @@ void QueueCoordinator::ResetHangingDownloads()
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
|
||||
{
|
||||
ArticleDownloader* pArticleDownloader = *it;
|
||||
if (tm - pArticleDownloader->GetLastUpdateTime() > TimeOut &&
|
||||
|
||||
if (tm - pArticleDownloader->GetLastUpdateTime() > g_pOptions->GetConnectionTimeout() + 1 &&
|
||||
pArticleDownloader->GetStatus() == ArticleDownloader::adRunning)
|
||||
{
|
||||
error("Cancelling hanging download %s", pArticleDownloader->GetInfoName());
|
||||
pArticleDownloader->Stop();
|
||||
}
|
||||
|
||||
if (tm - pArticleDownloader->GetLastUpdateTime() > g_pOptions->GetTerminateTimeout() &&
|
||||
pArticleDownloader->GetStatus() == ArticleDownloader::adRunning)
|
||||
{
|
||||
ArticleInfo* pArticleInfo = pArticleDownloader->GetArticleInfo();
|
||||
@@ -753,6 +856,7 @@ void QueueCoordinator::ResetHangingDownloads()
|
||||
error("Could not terminate hanging download %s", Util::BaseFileName(pArticleInfo->GetResultFilename()));
|
||||
}
|
||||
m_ActiveDownloads.erase(it);
|
||||
pArticleDownloader->GetFileInfo()->SetActiveDownloads(pArticleDownloader->GetFileInfo()->GetActiveDownloads() - 1);
|
||||
// it's not safe to destroy pArticleDownloader, because the state of object is unknown
|
||||
delete pArticleDownloader;
|
||||
it = m_ActiveDownloads.begin();
|
||||
@@ -822,7 +926,7 @@ void QueueCoordinator::AdjustStartTime()
|
||||
if (tDiff > 60 || tDiff < 0)
|
||||
{
|
||||
m_tStartServer += tDiff + 1; // "1" because the method is called once per second
|
||||
if (m_tStartDownload != 0)
|
||||
if (m_tStartDownload != 0 && !m_bStandBy)
|
||||
{
|
||||
m_tStartDownload += tDiff + 1;
|
||||
}
|
||||
@@ -834,9 +938,7 @@ bool QueueCoordinator::SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* s
|
||||
{
|
||||
if (pNZBInfo->GetPostProcess())
|
||||
{
|
||||
char szNZBNiceName[1024];
|
||||
pNZBInfo->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
error("Could not change category for %s. File in post-process-stage", szNZBNiceName);
|
||||
error("Could not change category for %s. File in post-process-stage", pNZBInfo->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -853,6 +955,36 @@ bool QueueCoordinator::SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* s
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool QueueCoordinator::SetQueueEntryNZBName(NZBInfo* pNZBInfo, const char* szName)
|
||||
{
|
||||
if (pNZBInfo->GetPostProcess())
|
||||
{
|
||||
error("Could not rename %s. File in post-process-stage", pNZBInfo->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen(szName) == 0)
|
||||
{
|
||||
error("Could not rename %s. The new name cannot be empty", pNZBInfo->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
char szOldDestDir[1024];
|
||||
strncpy(szOldDestDir, pNZBInfo->GetDestDir(), 1024);
|
||||
szOldDestDir[1024-1] = '\0';
|
||||
|
||||
char szNZBNicename[1024];
|
||||
NZBInfo::MakeNiceNZBName(szName, szNZBNicename, sizeof(szNZBNicename), false);
|
||||
pNZBInfo->SetName(szNZBNicename);
|
||||
|
||||
pNZBInfo->BuildDestDirName();
|
||||
|
||||
bool bDirUnchanged = !strcmp(pNZBInfo->GetDestDir(), szOldDestDir);
|
||||
bool bOK = bDirUnchanged || ArticleDownloader::MoveCompletedFiles(pNZBInfo, szOldDestDir);
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: DownloadQueue must be locked prior to call of this function
|
||||
*/
|
||||
@@ -860,11 +992,7 @@ bool QueueCoordinator::MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZB
|
||||
{
|
||||
if (pDestNZBInfo->GetPostProcess() || pSrcNZBInfo->GetPostProcess())
|
||||
{
|
||||
char szDestNZBNiceName[1024];
|
||||
pDestNZBInfo->GetNiceNZBName(szDestNZBNiceName, 1024);
|
||||
char szSrcNZBNiceName[1024];
|
||||
pSrcNZBInfo->GetNiceNZBName(szSrcNZBNiceName, 1024);
|
||||
error("Could not merge %s and %s. File in post-process-stage", szDestNZBNiceName, szSrcNZBNiceName);
|
||||
error("Could not merge %s and %s. File in post-process-stage", pDestNZBInfo->GetName(), pSrcNZBInfo->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -903,3 +1031,76 @@ bool QueueCoordinator::MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZB
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates new nzb-item out of existing files from other nzb-items.
|
||||
* If any of file-items is being downloaded the command fail.
|
||||
* For each file-item an event "eaFileDeleted" is fired.
|
||||
*
|
||||
* NOTE: DownloadQueue must be locked prior to call of this function
|
||||
*/
|
||||
bool QueueCoordinator::SplitQueueEntries(FileQueue* pFileList, const char* szName, NZBInfo** pNewNZBInfo)
|
||||
{
|
||||
if (pFileList->empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NZBInfo* pSrcNZBInfo = NULL;
|
||||
|
||||
for (FileQueue::iterator it = pFileList->begin(); it != pFileList->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetActiveDownloads() > 0 || pFileInfo->GetCompleted() > 0)
|
||||
{
|
||||
error("Could not split %s. File is already (partially) downloaded", pFileInfo->GetFilename());
|
||||
return false;
|
||||
}
|
||||
if (pFileInfo->GetNZBInfo()->GetPostProcess())
|
||||
{
|
||||
error("Could not split %s. File in post-process-stage", pFileInfo->GetFilename());
|
||||
return false;
|
||||
}
|
||||
if (!pSrcNZBInfo)
|
||||
{
|
||||
pSrcNZBInfo = pFileInfo->GetNZBInfo();
|
||||
}
|
||||
}
|
||||
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
pNZBInfo->AddReference();
|
||||
m_DownloadQueue.GetNZBInfoList()->Add(pNZBInfo);
|
||||
|
||||
pNZBInfo->SetFilename(pSrcNZBInfo->GetFilename());
|
||||
pNZBInfo->SetName(szName);
|
||||
pNZBInfo->SetCategory(pSrcNZBInfo->GetCategory());
|
||||
pNZBInfo->BuildDestDirName();
|
||||
pNZBInfo->SetQueuedFilename(pSrcNZBInfo->GetQueuedFilename());
|
||||
|
||||
for (NZBParameterList::iterator it = pSrcNZBInfo->GetParameters()->begin(); it != pSrcNZBInfo->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pNZBParameter = *it;
|
||||
pNZBInfo->SetParameter(pNZBParameter->GetName(), pNZBParameter->GetValue());
|
||||
}
|
||||
|
||||
for (FileQueue::iterator it = pFileList->begin(); it != pFileList->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
|
||||
Aspect aspect = { eaFileDeleted, &m_DownloadQueue, pFileInfo->GetNZBInfo(), pFileInfo };
|
||||
Notify(&aspect);
|
||||
|
||||
pFileInfo->SetNZBInfo(pNZBInfo);
|
||||
|
||||
pSrcNZBInfo->SetFileCount(pSrcNZBInfo->GetFileCount() - 1);
|
||||
pSrcNZBInfo->SetSize(pSrcNZBInfo->GetSize() - pFileInfo->GetSize());
|
||||
|
||||
pNZBInfo->SetFileCount(pNZBInfo->GetFileCount() + 1);
|
||||
pNZBInfo->SetSize(pNZBInfo->GetSize() + pFileInfo->GetSize());
|
||||
}
|
||||
|
||||
pNZBInfo->Release();
|
||||
|
||||
*pNewNZBInfo = pNZBInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -63,6 +63,7 @@ private:
|
||||
QueueEditor m_QueueEditor;
|
||||
Mutex m_mutexDownloadQueue;
|
||||
bool m_bHasMoreJobs;
|
||||
int m_iDownloadsLimit;
|
||||
|
||||
// statistics
|
||||
static const int SPEEDMETER_SLOTS = 30;
|
||||
@@ -71,6 +72,12 @@ private:
|
||||
int m_iSpeedTotalBytes;
|
||||
int m_iSpeedTime[SPEEDMETER_SLOTS];
|
||||
int m_iSpeedStartTime;
|
||||
time_t m_tSpeedCorrection;
|
||||
#ifdef HAVE_SPINLOCK
|
||||
SpinLock m_spinlockSpeed;
|
||||
#else
|
||||
Mutex m_mutexSpeed;
|
||||
#endif
|
||||
|
||||
int m_iSpeedBytesIndex;
|
||||
long long m_iAllBytes;
|
||||
@@ -83,7 +90,6 @@ private:
|
||||
|
||||
bool GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArticleInfo);
|
||||
void StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pArticleInfo, NNTPConnection* pConnection);
|
||||
void BuildArticleFilename(ArticleDownloader* pArticleDownloader, FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
|
||||
bool IsDupe(FileInfo* pFileInfo);
|
||||
void ArticleCompleted(ArticleDownloader* pArticleDownloader);
|
||||
void DeleteFileInfo(FileInfo* pFileInfo, bool bCompleted);
|
||||
@@ -101,7 +107,7 @@ public:
|
||||
|
||||
// statistics
|
||||
long long CalcRemainingSize();
|
||||
virtual float CalcCurrentDownloadSpeed();
|
||||
virtual int CalcCurrentDownloadSpeed();
|
||||
virtual void AddSpeedReading(int iBytes);
|
||||
void CalcStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy);
|
||||
|
||||
@@ -113,7 +119,9 @@ public:
|
||||
bool GetStandBy() { return m_bStandBy; }
|
||||
bool DeleteQueueEntry(FileInfo* pFileInfo);
|
||||
bool SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* szCategory);
|
||||
bool SetQueueEntryNZBName(NZBInfo* pNZBInfo, const char* szName);
|
||||
bool MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZBInfo);
|
||||
bool SplitQueueEntries(FileQueue* pFileList, const char* szName, NZBInfo** pNewNZBInfo);
|
||||
void DiscardDiskFile(FileInfo* pFileInfo);
|
||||
QueueEditor* GetQueueEditor() { return &m_QueueEditor; }
|
||||
|
||||
|
||||
262
QueueEditor.cpp
262
QueueEditor.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -33,9 +33,10 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <set>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
@@ -110,7 +111,7 @@ void QueueEditor::PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause)
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes entry with index iEntry
|
||||
* Removes entry
|
||||
* returns true if successful, false if operation is not possible
|
||||
*/
|
||||
void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
|
||||
@@ -120,7 +121,7 @@ void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves entry identified with iID in the queue
|
||||
* Moves entry in the queue
|
||||
* returns true if successful, false if operation is not possible
|
||||
*/
|
||||
void QueueEditor::MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, int iOffset)
|
||||
@@ -148,12 +149,23 @@ void QueueEditor::MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set priority for entry
|
||||
* returns true if successful, false if operation is not possible
|
||||
*/
|
||||
void QueueEditor::SetPriorityEntry(FileInfo* pFileInfo, const char* szPriority)
|
||||
{
|
||||
debug("Setting priority %s for file %s", szPriority, pFileInfo->GetFilename());
|
||||
int iPriority = atoi(szPriority);
|
||||
pFileInfo->SetPriority(iPriority);
|
||||
}
|
||||
|
||||
bool QueueEditor::EditEntry(int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
|
||||
{
|
||||
IDList cIDList;
|
||||
cIDList.clear();
|
||||
cIDList.push_back(ID);
|
||||
return EditList(&cIDList, bSmartOrder, eAction, iOffset, szText);
|
||||
return EditList(&cIDList, NULL, mmID, bSmartOrder, eAction, iOffset, szText);
|
||||
}
|
||||
|
||||
bool QueueEditor::LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
|
||||
@@ -164,11 +176,20 @@ bool QueueEditor::LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bS
|
||||
return InternEditList(pDownloadQueue, &cIDList, bSmartOrder, eAction, iOffset, szText);
|
||||
}
|
||||
|
||||
bool QueueEditor::EditList(IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
|
||||
bool QueueEditor::EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, bool bSmartOrder,
|
||||
EEditAction eAction, int iOffset, const char* szText)
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
bool bOK = InternEditList(pDownloadQueue, pIDList, bSmartOrder, eAction, iOffset, szText);
|
||||
bool bOK = true;
|
||||
|
||||
if (pNameList)
|
||||
{
|
||||
pIDList = new IDList();
|
||||
bOK = BuildIDListFromNameList(pDownloadQueue, pIDList, pNameList, eMatchMode, eAction);
|
||||
}
|
||||
|
||||
bOK = bOK && (InternEditList(pDownloadQueue, pIDList, bSmartOrder, eAction, iOffset, szText) || eMatchMode == mmRegEx);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
@@ -177,6 +198,11 @@ bool QueueEditor::EditList(IDList* pIDList, bool bSmartOrder, EEditAction eActio
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (pNameList)
|
||||
{
|
||||
delete pIDList;
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
@@ -201,7 +227,15 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
|
||||
}
|
||||
else if (eAction == eaGroupMerge)
|
||||
{
|
||||
MergeGroups(pDownloadQueue, &cItemList);
|
||||
return MergeGroups(pDownloadQueue, &cItemList);
|
||||
}
|
||||
else if (eAction == eaFileSplit)
|
||||
{
|
||||
return SplitGroup(pDownloadQueue, &cItemList, szText);
|
||||
}
|
||||
else if (eAction == eaFileReorder)
|
||||
{
|
||||
ReorderFiles(pDownloadQueue, &cItemList);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -228,10 +262,18 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
|
||||
DeleteEntry(pItem->m_pFileInfo);
|
||||
break;
|
||||
|
||||
case eaFileSetPriority:
|
||||
SetPriorityEntry(pItem->m_pFileInfo, szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetCategory:
|
||||
SetNZBCategory(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetName:
|
||||
SetNZBName(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetParameter:
|
||||
SetNZBParameter(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
@@ -244,12 +286,15 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
|
||||
case eaGroupMoveOffset:
|
||||
case eaGroupPauseAllPars:
|
||||
case eaGroupPauseExtraPars:
|
||||
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset);
|
||||
case eaGroupSetPriority:
|
||||
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset, szText);
|
||||
break;
|
||||
|
||||
case eaFilePauseAllPars:
|
||||
case eaFilePauseExtraPars:
|
||||
case eaGroupMerge:
|
||||
case eaFileReorder:
|
||||
case eaFileSplit:
|
||||
// remove compiler warning "enumeration not handled in switch"
|
||||
break;
|
||||
}
|
||||
@@ -365,7 +410,79 @@ void QueueEditor::PrepareList(DownloadQueue* pDownloadQueue, ItemList* pItemList
|
||||
}
|
||||
}
|
||||
|
||||
bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset)
|
||||
bool QueueEditor::BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction)
|
||||
{
|
||||
#ifndef HAVE_REGEX_H
|
||||
if (eMatchMode == mmRegEx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::set<int> uniqueIDs;
|
||||
|
||||
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
|
||||
{
|
||||
const char* szName = *it;
|
||||
|
||||
RegEx *pRegEx = NULL;
|
||||
if (eMatchMode == mmRegEx)
|
||||
{
|
||||
pRegEx = new RegEx(szName);
|
||||
if (!pRegEx->IsValid())
|
||||
{
|
||||
delete pRegEx;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool bFound = false;
|
||||
|
||||
for (FileQueue::iterator it2 = pDownloadQueue->GetFileQueue()->begin(); it2 != pDownloadQueue->GetFileQueue()->end(); it2++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it2;
|
||||
if (eAction < eaGroupMoveOffset)
|
||||
{
|
||||
// file action
|
||||
char szFilename[MAX_PATH];
|
||||
snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename()));
|
||||
if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) &&
|
||||
(uniqueIDs.find(pFileInfo->GetID()) == uniqueIDs.end()))
|
||||
{
|
||||
uniqueIDs.insert(pFileInfo->GetID());
|
||||
pIDList->push_back(pFileInfo->GetID());
|
||||
bFound = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// group action
|
||||
const char *szFilename = pFileInfo->GetNZBInfo()->GetName();
|
||||
if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) &&
|
||||
(uniqueIDs.find(pFileInfo->GetNZBInfo()->GetID()) == uniqueIDs.end()))
|
||||
{
|
||||
uniqueIDs.insert(pFileInfo->GetNZBInfo()->GetID());
|
||||
pIDList->push_back(pFileInfo->GetID());
|
||||
bFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pRegEx)
|
||||
{
|
||||
delete pRegEx;
|
||||
}
|
||||
|
||||
if (!bFound && (eMatchMode == mmName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset, const char* szText)
|
||||
{
|
||||
IDList cIDList;
|
||||
cIDList.clear();
|
||||
@@ -431,10 +548,13 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
pFileInfo->GetNZBInfo()->SetCleanupDisk(CanCleanupDisk(pDownloadQueue, pFileInfo->GetNZBInfo()));
|
||||
}
|
||||
|
||||
EEditAction GroupToFileMap[] = { (EEditAction)0, eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars,
|
||||
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars, (EEditAction)0, (EEditAction)0, (EEditAction)0 };
|
||||
EEditAction GroupToFileMap[] = { (EEditAction)0, eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause,
|
||||
eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority, eaFileReorder, eaFileSplit,
|
||||
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete,
|
||||
eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority,
|
||||
(EEditAction)0, (EEditAction)0, (EEditAction)0 };
|
||||
|
||||
return InternEditList(pDownloadQueue, &cIDList, true, GroupToFileMap[eAction], iOffset, NULL);
|
||||
return InternEditList(pDownloadQueue, &cIDList, true, GroupToFileMap[eAction], iOffset, szText);
|
||||
}
|
||||
|
||||
void QueueEditor::BuildGroupList(DownloadQueue* pDownloadQueue, FileList* pGroupList)
|
||||
@@ -533,11 +653,11 @@ void QueueEditor::AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pID
|
||||
for (FileList::iterator it = cAffectedGroupList.begin(); it != cAffectedGroupList.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
AlignGroup(pDownloadQueue, pFileInfo);
|
||||
AlignGroup(pDownloadQueue, pFileInfo->GetNZBInfo());
|
||||
}
|
||||
}
|
||||
|
||||
void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFileInfo)
|
||||
void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
FileInfo* pLastFileInfo = NULL;
|
||||
unsigned int iLastNum = 0;
|
||||
@@ -545,7 +665,7 @@ void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFile
|
||||
while (iNum < pDownloadQueue->GetFileQueue()->size())
|
||||
{
|
||||
FileInfo* pFileInfo = pDownloadQueue->GetFileQueue()->at(iNum);
|
||||
if (pFirstFileInfo->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo)
|
||||
{
|
||||
if (pLastFileInfo && iNum - iLastNum > 1)
|
||||
{
|
||||
@@ -687,6 +807,13 @@ void QueueEditor::SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory)
|
||||
g_pQueueCoordinator->SetQueueEntryNZBCategory(pNZBInfo, szCategory);
|
||||
}
|
||||
|
||||
void QueueEditor::SetNZBName(NZBInfo* pNZBInfo, const char* szName)
|
||||
{
|
||||
debug("QueueEditor: renaming '%s' to '%s'", Util::BaseFileName(pNZBInfo->GetFilename()), szName);
|
||||
|
||||
g_pQueueCoordinator->SetQueueEntryNZBName(pNZBInfo, szName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if deletion of already downloaded files is possible (when nzb id deleted from queue).
|
||||
* The deletion is most always possible, except the case if all remaining files in queue
|
||||
@@ -712,13 +839,15 @@ bool QueueEditor::CanCleanupDisk(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInf
|
||||
return false;
|
||||
}
|
||||
|
||||
void QueueEditor::MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList)
|
||||
bool QueueEditor::MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList)
|
||||
{
|
||||
if (pItemList->size() == 0)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bOK = true;
|
||||
|
||||
EditItem* pDestItem = pItemList->front();
|
||||
|
||||
for (ItemList::iterator it = pItemList->begin() + 1; it != pItemList->end(); it++)
|
||||
@@ -727,23 +856,90 @@ void QueueEditor::MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList
|
||||
if (pItem->m_pFileInfo->GetNZBInfo() != pDestItem->m_pFileInfo->GetNZBInfo())
|
||||
{
|
||||
debug("merge %s to %s", pItem->m_pFileInfo->GetNZBInfo()->GetFilename(), pDestItem->m_pFileInfo->GetNZBInfo()->GetFilename());
|
||||
g_pQueueCoordinator->MergeQueueEntries(pDestItem->m_pFileInfo->GetNZBInfo(), pItem->m_pFileInfo->GetNZBInfo());
|
||||
if (g_pQueueCoordinator->MergeQueueEntries(pDestItem->m_pFileInfo->GetNZBInfo(), pItem->m_pFileInfo->GetNZBInfo()))
|
||||
{
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
delete pItem;
|
||||
}
|
||||
|
||||
// align group ("AlignGroup" needs the first file item as parameter)
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() == pDestItem->m_pFileInfo->GetNZBInfo())
|
||||
{
|
||||
AlignGroup(pDownloadQueue, pFileInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AlignGroup(pDownloadQueue, pDestItem->m_pFileInfo->GetNZBInfo());
|
||||
|
||||
delete pDestItem;
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool QueueEditor::SplitGroup(DownloadQueue* pDownloadQueue, ItemList* pItemList, const char* szName)
|
||||
{
|
||||
if (pItemList->size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FileQueue* pFileList = new FileQueue();
|
||||
|
||||
for (ItemList::iterator it = pItemList->begin(); it != pItemList->end(); it++)
|
||||
{
|
||||
EditItem* pItem = *it;
|
||||
pFileList->push_back(pItem->m_pFileInfo);
|
||||
delete pItem;
|
||||
}
|
||||
|
||||
NZBInfo* pNewNZBInfo = NULL;
|
||||
bool bOK = g_pQueueCoordinator->SplitQueueEntries(pFileList, szName, &pNewNZBInfo);
|
||||
if (bOK)
|
||||
{
|
||||
AlignGroup(pDownloadQueue, pNewNZBInfo);
|
||||
}
|
||||
|
||||
delete pFileList;
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void QueueEditor::ReorderFiles(DownloadQueue* pDownloadQueue, ItemList* pItemList)
|
||||
{
|
||||
if (pItemList->size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditItem* pFirstItem = pItemList->front();
|
||||
NZBInfo* pNZBInfo = pFirstItem->m_pFileInfo->GetNZBInfo();
|
||||
unsigned int iInsertPos = 0;
|
||||
|
||||
// find first file of the group
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
iInsertPos++;
|
||||
}
|
||||
|
||||
// now can reorder
|
||||
for (ItemList::iterator it = pItemList->begin(); it != pItemList->end(); it++)
|
||||
{
|
||||
EditItem* pItem = *it;
|
||||
FileInfo* pFileInfo = pItem->m_pFileInfo;
|
||||
|
||||
// move file item
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo1 = *it;
|
||||
if (pFileInfo1 == pFileInfo)
|
||||
{
|
||||
pDownloadQueue->GetFileQueue()->erase(it);
|
||||
pDownloadQueue->GetFileQueue()->insert(pDownloadQueue->GetFileQueue()->begin() + iInsertPos, pFileInfo);
|
||||
iInsertPos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete pItem;
|
||||
}
|
||||
}
|
||||
|
||||
void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
|
||||
@@ -761,7 +957,7 @@ void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not set nzb parameter for %s: invalid argument: %s", Util::BaseFileName(pNZBInfo->GetFilename()), szParamString);
|
||||
error("Could not set nzb parameter for %s: invalid argument: %s", pNZBInfo->GetName(), szParamString);
|
||||
}
|
||||
|
||||
free(szStr);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -43,6 +43,9 @@ public:
|
||||
eaFileDelete,
|
||||
eaFilePauseAllPars,
|
||||
eaFilePauseExtraPars,
|
||||
eaFileSetPriority,
|
||||
eaFileReorder,
|
||||
eaFileSplit,
|
||||
eaGroupMoveOffset, // move to m_iOffset relative to the current position in queue
|
||||
eaGroupMoveTop,
|
||||
eaGroupMoveBottom,
|
||||
@@ -51,9 +54,18 @@ public:
|
||||
eaGroupDelete,
|
||||
eaGroupPauseAllPars,
|
||||
eaGroupPauseExtraPars,
|
||||
eaGroupSetPriority,
|
||||
eaGroupSetCategory,
|
||||
eaGroupMerge,
|
||||
eaGroupSetParameter
|
||||
eaGroupSetParameter,
|
||||
eaGroupSetName
|
||||
};
|
||||
|
||||
enum EMatchMode
|
||||
{
|
||||
mmID = 1,
|
||||
mmName,
|
||||
mmRegEx
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -74,28 +86,33 @@ private:
|
||||
int FindFileInfoEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo);
|
||||
bool InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
void PrepareList(DownloadQueue* pDownloadQueue, ItemList* pItemList, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset);
|
||||
bool EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset);
|
||||
bool BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction);
|
||||
bool EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset, const char* szText);
|
||||
void BuildGroupList(DownloadQueue* pDownloadQueue, FileList* pGroupList);
|
||||
void AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, int iOffset);
|
||||
bool ItemExists(FileList* pFileList, FileInfo* pFileInfo);
|
||||
void AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFileInfo);
|
||||
void AlignGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void PauseParsInGroups(ItemList* pItemList, bool bExtraParsOnly);
|
||||
void PausePars(FileList* pFileList, bool bExtraParsOnly);
|
||||
void SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory);
|
||||
void SetNZBName(NZBInfo* pNZBInfo, const char* szName);
|
||||
bool CanCleanupDisk(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList);
|
||||
bool MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList);
|
||||
bool SplitGroup(DownloadQueue* pDownloadQueue, ItemList* pItemList, const char* szName);
|
||||
void ReorderFiles(DownloadQueue* pDownloadQueue, ItemList* pItemList);
|
||||
void SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString);
|
||||
|
||||
void PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause);
|
||||
void DeleteEntry(FileInfo* pFileInfo);
|
||||
void MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, int iOffset);
|
||||
void SetPriorityEntry(FileInfo* pFileInfo, const char* szPriority);
|
||||
|
||||
public:
|
||||
QueueEditor();
|
||||
~QueueEditor();
|
||||
|
||||
bool EditEntry(int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
bool EditList(IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
bool EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
|
||||
bool LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
bool LockedEditList(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
|
||||
|
||||
137
README
137
README
@@ -2,6 +2,10 @@
|
||||
NZBGet ReadMe
|
||||
=====================================
|
||||
|
||||
This is a short documentation. For more information please
|
||||
visit NZBGet home page at
|
||||
http://nzbget.sourceforge.net
|
||||
|
||||
Contents
|
||||
--------
|
||||
1. About NZBGet
|
||||
@@ -29,6 +33,9 @@ In server/client mode NZBGet runs as server in background.
|
||||
Then you use client to send requests to server. The sample requests
|
||||
are: download nzb-file, list files in queue, etc.
|
||||
|
||||
There is also a built-in web-interface. The server has RPC-support
|
||||
and can be controlled from third party applications too.
|
||||
|
||||
Standalone-tool, server and client are all contained in only one
|
||||
executable file "nzbget". The mode in which the program works
|
||||
depends on command-line parameters passed to the program.
|
||||
@@ -41,13 +48,12 @@ NZBGet is written in C++ and was initialy developed on Linux.
|
||||
It was ported to Windows later and tested for compatibility with
|
||||
several POSIX-OS'es.
|
||||
|
||||
The current version (0.7.0) should run at least on:
|
||||
- Linux Debian 4.0 on x86;
|
||||
- Linux with uClibc and BusyBox on MIPSEL and ARM;
|
||||
- FreeBSD 7.0 on x86;
|
||||
- OpenSolaris 2008.11 on x86;
|
||||
- Mac OS X;
|
||||
- Windows XP SP2 on x86.
|
||||
It should run at least on:
|
||||
- Linux Debian 5.0 on x86;
|
||||
- Linux with uClibc on MIPSEL and ARM;
|
||||
- OpenBSD 5.0 on x86;
|
||||
- Mac OS X 10.7 Lion on x64;
|
||||
- Windows XP SP3 on x86 and Windows 7 on x64.
|
||||
|
||||
Clients and servers running on different OS'es may communicate with
|
||||
each other. For example, you can use NZBGet as client on Windows to
|
||||
@@ -89,6 +95,9 @@ And the following libraries are optional:
|
||||
or
|
||||
- OpenSSL (http://www.openssl.org)
|
||||
|
||||
- for gzip support in web-server and web-client (enabled by default):
|
||||
- zlib (http://www.zlib.net)
|
||||
|
||||
All these libraries are included in modern Linux distributions and
|
||||
should be available as installable packages. Please note that you also
|
||||
need the developer packages for these libraries too, they package names
|
||||
@@ -99,24 +108,41 @@ download the libraries at the given URLs and compile them (see hints below).
|
||||
4. Installation on POSIX
|
||||
=====================================
|
||||
|
||||
Well, the usual stuff:
|
||||
Installation from the source distribution archive (nzbget-VERSION.tar.gz):
|
||||
|
||||
- untar the nzbget-source via
|
||||
tar -zxf nzbget-VERSION.tar.gz
|
||||
|
||||
- change into nzbget-directory via
|
||||
cd nzbget-VERSION
|
||||
|
||||
- configure it via
|
||||
./configure
|
||||
|
||||
(maybe you have to tell configure, where to find some libraries.
|
||||
./configure --help is your friend!)
|
||||
also see "Configure-options" later.)
|
||||
./configure --help is your friend!
|
||||
also see "Configure-options" later)
|
||||
|
||||
- in a case you don't have root access or want to install the program
|
||||
in your home directory use the configure parameter --prefix, e. g.:
|
||||
|
||||
./configure --prefix ~/usr
|
||||
|
||||
- compile it via
|
||||
make
|
||||
- become root via
|
||||
|
||||
- to install system wide become root via:
|
||||
su
|
||||
- install it via
|
||||
|
||||
- install it via:
|
||||
make install
|
||||
|
||||
- install configuration files into <prefix>/etc via:
|
||||
make install-conf
|
||||
|
||||
(you can skip this step if you intend to store configuration
|
||||
files in a non-standard location)
|
||||
|
||||
Configure-options
|
||||
-----------------
|
||||
You may run configure with additional arguments:
|
||||
@@ -132,6 +158,9 @@ You may run configure with additional arguments:
|
||||
|
||||
--disable-tls - to make without TLS/SSL support. Use this option if
|
||||
you can not neither GnuTLS nor OpenSSL.
|
||||
|
||||
--disable-gzip - to make without gzip support. Use this option
|
||||
if you can not use zlib.
|
||||
|
||||
--enable-debug - to build in debug-mode, if you want to see and log
|
||||
debug-messages.
|
||||
@@ -245,17 +274,27 @@ in MS Visual C++ 2005 you should be able to compile NZBGet.
|
||||
6. Configuration
|
||||
=====================================
|
||||
|
||||
NZBGet needs a configuration-file to work properly.
|
||||
NZBGet needs a configuration file.
|
||||
|
||||
You need to set at least the option "MAINDIR" and one newsserver in
|
||||
configuration file. Have a look at the example in nzbget.conf.example,
|
||||
it has comments on how to use each option.
|
||||
An example configuration file is provided in "nzbget.conf", which
|
||||
is installed into "<prefix>/share/nzbget" (where <prefix> depends on
|
||||
system configuration and configure options - typically "/usr/local",
|
||||
"/usr" or "/opt"). The installer adjusts the file according to your
|
||||
system paths. If you have performed the installation step
|
||||
"make install-conf" this file is already copied to "<prefix>/etc" and
|
||||
NZBGet finds it automatically. If you install the program manually
|
||||
from a binary archive you have to copy the file from "<prefix>/share/nzbget"
|
||||
to one of the locations listed below.
|
||||
|
||||
Open the file in a text editor and modify it accodring to your needs.
|
||||
|
||||
You need to set at least the option "MAINDIR" and one news server in
|
||||
configuration file. The file has comments on how to use each option.
|
||||
|
||||
The program looks for configuration file in following standard
|
||||
locations (in this order):
|
||||
|
||||
On POSIX systems:
|
||||
|
||||
~/.nzbget
|
||||
/etc/nzbget.conf
|
||||
/usr/etc/nzbget.conf
|
||||
@@ -383,7 +422,7 @@ Running client & server on seperate machines:
|
||||
Since nzbget communicates via TCP/IP it's possible to have a server running on
|
||||
one computer and adding downloads via a client on another computer.
|
||||
|
||||
Do this by setting the "serverip" option in the nzbget.conf file to point to the
|
||||
Do this by setting the "ControlIP" option in the nzbget.conf file to point to the
|
||||
IP of the server (default is localhost which means client and server runs on
|
||||
same computer)
|
||||
|
||||
@@ -402,28 +441,58 @@ nzbget-client-commands in this terminal.
|
||||
Post processing scripts
|
||||
-----------------------
|
||||
|
||||
After the download of nzb-file is completed nzbget can call post-process-script,
|
||||
defined in configuration file. See example configuration file for the
|
||||
description of parameters passed to the script.
|
||||
After the download of nzb-file is completed nzbget can call post-processing
|
||||
scripts, defined in configuration file.
|
||||
|
||||
An example script for unraring of downloaded files is provided in file
|
||||
postprocess-example.sh. The usage instructions are included in the file,
|
||||
please open the file in any text editor to read them.
|
||||
NOTE: That example script is for POSIX systems (not for Windows).
|
||||
Example post-processing scripts are provided in directory "ppscripts".
|
||||
|
||||
To use the scripts copy them into your local directory and set options
|
||||
<ScriptDir>, <DefScript> and <ScriptOrder>.
|
||||
|
||||
For information on writing your own post-processing scripts please
|
||||
visit NZBGet web site.
|
||||
|
||||
Web-interface
|
||||
-------------
|
||||
|
||||
NZBGet has a built-in web-server providing the access to the program
|
||||
functions via web-interface.
|
||||
|
||||
To activate web-interface set the option "WebDir" to the path with
|
||||
web-interface files. If you install using "make install-conf" as
|
||||
described above the option is set automatically. If you install using
|
||||
binary files you should check if the option is set correctly.
|
||||
|
||||
To access web-interface from your web-browser use the server address
|
||||
and port defined in NZBGet configuration file in options "ControlIP" and
|
||||
"ControlPort". For example:
|
||||
|
||||
http://localhost:6789/
|
||||
|
||||
For login credentials type username "nzbget" (predefined and not changeable)
|
||||
and the password from the option "ControlPassword" (default is tegbzn6789).
|
||||
|
||||
In a case your browser forget credentials, to prevent typing them each
|
||||
time, there is a workaround - use URL in the form:
|
||||
|
||||
http://localhost:6789/nzbget:password/
|
||||
|
||||
Please note, that in this case the password is saved in a bookmark or in
|
||||
browser history in plain text and is easy to find by persons having
|
||||
access to your computer.
|
||||
|
||||
=====================================
|
||||
8. Authors
|
||||
=====================================
|
||||
|
||||
NZBGet was initialiy written by Sven Henkel (sidddy@users.sourceforge.net).
|
||||
|
||||
Up to version 0.2.3 it was developed and maintained by Bo Cordes Petersen
|
||||
(placebodk@users.sourceforge.net).
|
||||
|
||||
Beginning at version 0.3.0 the program is being developed by Andrei Prygounkov
|
||||
NZBGet is developed and maintained by Andrey Prygunkov
|
||||
(hugbug@users.sourceforge.net).
|
||||
|
||||
Module TLS (TLS.c, TLS.h) is based on work by Martin Lambers (marlam@marlam.de).
|
||||
The original project was initially created by Sven Henkel
|
||||
(sidddy@users.sourceforge.net) in 2004 and later developed by
|
||||
Bo Cordes Petersen (placebodk@users.sourceforge.net) until 2005.
|
||||
In 2007 the abandoned project was overtaken by Andrey Prygunkov.
|
||||
Since then the program has been completely rewritten.
|
||||
|
||||
=====================================
|
||||
9. Copyright
|
||||
@@ -450,9 +519,9 @@ libpar2 is distributed under GPL; libsigc++ and GnuTLS - under LGPL.
|
||||
10. Contact
|
||||
=====================================
|
||||
|
||||
If you encounter any problem, feel free to use forums on
|
||||
If you encounter any problem, feel free to use the forum
|
||||
|
||||
sourceforge.net/projects/nzbget
|
||||
nzbget.sourceforge.net/forum
|
||||
|
||||
or contact me at
|
||||
|
||||
|
||||
507
RemoteClient.cpp
507
RemoteClient.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "RemoteClient.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
@@ -55,7 +56,6 @@ extern Options* g_pOptions;
|
||||
RemoteClient::RemoteClient()
|
||||
{
|
||||
m_pConnection = NULL;
|
||||
m_pNetAddress = NULL;
|
||||
m_bVerbose = true;
|
||||
|
||||
/*
|
||||
@@ -80,11 +80,6 @@ RemoteClient::~RemoteClient()
|
||||
{
|
||||
delete m_pConnection;
|
||||
}
|
||||
|
||||
if (m_pNetAddress)
|
||||
{
|
||||
delete m_pNetAddress;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::printf(const char * msg,...)
|
||||
@@ -109,13 +104,19 @@ void RemoteClient::perror(const char * msg)
|
||||
bool RemoteClient::InitConnection()
|
||||
{
|
||||
// Create a connection to the server
|
||||
m_pNetAddress = new NetAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
||||
m_pConnection = new Connection(m_pNetAddress);
|
||||
|
||||
const char *szControlIP = g_pOptions->GetControlIP();
|
||||
if (!strcmp(szControlIP, "0.0.0.0"))
|
||||
{
|
||||
szControlIP = "127.0.0.1";
|
||||
}
|
||||
|
||||
m_pConnection = new Connection(szControlIP, g_pOptions->GetControlPort(), false);
|
||||
|
||||
bool OK = m_pConnection->Connect();
|
||||
if (!OK)
|
||||
{
|
||||
printf("Unable to send request to nzbserver at %s (port %i)\n", g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
||||
printf("Unable to send request to nzbserver at %s (port %i)\n", szControlIP, g_pOptions->GetControlPort());
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
@@ -125,7 +126,11 @@ void RemoteClient::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest,
|
||||
pMessageBase->m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
pMessageBase->m_iType = htonl(iRequest);
|
||||
pMessageBase->m_iStructSize = htonl(iSize);
|
||||
strncpy(pMessageBase->m_szPassword, g_pOptions->GetServerPassword(), NZBREQUESTPASSWORDSIZE - 1);
|
||||
|
||||
strncpy(pMessageBase->m_szUsername, g_pOptions->GetControlUsername(), NZBREQUESTPASSWORDSIZE - 1);
|
||||
pMessageBase->m_szUsername[NZBREQUESTPASSWORDSIZE - 1] = '\0';
|
||||
|
||||
strncpy(pMessageBase->m_szPassword, g_pOptions->GetControlPassword(), NZBREQUESTPASSWORDSIZE - 1);
|
||||
pMessageBase->m_szPassword[NZBREQUESTPASSWORDSIZE - 1] = '\0';
|
||||
}
|
||||
|
||||
@@ -137,35 +142,22 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
SNZBDownloadResponse BoolResponse;
|
||||
memset(&BoolResponse, 0, sizeof(BoolResponse));
|
||||
|
||||
int iResponseLen = m_pConnection->Recv((char*)&BoolResponse, sizeof(BoolResponse));
|
||||
if (iResponseLen != sizeof(BoolResponse) ||
|
||||
bool bRead = m_pConnection->Recv((char*)&BoolResponse, sizeof(BoolResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(BoolResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(BoolResponse.m_MessageBase.m_iStructSize) != sizeof(BoolResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int iTextLen = ntohl(BoolResponse.m_iTrailingDataLength);
|
||||
char* buf = (char*)malloc(iTextLen);
|
||||
iResponseLen = m_pConnection->Recv(buf, iTextLen);
|
||||
if (iResponseLen != iTextLen)
|
||||
bRead = m_pConnection->Recv(buf, iTextLen);
|
||||
if (!bRead)
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -177,7 +169,7 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
/*
|
||||
* Sends a message to the running nzbget process.
|
||||
*/
|
||||
bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst)
|
||||
bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
|
||||
{
|
||||
// Read the file into the buffer
|
||||
char* szBuffer = NULL;
|
||||
@@ -194,7 +186,9 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
SNZBDownloadRequest DownloadRequest;
|
||||
InitMessageBase(&DownloadRequest.m_MessageBase, eRemoteRequestDownload, sizeof(DownloadRequest));
|
||||
DownloadRequest.m_bAddFirst = htonl(bAddFirst);
|
||||
DownloadRequest.m_iTrailingDataLength = htonl(iLength);
|
||||
DownloadRequest.m_bAddPaused = htonl(bAddPaused);
|
||||
DownloadRequest.m_iPriority = htonl(iPriority);
|
||||
DownloadRequest.m_iTrailingDataLength = htonl(iLength - 1);
|
||||
|
||||
strncpy(DownloadRequest.m_szFilename, szFilename, NZBREQUESTFILENAMESIZE - 1);
|
||||
DownloadRequest.m_szFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
@@ -205,7 +199,7 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
}
|
||||
DownloadRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
if (m_pConnection->Send((char*)(&DownloadRequest), sizeof(DownloadRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&DownloadRequest), sizeof(DownloadRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
OK = false;
|
||||
@@ -239,23 +233,29 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
SNZBListResponseNZBEntry* pListAnswer = (SNZBListResponseNZBEntry*) pBufPtr;
|
||||
|
||||
const char* szFileName = pBufPtr + sizeof(SNZBListResponseNZBEntry);
|
||||
const char* szDestDir = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen);
|
||||
const char* szCategory = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) + ntohl(pListAnswer->m_iDestDirLen);
|
||||
const char* m_szQueuedFilename = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) + ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen);
|
||||
const char* szName = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen);
|
||||
const char* szDestDir = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
ntohl(pListAnswer->m_iNameLen);
|
||||
const char* szCategory = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen);
|
||||
const char* m_szQueuedFilename = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen);
|
||||
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
MatchedNZBInfo* pNZBInfo = new MatchedNZBInfo();
|
||||
pNZBInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo)));
|
||||
pNZBInfo->SetFilename(szFileName);
|
||||
pNZBInfo->SetName(szName);
|
||||
pNZBInfo->SetDestDir(szDestDir);
|
||||
pNZBInfo->SetCategory(szCategory);
|
||||
pNZBInfo->SetQueuedFilename(m_szQueuedFilename);
|
||||
pNZBInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
|
||||
|
||||
pNZBInfo->AddReference();
|
||||
pDownloadQueue->GetNZBInfoList()->Add(pNZBInfo);
|
||||
|
||||
pBufPtr += sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen) +
|
||||
ntohl(pListAnswer->m_iQueuedFilenameLen);
|
||||
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) +
|
||||
ntohl(pListAnswer->m_iCategoryLen) + ntohl(pListAnswer->m_iQueuedFilenameLen);
|
||||
}
|
||||
|
||||
//read ppp entries
|
||||
@@ -281,7 +281,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
const char* szSubject = pBufPtr + sizeof(SNZBListResponseFileEntry);
|
||||
const char* szFileName = pBufPtr + sizeof(SNZBListResponseFileEntry) + ntohl(pListAnswer->m_iSubjectLen);
|
||||
|
||||
FileInfo* pFileInfo = new FileInfo();
|
||||
MatchedFileInfo* pFileInfo = new MatchedFileInfo();
|
||||
pFileInfo->SetID(ntohl(pListAnswer->m_iID));
|
||||
pFileInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo)));
|
||||
pFileInfo->SetRemainingSize(Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
|
||||
@@ -289,6 +289,9 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
pFileInfo->SetSubject(szSubject);
|
||||
pFileInfo->SetFilename(szFileName);
|
||||
pFileInfo->SetFilenameConfirmed(ntohl(pListAnswer->m_bFilenameConfirmed));
|
||||
pFileInfo->SetActiveDownloads(ntohl(pListAnswer->m_iActiveDownloads));
|
||||
pFileInfo->SetPriority(ntohl(pListAnswer->m_iPriority));
|
||||
pFileInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
|
||||
|
||||
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
|
||||
|
||||
@@ -304,7 +307,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
pDownloadQueue->GetNZBInfoList()->ReleaseAll();
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPattern)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
@@ -312,8 +315,15 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
InitMessageBase(&ListRequest.m_MessageBase, eRemoteRequestList, sizeof(ListRequest));
|
||||
ListRequest.m_bFileList = htonl(true);
|
||||
ListRequest.m_bServerState = htonl(true);
|
||||
ListRequest.m_iMatchMode = htonl(szPattern ? eRemoteMatchModeRegEx : eRemoteMatchModeID);
|
||||
ListRequest.m_bMatchGroup = htonl(bGroups);
|
||||
if (szPattern)
|
||||
{
|
||||
strncpy(ListRequest.m_szPattern, szPattern, NZBREQUESTFILENAMESIZE - 1);
|
||||
ListRequest.m_szPattern[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
}
|
||||
|
||||
if (m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -323,19 +333,12 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBListResponse ListResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (iResponseLen != sizeof(ListResponse) ||
|
||||
bool bRead = m_pConnection->Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(ListResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(ListResponse.m_MessageBase.m_iStructSize) != sizeof(ListResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -343,7 +346,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
if (ntohl(ListResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(ListResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -352,6 +355,13 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
|
||||
if (szPattern && !ListResponse.m_bRegExValid)
|
||||
{
|
||||
printf("Error in regular expression\n");
|
||||
free(pBuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bFiles)
|
||||
{
|
||||
if (ntohl(ListResponse.m_iTrailingDataLength) == 0)
|
||||
@@ -368,17 +378,33 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
|
||||
long long lRemaining = 0;
|
||||
long long lPaused = 0;
|
||||
int iMatches = 0;
|
||||
|
||||
for (FileQueue::iterator it = cRemoteQueue.GetFileQueue()->begin(); it != cRemoteQueue.GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
|
||||
char szPriority[100];
|
||||
szPriority[0] = '\0';
|
||||
if (pFileInfo->GetPriority() != 0)
|
||||
{
|
||||
sprintf(szPriority, "[%+i] ", pFileInfo->GetPriority());
|
||||
}
|
||||
|
||||
char szCompleted[100];
|
||||
szCompleted[0] = '\0';
|
||||
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(100 - Util::Int64ToFloat(pFileInfo->GetRemainingSize()) * 100.0 / Util::Int64ToFloat(pFileInfo->GetSize())), "%");
|
||||
}
|
||||
|
||||
char szThreads[100];
|
||||
szThreads[0] = '\0';
|
||||
if (pFileInfo->GetActiveDownloads() > 0)
|
||||
{
|
||||
sprintf(szThreads, ", %i thread%s", pFileInfo->GetActiveDownloads(), (pFileInfo->GetActiveDownloads() > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
char szStatus[100];
|
||||
if (pFileInfo->GetPaused())
|
||||
{
|
||||
@@ -390,18 +416,30 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
szStatus[0] = '\0';
|
||||
lRemaining += pFileInfo->GetRemainingSize();
|
||||
}
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
|
||||
printf("[%i] %s%c%s (%.2f MB%s)%s\n", pFileInfo->GetID(), szNZBNiceName, (int)PATH_SEPARATOR, pFileInfo->GetFilename(),
|
||||
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0), szCompleted, szStatus);
|
||||
|
||||
if (!szPattern || ((MatchedFileInfo*)pFileInfo)->m_bMatch)
|
||||
{
|
||||
printf("[%i] %s%s/%s (%.2f MB%s%s)%s\n", pFileInfo->GetID(), szPriority, pFileInfo->GetNZBInfo()->GetName(),
|
||||
pFileInfo->GetFilename(),
|
||||
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
|
||||
szCompleted, szThreads, szStatus);
|
||||
iMatches++;
|
||||
}
|
||||
|
||||
delete pFileInfo;
|
||||
}
|
||||
|
||||
if (iMatches == 0)
|
||||
{
|
||||
printf("No matches founds\n");
|
||||
}
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
|
||||
if (szPattern)
|
||||
{
|
||||
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),
|
||||
@@ -433,6 +471,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
|
||||
long long lRemaining = 0;
|
||||
long long lPaused = 0;
|
||||
int iMatches = 0;
|
||||
|
||||
for (GroupQueue::iterator it = cGroupQueue.begin(); it != cGroupQueue.end(); it++)
|
||||
{
|
||||
@@ -444,6 +483,20 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
char szRemaining[20];
|
||||
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
|
||||
|
||||
char szPriority[100];
|
||||
szPriority[0] = '\0';
|
||||
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
|
||||
{
|
||||
if (pGroupInfo->GetMinPriority() == pGroupInfo->GetMaxPriority())
|
||||
{
|
||||
sprintf(szPriority, "[%+i] ", pGroupInfo->GetMinPriority());
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(szPriority, "[%+i..%+i] ", pGroupInfo->GetMinPriority(), pGroupInfo->GetMaxPriority());
|
||||
}
|
||||
}
|
||||
|
||||
char szPaused[20];
|
||||
szPaused[0] = '\0';
|
||||
if (pGroupInfo->GetPausedSize() > 0)
|
||||
@@ -454,9 +507,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
lPaused += pGroupInfo->GetPausedSize();
|
||||
}
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
pGroupInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
|
||||
char szCategory[1024];
|
||||
szCategory[0] = '\0';
|
||||
if (pGroupInfo->GetNZBInfo()->GetCategory() && strlen(pGroupInfo->GetNZBInfo()->GetCategory()) > 0)
|
||||
@@ -464,6 +514,13 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
sprintf(szCategory, " (%s)", pGroupInfo->GetNZBInfo()->GetCategory());
|
||||
}
|
||||
|
||||
char szThreads[100];
|
||||
szThreads[0] = '\0';
|
||||
if (pGroupInfo->GetActiveDownloads() > 0)
|
||||
{
|
||||
sprintf(szThreads, ", %i thread%s", pGroupInfo->GetActiveDownloads(), (pGroupInfo->GetActiveDownloads() > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
char szParameters[1024];
|
||||
szParameters[0] = '\0';
|
||||
for (NZBParameterList::iterator it = pGroupInfo->GetNZBInfo()->GetParameters()->begin(); it != pGroupInfo->GetNZBInfo()->GetParameters()->end(); it++)
|
||||
@@ -486,9 +543,14 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
strncat(szParameters, ")", 1024);
|
||||
}
|
||||
|
||||
printf("[%i-%i] %s (%i file%s, %s%s)%s%s\n", pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), szNZBNiceName,
|
||||
pGroupInfo->GetRemainingFileCount(), pGroupInfo->GetRemainingFileCount() > 1 ? "s" : "", szRemaining,
|
||||
szPaused, szCategory, szParameters);
|
||||
if (!szPattern || ((MatchedNZBInfo*)pGroupInfo->GetNZBInfo())->m_bMatch)
|
||||
{
|
||||
printf("[%i-%i] %s%s (%i file%s, %s%s%s)%s%s\n", pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), szPriority,
|
||||
pGroupInfo->GetNZBInfo()->GetName(), pGroupInfo->GetRemainingFileCount(),
|
||||
pGroupInfo->GetRemainingFileCount() > 1 ? "s" : "", szRemaining,
|
||||
szPaused, szThreads, szCategory, szParameters);
|
||||
iMatches++;
|
||||
}
|
||||
|
||||
delete pGroupInfo;
|
||||
}
|
||||
@@ -498,8 +560,17 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
if (iMatches == 0)
|
||||
{
|
||||
printf("No matches founds\n");
|
||||
}
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
printf("Groups: %i\n", cGroupQueue.size());
|
||||
if (szPattern)
|
||||
{
|
||||
printf("Matches: %i\n", iMatches);
|
||||
}
|
||||
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
|
||||
if (lPaused > 0)
|
||||
{
|
||||
@@ -613,7 +684,7 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
LogRequest.m_iLines = htonl(iLines);
|
||||
LogRequest.m_iIDFrom = 0;
|
||||
|
||||
if (m_pConnection->Send((char*)(&LogRequest), sizeof(LogRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&LogRequest), sizeof(LogRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -623,19 +694,12 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
|
||||
// Now listen for the returned log
|
||||
SNZBLogResponse LogResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (iResponseLen != sizeof(LogResponse) ||
|
||||
bool bRead = m_pConnection->Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(LogResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(LogResponse.m_MessageBase.m_iStructSize) != sizeof(LogResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -643,7 +707,7 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
if (ntohl(LogResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(LogResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -706,7 +770,7 @@ bool RemoteClient::RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAct
|
||||
PauseUnpauseRequest.m_bPause = htonl(bPause);
|
||||
PauseUnpauseRequest.m_iAction = htonl(iAction);
|
||||
|
||||
if (m_pConnection->Send((char*)(&PauseUnpauseRequest), sizeof(PauseUnpauseRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&PauseUnpauseRequest), sizeof(PauseUnpauseRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -719,15 +783,15 @@ bool RemoteClient::RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAct
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerSetDownloadRate(float fRate)
|
||||
bool RemoteClient::RequestServerSetDownloadRate(int iRate)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBSetDownloadRateRequest SetDownloadRateRequest;
|
||||
InitMessageBase(&SetDownloadRateRequest.m_MessageBase, eRemoteRequestSetDownloadRate, sizeof(SetDownloadRateRequest));
|
||||
SetDownloadRateRequest.m_iDownloadRate = htonl((unsigned int)(fRate * 1024));
|
||||
SetDownloadRateRequest.m_iDownloadRate = htonl(iRate);
|
||||
|
||||
if (m_pConnection->Send((char*)(&SetDownloadRateRequest), sizeof(SetDownloadRateRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&SetDownloadRateRequest), sizeof(SetDownloadRateRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -747,7 +811,7 @@ bool RemoteClient::RequestServerDumpDebug()
|
||||
SNZBDumpDebugRequest DumpDebugInfo;
|
||||
InitMessageBase(&DumpDebugInfo.m_MessageBase, eRemoteRequestDumpDebug, sizeof(DumpDebugInfo));
|
||||
|
||||
if (m_pConnection->Send((char*)(&DumpDebugInfo), sizeof(DumpDebugInfo)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&DumpDebugInfo), sizeof(DumpDebugInfo)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -760,9 +824,10 @@ bool RemoteClient::RequestServerDumpDebug()
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText, int* pIDList, int iIDCount, bool bSmartOrder)
|
||||
bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
|
||||
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder)
|
||||
{
|
||||
if (iIDCount <= 0 || pIDList == NULL)
|
||||
if ((iIDCount <= 0 || pIDList == NULL) && (pNameList == NULL || pNameList->size() == 0))
|
||||
{
|
||||
printf("File(s) not specified\n");
|
||||
return false;
|
||||
@@ -770,18 +835,38 @@ bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset
|
||||
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
int iIDLength = sizeof(int32_t) * iIDCount;
|
||||
|
||||
int iNameCount = 0;
|
||||
int iNameLength = 0;
|
||||
if (pNameList && pNameList->size() > 0)
|
||||
{
|
||||
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
|
||||
{
|
||||
const char *szName = *it;
|
||||
iNameLength += strlen(szName) + 1;
|
||||
iNameCount++;
|
||||
}
|
||||
// align size to 4-bytes, needed by ARM-processor (and may be others)
|
||||
iNameLength += iNameLength % 4 > 0 ? 4 - iNameLength % 4 : 0;
|
||||
}
|
||||
|
||||
int iTextLen = szText ? strlen(szText) + 1 : 0;
|
||||
// align size to 4-bytes, needed by ARM-processor (and may be others)
|
||||
iTextLen += iTextLen % 4 > 0 ? 4 - iTextLen % 4 : 0;
|
||||
int iLength = sizeof(int32_t) * iIDCount + iTextLen;
|
||||
|
||||
int iLength = iTextLen + iIDLength + iNameLength;
|
||||
|
||||
SNZBEditQueueRequest EditQueueRequest;
|
||||
InitMessageBase(&EditQueueRequest.m_MessageBase, eRemoteRequestEditQueue, sizeof(EditQueueRequest));
|
||||
EditQueueRequest.m_iAction = htonl(iAction);
|
||||
EditQueueRequest.m_iMatchMode = htonl(iMatchMode);
|
||||
EditQueueRequest.m_iOffset = htonl((int)iOffset);
|
||||
EditQueueRequest.m_bSmartOrder = htonl(bSmartOrder);
|
||||
EditQueueRequest.m_iTextLen = htonl(iTextLen);
|
||||
EditQueueRequest.m_iNrTrailingEntries = htonl(iIDCount);
|
||||
EditQueueRequest.m_iNrTrailingIDEntries = htonl(iIDCount);
|
||||
EditQueueRequest.m_iNrTrailingNameEntries = htonl(iNameCount);
|
||||
EditQueueRequest.m_iTrailingNameEntriesLen = htonl(iNameLength);
|
||||
EditQueueRequest.m_iTrailingDataLength = htonl(iLength);
|
||||
|
||||
char* pTrailingData = (char*)malloc(iLength);
|
||||
@@ -797,9 +882,21 @@ bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset
|
||||
{
|
||||
pIDs[i] = htonl(pIDList[i]);
|
||||
}
|
||||
|
||||
|
||||
if (iNameCount > 0)
|
||||
{
|
||||
char *pNames = pTrailingData + iTextLen + iIDLength;
|
||||
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
|
||||
{
|
||||
const char *szName = *it;
|
||||
int iLen = strlen(szName);
|
||||
strncpy(pNames, szName, iLen + 1);
|
||||
pNames += iLen + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool OK = false;
|
||||
if (m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
}
|
||||
@@ -823,7 +920,28 @@ bool RemoteClient::RequestServerShutdown()
|
||||
SNZBShutdownRequest ShutdownRequest;
|
||||
InitMessageBase(&ShutdownRequest.m_MessageBase, eRemoteRequestShutdown, sizeof(ShutdownRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest)) >= 0;
|
||||
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
}
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerReload()
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBReloadRequest ReloadRequest;
|
||||
InitMessageBase(&ReloadRequest.m_MessageBase, eRemoteRequestReload, sizeof(ReloadRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ReloadRequest), sizeof(ReloadRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -844,7 +962,7 @@ bool RemoteClient::RequestServerVersion()
|
||||
SNZBVersionRequest VersionRequest;
|
||||
InitMessageBase(&VersionRequest.m_MessageBase, eRemoteRequestVersion, sizeof(VersionRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&VersionRequest), sizeof(VersionRequest)) >= 0;
|
||||
bool OK = m_pConnection->Send((char*)(&VersionRequest), sizeof(VersionRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -865,7 +983,7 @@ bool RemoteClient::RequestPostQueue()
|
||||
SNZBPostQueueRequest PostQueueRequest;
|
||||
InitMessageBase(&PostQueueRequest.m_MessageBase, eRemoteRequestPostQueue, sizeof(PostQueueRequest));
|
||||
|
||||
if (m_pConnection->Send((char*)(&PostQueueRequest), sizeof(PostQueueRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&PostQueueRequest), sizeof(PostQueueRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -875,19 +993,12 @@ bool RemoteClient::RequestPostQueue()
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBPostQueueResponse PostQueueResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
if (iResponseLen != sizeof(PostQueueResponse) ||
|
||||
bool bRead = m_pConnection->Recv((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(PostQueueResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(PostQueueResponse.m_MessageBase.m_iStructSize) != sizeof(PostQueueResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -895,7 +1006,7 @@ bool RemoteClient::RequestPostQueue()
|
||||
if (ntohl(PostQueueResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(PostQueueResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(PostQueueResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(PostQueueResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -920,22 +1031,21 @@ bool RemoteClient::RequestPostQueue()
|
||||
|
||||
int iStageProgress = ntohl(pPostQueueAnswer->m_iStageProgress);
|
||||
|
||||
static const int EXECUTING_SCRIPT = 5;
|
||||
char szCompleted[100];
|
||||
szCompleted[0] = '\0';
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != EXECUTING_SCRIPT)
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != (int)PostInfo::ptExecutingScript)
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(iStageProgress / 10), "%");
|
||||
}
|
||||
|
||||
const char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Executing postprocess-script", "" };
|
||||
char* szInfoName = pBufPtr + sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen) + ntohl(pPostQueueAnswer->m_iParFilename);
|
||||
const char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Unpacking", ", Executing postprocess-script", "" };
|
||||
char* szInfoName = pBufPtr + sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen);
|
||||
|
||||
printf("[%i] %s%s%s\n", ntohl(pPostQueueAnswer->m_iID), szInfoName, szPostStageName[ntohl(pPostQueueAnswer->m_iStage)], szCompleted);
|
||||
|
||||
pBufPtr += sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen) +
|
||||
ntohl(pPostQueueAnswer->m_iParFilename) + ntohl(pPostQueueAnswer->m_iInfoNameLen) +
|
||||
ntohl(pPostQueueAnswer->m_iDestDirLen) + ntohl(pPostQueueAnswer->m_iProgressLabelLen);
|
||||
ntohl(pPostQueueAnswer->m_iInfoNameLen) + ntohl(pPostQueueAnswer->m_iDestDirLen) +
|
||||
ntohl(pPostQueueAnswer->m_iProgressLabelLen);
|
||||
}
|
||||
|
||||
free(pBuf);
|
||||
@@ -956,7 +1066,7 @@ bool RemoteClient::RequestWriteLog(int iKind, const char* szText)
|
||||
int iLength = strlen(szText) + 1;
|
||||
WriteLogRequest.m_iTrailingDataLength = htonl(iLength);
|
||||
|
||||
if (m_pConnection->Send((char*)(&WriteLogRequest), sizeof(WriteLogRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&WriteLogRequest), sizeof(WriteLogRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -968,14 +1078,16 @@ bool RemoteClient::RequestWriteLog(int iKind, const char* szText)
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestScan()
|
||||
bool RemoteClient::RequestScan(bool bSyncMode)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBScanRequest ScanRequest;
|
||||
InitMessageBase(&ScanRequest.m_MessageBase, eRemoteRequestScan, sizeof(ScanRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ScanRequest), sizeof(ScanRequest)) >= 0;
|
||||
ScanRequest.m_bSyncMode = htonl(bSyncMode);
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ScanRequest), sizeof(ScanRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -996,7 +1108,7 @@ bool RemoteClient::RequestHistory()
|
||||
SNZBHistoryRequest HistoryRequest;
|
||||
InitMessageBase(&HistoryRequest.m_MessageBase, eRemoteRequestHistory, sizeof(HistoryRequest));
|
||||
|
||||
if (m_pConnection->Send((char*)(&HistoryRequest), sizeof(HistoryRequest)) < 0)
|
||||
if (!m_pConnection->Send((char*)(&HistoryRequest), sizeof(HistoryRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -1006,19 +1118,12 @@ bool RemoteClient::RequestHistory()
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBHistoryResponse HistoryResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
if (iResponseLen != sizeof(HistoryResponse) ||
|
||||
bool bRead = m_pConnection->Recv((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(HistoryResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(HistoryResponse.m_MessageBase.m_iStructSize) != sizeof(HistoryResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1026,7 +1131,7 @@ bool RemoteClient::RequestHistory()
|
||||
if (ntohl(HistoryResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(HistoryResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(HistoryResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(HistoryResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -1049,27 +1154,33 @@ bool RemoteClient::RequestHistory()
|
||||
{
|
||||
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) pBufPtr;
|
||||
|
||||
const char* szFileName = pBufPtr + sizeof(SNZBHistoryResponseEntry);
|
||||
HistoryInfo::EKind eKind = (HistoryInfo::EKind)ntohl(pListAnswer->m_iKind);
|
||||
const char* szNicename = pBufPtr + sizeof(SNZBHistoryResponseEntry);
|
||||
|
||||
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
|
||||
if (eKind == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
NZBInfo::MakeNiceNZBName(szFileName, szNZBNiceName, 1024);
|
||||
char szSize[20];
|
||||
Util::FormatFileSize(szSize, sizeof(szSize), lSize);
|
||||
|
||||
char szSize[20];
|
||||
Util::FormatFileSize(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" };
|
||||
|
||||
const char* szParStatusText[] = { "", ", Par failed", ", Par possible", ", Par successful" };
|
||||
const char* szScriptStatusText[] = { "", ", Script status unknown", ", Script failed", ", Script successful" };
|
||||
printf("[%i] %s (%i files, %s%s%s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
ntohl(pListAnswer->m_iFileCount), szSize,
|
||||
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
|
||||
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
|
||||
}
|
||||
else if (eKind == HistoryInfo::hkUrlInfo)
|
||||
{
|
||||
const char* szUrlStatusText[] = { "", "", "Url download successful", "Url download failed", "" };
|
||||
|
||||
printf("[%i] %s (%i files, %s%s%s)\n", ntohl(pListAnswer->m_iID), szNZBNiceName,
|
||||
ntohl(pListAnswer->m_iFileCount), szSize,
|
||||
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
|
||||
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
|
||||
printf("[%i] %s (%s)\n", ntohl(pListAnswer->m_iID), szNicename,
|
||||
szUrlStatusText[ntohl(pListAnswer->m_iUrlStatus)]);
|
||||
}
|
||||
|
||||
pBufPtr += sizeof(SNZBHistoryResponseEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen) +
|
||||
ntohl(pListAnswer->m_iQueuedFilenameLen);
|
||||
pBufPtr += sizeof(SNZBHistoryResponseEntry) + ntohl(pListAnswer->m_iNicenameLen);
|
||||
}
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
@@ -1080,3 +1191,117 @@ bool RemoteClient::RequestHistory()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBDownloadUrlRequest DownloadUrlRequest;
|
||||
InitMessageBase(&DownloadUrlRequest.m_MessageBase, eRemoteRequestDownloadUrl, sizeof(DownloadUrlRequest));
|
||||
DownloadUrlRequest.m_bAddFirst = htonl(bAddFirst);
|
||||
DownloadUrlRequest.m_bAddPaused = htonl(bAddPaused);
|
||||
DownloadUrlRequest.m_iPriority = htonl(iPriority);
|
||||
|
||||
strncpy(DownloadUrlRequest.m_szURL, szURL, NZBREQUESTFILENAMESIZE - 1);
|
||||
DownloadUrlRequest.m_szURL[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
DownloadUrlRequest.m_szCategory[0] = '\0';
|
||||
if (szCategory)
|
||||
{
|
||||
strncpy(DownloadUrlRequest.m_szCategory, szCategory, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadUrlRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
DownloadUrlRequest.m_szNZBFilename[0] = '\0';
|
||||
if (szNZBFilename)
|
||||
{
|
||||
strncpy(DownloadUrlRequest.m_szNZBFilename, szNZBFilename, NZBREQUESTFILENAMESIZE - 1);
|
||||
}
|
||||
DownloadUrlRequest.m_szNZBFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&DownloadUrlRequest), sizeof(DownloadUrlRequest));
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
}
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestUrlQueue()
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBUrlQueueRequest UrlQueueRequest;
|
||||
InitMessageBase(&UrlQueueRequest.m_MessageBase, eRemoteRequestUrlQueue, sizeof(UrlQueueRequest));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&UrlQueueRequest), sizeof(UrlQueueRequest)))
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Request sent\n");
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBUrlQueueResponse UrlQueueResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
|
||||
if (!bRead ||
|
||||
(int)ntohl(UrlQueueResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(UrlQueueResponse.m_MessageBase.m_iStructSize) != sizeof(UrlQueueResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char* pBuf = NULL;
|
||||
if (ntohl(UrlQueueResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(UrlQueueResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(UrlQueueResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
|
||||
if (ntohl(UrlQueueResponse.m_iTrailingDataLength) == 0)
|
||||
{
|
||||
printf("Server has no urls queued for download\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Url-Queue\n");
|
||||
printf("-----------------------------------\n");
|
||||
|
||||
char* pBufPtr = (char*)pBuf;
|
||||
for (unsigned int i = 0; i < ntohl(UrlQueueResponse.m_iNrTrailingEntries); i++)
|
||||
{
|
||||
SNZBUrlQueueResponseEntry* pUrlQueueAnswer = (SNZBUrlQueueResponseEntry*) pBufPtr;
|
||||
|
||||
const char* szURL = pBufPtr + sizeof(SNZBUrlQueueResponseEntry);
|
||||
const char* szTitle = pBufPtr + sizeof(SNZBUrlQueueResponseEntry) + ntohl(pUrlQueueAnswer->m_iURLLen);
|
||||
|
||||
char szNiceName[1024];
|
||||
UrlInfo::MakeNiceName(szURL, szTitle, szNiceName, 1024);
|
||||
|
||||
printf("[%i] %s\n", ntohl(pUrlQueueAnswer->m_iID), szNiceName);
|
||||
|
||||
pBufPtr += sizeof(SNZBUrlQueueResponseEntry) + ntohl(pUrlQueueAnswer->m_iURLLen) +
|
||||
ntohl(pUrlQueueAnswer->m_iNZBFilenameLen);
|
||||
}
|
||||
|
||||
free(pBuf);
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -35,8 +35,19 @@
|
||||
class RemoteClient
|
||||
{
|
||||
private:
|
||||
class MatchedNZBInfo: public NZBInfo
|
||||
{
|
||||
public:
|
||||
bool m_bMatch;
|
||||
};
|
||||
|
||||
class MatchedFileInfo: public FileInfo
|
||||
{
|
||||
public:
|
||||
bool m_bMatch;
|
||||
};
|
||||
|
||||
Connection* m_pConnection;
|
||||
NetAddress* m_pNetAddress;
|
||||
bool m_bVerbose;
|
||||
|
||||
bool InitConnection();
|
||||
@@ -49,19 +60,23 @@ public:
|
||||
RemoteClient();
|
||||
~RemoteClient();
|
||||
void SetVerbose(bool bVerbose) { m_bVerbose = bVerbose; };
|
||||
bool RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst);
|
||||
bool RequestServerList(bool bFiles, bool bGroups);
|
||||
bool RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
|
||||
bool RequestServerList(bool bFiles, bool bGroups, const char* szPattern);
|
||||
bool RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAction iAction);
|
||||
bool RequestServerSetDownloadRate(float fRate);
|
||||
bool RequestServerSetDownloadRate(int iRate);
|
||||
bool RequestServerDumpDebug();
|
||||
bool RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText, int* pIDList, int iIDCount, bool bSmartOrder);
|
||||
bool RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
|
||||
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder);
|
||||
bool RequestServerLog(int iLines);
|
||||
bool RequestServerShutdown();
|
||||
bool RequestServerReload();
|
||||
bool RequestServerVersion();
|
||||
bool RequestPostQueue();
|
||||
bool RequestWriteLog(int iKind, const char* szText);
|
||||
bool RequestScan();
|
||||
bool RequestScan(bool bSyncMode);
|
||||
bool RequestHistory();
|
||||
bool RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
|
||||
bool RequestUrlQueue();
|
||||
void BuildFileList(SNZBListResponse* pListResponse, const char* pTrailingData, DownloadQueue* pDownloadQueue);
|
||||
};
|
||||
|
||||
|
||||
142
RemoteServer.cpp
142
RemoteServer.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -44,20 +44,21 @@
|
||||
#include "nzbget.h"
|
||||
#include "RemoteServer.h"
|
||||
#include "BinRpc.h"
|
||||
#include "XmlRpc.h"
|
||||
#include "WebServer.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
//*****************************************************************
|
||||
// RemoteServer
|
||||
|
||||
RemoteServer::RemoteServer()
|
||||
RemoteServer::RemoteServer(bool bTLS)
|
||||
{
|
||||
debug("Creating RemoteServer");
|
||||
|
||||
m_pNetAddress = new NetAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
|
||||
m_bTLS = bTLS;
|
||||
m_pConnection = NULL;
|
||||
}
|
||||
|
||||
@@ -69,32 +70,50 @@ RemoteServer::~RemoteServer()
|
||||
{
|
||||
delete m_pConnection;
|
||||
}
|
||||
delete m_pNetAddress;
|
||||
}
|
||||
|
||||
void RemoteServer::Run()
|
||||
{
|
||||
debug("Entering RemoteServer-loop");
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_bTLS)
|
||||
{
|
||||
if (strlen(g_pOptions->GetSecureCert()) == 0 || !Util::FileExists(g_pOptions->GetSecureCert()))
|
||||
{
|
||||
error("Could not initialize TLS, secure certificate is not configured or the cert-file was not found. Check option <SecureCert>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(g_pOptions->GetSecureKey()) == 0 || !Util::FileExists(g_pOptions->GetSecureKey()))
|
||||
{
|
||||
error("Could not initialize TLS, secure key is not configured or the key-file was not found. Check option <SecureKey>");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
bool bBind = true;
|
||||
|
||||
if (!m_pConnection)
|
||||
{
|
||||
m_pConnection = new Connection(m_pNetAddress);
|
||||
m_pConnection = new Connection(g_pOptions->GetControlIP(),
|
||||
m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(),
|
||||
m_bTLS);
|
||||
m_pConnection->SetTimeout(g_pOptions->GetConnectionTimeout());
|
||||
m_pConnection->SetSuppressErrors(false);
|
||||
bBind = m_pConnection->Bind() == 0;
|
||||
bBind = m_pConnection->Bind();
|
||||
}
|
||||
|
||||
// Accept connections and store the "new" socket value
|
||||
SOCKET iSocket = INVALID_SOCKET;
|
||||
// Accept connections and store the new Connection
|
||||
Connection* pAcceptedConnection = NULL;
|
||||
if (bBind)
|
||||
{
|
||||
iSocket = m_pConnection->Accept();
|
||||
pAcceptedConnection = m_pConnection->Accept();
|
||||
}
|
||||
if (!bBind || iSocket == INVALID_SOCKET)
|
||||
if (!bBind || pAcceptedConnection == NULL)
|
||||
{
|
||||
// Remote server could not bind or accept connection, waiting 1/2 sec and try again
|
||||
if (IsStopped())
|
||||
@@ -109,9 +128,13 @@ void RemoteServer::Run()
|
||||
|
||||
RequestProcessor* commandThread = new RequestProcessor();
|
||||
commandThread->SetAutoDestroy(true);
|
||||
commandThread->SetSocket(iSocket);
|
||||
commandThread->SetConnection(pAcceptedConnection);
|
||||
#ifndef DISABLE_TLS
|
||||
commandThread->SetTLS(m_bTLS);
|
||||
#endif
|
||||
commandThread->Start();
|
||||
}
|
||||
|
||||
if (m_pConnection)
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
@@ -136,32 +159,32 @@ void RemoteServer::Stop()
|
||||
//*****************************************************************
|
||||
// RequestProcessor
|
||||
|
||||
RequestProcessor::~RequestProcessor()
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
delete m_pConnection;
|
||||
}
|
||||
|
||||
void RequestProcessor::Run()
|
||||
{
|
||||
// Read the first 4 bytes to determine request type
|
||||
bool bOK = false;
|
||||
int iSignature = 0;
|
||||
int iBytesReceived = recv(m_iSocket, (char*)&iSignature, sizeof(iSignature), 0);
|
||||
if (iBytesReceived < 0)
|
||||
|
||||
m_pConnection->SetSuppressErrors(true);
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_bTLS && !m_pConnection->StartTLS(false, g_pOptions->GetSecureCert(), g_pOptions->GetSecureKey()))
|
||||
{
|
||||
debug("Could not establish secure connection to web-client: Start TLS failed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Info - connection received
|
||||
#ifdef WIN32
|
||||
char* ip = NULL;
|
||||
#else
|
||||
char ip[20];
|
||||
#endif
|
||||
struct sockaddr_in PeerName;
|
||||
int iPeerNameLength = sizeof(PeerName);
|
||||
if (getpeername(m_iSocket, (struct sockaddr*)&PeerName, (SOCKLEN_T*) &iPeerNameLength) >= 0)
|
||||
// Read the first 4 bytes to determine request type
|
||||
int iSignature = 0;
|
||||
if (!m_pConnection->Recv((char*)&iSignature, 4))
|
||||
{
|
||||
#ifdef WIN32
|
||||
ip = inet_ntoa(PeerName.sin_addr);
|
||||
#else
|
||||
inet_ntop(AF_INET, &PeerName.sin_addr, ip, sizeof(ip));
|
||||
#endif
|
||||
debug("Could not read request signature, request received on port %i from %s", m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int)ntohl(iSignature) == (int)NZBMESSAGE_SIGNATURE)
|
||||
@@ -169,62 +192,47 @@ void RequestProcessor::Run()
|
||||
// binary request received
|
||||
bOK = true;
|
||||
BinRpcProcessor processor;
|
||||
processor.SetSocket(m_iSocket);
|
||||
processor.SetSignature(iSignature);
|
||||
processor.SetClientIP(ip);
|
||||
processor.SetConnection(m_pConnection);
|
||||
processor.Execute();
|
||||
}
|
||||
else if (!strncmp((char*)&iSignature, "POST", 4) || !strncmp((char*)&iSignature, "GET ", 4))
|
||||
else if (!strncmp((char*)&iSignature, "POST", 4) ||
|
||||
!strncmp((char*)&iSignature, "GET ", 4) ||
|
||||
!strncmp((char*)&iSignature, "OPTI", 4))
|
||||
{
|
||||
// XML-RPC or JSON-RPC request received
|
||||
Connection con(m_iSocket, false);
|
||||
// HTTP request received
|
||||
char szBuffer[1024];
|
||||
if (con.ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
if (m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
{
|
||||
XmlRpcProcessor::EHttpMethod eHttpMethod = XmlRpcProcessor::hmGet;
|
||||
WebProcessor::EHttpMethod eHttpMethod = WebProcessor::hmGet;
|
||||
char* szUrl = szBuffer;
|
||||
if (!strncmp((char*)&iSignature, "POST", 4))
|
||||
{
|
||||
eHttpMethod = XmlRpcProcessor::hmPost;
|
||||
eHttpMethod = WebProcessor::hmPost;
|
||||
szUrl++;
|
||||
}
|
||||
if (!strncmp((char*)&iSignature, "OPTI", 4) && strlen(szUrl) > 4)
|
||||
{
|
||||
eHttpMethod = WebProcessor::hmOptions;
|
||||
szUrl += 4;
|
||||
}
|
||||
if (char* p = strchr(szUrl, ' '))
|
||||
{
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
XmlRpcProcessor::ERpcProtocol eProtocol = XmlRpcProcessor::rpUndefined;
|
||||
if (!strcmp(szUrl, "/xmlrpc") || !strncmp(szUrl, "/xmlrpc/", 8))
|
||||
{
|
||||
eProtocol = XmlRpcProcessor::rpXmlRpc;
|
||||
}
|
||||
else if (!strcmp(szUrl, "/jsonrpc") || !strncmp(szUrl, "/jsonrpc/", 9))
|
||||
{
|
||||
eProtocol = XmlRpcProcessor::rpJsonRpc;
|
||||
}
|
||||
else if (!strcmp(szUrl, "/jsonprpc") || !strncmp(szUrl, "/jsonprpc/", 10))
|
||||
{
|
||||
eProtocol = XmlRpcProcessor::rpJsonPRpc;
|
||||
}
|
||||
debug("url: %s", szUrl);
|
||||
|
||||
if (eProtocol != XmlRpcProcessor::rpUndefined)
|
||||
{
|
||||
XmlRpcProcessor processor;
|
||||
processor.SetConnection(&con);
|
||||
processor.SetClientIP(ip);
|
||||
processor.SetProtocol(eProtocol);
|
||||
processor.SetHttpMethod(eHttpMethod);
|
||||
processor.SetUrl(szUrl);
|
||||
processor.Execute();
|
||||
bOK = true;
|
||||
}
|
||||
WebProcessor processor;
|
||||
processor.SetConnection(m_pConnection);
|
||||
processor.SetUrl(szUrl);
|
||||
processor.SetHttpMethod(eHttpMethod);
|
||||
processor.Execute();
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bOK)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetServerPort(), ip);
|
||||
warn("Non-nzbget request received on port %i from %s", m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
}
|
||||
|
||||
closesocket(m_iSocket);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -28,17 +28,16 @@
|
||||
#define REMOTESERVER_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "NetAddress.h"
|
||||
#include "Connection.h"
|
||||
|
||||
class RemoteServer : public Thread
|
||||
{
|
||||
private:
|
||||
NetAddress* m_pNetAddress;
|
||||
bool m_bTLS;
|
||||
Connection* m_pConnection;
|
||||
|
||||
public:
|
||||
RemoteServer();
|
||||
RemoteServer(bool bTLS);
|
||||
~RemoteServer();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
@@ -47,11 +46,14 @@ public:
|
||||
class RequestProcessor : public Thread
|
||||
{
|
||||
private:
|
||||
SOCKET m_iSocket;
|
||||
bool m_bTLS;
|
||||
Connection* m_pConnection;
|
||||
|
||||
public:
|
||||
~RequestProcessor();
|
||||
virtual void Run();
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; };
|
||||
void SetTLS(bool bTLS) { m_bTLS = bTLS; }
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
236
Scanner.cpp
236
Scanner.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -33,12 +33,13 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Scanner.h"
|
||||
@@ -65,14 +66,49 @@ Scanner::FileData::~FileData()
|
||||
free(m_szFilename);
|
||||
}
|
||||
|
||||
|
||||
Scanner::QueueData::QueueData(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused)
|
||||
{
|
||||
m_szFilename = strdup(szFilename);
|
||||
m_szNZBName = strdup(szNZBName);
|
||||
m_szCategory = strdup(szCategory ? szCategory : "");
|
||||
m_iPriority = iPriority;
|
||||
m_bAddTop = bAddTop;
|
||||
m_bAddPaused = bAddPaused;
|
||||
|
||||
if (pParameters)
|
||||
{
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
NZBParameter* pNZBParameter = *it;
|
||||
m_Parameters.SetParameter(pNZBParameter->GetName(), pNZBParameter->GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scanner::QueueData::~QueueData()
|
||||
{
|
||||
free(m_szFilename);
|
||||
free(m_szNZBName);
|
||||
free(m_szCategory);
|
||||
|
||||
for (NZBParameterList::iterator it = m_Parameters.begin(); it != m_Parameters.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Parameters.clear();
|
||||
}
|
||||
|
||||
|
||||
Scanner::Scanner()
|
||||
{
|
||||
debug("Creating Scanner");
|
||||
|
||||
m_bRequestedNZBDirScan = false;
|
||||
m_bScanning = false;
|
||||
m_iNZBDirInterval = g_pOptions->GetNzbDirInterval() * 1000;
|
||||
m_iPass = 0;
|
||||
m_iStepMSec = 0;
|
||||
|
||||
const char* szNZBScript = g_pOptions->GetNZBProcess();
|
||||
m_bNZBScript = szNZBScript && strlen(szNZBScript) > 0;
|
||||
@@ -87,18 +123,38 @@ Scanner::~Scanner()
|
||||
delete *it;
|
||||
}
|
||||
m_FileList.clear();
|
||||
|
||||
ClearQueueList();
|
||||
}
|
||||
|
||||
void Scanner::ClearQueueList()
|
||||
{
|
||||
for (QueueList::iterator it = m_QueueList.begin(); it != m_QueueList.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_QueueList.clear();
|
||||
}
|
||||
|
||||
void Scanner::Check()
|
||||
{
|
||||
if (g_pOptions->GetNzbDir() && (m_bRequestedNZBDirScan ||
|
||||
m_mutexScan.Lock();
|
||||
|
||||
if (m_bRequestedNZBDirScan ||
|
||||
(!g_pOptions->GetPauseScan() && g_pOptions->GetNzbDirInterval() > 0 &&
|
||||
m_iNZBDirInterval >= g_pOptions->GetNzbDirInterval() * 1000)))
|
||||
m_iNZBDirInterval >= g_pOptions->GetNzbDirInterval() * 1000))
|
||||
{
|
||||
// check nzbdir every g_pOptions->GetNzbDirInterval() seconds or if requested
|
||||
bool bCheckStat = !m_bRequestedNZBDirScan;
|
||||
m_bRequestedNZBDirScan = false;
|
||||
m_bScanning = true;
|
||||
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
|
||||
if (!bCheckStat && m_bNZBScript)
|
||||
{
|
||||
// if immediate scan requested, we need second scan to process files extracted by NzbProcess-script
|
||||
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
|
||||
}
|
||||
m_bScanning = false;
|
||||
m_iNZBDirInterval = 0;
|
||||
|
||||
// if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval
|
||||
@@ -106,7 +162,7 @@ void Scanner::Check()
|
||||
// - one additional scan is neccessary to check sizes of detected files;
|
||||
// - another scan is required to check files which were extracted by NzbProcess-script;
|
||||
// - third scan is needed to check sizes of extracted files.
|
||||
if (g_pOptions->GetNzbDirFileAge() < g_pOptions->GetNzbDirInterval())
|
||||
if (g_pOptions->GetNzbDirInterval() > 0 && g_pOptions->GetNzbDirFileAge() < g_pOptions->GetNzbDirInterval())
|
||||
{
|
||||
int iMaxPass = m_bNZBScript ? 3 : 1;
|
||||
if (m_iPass < iMaxPass)
|
||||
@@ -123,7 +179,10 @@ void Scanner::Check()
|
||||
|
||||
DropOldFiles();
|
||||
}
|
||||
m_iNZBDirInterval += m_iStepMSec;
|
||||
m_iNZBDirInterval += 200;
|
||||
|
||||
ClearQueueList();
|
||||
m_mutexScan.Unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,14 +327,34 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
|
||||
return;
|
||||
}
|
||||
|
||||
char* szNZBName = strdup("");
|
||||
char* szNZBCategory = strdup(szCategory);
|
||||
NZBParameterList* pParameterList = new NZBParameterList;
|
||||
NZBParameterList* pParameters = new NZBParameterList();
|
||||
int iPriority = 0;
|
||||
bool bAddTop = false;
|
||||
bool bAddPaused = false;
|
||||
|
||||
for (QueueList::iterator it = m_QueueList.begin(); it != m_QueueList.end(); it++)
|
||||
{
|
||||
QueueData* pQueueData = *it;
|
||||
if (Util::SameFilename(pQueueData->GetFilename(), szFullFilename))
|
||||
{
|
||||
free(szNZBName);
|
||||
szNZBName = strdup(pQueueData->GetNZBName());
|
||||
free(szNZBCategory);
|
||||
szNZBCategory = strdup(pQueueData->GetCategory());
|
||||
iPriority = pQueueData->GetPriority();
|
||||
bAddTop = pQueueData->GetAddTop();
|
||||
bAddPaused = pQueueData->GetAddPaused();
|
||||
}
|
||||
}
|
||||
|
||||
bool bExists = true;
|
||||
|
||||
if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed"))
|
||||
{
|
||||
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory, &szNZBCategory, pParameterList);
|
||||
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory,
|
||||
&szNZBName, &szNZBCategory, &iPriority, pParameters, &bAddTop, &bAddPaused);
|
||||
bExists = Util::FileExists(szFullFilename);
|
||||
if (bExists && strcasecmp(szExtension, ".nzb"))
|
||||
{
|
||||
@@ -283,7 +362,8 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
|
||||
bool bRenameOK = Util::RenameBak(szFullFilename, "processed", false, bakname2, 1024);
|
||||
if (!bRenameOK)
|
||||
{
|
||||
error("Could not rename file %s to %s! Errcode: %i", szFullFilename, bakname2, errno);
|
||||
char szSysErrStr[256];
|
||||
error("Could not rename file %s to %s: %s", szFullFilename, bakname2, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,35 +374,38 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
|
||||
bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024);
|
||||
if (bRenameOK)
|
||||
{
|
||||
AddFileToQueue(szRenamedName, szNZBCategory, pParameterList);
|
||||
AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not rename file %s to %s! Errcode: %i", szFullFilename, szRenamedName, errno);
|
||||
char szSysErrStr[256];
|
||||
error("Could not rename file %s to %s: %s", szFullFilename, szRenamedName, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
}
|
||||
}
|
||||
else if (bExists && !strcasecmp(szExtension, ".nzb"))
|
||||
{
|
||||
AddFileToQueue(szFullFilename, szNZBCategory, pParameterList);
|
||||
AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
}
|
||||
|
||||
for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++)
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
pParameterList->clear();
|
||||
delete pParameterList;
|
||||
pParameters->clear();
|
||||
delete pParameters;
|
||||
|
||||
free(szNZBName);
|
||||
free(szNZBCategory);
|
||||
}
|
||||
|
||||
void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList)
|
||||
void Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused)
|
||||
{
|
||||
const char* szBasename = Util::BaseFileName(szFilename);
|
||||
|
||||
info("Collection %s found", szBasename);
|
||||
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromFile(szFilename, szCategory);
|
||||
NZBFile* pNZBFile = NZBFile::Create(szFilename, szCategory);
|
||||
if (!pNZBFile)
|
||||
{
|
||||
error("Could not add collection %s to queue", szBasename);
|
||||
@@ -332,20 +415,35 @@ void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZB
|
||||
bool bRenameOK = Util::RenameBak(szFilename, pNZBFile ? "queued" : "error", false, bakname2, 1024);
|
||||
if (!bRenameOK)
|
||||
{
|
||||
error("Could not rename file %s to %s! Errcode: %i", szFilename, bakname2, errno);
|
||||
char szSysErrStr[256];
|
||||
error("Could not rename file %s to %s: %s", szFilename, bakname2, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
}
|
||||
|
||||
if (pNZBFile && bRenameOK)
|
||||
{
|
||||
pNZBFile->GetNZBInfo()->SetQueuedFilename(bakname2);
|
||||
|
||||
for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++)
|
||||
if (szNZBName && strlen(szNZBName) > 0)
|
||||
{
|
||||
pNZBFile->GetNZBInfo()->SetName(NULL);
|
||||
pNZBFile->GetNZBInfo()->SetFilename(szNZBName);
|
||||
pNZBFile->GetNZBInfo()->BuildDestDirName();
|
||||
}
|
||||
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
pNZBFile->GetNZBInfo()->SetParameter(pParameter->GetName(), pParameter->GetValue());
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, false);
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->SetPriority(iPriority);
|
||||
pFileInfo->SetPaused(bAddPaused);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, bAddTop);
|
||||
info("Collection %s added to queue", szBasename);
|
||||
}
|
||||
|
||||
@@ -355,9 +453,93 @@ void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZB
|
||||
}
|
||||
}
|
||||
|
||||
void Scanner::ScanNZBDir()
|
||||
void Scanner::ScanNZBDir(bool bSyncMode)
|
||||
{
|
||||
// ideally we should use mutex to access "m_bRequestedNZBDirScan",
|
||||
// but it's not critical here.
|
||||
m_mutexScan.Lock();
|
||||
m_bScanning = true;
|
||||
m_bRequestedNZBDirScan = true;
|
||||
m_mutexScan.Unlock();
|
||||
|
||||
while (bSyncMode && (m_bScanning || m_bRequestedNZBDirScan))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
bool Scanner::AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused,
|
||||
const char* szFileName, const char* szBuffer, int iBufSize, bool bSyncMode)
|
||||
{
|
||||
char szTempFileName[1024];
|
||||
|
||||
if (szFileName)
|
||||
{
|
||||
strncpy(szTempFileName, szFileName, 1024);
|
||||
szTempFileName[1024-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
int iNum = 1;
|
||||
while (iNum == 1 || Util::FileExists(szTempFileName))
|
||||
{
|
||||
snprintf(szTempFileName, 1024, "%snzb-%i.tmp", g_pOptions->GetTempDir(), iNum);
|
||||
szTempFileName[1024-1] = '\0';
|
||||
iNum++;
|
||||
}
|
||||
|
||||
if (!Util::SaveBufferIntoFile(szTempFileName, szBuffer, iBufSize))
|
||||
{
|
||||
error("Could not create file %s", szTempFileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// move file into NzbDir, make sure the file name is unique
|
||||
char szValidNZBName[1024];
|
||||
strncpy(szValidNZBName, Util::BaseFileName(szNZBName), 1024);
|
||||
szValidNZBName[1024-1] = '\0';
|
||||
Util::MakeValidFilename(szValidNZBName, '_', false);
|
||||
|
||||
char szScanFileName[1024];
|
||||
snprintf(szScanFileName, 1024, "%s%s", g_pOptions->GetNzbDir(), szValidNZBName);
|
||||
|
||||
char *szExt = strrchr(szValidNZBName, '.');
|
||||
if (szExt)
|
||||
{
|
||||
*szExt = '\0';
|
||||
szExt++;
|
||||
}
|
||||
|
||||
int iNum = 2;
|
||||
while (Util::FileExists(szScanFileName))
|
||||
{
|
||||
if (szExt)
|
||||
{
|
||||
snprintf(szScanFileName, 1024, "%s%s_%i.%s", g_pOptions->GetNzbDir(), szValidNZBName, iNum, szExt);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szScanFileName, 1024, "%s%s_%i", g_pOptions->GetNzbDir(), szValidNZBName, iNum);
|
||||
}
|
||||
szScanFileName[1024-1] = '\0';
|
||||
iNum++;
|
||||
}
|
||||
|
||||
if (!Util::MoveFile(szTempFileName, szScanFileName))
|
||||
{
|
||||
char szSysErrStr[256];
|
||||
error("Could not move file %s to %s: %s", szTempFileName, szScanFileName, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
remove(szTempFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
QueueData* pQueueData = new QueueData(szScanFileName, szNZBName, szCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
|
||||
m_mutexScan.Lock();
|
||||
m_QueueList.push_back(pQueueData);
|
||||
m_mutexScan.Unlock();
|
||||
|
||||
ScanNZBDir(bSyncMode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
45
Scanner.h
45
Scanner.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <deque>
|
||||
#include <time.h>
|
||||
#include "DownloadInfo.h"
|
||||
#include "Thread.h"
|
||||
|
||||
class Scanner
|
||||
{
|
||||
@@ -52,25 +53,57 @@ private:
|
||||
|
||||
typedef std::deque<FileData*> FileList;
|
||||
|
||||
class QueueData
|
||||
{
|
||||
private:
|
||||
char* m_szFilename;
|
||||
char* m_szNZBName;
|
||||
char* m_szCategory;
|
||||
int m_iPriority;
|
||||
NZBParameterList m_Parameters;
|
||||
bool m_bAddTop;
|
||||
bool m_bAddPaused;
|
||||
|
||||
public:
|
||||
QueueData(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused);
|
||||
~QueueData();
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
const char* GetNZBName() { return m_szNZBName; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
int GetPriority() { return m_iPriority; }
|
||||
NZBParameterList* GetParameters() { return &m_Parameters; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
bool GetAddPaused() { return m_bAddPaused; }
|
||||
};
|
||||
|
||||
typedef std::deque<QueueData*> QueueList;
|
||||
|
||||
bool m_bRequestedNZBDirScan;
|
||||
int m_iNZBDirInterval;
|
||||
bool m_bNZBScript;
|
||||
int m_iPass;
|
||||
int m_iStepMSec;
|
||||
FileList m_FileList;
|
||||
QueueList m_QueueList;
|
||||
bool m_bScanning;
|
||||
Mutex m_mutexScan;
|
||||
|
||||
void CheckIncomingNZBs(const char* szDirectory, const char* szCategory, bool bCheckStat);
|
||||
void AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList);
|
||||
void AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused);
|
||||
void ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename, const char* szFullFilename, const char* szCategory);
|
||||
bool CanProcessFile(const char* szFullFilename, bool bCheckStat);
|
||||
void DropOldFiles();
|
||||
void ClearQueueList();
|
||||
|
||||
public:
|
||||
Scanner();
|
||||
~Scanner();
|
||||
void SetStepInterval(int iStepMSec) { m_iStepMSec = iStepMSec; }
|
||||
void ScanNZBDir();
|
||||
void ScanNZBDir(bool bSyncMode);
|
||||
void Check();
|
||||
bool AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddPaused, bool bAddTop,
|
||||
const char* szFileName, const char* szBuffer, int iBufSize, bool bSyncMode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Scheduler.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2009 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -43,6 +43,7 @@ private:
|
||||
public:
|
||||
EnvironmentStrings();
|
||||
~EnvironmentStrings();
|
||||
void Clear();
|
||||
void InitFromCurrentProcess();
|
||||
void Append(char* szString);
|
||||
#ifdef WIN32
|
||||
@@ -59,22 +60,28 @@ private:
|
||||
const char* m_szWorkingDir;
|
||||
const char** m_szArgs;
|
||||
bool m_bFreeArgs;
|
||||
const char* m_szStdArgs[2];
|
||||
const char* m_szInfoName;
|
||||
const char* m_szDefaultKindPrefix;
|
||||
const char* m_szLogPrefix;
|
||||
EnvironmentStrings m_environmentStrings;
|
||||
Options::EScriptLogKind m_eDefaultLogKind;
|
||||
bool m_bTerminated;
|
||||
#ifdef WIN32
|
||||
HANDLE m_hProcess;
|
||||
char m_szCmdLine[2048];
|
||||
#else
|
||||
pid_t m_hProcess;
|
||||
#endif
|
||||
|
||||
void ProcessOutput(char* szText);
|
||||
void PrepareEnvironmentStrings();
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
void ProcessOutput(char* szText);
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
bool GetTerminated() { return m_bTerminated; }
|
||||
void ResetEnv();
|
||||
void PrepareEnvOptions(const char* szStripPrefix);
|
||||
void PrepareEnvParameters(NZBInfo* pNZBInfo, const char* szStripPrefix);
|
||||
void PrepareArgs();
|
||||
|
||||
public:
|
||||
ScriptController();
|
||||
@@ -88,42 +95,64 @@ public:
|
||||
void SetArgs(const char** szArgs, bool bFreeArgs) { m_szArgs = szArgs; m_bFreeArgs = bFreeArgs; }
|
||||
void SetInfoName(const char* szInfoName) { m_szInfoName = szInfoName; }
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetDefaultKindPrefix(const char* szDefaultKindPrefix) { m_szDefaultKindPrefix = szDefaultKindPrefix; }
|
||||
void SetDefaultLogKind(Options::EScriptLogKind eDefaultLogKind) { m_eDefaultLogKind = eDefaultLogKind; }
|
||||
void SetLogPrefix(const char* szLogPrefix) { m_szLogPrefix = szLogPrefix; }
|
||||
void SetEnvVar(const char* szName, const char* szValue);
|
||||
void SetEnvVarSpecial(const char* szPrefix, const char* szName, const char* szValue);
|
||||
};
|
||||
|
||||
class PostScriptController : public Thread, ScriptController
|
||||
class PostScriptController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
bool m_bNZBFileCompleted;
|
||||
bool m_bHasFailedParJobs;
|
||||
char m_szNZBName[1024];
|
||||
|
||||
void ExecuteScript(const char* szScriptName, const char* szDisplayName, const char* szLocation);
|
||||
void PrepareParams(const char* szScriptName);
|
||||
ScriptStatus::EStatus AnalyseExitCode(int iExitCode);
|
||||
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartScriptJob(PostInfo* pPostInfo, const char* szScript,
|
||||
bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
static void StartJob(PostInfo* pPostInfo);
|
||||
static void InitParamsForNewNZB(NZBInfo* pNZBInfo);
|
||||
};
|
||||
|
||||
class NZBScriptController : public ScriptController
|
||||
{
|
||||
private:
|
||||
char** m_pNZBName;
|
||||
char** m_pCategory;
|
||||
NZBParameterList* m_pParameterList;
|
||||
int* m_iPriority;
|
||||
NZBParameterList* m_pParameters;
|
||||
bool* m_bAddTop;
|
||||
bool* m_bAddPaused;
|
||||
int m_iPrefixLen;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory, char** pCategory, NZBParameterList* pParameterList);
|
||||
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory,
|
||||
char** pNZBName, char** pCategory, int* iPriority, NZBParameterList* pParameters,
|
||||
bool* bAddTop, bool* bAddPaused);
|
||||
};
|
||||
|
||||
class SchedulerScriptController : public Thread, ScriptController
|
||||
class NZBAddedScriptController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
char* m_szNZBName;
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
static void StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript);
|
||||
};
|
||||
|
||||
class SchedulerScriptController : public Thread, public ScriptController
|
||||
{
|
||||
public:
|
||||
virtual void Run();
|
||||
|
||||
120
ServerPool.cpp
120
ServerPool.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ServerPool.h"
|
||||
@@ -82,70 +83,119 @@ void ServerPool::AddServer(NewsServer* pNewsServer)
|
||||
{
|
||||
debug("Adding server to ServerPool");
|
||||
|
||||
m_Servers.push_back(pNewsServer);
|
||||
if (pNewsServer->GetMaxConnections() > 0)
|
||||
{
|
||||
m_Servers.push_back(pNewsServer);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pNewsServer;
|
||||
}
|
||||
}
|
||||
|
||||
void ServerPool::NormalizeLevels()
|
||||
{
|
||||
if (m_Servers.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(m_Servers.begin(), m_Servers.end(), CompareServers);
|
||||
|
||||
NewsServer* pNewsServer = m_Servers.front();
|
||||
|
||||
m_iMaxLevel = 0;
|
||||
int iCurLevel = pNewsServer->GetLevel();
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (pNewsServer->GetLevel() != iCurLevel)
|
||||
{
|
||||
m_iMaxLevel++;
|
||||
}
|
||||
|
||||
pNewsServer->SetLevel(m_iMaxLevel);
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerPool::CompareServers(NewsServer* pServer1, NewsServer* pServer2)
|
||||
{
|
||||
return pServer1->GetLevel() < pServer2->GetLevel();
|
||||
}
|
||||
|
||||
void ServerPool::InitConnections()
|
||||
{
|
||||
debug("Initializing connections in ServerPool");
|
||||
|
||||
m_iMaxLevel = 0;
|
||||
NormalizeLevels();
|
||||
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (m_iMaxLevel < pNewsServer->GetLevel())
|
||||
{
|
||||
m_iMaxLevel = pNewsServer->GetLevel();
|
||||
}
|
||||
for (int i = 0; i < pNewsServer->GetMaxConnections(); i++)
|
||||
{
|
||||
PooledConnection* pConnection = new PooledConnection(pNewsServer);
|
||||
pConnection->SetTimeout(m_iTimeout);
|
||||
m_Connections.push_back(pConnection);
|
||||
}
|
||||
if ((int)m_Levels.size() <= pNewsServer->GetLevel())
|
||||
{
|
||||
m_Levels.push_back(0);
|
||||
}
|
||||
m_Levels[pNewsServer->GetLevel()] += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
|
||||
for (int iLevel = 0; iLevel <= m_iMaxLevel; iLevel++)
|
||||
if (m_Levels.empty())
|
||||
{
|
||||
int iMaxConnectionsForLevel = 0;
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (iLevel == pNewsServer->GetLevel())
|
||||
{
|
||||
iMaxConnectionsForLevel += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
}
|
||||
|
||||
m_Levels.push_back(iMaxConnectionsForLevel);
|
||||
warn("No news servers defined, download is not possible");
|
||||
}
|
||||
}
|
||||
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel)
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers)
|
||||
{
|
||||
PooledConnection* pConnection = NULL;
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
if (m_Levels[iLevel] > 0)
|
||||
if (iLevel < (int)m_Levels.size() && m_Levels[iLevel] > 0)
|
||||
{
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection1 = *it;
|
||||
if (!pConnection1->GetInUse() && pConnection1->GetNewsServer()->GetLevel() == iLevel)
|
||||
PooledConnection* pCandidateConnection = *it;
|
||||
NewsServer* pCandidateServer = pCandidateConnection->GetNewsServer();
|
||||
if (!pCandidateConnection->GetInUse() && pCandidateServer->GetLevel() == iLevel &&
|
||||
(!pWantServer || pCandidateServer == pWantServer ||
|
||||
(pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())))
|
||||
{
|
||||
// free connection found, take it!
|
||||
pConnection = pConnection1;
|
||||
pConnection->SetInUse(true);
|
||||
break;
|
||||
// free connection found, check if it's not from the server which should be ignored
|
||||
bool bUseConnection = true;
|
||||
if (pIgnoreServers && !pWantServer)
|
||||
{
|
||||
for (Servers::iterator it = pIgnoreServers->begin(); it != pIgnoreServers->end(); it++)
|
||||
{
|
||||
NewsServer* pIgnoreServer = *it;
|
||||
if (pIgnoreServer == pCandidateServer ||
|
||||
(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
|
||||
pIgnoreServer->GetLevel() == pCandidateServer->GetLevel()))
|
||||
{
|
||||
bUseConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bUseConnection)
|
||||
{
|
||||
pConnection = pCandidateConnection;
|
||||
pConnection->SetInUse(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Levels[iLevel]--;
|
||||
|
||||
if (!pConnection)
|
||||
if (pConnection)
|
||||
{
|
||||
error("ServerPool: internal error, no free connection found, but there should be one");
|
||||
m_Levels[iLevel]--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +237,7 @@ void ServerPool::CloseUnusedConnections()
|
||||
int tdiff = (int)(curtime - pConnection->GetFreeTime());
|
||||
if (tdiff > CONNECTION_HOLD_SECODNS)
|
||||
{
|
||||
debug("Closing unused connection to %s", pConnection->GetNewsServer()->GetHost());
|
||||
debug("Closing unused connection to %s", pConnection->GetHost());
|
||||
pConnection->Disconnect();
|
||||
}
|
||||
}
|
||||
@@ -208,7 +258,7 @@ void ServerPool::LogDebugInfo()
|
||||
debug(" Connections: %i", m_Connections.size());
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
debug(" Connection: Level=%i, InUse:%i", (*it)->GetNewsServer()->GetLevel(), (int)(*it)->GetInUse());
|
||||
debug(" %s: Level=%i, InUse:%i", (*it)->GetNewsServer()->GetHost(), (*it)->GetNewsServer()->GetLevel(), (int)(*it)->GetInUse());
|
||||
}
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
|
||||
14
ServerPool.h
14
ServerPool.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
class ServerPool
|
||||
{
|
||||
public:
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
|
||||
private:
|
||||
class PooledConnection : public NNTPConnection
|
||||
{
|
||||
@@ -50,7 +53,6 @@ private:
|
||||
void SetFreeTimeNow() { m_tFreeTime = ::time(NULL); }
|
||||
};
|
||||
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
typedef std::vector<int> Levels;
|
||||
typedef std::vector<PooledConnection*> Connections;
|
||||
|
||||
@@ -61,6 +63,9 @@ private:
|
||||
Mutex m_mutexConnections;
|
||||
int m_iTimeout;
|
||||
|
||||
void NormalizeLevels();
|
||||
static bool CompareServers(NewsServer* pServer1, NewsServer* pServer2);
|
||||
|
||||
public:
|
||||
ServerPool();
|
||||
~ServerPool();
|
||||
@@ -68,7 +73,8 @@ public:
|
||||
void AddServer(NewsServer* pNewsServer);
|
||||
void InitConnections();
|
||||
int GetMaxLevel() { return m_iMaxLevel; }
|
||||
NNTPConnection* GetConnection(int iLevel);
|
||||
Servers* GetServers() { return &m_Servers; } // Only for read access (no lockings)
|
||||
NNTPConnection* GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers);
|
||||
void FreeConnection(NNTPConnection* pConnection, bool bUsed);
|
||||
void CloseUnusedConnections();
|
||||
|
||||
|
||||
206
TLS.h
206
TLS.h
@@ -1,13 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Based on "tls.h" from project "mpop" by Martin Lambers
|
||||
* Original source code available on http://sourceforge.net/projects/mpop/
|
||||
*
|
||||
* Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007
|
||||
* Martin Lambers <marlam@marlam.de>
|
||||
*
|
||||
* Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -33,180 +27,36 @@
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
|
||||
#include <time.h>
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
# include <gnutls/gnutls.h>
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
#ifdef HAVE_OPENSSL
|
||||
# include <openssl/ssl.h>
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
|
||||
/*
|
||||
* If a function with an 'errstr' argument returns a value != TLS_EOK,
|
||||
* '*errstr' either points to an allocates string containing an error
|
||||
* description or is NULL.
|
||||
* If such a function returns TLS_EOK, 'errstr' will not be changed.
|
||||
*/
|
||||
#define TLS_EOK 0 /* no error */
|
||||
#define TLS_ELIBFAILED 1 /* The underlying library failed */
|
||||
#define TLS_ESEED 2 /* Cannot seed pseudo random number generator */
|
||||
#define TLS_ECERT 3 /* Certificate check or verification failed */
|
||||
#define TLS_EIO 4 /* Input/output error */
|
||||
#define TLS_EFILE 5 /* A file does not exist/cannot be read */
|
||||
#define TLS_EHANDSHAKE 6 /* TLS handshake failed */
|
||||
|
||||
|
||||
/*
|
||||
* Always use tls_clear() before using a tls_t!
|
||||
* Never call a tls_*() function with tls_t NULL!
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
class TLSSocket
|
||||
{
|
||||
int have_trust_file;
|
||||
int is_active;
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
#ifdef HAVE_OPENSSL
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
} tls_t;
|
||||
private:
|
||||
bool m_bIsClient;
|
||||
char* m_szCertFile;
|
||||
char* m_szKeyFile;
|
||||
char* m_szCipher;
|
||||
SOCKET m_iSocket;
|
||||
bool m_bSuppressErrors;
|
||||
int m_iRetCode;
|
||||
bool m_bInitialized;
|
||||
bool m_bConnected;
|
||||
|
||||
/*
|
||||
* Information about a X509 certificate.
|
||||
* The 6 owner_info and issuer_info fields are:
|
||||
* Common Name
|
||||
* Organization
|
||||
* Organizational unit
|
||||
* Locality
|
||||
* State/Province
|
||||
* Country
|
||||
* Each of these entries may be NULL if it was not provided.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned char sha1_fingerprint[20];
|
||||
unsigned char md5_fingerprint[16];
|
||||
time_t activation_time;
|
||||
time_t expiration_time;
|
||||
char *owner_info[6];
|
||||
char *issuer_info[6];
|
||||
} tls_cert_info_t;
|
||||
// using "void*" to prevent the including of GnuTLS/OpenSSL header files into TLS.h
|
||||
void* m_pContext;
|
||||
void* m_pSession;
|
||||
|
||||
/*
|
||||
* tls_lib_init()
|
||||
*
|
||||
* Initialize underlying TLS library. If this function returns TLS_ELIBFAILED,
|
||||
* *errstr will always point to an error string.
|
||||
* Used error codes: TLS_ELIBFAILED
|
||||
*/
|
||||
int tls_lib_init(char **errstr);
|
||||
void ReportError(const char* szErrMsg);
|
||||
|
||||
/*
|
||||
* tls_clear()
|
||||
*
|
||||
* Clears a tls_t type (marks it inactive).
|
||||
*/
|
||||
void tls_clear(tls_t *tls);
|
||||
|
||||
/*
|
||||
* tls_init()
|
||||
*
|
||||
* Initializes a tls_t. If both 'key_file' and 'ca_file' are not NULL, they are
|
||||
* set to be used when the peer request a certificate. If 'trust_file' is not
|
||||
* NULL, it will be used to verify the peer certificate.
|
||||
* All files must be in PEM format.
|
||||
* If 'force_sslv3' is set, then only the SSLv3 protocol will be accepted. This
|
||||
* option might be needed to talk to some obsolete broken servers. Only use this
|
||||
* if you have to.
|
||||
* Used error codes: TLS_ELIBFAILED, TLS_EFILE
|
||||
*/
|
||||
int tls_init(tls_t *tls,
|
||||
const char *key_file, const char *ca_file, const char *trust_file,
|
||||
int force_sslv3, char **errstr);
|
||||
|
||||
/*
|
||||
* tls_start()
|
||||
*
|
||||
* Starts TLS encryption on a socket.
|
||||
* 'tls' must be initialized using tls_init().
|
||||
* If 'no_certcheck' is true, then no checks will be performed on the peer
|
||||
* certificate. If it is false and no trust file was set with tls_init(),
|
||||
* only sanity checks are performed on the peer certificate. If it is false
|
||||
* and a trust file was set, real verification of the peer certificate is
|
||||
* performed.
|
||||
* 'hostname' is the host to start TLS with. It is needed for sanity checks/
|
||||
* verification.
|
||||
* 'tci' must be allocated with tls_cert_info_new(). Information about the
|
||||
* peer's certificata will be stored in it. It can later be freed with
|
||||
* tls_cert_info_free(). 'tci' is allowed to be NULL; no certificate
|
||||
* information will be passed in this case.
|
||||
* Used error codes: TLS_ELIBFAILED, TLS_ECERT, TLS_EHANDSHAKE
|
||||
*/
|
||||
int tls_start(tls_t *tls, int fd, const char *hostname, int no_certcheck,
|
||||
tls_cert_info_t *tci, char **errstr);
|
||||
|
||||
/*
|
||||
* tls_is_active()
|
||||
*
|
||||
* Returns whether 'tls' is an active TLS connection.
|
||||
*/
|
||||
int tls_is_active(tls_t *tls);
|
||||
|
||||
/*
|
||||
* tls_cert_info_new()
|
||||
* Returns a new tls_cert_info_t
|
||||
*/
|
||||
tls_cert_info_t *tls_cert_info_new(void);
|
||||
|
||||
/*
|
||||
* tls_cert_info_free()
|
||||
* Frees a tls_cert_info_t
|
||||
*/
|
||||
void tls_cert_info_free(tls_cert_info_t *tci);
|
||||
|
||||
/*
|
||||
* tls_cert_info_get()
|
||||
*
|
||||
* Extracts certificate information from the TLS connection 'tls' and stores
|
||||
* it in 'tci'. See the description of tls_cert_info_t above.
|
||||
* Used error codes: TLS_ECERT
|
||||
*/
|
||||
int tls_cert_info_get(tls_t *tls, tls_cert_info_t *tci, char **errstr);
|
||||
|
||||
/*
|
||||
* tls_getbuf()
|
||||
*
|
||||
* Reads a buffer using TLS and stores it in 's'.
|
||||
* Used error codes: TLS_EIO
|
||||
*/
|
||||
int tls_getbuf(tls_t *tls, char* s, size_t len, size_t* readlen, char **errstr);
|
||||
|
||||
/*
|
||||
* tls_putbuf()
|
||||
*
|
||||
* Writes 'len' characters from the string 's' using TLS.
|
||||
* Used error codes: TLS_EIO
|
||||
*/
|
||||
int tls_putbuf(tls_t *tls, const char *s, size_t len, char **errstr);
|
||||
|
||||
/*
|
||||
* tls_close()
|
||||
*
|
||||
* Close a TLS connection and mark it inactive
|
||||
*/
|
||||
void tls_close(tls_t *tls);
|
||||
|
||||
/*
|
||||
* tls_lib_deinit()
|
||||
*
|
||||
* Deinit underlying TLS library.
|
||||
*/
|
||||
void tls_lib_deinit(void);
|
||||
public:
|
||||
TLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile, const char* szKeyFile, const char* szCipher);
|
||||
~TLSSocket();
|
||||
static void Init();
|
||||
static void Final();
|
||||
bool Start();
|
||||
void Close();
|
||||
int Send(const char* pBuffer, int iSize);
|
||||
int Recv(char* pBuffer, int iSize);
|
||||
void SetSuppressErrors(bool bSuppressErrors) { m_bSuppressErrors = bSuppressErrors; }
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
46
Thread.cpp
46
Thread.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -98,6 +98,48 @@ void Mutex::Unlock()
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_SPINLOCK
|
||||
SpinLock::SpinLock()
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_pSpinLockObj = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION));
|
||||
InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *)m_pSpinLockObj, 0x00FFFFFF);
|
||||
#else
|
||||
m_pSpinLockObj = (pthread_spinlock_t *)malloc(sizeof(pthread_spinlock_t));
|
||||
pthread_spin_init((pthread_spinlock_t *)m_pSpinLockObj, PTHREAD_PROCESS_PRIVATE);
|
||||
#endif
|
||||
}
|
||||
|
||||
SpinLock::~SpinLock()
|
||||
{
|
||||
#ifdef WIN32
|
||||
DeleteCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
|
||||
#else
|
||||
pthread_spin_destroy((pthread_spinlock_t *)m_pSpinLockObj);
|
||||
#endif
|
||||
free((void*)m_pSpinLockObj);
|
||||
}
|
||||
|
||||
void SpinLock::Lock()
|
||||
{
|
||||
#ifdef WIN32
|
||||
EnterCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
|
||||
#else
|
||||
pthread_spin_lock((pthread_spinlock_t *)m_pSpinLockObj);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpinLock::Unlock()
|
||||
{
|
||||
#ifdef WIN32
|
||||
LeaveCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
|
||||
#else
|
||||
pthread_spin_unlock((pthread_spinlock_t *)m_pSpinLockObj);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void Thread::Init()
|
||||
{
|
||||
debug("Initializing global thread data");
|
||||
|
||||
21
Thread.h
21
Thread.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -39,6 +39,23 @@ public:
|
||||
void Unlock();
|
||||
};
|
||||
|
||||
#ifdef HAVE_SPINLOCK
|
||||
class SpinLock
|
||||
{
|
||||
private:
|
||||
#ifdef WIN32
|
||||
void* m_pSpinLockObj;
|
||||
#else
|
||||
volatile void* m_pSpinLockObj;
|
||||
#endif
|
||||
|
||||
public:
|
||||
SpinLock();
|
||||
~SpinLock();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
};
|
||||
#endif
|
||||
|
||||
class Thread
|
||||
{
|
||||
|
||||
888
Unpack.cpp
Normal file
888
Unpack.cpp
Normal file
@@ -0,0 +1,888 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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 "Unpack.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "ParCoordinator.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern DownloadQueueHolder* g_pDownloadQueueHolder;
|
||||
|
||||
void UnpackController::FileList::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
bool UnpackController::FileList::Exists(const char* szFilename)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
char* szFilename1 = *it;
|
||||
if (!strcmp(szFilename1, szFilename))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UnpackController::~UnpackController()
|
||||
{
|
||||
m_archiveFiles.Clear();
|
||||
}
|
||||
|
||||
void UnpackController::StartJob(PostInfo* pPostInfo)
|
||||
{
|
||||
UnpackController* pUnpackController = new UnpackController();
|
||||
pUnpackController->m_pPostInfo = pPostInfo;
|
||||
pUnpackController->SetAutoDestroy(false);
|
||||
|
||||
pPostInfo->SetPostThread(pUnpackController);
|
||||
|
||||
pUnpackController->Start();
|
||||
}
|
||||
|
||||
void UnpackController::Run()
|
||||
{
|
||||
// the locking is needed for accessing the members of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
|
||||
strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
|
||||
m_szDestDir[1024-1] = '\0';
|
||||
|
||||
strncpy(m_szName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
|
||||
m_szName[1024-1] = '\0';
|
||||
|
||||
m_bCleanedUpDisk = false;
|
||||
bool bUnpack = true;
|
||||
m_szPassword[0] = '\0';
|
||||
m_szFinalDir[0] = '\0';
|
||||
|
||||
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:") && !strcasecmp(pParameter->GetValue(), "no"))
|
||||
{
|
||||
bUnpack = false;
|
||||
}
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:Password"))
|
||||
{
|
||||
strncpy(m_szPassword, pParameter->GetValue(), 1024-1);
|
||||
m_szPassword[1024-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
|
||||
snprintf(m_szInfoName, 1024, "unpack for %s", m_szName);
|
||||
m_szInfoName[1024-1] = '\0';
|
||||
|
||||
snprintf(m_szInfoNameUp, 1024, "Unpack for %s", m_szName); // first letter in upper case
|
||||
m_szInfoNameUp[1024-1] = '\0';
|
||||
|
||||
CheckStateFiles();
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && m_bHasBrokenFiles && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && m_bHasParFiles)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s has broken files", m_szName);
|
||||
RequestParCheck(false);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bUnpack)
|
||||
{
|
||||
bool bScanNonStdFiles = m_pPostInfo->GetNZBInfo()->GetRenameStatus() > NZBInfo::rsSkipped ||
|
||||
m_pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess ||
|
||||
!m_bHasParFiles;
|
||||
CheckArchiveFiles(bScanNonStdFiles);
|
||||
}
|
||||
|
||||
if (bUnpack && (m_bHasRarFiles || m_bHasNonStdRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles))
|
||||
{
|
||||
SetInfoName(m_szInfoName);
|
||||
SetWorkingDir(m_szDestDir);
|
||||
|
||||
PrintMessage(Message::mkInfo, "Unpacking %s", m_szName);
|
||||
|
||||
CreateUnpackDir();
|
||||
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
|
||||
if (m_bHasRarFiles || m_bHasNonStdRarFiles)
|
||||
{
|
||||
ExecuteUnrar();
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipFiles && m_bUnpackOK)
|
||||
{
|
||||
ExecuteSevenZip(false);
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipMultiFiles && m_bUnpackOK)
|
||||
{
|
||||
ExecuteSevenZip(true);
|
||||
}
|
||||
|
||||
Completed();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, (bUnpack ? "Nothing to unpack for %s" : "Unpack for %s skipped"), m_szName);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && m_bHasParFiles)
|
||||
{
|
||||
RequestParCheck(m_pPostInfo->GetNZBInfo()->GetRenameStatus() <= NZBInfo::rsSkipped);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteUnrar()
|
||||
{
|
||||
// Format:
|
||||
// unrar x -y -p- -o+ *.rar ./_unpack
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[8];
|
||||
szArgs[0] = g_pOptions->GetUnrarCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
szArgs[3] = szPasswordParam;
|
||||
}
|
||||
szArgs[4] = "-o+";
|
||||
szArgs[5] = m_bHasNonStdRarFiles ? "*.*" : "*.rar";
|
||||
szArgs[6] = m_szUnpackDir;
|
||||
szArgs[7] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetUnrarCmd());
|
||||
SetLogPrefix("Unrar");
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upUnrar;
|
||||
|
||||
SetProgressLabel("");
|
||||
int iExitCode = Execute();
|
||||
SetLogPrefix(NULL);
|
||||
SetProgressLabel("");
|
||||
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Unrar error code: %i", iExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
|
||||
{
|
||||
// Format:
|
||||
// 7z x -y -p- -o./_unpack *.7z
|
||||
// OR
|
||||
// 7z x -y -p- -o./_unpack *.7z.001
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[7];
|
||||
szArgs[0] = g_pOptions->GetSevenZipCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
szArgs[3] = szPasswordParam;
|
||||
}
|
||||
|
||||
char szUnpackDirParam[1024];
|
||||
snprintf(szUnpackDirParam, 1024, "-o%s", m_szUnpackDir);
|
||||
szArgs[4] = szUnpackDirParam;
|
||||
|
||||
szArgs[5] = bMultiVolumes ? "*.7z.001" : "*.7z";
|
||||
szArgs[6] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetSevenZipCmd());
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upSevenZip;
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing 7-Zip");
|
||||
SetLogPrefix("7-Zip");
|
||||
SetProgressLabel("");
|
||||
int iExitCode = Execute();
|
||||
SetLogPrefix(NULL);
|
||||
SetProgressLabel("");
|
||||
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "7-Zip error code: %i", iExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::Completed()
|
||||
{
|
||||
bool bCleanupSuccess = Cleanup();
|
||||
|
||||
if (m_bUnpackOK && bCleanupSuccess)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s %s", m_szInfoNameUp, "successful");
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSuccess);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackCleanedUpDisk(m_bCleanedUpDisk);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (!m_bUnpackOK && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && !m_bUnpackStartError && !GetTerminated() && m_bHasParFiles)
|
||||
{
|
||||
RequestParCheck(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usFailure);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void UnpackController::RequestParCheck(bool bRename)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s requested %s", m_szInfoNameUp, bRename ? "par-rename": "par-check/repair");
|
||||
if (bRename)
|
||||
{
|
||||
m_pPostInfo->SetRequestParRename(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPostInfo->SetRequestParCheck(true);
|
||||
}
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
#endif
|
||||
|
||||
void UnpackController::CheckStateFiles()
|
||||
{
|
||||
char szBrokenLog[1024];
|
||||
snprintf(szBrokenLog, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_brokenlog.txt");
|
||||
szBrokenLog[1024-1] = '\0';
|
||||
m_bHasBrokenFiles = Util::FileExists(szBrokenLog);
|
||||
|
||||
m_bHasParFiles = ParCoordinator::FindMainPars(m_szDestDir, NULL);
|
||||
}
|
||||
|
||||
void UnpackController::CreateUnpackDir()
|
||||
{
|
||||
m_bInterDir = strlen(g_pOptions->GetInterDir()) > 0 &&
|
||||
!strncmp(m_szDestDir, g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
|
||||
if (m_bInterDir)
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szFinalDir, 1024);
|
||||
m_szFinalDir[1024-1] = '\0';
|
||||
snprintf(m_szUnpackDir, 1024, "%s%c%s", m_szFinalDir, PATH_SEPARATOR, "_unpack");
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(m_szUnpackDir, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_unpack");
|
||||
}
|
||||
m_szUnpackDir[1024-1] = '\0';
|
||||
|
||||
char szErrBuf[1024];
|
||||
if (!Util::ForceDirectories(m_szUnpackDir, szErrBuf, sizeof(szErrBuf)))
|
||||
{
|
||||
error("Could not create directory %s: %s", m_szUnpackDir, szErrBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
|
||||
{
|
||||
m_bHasRarFiles = false;
|
||||
m_bHasNonStdRarFiles = false;
|
||||
m_bHasSevenZipFiles = false;
|
||||
m_bHasSevenZipMultiFiles = false;
|
||||
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExRarMultiSeq(".*\\.(r|s)[0-9][0-9]$");
|
||||
RegEx regExSevenZip(".*\\.7z$");
|
||||
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
if (regExRar.Match(filename))
|
||||
{
|
||||
m_bHasRarFiles = true;
|
||||
}
|
||||
else if (regExSevenZip.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipFiles = true;
|
||||
}
|
||||
else if (regExSevenZipMulti.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipMultiFiles = true;
|
||||
}
|
||||
else if (bScanNonStdFiles && !m_bHasNonStdRarFiles && !regExRarMultiSeq.Match(filename))
|
||||
{
|
||||
// Check if file has RAR signature
|
||||
char rarSignature[] = {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00};
|
||||
char fileSignature[7];
|
||||
|
||||
FILE* infile;
|
||||
infile = fopen(szFullFilename, "rb");
|
||||
if (infile)
|
||||
{
|
||||
int cnt = (int)fread(fileSignature, 1, sizeof(fileSignature), infile);
|
||||
fclose(infile);
|
||||
if (cnt == sizeof(fileSignature) && !strcmp(rarSignature, fileSignature))
|
||||
{
|
||||
m_bHasNonStdRarFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UnpackController::Cleanup()
|
||||
{
|
||||
// By success:
|
||||
// - move unpacked files to destination dir;
|
||||
// - remove _unpack-dir;
|
||||
// - delete archive-files.
|
||||
// By failure:
|
||||
// - remove _unpack-dir.
|
||||
|
||||
bool bOK = true;
|
||||
|
||||
FileList extractedFiles;
|
||||
|
||||
if (m_bUnpackOK)
|
||||
{
|
||||
// moving files back
|
||||
DirBrowser dir(m_szUnpackDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szUnpackDir, PATH_SEPARATOR, filename);
|
||||
szSrcFile[1024-1] = '\0';
|
||||
|
||||
char szDstFile[1024];
|
||||
snprintf(szDstFile, 1024, "%s%c%s", m_szFinalDir[0] != '\0' ? m_szFinalDir : m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szDstFile[1024-1] = '\0';
|
||||
|
||||
// silently overwrite existing files
|
||||
remove(szDstFile);
|
||||
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s", szSrcFile, szDstFile);
|
||||
bOK = false;
|
||||
}
|
||||
|
||||
extractedFiles.push_back(strdup(filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bOK && !Util::DeleteDirectoryWithContent(m_szUnpackDir))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not remove temporary directory %s", m_szUnpackDir);
|
||||
}
|
||||
|
||||
if (m_bUnpackOK && bOK && g_pOptions->GetUnpackCleanupDisk())
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting archive files");
|
||||
|
||||
// Delete rar-files (only files which were used by unrar)
|
||||
for (FileList::iterator it = m_archiveFiles.begin(); it != m_archiveFiles.end(); it++)
|
||||
{
|
||||
char* szFilename = *it;
|
||||
|
||||
if (m_bInterDir || !extractedFiles.Exists(szFilename))
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szFilename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", szFilename);
|
||||
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately 7-Zip doesn't print the processed archive-files to the output.
|
||||
// Therefore we don't know for sure which files were extracted.
|
||||
// We just delete all 7z-files in the directory.
|
||||
|
||||
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename)
|
||||
&& regExSevenZip.Match(filename) && (m_bInterDir || !extractedFiles.Exists(filename)))
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
|
||||
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bCleanedUpDisk = true;
|
||||
}
|
||||
|
||||
extractedFiles.Clear();
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unrar prints progress information into the same line using backspace control character.
|
||||
* In order to print progress continuously we analyze the output after every char
|
||||
* and update post-job progress information.
|
||||
*/
|
||||
bool UnpackController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
bool bPrinted = false;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < iBufSize - 1; i++)
|
||||
{
|
||||
int ch = fgetc(pStream);
|
||||
szBuf[i] = ch;
|
||||
szBuf[i+1] = '\0';
|
||||
if (ch == EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ch == '\n')
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
|
||||
char* szBackspace = strrchr(szBuf, '\b');
|
||||
if (szBackspace)
|
||||
{
|
||||
if (!bPrinted)
|
||||
{
|
||||
char tmp[1024];
|
||||
strncpy(tmp, szBuf, 1024);
|
||||
tmp[1024-1] = '\0';
|
||||
char* szTmpPercent = strrchr(tmp, '\b');
|
||||
if (szTmpPercent)
|
||||
{
|
||||
*szTmpPercent = '\0';
|
||||
}
|
||||
if (strncmp(szBuf, "...", 3))
|
||||
{
|
||||
ProcessOutput(tmp);
|
||||
}
|
||||
bPrinted = true;
|
||||
}
|
||||
if (strchr(szBackspace, '%'))
|
||||
{
|
||||
int iPercent = atoi(szBackspace + 1);
|
||||
m_pPostInfo->SetStageProgress(iPercent * 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
szBuf[i] = '\0';
|
||||
|
||||
if (bPrinted)
|
||||
{
|
||||
szBuf[0] = '\0';
|
||||
}
|
||||
|
||||
return i > 0;
|
||||
}
|
||||
|
||||
void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
char szMsgText[1024];
|
||||
strncpy(szMsgText, szText, 1024);
|
||||
szMsgText[1024-1] = '\0';
|
||||
|
||||
// Modify unrar messages for better readability:
|
||||
// remove the destination path part from message "Extracting file.xxx"
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: Extracting ", 19) &&
|
||||
!strncmp(szText + 19, m_szUnpackDir, strlen(m_szUnpackDir)))
|
||||
{
|
||||
snprintf(szMsgText, 1024, "Unrar: Extracting %s", szText + 19 + strlen(m_szUnpackDir) + 1);
|
||||
szMsgText[1024-1] = '\0';
|
||||
}
|
||||
|
||||
ScriptController::AddMessage(eKind, szMsgText);
|
||||
m_pPostInfo->AppendMessage(eKind, szMsgText);
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szMsgText, "Unrar: UNRAR ", 6) &&
|
||||
strstr(szMsgText, " Copyright ") && strstr(szMsgText, " Alexander Roshal"))
|
||||
{
|
||||
// reset start time for a case if user uses unpack-script to do some things
|
||||
// (like sending Wake-On-Lan message) before executing unrar
|
||||
m_pPostInfo->SetStageTime(time(NULL));
|
||||
}
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szMsgText, "Unrar: Extracting ", 18))
|
||||
{
|
||||
SetProgressLabel(szMsgText + 7);
|
||||
}
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: Extracting from ", 23))
|
||||
{
|
||||
const char *szFilename = szText + 23;
|
||||
debug("Filename: %s", szFilename);
|
||||
m_archiveFiles.push_back(strdup(szFilename));
|
||||
SetProgressLabel(szText + 7);
|
||||
}
|
||||
|
||||
if ((m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: All OK", 13)) ||
|
||||
(m_eUnpacker == upSevenZip && !strncmp(szText, "7-Zip: Everything is Ok", 23)))
|
||||
{
|
||||
m_bAllOKMessageReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::Stop()
|
||||
{
|
||||
debug("Stopping unpack");
|
||||
Thread::Stop();
|
||||
Terminate();
|
||||
}
|
||||
|
||||
void UnpackController::SetProgressLabel(const char* szProgressLabel)
|
||||
{
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
m_pPostInfo->SetProgressLabel(szProgressLabel);
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
|
||||
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';
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
|
||||
info("Moving completed files for %s", szNZBName);
|
||||
|
||||
bool bOK = MoveFiles();
|
||||
|
||||
szInfoName[0] = 'M'; // uppercase
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
info("%s successful", szInfoName);
|
||||
// save new dest dir
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir);
|
||||
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msSuccess);
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%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)))
|
||||
{
|
||||
error("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];
|
||||
snprintf(szDstFile, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szDstFile[1024-1] = '\0';
|
||||
|
||||
// prevent overwriting of existing files
|
||||
int dupcount = 0;
|
||||
while (Util::FileExists(szDstFile))
|
||||
{
|
||||
dupcount++;
|
||||
snprintf(szDstFile, 1024, "%s%c%s_duplicate%d", m_szDestDir, PATH_SEPARATOR, filename, dupcount);
|
||||
szDstFile[1024-1] = '\0';
|
||||
}
|
||||
|
||||
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s! Errcode: %i", szSrcFile, szDstFile, errno);
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Util::RemoveDirectory(m_szInterDir);
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
|
||||
info("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)
|
||||
{
|
||||
info("%s successful", szInfoName);
|
||||
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
|
||||
}
|
||||
else if (bOK)
|
||||
{
|
||||
info("Nothing to cleanup for %s", szNZBName);
|
||||
m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%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;
|
||||
|
||||
ExtList extList;
|
||||
|
||||
// split ExtCleanupDisk into tokens and create a list
|
||||
char* szExtCleanupDisk = strdup(g_pOptions->GetExtCleanupDisk());
|
||||
|
||||
char* saveptr;
|
||||
char* szExt = strtok_r(szExtCleanupDisk, ",; ", &saveptr);
|
||||
while (szExt)
|
||||
{
|
||||
extList.push_back(szExt);
|
||||
szExt = strtok_r(NULL, ",; ", &saveptr);
|
||||
}
|
||||
|
||||
DirBrowser dir(szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
// check file extension
|
||||
|
||||
int iFilenameLen = strlen(filename);
|
||||
bool bDeleteIt = false;
|
||||
for (ExtList::iterator it = extList.begin(); it != extList.end(); it++)
|
||||
{
|
||||
const char* szExt = *it;
|
||||
int iExtLen = strlen(szExt);
|
||||
if (iFilenameLen >= iExtLen && !strcasecmp(szExt, filename + iFilenameLen - iExtLen))
|
||||
{
|
||||
bDeleteIt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bDeleteIt)
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s! Errcode: %i", szFullFilename, errno);
|
||||
bOK = false;
|
||||
}
|
||||
|
||||
*bDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
free(szExtCleanupDisk);
|
||||
|
||||
return bOK;
|
||||
}
|
||||
129
Unpack.h
Normal file
129
Unpack.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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 UNPACK_H
|
||||
#define UNPACK_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "ScriptController.h"
|
||||
|
||||
class UnpackController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
enum EUnpacker
|
||||
{
|
||||
upUnrar,
|
||||
upSevenZip
|
||||
};
|
||||
|
||||
typedef std::deque<char*> FileListBase;
|
||||
class FileList : public FileListBase
|
||||
{
|
||||
public:
|
||||
void Clear();
|
||||
bool Exists(const char* szFilename);
|
||||
};
|
||||
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
char m_szName[1024];
|
||||
char m_szInfoName[1024];
|
||||
char m_szInfoNameUp[1024];
|
||||
char m_szDestDir[1024];
|
||||
char m_szFinalDir[1024];
|
||||
char m_szUnpackDir[1024];
|
||||
char m_szPassword[1024];
|
||||
bool m_bInterDir;
|
||||
bool m_bAllOKMessageReceived;
|
||||
bool m_bNoFilesMessageReceived;
|
||||
bool m_bHasParFiles;
|
||||
bool m_bHasBrokenFiles;
|
||||
bool m_bHasRarFiles;
|
||||
bool m_bHasNonStdRarFiles;
|
||||
bool m_bHasSevenZipFiles;
|
||||
bool m_bHasSevenZipMultiFiles;
|
||||
bool m_bUnpackOK;
|
||||
bool m_bUnpackStartError;
|
||||
bool m_bCleanedUpDisk;
|
||||
EUnpacker m_eUnpacker;
|
||||
FileList m_archiveFiles;
|
||||
|
||||
protected:
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
void ExecuteUnrar();
|
||||
void ExecuteSevenZip(bool bMultiVolumes);
|
||||
void Completed();
|
||||
void CreateUnpackDir();
|
||||
bool Cleanup();
|
||||
void CheckStateFiles();
|
||||
void CheckArchiveFiles(bool bScanNonStdFiles);
|
||||
void SetProgressLabel(const char* szProgressLabel);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RequestParCheck(bool bRename);
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual ~UnpackController();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
typedef std::deque<char*> ExtList;
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
static void StartJob(PostInfo* pPostInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
428
UrlCoordinator.cpp
Normal file
428
UrlCoordinator.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 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 <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "UrlCoordinator.h"
|
||||
#include "Options.h"
|
||||
#include "WebDownloader.h"
|
||||
#include "DiskState.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "NZBFile.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "Scanner.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern DiskState* g_pDiskState;
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern Scanner* g_pScanner;
|
||||
|
||||
|
||||
UrlDownloader::UrlDownloader() : WebDownloader()
|
||||
{
|
||||
m_szCategory = NULL;
|
||||
}
|
||||
|
||||
UrlDownloader::~UrlDownloader()
|
||||
{
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
}
|
||||
|
||||
void UrlDownloader::ProcessHeader(const char* szLine)
|
||||
{
|
||||
WebDownloader::ProcessHeader(szLine);
|
||||
|
||||
if (!strncmp(szLine, "X-DNZB-Category: ", 17))
|
||||
{
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
|
||||
const char *szCat = szLine + 17;
|
||||
|
||||
int iCatLen = strlen(szCat);
|
||||
|
||||
// trim trailing CR/LF/spaces
|
||||
while (iCatLen > 0 && (szCat[iCatLen-1] == '\n' || szCat[iCatLen-1] == '\r' || szCat[iCatLen-1] == ' ')) iCatLen--;
|
||||
|
||||
m_szCategory = (char*)malloc(iCatLen + 1);
|
||||
strncpy(m_szCategory, szCat, iCatLen);
|
||||
m_szCategory[iCatLen] = '\0';
|
||||
|
||||
debug("Category: %s", m_szCategory);
|
||||
}
|
||||
}
|
||||
|
||||
UrlCoordinator::UrlCoordinator()
|
||||
{
|
||||
debug("Creating UrlCoordinator");
|
||||
|
||||
m_bHasMoreJobs = true;
|
||||
}
|
||||
|
||||
UrlCoordinator::~UrlCoordinator()
|
||||
{
|
||||
debug("Destroying UrlCoordinator");
|
||||
// Cleanup
|
||||
|
||||
debug("Deleting UrlDownloaders");
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_ActiveDownloads.clear();
|
||||
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
pDownloadQueue->GetUrlQueue()->clear();
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
debug("UrlCoordinator destroyed");
|
||||
}
|
||||
|
||||
void UrlCoordinator::Run()
|
||||
{
|
||||
debug("Entering UrlCoordinator-loop");
|
||||
|
||||
int iResetCounter = 0;
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
// start download for next URL
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
if ((int)m_ActiveDownloads.size() < g_pOptions->GetUrlConnections())
|
||||
{
|
||||
UrlInfo* pUrlInfo;
|
||||
bool bHasMoreUrls = GetNextUrl(pDownloadQueue, pUrlInfo);
|
||||
bool bUrlDownloadsRunning = !m_ActiveDownloads.empty();
|
||||
m_bHasMoreJobs = bHasMoreUrls || bUrlDownloadsRunning;
|
||||
if (bHasMoreUrls && !IsStopped())
|
||||
{
|
||||
StartUrlDownload(pUrlInfo);
|
||||
}
|
||||
}
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
int iSleepInterval = 100;
|
||||
usleep(iSleepInterval * 1000);
|
||||
|
||||
iResetCounter += iSleepInterval;
|
||||
if (iResetCounter >= 1000)
|
||||
{
|
||||
// this code should not be called too often, once per second is OK
|
||||
ResetHangingDownloads();
|
||||
iResetCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// waiting for downloads
|
||||
debug("UrlCoordinator: waiting for Downloads to complete");
|
||||
bool completed = false;
|
||||
while (!completed)
|
||||
{
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
completed = m_ActiveDownloads.size() == 0;
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
usleep(100 * 1000);
|
||||
ResetHangingDownloads();
|
||||
}
|
||||
debug("UrlCoordinator: Downloads are completed");
|
||||
|
||||
debug("Exiting UrlCoordinator-loop");
|
||||
}
|
||||
|
||||
void UrlCoordinator::Stop()
|
||||
{
|
||||
Thread::Stop();
|
||||
|
||||
debug("Stopping UrlDownloads");
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
(*it)->Stop();
|
||||
}
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
debug("UrlDownloads are notified");
|
||||
}
|
||||
|
||||
void UrlCoordinator::ResetHangingDownloads()
|
||||
{
|
||||
const int TimeOut = g_pOptions->GetTerminateTimeout();
|
||||
if (TimeOut == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
time_t tm = ::time(NULL);
|
||||
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
|
||||
{
|
||||
UrlDownloader* pUrlDownloader = *it;
|
||||
if (tm - pUrlDownloader->GetLastUpdateTime() > TimeOut &&
|
||||
pUrlDownloader->GetStatus() == UrlDownloader::adRunning)
|
||||
{
|
||||
UrlInfo* pUrlInfo = pUrlDownloader->GetUrlInfo();
|
||||
debug("Terminating hanging download %s", pUrlDownloader->GetInfoName());
|
||||
if (pUrlDownloader->Terminate())
|
||||
{
|
||||
error("Terminated hanging download %s", pUrlDownloader->GetInfoName());
|
||||
pUrlInfo->SetStatus(UrlInfo::aiUndefined);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not terminate hanging download %s", pUrlDownloader->GetInfoName());
|
||||
}
|
||||
m_ActiveDownloads.erase(it);
|
||||
// it's not safe to destroy pUrlDownloader, because the state of object is unknown
|
||||
delete pUrlDownloader;
|
||||
it = m_ActiveDownloads.begin();
|
||||
continue;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
void UrlCoordinator::LogDebugInfo()
|
||||
{
|
||||
debug(" UrlCoordinator");
|
||||
debug(" ----------------");
|
||||
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
debug(" Active Downloads: %i", m_ActiveDownloads.size());
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
UrlDownloader* pUrlDownloader = *it;
|
||||
pUrlDownloader->LogDebugInfo();
|
||||
}
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
void UrlCoordinator::AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst)
|
||||
{
|
||||
debug("Adding NZB-URL to queue");
|
||||
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
pDownloadQueue->GetUrlQueue()->push_back(pUrlInfo);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns next URL for download.
|
||||
*/
|
||||
bool UrlCoordinator::GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo)
|
||||
{
|
||||
bool bOK = false;
|
||||
|
||||
for (UrlQueue::iterator at = pDownloadQueue->GetUrlQueue()->begin(); at != pDownloadQueue->GetUrlQueue()->end(); at++)
|
||||
{
|
||||
pUrlInfo = *at;
|
||||
if (pUrlInfo->GetStatus() == 0)
|
||||
{
|
||||
bOK = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
|
||||
{
|
||||
debug("Starting new UrlDownloader");
|
||||
|
||||
UrlDownloader* pUrlDownloader = new UrlDownloader();
|
||||
pUrlDownloader->SetAutoDestroy(true);
|
||||
pUrlDownloader->Attach(this);
|
||||
pUrlDownloader->SetUrlInfo(pUrlInfo);
|
||||
pUrlDownloader->SetURL(pUrlInfo->GetURL());
|
||||
|
||||
char tmp[1024];
|
||||
|
||||
pUrlInfo->GetName(tmp, 1024);
|
||||
pUrlDownloader->SetInfoName(tmp);
|
||||
|
||||
snprintf(tmp, 1024, "%surl-%i.tmp", g_pOptions->GetTempDir(), pUrlInfo->GetID());
|
||||
tmp[1024-1] = '\0';
|
||||
pUrlDownloader->SetOutputFilename(tmp);
|
||||
|
||||
pUrlInfo->SetStatus(UrlInfo::aiRunning);
|
||||
|
||||
m_ActiveDownloads.push_back(pUrlDownloader);
|
||||
pUrlDownloader->Start();
|
||||
}
|
||||
|
||||
void UrlCoordinator::Update(Subject* Caller, void* Aspect)
|
||||
{
|
||||
debug("Notification from UrlDownloader received");
|
||||
|
||||
UrlDownloader* pUrlDownloader = (UrlDownloader*) Caller;
|
||||
if ((pUrlDownloader->GetStatus() == WebDownloader::adFinished) ||
|
||||
(pUrlDownloader->GetStatus() == WebDownloader::adFailed) ||
|
||||
(pUrlDownloader->GetStatus() == WebDownloader::adRetry))
|
||||
{
|
||||
UrlCompleted(pUrlDownloader);
|
||||
}
|
||||
}
|
||||
|
||||
void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
{
|
||||
debug("URL downloaded");
|
||||
|
||||
UrlInfo* pUrlInfo = pUrlDownloader->GetUrlInfo();
|
||||
|
||||
if (pUrlDownloader->GetStatus() == WebDownloader::adFinished)
|
||||
{
|
||||
pUrlInfo->SetStatus(UrlInfo::aiFinished);
|
||||
}
|
||||
else if (pUrlDownloader->GetStatus() == WebDownloader::adFailed)
|
||||
{
|
||||
pUrlInfo->SetStatus(UrlInfo::aiFailed);
|
||||
}
|
||||
else if (pUrlDownloader->GetStatus() == WebDownloader::adRetry)
|
||||
{
|
||||
pUrlInfo->SetStatus(UrlInfo::aiUndefined);
|
||||
}
|
||||
|
||||
char filename[1024];
|
||||
if (pUrlDownloader->GetOriginalFilename())
|
||||
{
|
||||
strncpy(filename, pUrlDownloader->GetOriginalFilename(), 1024);
|
||||
filename[1024-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(filename, Util::BaseFileName(pUrlInfo->GetURL()), 1024);
|
||||
filename[1024-1] = '\0';
|
||||
|
||||
// TODO: decode URL escaping
|
||||
}
|
||||
|
||||
Util::MakeValidFilename(filename, '_', false);
|
||||
|
||||
debug("Filename: [%s]", filename);
|
||||
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
// delete Download from Queue
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
UrlDownloader* pa = *it;
|
||||
if (pa == pUrlDownloader)
|
||||
{
|
||||
m_ActiveDownloads.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool bDeleteObj = false;
|
||||
|
||||
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished || pUrlInfo->GetStatus() == UrlInfo::aiFailed)
|
||||
{
|
||||
// delete UrlInfo from Queue
|
||||
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
|
||||
{
|
||||
UrlInfo* pa = *it;
|
||||
if (pa == pUrlInfo)
|
||||
{
|
||||
pDownloadQueue->GetUrlQueue()->erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bDeleteObj = true;
|
||||
|
||||
if (g_pOptions->GetKeepHistory() > 0 && pUrlInfo->GetStatus() == UrlInfo::aiFailed)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = new HistoryInfo(pUrlInfo);
|
||||
pHistoryInfo->SetTime(time(NULL));
|
||||
pDownloadQueue->GetHistoryList()->push_front(pHistoryInfo);
|
||||
bDeleteObj = false;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished)
|
||||
{
|
||||
// add nzb-file to download queue
|
||||
AddToNZBQueue(pUrlInfo, pUrlDownloader->GetOutputFilename(), filename, pUrlDownloader->GetCategory());
|
||||
}
|
||||
|
||||
if (bDeleteObj)
|
||||
{
|
||||
delete pUrlInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void UrlCoordinator::AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory)
|
||||
{
|
||||
g_pScanner->AddExternalFile(
|
||||
pUrlInfo->GetNZBFilename() && strlen(pUrlInfo->GetNZBFilename()) > 0 ? pUrlInfo->GetNZBFilename() : szOriginalFilename,
|
||||
strlen(pUrlInfo->GetCategory()) > 0 ? pUrlInfo->GetCategory() : szOriginalCategory,
|
||||
pUrlInfo->GetPriority(), NULL, pUrlInfo->GetAddTop(), pUrlInfo->GetAddPaused(), szTempFilename, NULL, 0, false);
|
||||
}
|
||||
86
UrlCoordinator.h
Normal file
86
UrlCoordinator.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef URLCOORDINATOR_H
|
||||
#define URLCOORDINATOR_H
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <time.h>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "WebDownloader.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Observer.h"
|
||||
|
||||
class UrlDownloader;
|
||||
|
||||
class UrlCoordinator : public Thread, public Observer, public Subject
|
||||
{
|
||||
public:
|
||||
typedef std::list<UrlDownloader*> ActiveDownloads;
|
||||
|
||||
private:
|
||||
ActiveDownloads m_ActiveDownloads;
|
||||
bool m_bHasMoreJobs;
|
||||
|
||||
bool GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo);
|
||||
void StartUrlDownload(UrlInfo* pUrlInfo);
|
||||
void UrlCompleted(UrlDownloader* pUrlDownloader);
|
||||
void ResetHangingDownloads();
|
||||
void AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory);
|
||||
|
||||
public:
|
||||
UrlCoordinator();
|
||||
virtual ~UrlCoordinator();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
void Update(Subject* Caller, void* Aspect);
|
||||
|
||||
// Editing the queue
|
||||
void AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst);
|
||||
bool HasMoreJobs() { return m_bHasMoreJobs; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
class UrlDownloader : public WebDownloader
|
||||
{
|
||||
private:
|
||||
UrlInfo* m_pUrlInfo;
|
||||
char* m_szCategory;
|
||||
|
||||
protected:
|
||||
virtual void ProcessHeader(const char* szLine);
|
||||
|
||||
public:
|
||||
UrlDownloader();
|
||||
~UrlDownloader();
|
||||
void SetUrlInfo(UrlInfo* pUrlInfo) { m_pUrlInfo = pUrlInfo; }
|
||||
UrlInfo* GetUrlInfo() { return m_pUrlInfo; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
};
|
||||
|
||||
#endif
|
||||
161
Util.h
161
Util.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -57,6 +57,19 @@ public:
|
||||
const char* Next();
|
||||
};
|
||||
|
||||
class StringBuilder
|
||||
{
|
||||
private:
|
||||
char* m_szBuffer;
|
||||
int m_iBufferSize;
|
||||
int m_iUsedSize;
|
||||
public:
|
||||
StringBuilder();
|
||||
~StringBuilder();
|
||||
void Append(const char* szStr);
|
||||
const char* GetBuffer() { return m_szBuffer; }
|
||||
};
|
||||
|
||||
class Util
|
||||
{
|
||||
public:
|
||||
@@ -64,22 +77,30 @@ public:
|
||||
static char* BaseFileName(const char* filename);
|
||||
static void NormalizePathSeparators(char* szPath);
|
||||
static bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength);
|
||||
static bool SetFileSize(const char* szFilename, int iSize);
|
||||
static bool SaveBufferIntoFile(const char* szFileName, const char* szBuffer, int iBufLen);
|
||||
static bool CreateSparseFile(const char* szFilename, int iSize);
|
||||
static bool TruncateFile(const char* szFilename, int iSize);
|
||||
static void MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSlashes);
|
||||
static bool MoveFile(const char* szSrcFilename, const char* szDstFilename);
|
||||
static bool FileExists(const char* szFilename);
|
||||
static bool DirectoryExists(const char* szDirFilename);
|
||||
static bool CreateDirectory(const char* szDirFilename);
|
||||
static bool ForceDirectories(const char* szPath);
|
||||
static bool RemoveDirectory(const char* szDirFilename);
|
||||
static bool DeleteDirectoryWithContent(const char* szDirFilename);
|
||||
static bool ForceDirectories(const char* szPath, char* szErrBuf, int iBufSize);
|
||||
static bool GetCurrentDirectory(char* szBuffer, int iBufSize);
|
||||
static bool SetCurrentDirectory(const char* szDirFilename);
|
||||
static long long FileSize(const char* szFilename);
|
||||
static long long FreeDiskSize(const char* szPath);
|
||||
static bool DirEmpty(const char* szDirFilename);
|
||||
static bool RenameBak(const char* szFilename, const char* szBakPart, bool bRemoveOldExtension, char* szNewNameBuf, int iNewNameBufSize);
|
||||
#ifndef WIN32
|
||||
static bool ExpandHomePath(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
#endif
|
||||
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
static void FormatFileSize(char* szBuffer, int iBufLen, long long lFileSize);
|
||||
static bool SameFilename(const char* szFilename1, const char* szFilename2);
|
||||
static char* GetLastErrorMessage(char* szBuffer, int iBufLen);
|
||||
|
||||
/*
|
||||
* Split command line int arguments.
|
||||
@@ -105,6 +126,33 @@ public:
|
||||
*/
|
||||
static float Int64ToFloat(long long Int64);
|
||||
|
||||
static void TrimRight(char* szStr);
|
||||
|
||||
static char* Trim(char* szStr);
|
||||
|
||||
#ifdef WIN32
|
||||
static bool RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName, char* szBuffer, int* iBufLen);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns program version and revision number as string formatted like "0.7.0-r295".
|
||||
* If revision number is not available only version is returned ("0.7.0").
|
||||
*/
|
||||
static const char* VersionRevision() { return VersionRevisionBuf; };
|
||||
|
||||
/*
|
||||
* Initialize buffer for program version and revision number.
|
||||
* This function must be called during program initialization before any
|
||||
* call to "VersionRevision()".
|
||||
*/
|
||||
static void InitVersionRevision();
|
||||
|
||||
static char VersionRevisionBuf[40];
|
||||
};
|
||||
|
||||
class WebUtil
|
||||
{
|
||||
public:
|
||||
static unsigned int DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer);
|
||||
|
||||
/*
|
||||
@@ -155,19 +203,98 @@ public:
|
||||
static const char* JsonNextValue(const char* szJsonText, int* pValueLength);
|
||||
|
||||
/*
|
||||
* Returns program version and revision number as string formatted like "0.7.0-r295".
|
||||
* If revision number is not available only version is returned ("0.7.0").
|
||||
* Unquote http quoted string.
|
||||
* The string is decoded on the place overwriting the content of raw-data.
|
||||
*/
|
||||
static const char* VersionRevision() { return VersionRevisionBuf; };
|
||||
|
||||
/*
|
||||
* Initialize buffer for program version and revision number.
|
||||
* This function must be called during program initialization before any
|
||||
* call to "VersionRevision()".
|
||||
*/
|
||||
static void InitVersionRevision();
|
||||
|
||||
static char VersionRevisionBuf[40];
|
||||
static void HttpUnquote(char* raw);
|
||||
};
|
||||
|
||||
class URL
|
||||
{
|
||||
private:
|
||||
char* m_szAddress;
|
||||
char* m_szProtocol;
|
||||
char* m_szUser;
|
||||
char* m_szPassword;
|
||||
char* m_szHost;
|
||||
char* m_szResource;
|
||||
int m_iPort;
|
||||
bool m_bTLS;
|
||||
bool m_bValid;
|
||||
void ParseURL();
|
||||
|
||||
public:
|
||||
URL(const char* szAddress);
|
||||
~URL();
|
||||
bool IsValid() { return m_bValid; }
|
||||
const char* GetAddress() { return m_szAddress; }
|
||||
const char* GetProtocol() { return m_szProtocol; }
|
||||
const char* GetUser() { return m_szUser; }
|
||||
const char* GetPassword() { return m_szPassword; }
|
||||
const char* GetHost() { return m_szHost; }
|
||||
const char* GetResource() { return m_szResource; }
|
||||
int GetPort() { return m_iPort; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
};
|
||||
|
||||
class RegEx
|
||||
{
|
||||
private:
|
||||
void* m_pContext;
|
||||
bool m_bValid;
|
||||
|
||||
public:
|
||||
RegEx(const char *szPattern);
|
||||
~RegEx();
|
||||
bool IsValid() { return m_bValid; }
|
||||
bool Match(const char *szStr);
|
||||
};
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
class ZLib
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* calculates the size required for output buffer
|
||||
*/
|
||||
static unsigned int GZipLen(int iInputBufferLength);
|
||||
|
||||
/*
|
||||
* returns the size of bytes written to szOutputBuffer or 0 if the buffer is too small or an error occured.
|
||||
*/
|
||||
static unsigned int GZip(const void* szInputBuffer, int iInputBufferLength, void* szOutputBuffer, int iOutputBufferLength);
|
||||
};
|
||||
|
||||
class GUnzipStream
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
zlError,
|
||||
zlFinished,
|
||||
zlOK
|
||||
};
|
||||
|
||||
private:
|
||||
void* m_pZStream;
|
||||
void* m_pOutputBuffer;
|
||||
int m_iBufferSize;
|
||||
|
||||
public:
|
||||
GUnzipStream(int BufferSize);
|
||||
~GUnzipStream();
|
||||
|
||||
/*
|
||||
* set next memory block for uncompression
|
||||
*/
|
||||
void Write(const void *pInputBuffer, int iInputBufferLength);
|
||||
|
||||
/*
|
||||
* get next uncompressed memory block.
|
||||
* iOutputBufferLength - the size of uncompressed block. if it is "0" the next compressed block must be provided via "Write".
|
||||
*/
|
||||
EStatus Read(const void **pOutputBuffer, int *iOutputBufferLength);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
679
WebDownloader.cpp
Normal file
679
WebDownloader.cpp
Normal file
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 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>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "WebDownloader.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
WebDownloader::WebDownloader()
|
||||
{
|
||||
debug("Creating WebDownloader");
|
||||
|
||||
m_szURL = NULL;
|
||||
m_szOutputFilename = NULL;
|
||||
m_pConnection = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_bConfirmedLength = false;
|
||||
m_eStatus = adUndefined;
|
||||
m_szOriginalFilename = NULL;
|
||||
SetLastUpdateTimeNow();
|
||||
}
|
||||
|
||||
WebDownloader::~WebDownloader()
|
||||
{
|
||||
debug("Destroying WebDownloader");
|
||||
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
if (m_szOriginalFilename)
|
||||
{
|
||||
free(m_szOriginalFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void WebDownloader::SetOutputFilename(const char* v)
|
||||
{
|
||||
m_szOutputFilename = strdup(v);
|
||||
}
|
||||
|
||||
void WebDownloader::SetInfoName(const char* v)
|
||||
{
|
||||
m_szInfoName = strdup(v);
|
||||
}
|
||||
|
||||
void WebDownloader::SetURL(const char * szURL)
|
||||
{
|
||||
m_szURL = strdup(szURL);
|
||||
}
|
||||
|
||||
void WebDownloader::SetStatus(EStatus eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
Notify(NULL);
|
||||
}
|
||||
|
||||
void WebDownloader::Run()
|
||||
{
|
||||
debug("Entering WebDownloader-loop");
|
||||
|
||||
SetStatus(adRunning);
|
||||
|
||||
int iRemainedDownloadRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
|
||||
int iRemainedConnectRetries = iRemainedDownloadRetries > 10 ? iRemainedDownloadRetries : 10;
|
||||
|
||||
EStatus Status = adFailed;
|
||||
|
||||
while (!IsStopped() && iRemainedDownloadRetries > 0 && iRemainedConnectRetries > 0)
|
||||
{
|
||||
SetLastUpdateTimeNow();
|
||||
|
||||
Status = Download();
|
||||
|
||||
if ((((Status == adFailed) && (iRemainedDownloadRetries > 1)) ||
|
||||
((Status == adConnectError) && (iRemainedConnectRetries > 1)))
|
||||
&& !IsStopped() && !(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
int msec = 0;
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Status == adFinished || Status == adFatalError || Status == adNotFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Status != adConnectError)
|
||||
{
|
||||
iRemainedDownloadRetries--;
|
||||
}
|
||||
else
|
||||
{
|
||||
iRemainedConnectRetries--;
|
||||
}
|
||||
}
|
||||
|
||||
if (Status != adFinished && Status != adRetry)
|
||||
{
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (Status == adFailed)
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Download %s failed", m_szInfoName);
|
||||
}
|
||||
}
|
||||
|
||||
if (Status == adFinished)
|
||||
{
|
||||
detail("Download %s completed", m_szInfoName);
|
||||
}
|
||||
|
||||
SetStatus(Status);
|
||||
|
||||
debug("Exiting WebDownloader-loop");
|
||||
}
|
||||
|
||||
WebDownloader::EStatus WebDownloader::Download()
|
||||
{
|
||||
EStatus Status = adRunning;
|
||||
|
||||
URL url(m_szURL);
|
||||
|
||||
Status = CreateConnection(&url);
|
||||
if (Status != adRunning)
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
m_pConnection->SetSuppressErrors(false);
|
||||
|
||||
// connection
|
||||
bool bConnected = m_pConnection->Connect();
|
||||
if (!bConnected || IsStopped())
|
||||
{
|
||||
FreeConnection();
|
||||
return adConnectError;
|
||||
}
|
||||
|
||||
// Okay, we got a Connection. Now start downloading.
|
||||
detail("Downloading %s", m_szInfoName);
|
||||
|
||||
SendHeaders(&url);
|
||||
|
||||
Status = DownloadHeaders();
|
||||
|
||||
if (Status == adRunning)
|
||||
{
|
||||
Status = DownloadBody();
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
FreeConnection();
|
||||
|
||||
if (Status != adFinished)
|
||||
{
|
||||
// Download failed, delete broken output file
|
||||
remove(m_szOutputFilename);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
WebDownloader::EStatus WebDownloader::CreateConnection(URL *pUrl)
|
||||
{
|
||||
if (!pUrl->IsValid())
|
||||
{
|
||||
error("URL is not valid: %s", pUrl->GetAddress());
|
||||
return adFatalError;
|
||||
}
|
||||
|
||||
int iPort = pUrl->GetPort();
|
||||
if (iPort == 0 && !strcasecmp(pUrl->GetProtocol(), "http"))
|
||||
{
|
||||
iPort = 80;
|
||||
}
|
||||
if (iPort == 0 && !strcasecmp(pUrl->GetProtocol(), "https"))
|
||||
{
|
||||
iPort = 443;
|
||||
}
|
||||
|
||||
if (strcasecmp(pUrl->GetProtocol(), "http") && strcasecmp(pUrl->GetProtocol(), "https"))
|
||||
{
|
||||
error("Unsupported protocol in URL: %s", pUrl->GetAddress());
|
||||
return adFatalError;
|
||||
}
|
||||
|
||||
#ifdef DISABLE_TLS
|
||||
if (!strcasecmp(pUrl->GetProtocol(), "https"))
|
||||
{
|
||||
error("Program was compiled without TLS/SSL-support. Cannot download using https protocol. URL: %s", pUrl->GetAddress());
|
||||
return adFatalError;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool bTLS = !strcasecmp(pUrl->GetProtocol(), "https");
|
||||
|
||||
m_pConnection = new Connection(pUrl->GetHost(), iPort, bTLS);
|
||||
|
||||
return adRunning;
|
||||
}
|
||||
|
||||
void WebDownloader::SendHeaders(URL *pUrl)
|
||||
{
|
||||
char tmp[1024];
|
||||
|
||||
// retrieve file
|
||||
snprintf(tmp, 1024, "GET %s HTTP/1.0\r\n", pUrl->GetResource());
|
||||
tmp[1024-1] = '\0';
|
||||
m_pConnection->WriteLine(tmp);
|
||||
|
||||
snprintf(tmp, 1024, "User-Agent: nzbget/%s\r\n", Util::VersionRevision());
|
||||
tmp[1024-1] = '\0';
|
||||
m_pConnection->WriteLine(tmp);
|
||||
|
||||
snprintf(tmp, 1024, "Host: %s\r\n", pUrl->GetHost());
|
||||
tmp[1024-1] = '\0';
|
||||
m_pConnection->WriteLine(tmp);
|
||||
|
||||
m_pConnection->WriteLine("Accept: */*\r\n");
|
||||
#ifndef DISABLE_GZIP
|
||||
m_pConnection->WriteLine("Accept-Encoding: gzip\r\n");
|
||||
#endif
|
||||
m_pConnection->WriteLine("Connection: close\r\n");
|
||||
m_pConnection->WriteLine("\r\n");
|
||||
}
|
||||
|
||||
WebDownloader::EStatus WebDownloader::DownloadHeaders()
|
||||
{
|
||||
EStatus Status = adRunning;
|
||||
|
||||
m_bConfirmedLength = false;
|
||||
const int LineBufSize = 1024*10;
|
||||
char* szLineBuf = (char*)malloc(LineBufSize);
|
||||
m_iContentLen = -1;
|
||||
bool bFirstLine = true;
|
||||
m_bGZip = false;
|
||||
|
||||
// Headers
|
||||
while (!IsStopped())
|
||||
{
|
||||
SetLastUpdateTimeNow();
|
||||
|
||||
int iLen = 0;
|
||||
char* line = m_pConnection->ReadLine(szLineBuf, LineBufSize, &iLen);
|
||||
|
||||
if (bFirstLine)
|
||||
{
|
||||
Status = CheckResponse(szLineBuf);
|
||||
if (Status != adRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bFirstLine = false;
|
||||
}
|
||||
|
||||
// Have we encountered a timeout?
|
||||
if (!line)
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("URL %s failed: Unexpected end of file", m_szInfoName);
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
debug("Header: %s", line);
|
||||
|
||||
// detect body of response
|
||||
if (*line == '\r' || *line == '\n')
|
||||
{
|
||||
if (m_iContentLen == -1 && !m_bGZip)
|
||||
{
|
||||
warn("URL %s: Content-Length is not submitted by server, cannot verify whether the file is complete", m_szInfoName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ProcessHeader(line);
|
||||
}
|
||||
|
||||
free(szLineBuf);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
WebDownloader::EStatus WebDownloader::DownloadBody()
|
||||
{
|
||||
EStatus Status = adRunning;
|
||||
|
||||
m_pOutFile = NULL;
|
||||
bool bEnd = false;
|
||||
const int LineBufSize = 1024*10;
|
||||
char* szLineBuf = (char*)malloc(LineBufSize);
|
||||
int iWrittenLen = 0;
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
m_pGUnzipStream = NULL;
|
||||
if (m_bGZip)
|
||||
{
|
||||
m_pGUnzipStream = new GUnzipStream(1024*10);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Body
|
||||
while (!IsStopped())
|
||||
{
|
||||
SetLastUpdateTimeNow();
|
||||
|
||||
char* szBuffer;
|
||||
int iLen;
|
||||
m_pConnection->ReadBuffer(&szBuffer, &iLen);
|
||||
if (iLen == 0)
|
||||
{
|
||||
iLen = m_pConnection->TryRecv(szLineBuf, LineBufSize);
|
||||
szBuffer = szLineBuf;
|
||||
}
|
||||
|
||||
// Have we encountered a timeout?
|
||||
if (iLen <= 0)
|
||||
{
|
||||
if (m_iContentLen == -1)
|
||||
{
|
||||
bEnd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("URL %s failed: Unexpected end of file", m_szInfoName);
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
// write to output file
|
||||
if (!Write(szBuffer, iLen))
|
||||
{
|
||||
Status = adFatalError;
|
||||
break;
|
||||
}
|
||||
iWrittenLen += iLen;
|
||||
|
||||
//detect end of file
|
||||
if (iWrittenLen == m_iContentLen || (m_iContentLen == -1 && m_bGZip && m_bConfirmedLength))
|
||||
{
|
||||
bEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(szLineBuf);
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
if (m_pGUnzipStream)
|
||||
{
|
||||
delete m_pGUnzipStream;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_pOutFile)
|
||||
{
|
||||
fclose(m_pOutFile);
|
||||
}
|
||||
|
||||
if (!bEnd && Status == adRunning && !IsStopped())
|
||||
{
|
||||
warn("URL %s failed: file incomplete", m_szInfoName);
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (bEnd)
|
||||
{
|
||||
Status = adFinished;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
WebDownloader::EStatus WebDownloader::CheckResponse(const char* szResponse)
|
||||
{
|
||||
if (!szResponse)
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("URL %s: Connection closed by remote host", m_szInfoName);
|
||||
}
|
||||
return adConnectError;
|
||||
}
|
||||
|
||||
const char* szHTTPResponse = strchr(szResponse, ' ');
|
||||
if (strncmp(szResponse, "HTTP", 4) || !szHTTPResponse)
|
||||
{
|
||||
warn("URL %s failed: %s", m_szInfoName, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
|
||||
szHTTPResponse++;
|
||||
|
||||
if (!strncmp(szHTTPResponse, "400", 3) || !strncmp(szHTTPResponse, "499", 3))
|
||||
{
|
||||
warn("URL %s failed: %s", m_szInfoName, szHTTPResponse);
|
||||
return adConnectError;
|
||||
}
|
||||
else if (!strncmp(szHTTPResponse, "404", 3))
|
||||
{
|
||||
warn("URL %s failed: %s", m_szInfoName, szHTTPResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szHTTPResponse, "200", 3))
|
||||
{
|
||||
// OK
|
||||
return adRunning;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown error, no special handling
|
||||
warn("URL %s failed: %s", m_szInfoName, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
|
||||
void WebDownloader::ProcessHeader(const char* szLine)
|
||||
{
|
||||
if (!strncmp(szLine, "Content-Length: ", 16))
|
||||
{
|
||||
m_iContentLen = atoi(szLine + 16);
|
||||
m_bConfirmedLength = true;
|
||||
}
|
||||
|
||||
if (!strncmp(szLine, "Content-Encoding: gzip", 22))
|
||||
{
|
||||
m_bGZip = true;
|
||||
}
|
||||
|
||||
if (!strncmp(szLine, "Content-Disposition: ", 21))
|
||||
{
|
||||
ParseFilename(szLine);
|
||||
}
|
||||
}
|
||||
|
||||
void WebDownloader::ParseFilename(const char* szContentDisposition)
|
||||
{
|
||||
// Examples:
|
||||
// Content-Disposition: attachment; filename="fname.ext"
|
||||
// Content-Disposition: attachement;filename=fname.ext
|
||||
// Content-Disposition: attachement;filename=fname.ext;
|
||||
const char *p = strstr(szContentDisposition, "filename");
|
||||
if (!p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p = strchr(p, '=');
|
||||
if (!p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
while (*p == ' ') p++;
|
||||
|
||||
char fname[1024];
|
||||
strncpy(fname, p, 1024);
|
||||
fname[1024-1] = '\0';
|
||||
|
||||
char *pe = fname + strlen(fname) - 1;
|
||||
while ((*pe == ' ' || *pe == '\n' || *pe == '\r' || *pe == ';') && pe > fname) {
|
||||
*pe = '\0';
|
||||
pe--;
|
||||
}
|
||||
|
||||
WebUtil::HttpUnquote(fname);
|
||||
|
||||
if (m_szOriginalFilename)
|
||||
{
|
||||
free(m_szOriginalFilename);
|
||||
}
|
||||
m_szOriginalFilename = strdup(Util::BaseFileName(fname));
|
||||
|
||||
debug("OriginalFilename: %s", m_szOriginalFilename);
|
||||
}
|
||||
|
||||
bool WebDownloader::Write(void* pBuffer, int iLen)
|
||||
{
|
||||
if (!m_pOutFile && !PrepareFile())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
if (m_bGZip)
|
||||
{
|
||||
m_pGUnzipStream->Write(pBuffer, iLen);
|
||||
const void *pOutBuf;
|
||||
int iOutLen = 1;
|
||||
while (iOutLen > 0)
|
||||
{
|
||||
GUnzipStream::EStatus eGZStatus = m_pGUnzipStream->Read(&pOutBuf, &iOutLen);
|
||||
|
||||
if (eGZStatus == GUnzipStream::zlError)
|
||||
{
|
||||
error("URL %s: GUnzip failed", m_szInfoName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iOutLen > 0 && fwrite(pOutBuf, 1, iOutLen, m_pOutFile) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (eGZStatus == GUnzipStream::zlFinished)
|
||||
{
|
||||
m_bConfirmedLength = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
return fwrite(pBuffer, 1, iLen, m_pOutFile) > 0;
|
||||
}
|
||||
|
||||
bool WebDownloader::PrepareFile()
|
||||
{
|
||||
// prepare file for writing
|
||||
|
||||
const char* szFilename = m_szOutputFilename;
|
||||
m_pOutFile = fopen(szFilename, "wb");
|
||||
if (!m_pOutFile)
|
||||
{
|
||||
error("Could not %s file %s", "create", szFilename);
|
||||
return false;
|
||||
}
|
||||
if (g_pOptions->GetWriteBufferSize() > 0)
|
||||
{
|
||||
setvbuf(m_pOutFile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebDownloader::LogDebugInfo()
|
||||
{
|
||||
char szTime[50];
|
||||
#ifdef HAVE_CTIME_R_3
|
||||
ctime_r(&m_tLastUpdateTime, szTime, 50);
|
||||
#else
|
||||
ctime_r(&m_tLastUpdateTime, szTime);
|
||||
#endif
|
||||
|
||||
debug(" Web-Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(m_szOutputFilename));
|
||||
}
|
||||
|
||||
void WebDownloader::Stop()
|
||||
{
|
||||
debug("Trying to stop WebDownloader");
|
||||
Thread::Stop();
|
||||
m_mutexConnection.Lock();
|
||||
if (m_pConnection)
|
||||
{
|
||||
m_pConnection->SetSuppressErrors(true);
|
||||
m_pConnection->Cancel();
|
||||
}
|
||||
m_mutexConnection.Unlock();
|
||||
debug("WebDownloader stopped successfully");
|
||||
}
|
||||
|
||||
bool WebDownloader::Terminate()
|
||||
{
|
||||
Connection* pConnection = m_pConnection;
|
||||
bool terminated = Kill();
|
||||
if (terminated && pConnection)
|
||||
{
|
||||
debug("Terminating connection");
|
||||
pConnection->SetSuppressErrors(true);
|
||||
pConnection->Cancel();
|
||||
pConnection->Disconnect();
|
||||
delete pConnection;
|
||||
}
|
||||
return terminated;
|
||||
}
|
||||
|
||||
void WebDownloader::FreeConnection()
|
||||
{
|
||||
if (m_pConnection)
|
||||
{
|
||||
debug("Releasing connection");
|
||||
m_mutexConnection.Lock();
|
||||
if (m_pConnection->GetStatus() == Connection::csCancelled)
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
}
|
||||
delete m_pConnection;
|
||||
m_pConnection = NULL;
|
||||
m_mutexConnection.Unlock();
|
||||
}
|
||||
}
|
||||
103
WebDownloader.h
Normal file
103
WebDownloader.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WEBDOWNLOADER_H
|
||||
#define WEBDOWNLOADER_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "Observer.h"
|
||||
#include "Thread.h"
|
||||
#include "Connection.h"
|
||||
#include "Util.h"
|
||||
|
||||
class WebDownloader : public Thread, public Subject
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
adUndefined,
|
||||
adRunning,
|
||||
adFinished,
|
||||
adFailed,
|
||||
adRetry,
|
||||
adNotFound,
|
||||
adConnectError,
|
||||
adFatalError
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szURL;
|
||||
char* m_szOutputFilename;
|
||||
Connection* m_pConnection;
|
||||
Mutex m_mutexConnection;
|
||||
EStatus m_eStatus;
|
||||
time_t m_tLastUpdateTime;
|
||||
char* m_szInfoName;
|
||||
FILE* m_pOutFile;
|
||||
int m_iContentLen;
|
||||
bool m_bConfirmedLength;
|
||||
char* m_szOriginalFilename;
|
||||
bool m_bGZip;
|
||||
#ifndef DISABLE_GZIP
|
||||
GUnzipStream* m_pGUnzipStream;
|
||||
#endif
|
||||
|
||||
void SetStatus(EStatus eStatus);
|
||||
bool Write(void* pBuffer, int iLen);
|
||||
bool PrepareFile();
|
||||
void FreeConnection();
|
||||
EStatus CheckResponse(const char* szResponse);
|
||||
EStatus Download();
|
||||
EStatus CreateConnection(URL *pUrl);
|
||||
void ParseFilename(const char* szContentDisposition);
|
||||
void SendHeaders(URL *pUrl);
|
||||
EStatus DownloadHeaders();
|
||||
EStatus DownloadBody();
|
||||
|
||||
protected:
|
||||
virtual void ProcessHeader(const char* szLine);
|
||||
|
||||
public:
|
||||
WebDownloader();
|
||||
~WebDownloader();
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
bool Terminate();
|
||||
void SetInfoName(const char* v);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetURL(const char* szURL);
|
||||
const char* GetOutputFilename() { return m_szOutputFilename; }
|
||||
void SetOutputFilename(const char* v);
|
||||
time_t GetLastUpdateTime() { return m_tLastUpdateTime; }
|
||||
void SetLastUpdateTimeNow() { m_tLastUpdateTime = ::time(NULL); }
|
||||
bool GetConfirmedLength() { return m_bConfirmedLength; }
|
||||
const char* GetOriginalFilename() { return m_szOriginalFilename; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
#endif
|
||||
485
WebServer.cpp
Normal file
485
WebServer.cpp
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 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>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "WebServer.h"
|
||||
#include "XmlRpc.h"
|
||||
#include "Log.h"
|
||||
#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;
|
||||
|
||||
//*****************************************************************
|
||||
// WebProcessor
|
||||
|
||||
WebProcessor::WebProcessor()
|
||||
{
|
||||
m_pConnection = NULL;
|
||||
m_szRequest = NULL;
|
||||
m_szUrl = NULL;
|
||||
m_szOrigin = NULL;
|
||||
}
|
||||
|
||||
WebProcessor::~WebProcessor()
|
||||
{
|
||||
if (m_szRequest)
|
||||
{
|
||||
free(m_szRequest);
|
||||
}
|
||||
if (m_szUrl)
|
||||
{
|
||||
free(m_szUrl);
|
||||
}
|
||||
if (m_szOrigin)
|
||||
{
|
||||
free(m_szOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
void WebProcessor::SetUrl(const char* szUrl)
|
||||
{
|
||||
m_szUrl = strdup(szUrl);
|
||||
}
|
||||
|
||||
void WebProcessor::Execute()
|
||||
{
|
||||
m_bGZip =false;
|
||||
char szAuthInfo[1024];
|
||||
szAuthInfo[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;
|
||||
}
|
||||
}
|
||||
|
||||
debug("URL=%s", m_szUrl);
|
||||
debug("Authorization=%s", szAuthInfo);
|
||||
|
||||
if (m_eHttpMethod == hmPost && iContentLen <= 0)
|
||||
{
|
||||
error("Invalid-request: content length is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_eHttpMethod == hmOptions)
|
||||
{
|
||||
SendOptionsResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
char* sz_OldUrl = m_szUrl;
|
||||
m_szUrl = strdup(m_szUrl + 7);
|
||||
free(sz_OldUrl);
|
||||
}
|
||||
// http://localhost:6789/nzbget -> http://localhost:6789
|
||||
if (!strcmp(m_szUrl, "/nzbget"))
|
||||
{
|
||||
char szRedirectURL[1024];
|
||||
snprintf(szRedirectURL, 1024, "%s/", m_szUrl);
|
||||
szRedirectURL[1024-1] = '\0';
|
||||
SendRedirectResponse(szRedirectURL);
|
||||
return;
|
||||
}
|
||||
|
||||
// authorization via URL in format:
|
||||
// http://localhost:6789/username:password/jsonrpc
|
||||
char* pauth1 = strchr(m_szUrl + 1, ':');
|
||||
char* pauth2 = strchr(m_szUrl + 1, '/');
|
||||
if (pauth1 && pauth1 < pauth2)
|
||||
{
|
||||
char* pstart = m_szUrl + 1;
|
||||
int iLen = 0;
|
||||
char* pend = strchr(pstart + 1, '/');
|
||||
if (pend)
|
||||
{
|
||||
iLen = (int)(pend - pstart < (int)sizeof(szAuthInfo) - 1 ? pend - pstart : (int)sizeof(szAuthInfo) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
iLen = strlen(pstart);
|
||||
}
|
||||
strncpy(szAuthInfo, pstart, iLen);
|
||||
szAuthInfo[iLen] = '\0';
|
||||
char* sz_OldUrl = m_szUrl;
|
||||
m_szUrl = strdup(pend);
|
||||
free(sz_OldUrl);
|
||||
}
|
||||
|
||||
debug("Final URL=%s", m_szUrl);
|
||||
|
||||
if (strlen(g_pOptions->GetControlPassword()) > 0)
|
||||
{
|
||||
if (strlen(szAuthInfo) == 0)
|
||||
{
|
||||
SendAuthResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
// Authorization
|
||||
char* pw = strchr(szAuthInfo, ':');
|
||||
if (pw) *pw++ = '\0';
|
||||
if ((strlen(g_pOptions->GetControlUsername()) > 0 && strcmp(szAuthInfo, g_pOptions->GetControlUsername())) ||
|
||||
strcmp(pw, g_pOptions->GetControlPassword()))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void WebProcessor::Dispatch()
|
||||
{
|
||||
if (*m_szUrl != '/')
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (XmlRpcProcessor::IsRpcRequest(m_szUrl))
|
||||
{
|
||||
XmlRpcProcessor processor;
|
||||
processor.SetRequest(m_szRequest);
|
||||
processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost);
|
||||
processor.SetUrl(m_szUrl);
|
||||
processor.Execute();
|
||||
SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pOptions->GetWebDir() || strlen(g_pOptions->GetWebDir()) == 0)
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_eHttpMethod != hmGet)
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
// for security reasons we allow only characters "0..9 A..Z a..z . - _ /" in the URLs
|
||||
// we also don't allow ".." in the URLs
|
||||
for (char *p = m_szUrl; *p; p++)
|
||||
{
|
||||
if (!((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
|
||||
*p == '.' || *p == '-' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.'))
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *szDefRes = "";
|
||||
if (m_szUrl[strlen(m_szUrl)-1] == '/')
|
||||
{
|
||||
// default file in directory (if not specified) is "index.html"
|
||||
szDefRes = "index.html";
|
||||
}
|
||||
|
||||
char disk_filename[1024];
|
||||
snprintf(disk_filename, sizeof(disk_filename), "%s%s%s", g_pOptions->GetWebDir(), m_szUrl + 1, szDefRes);
|
||||
|
||||
disk_filename[sizeof(disk_filename)-1] = '\0';
|
||||
|
||||
SendFileResponse(disk_filename);
|
||||
}
|
||||
|
||||
void WebProcessor::SendAuthResponse()
|
||||
{
|
||||
const char* AUTH_RESPONSE_HEADER =
|
||||
"HTTP/1.0 401 Unauthorized\r\n"
|
||||
"WWW-Authenticate: Basic realm=\"NZBGet\"\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Server: nzbget-%s\r\n"
|
||||
"\r\n";
|
||||
char szResponseHeader[1024];
|
||||
snprintf(szResponseHeader, 1024, AUTH_RESPONSE_HEADER, Util::VersionRevision());
|
||||
|
||||
// Send the response answer
|
||||
debug("ResponseHeader=%s", szResponseHeader);
|
||||
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
|
||||
}
|
||||
|
||||
void WebProcessor::SendOptionsResponse()
|
||||
{
|
||||
const char* OPTIONS_RESPONSE_HEADER =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Connection: close\r\n"
|
||||
//"Content-Type: plain/text\r\n"
|
||||
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
|
||||
"Access-Control-Allow-Origin: %s\r\n"
|
||||
"Access-Control-Allow-Credentials: true\r\n"
|
||||
"Access-Control-Max-Age: 86400\r\n"
|
||||
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
|
||||
"Server: nzbget-%s\r\n"
|
||||
"\r\n";
|
||||
char szResponseHeader[1024];
|
||||
snprintf(szResponseHeader, 1024, OPTIONS_RESPONSE_HEADER,
|
||||
m_szOrigin ? m_szOrigin : "",
|
||||
Util::VersionRevision());
|
||||
|
||||
// Send the response answer
|
||||
debug("ResponseHeader=%s", szResponseHeader);
|
||||
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
|
||||
}
|
||||
|
||||
void WebProcessor::SendErrorResponse(const char* szErrCode)
|
||||
{
|
||||
const char* RESPONSE_HEADER =
|
||||
"HTTP/1.0 %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %i\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Server: nzbget-%s\r\n"
|
||||
"\r\n";
|
||||
|
||||
warn("Web-Server: %s, Resource: %s", szErrCode, m_szUrl);
|
||||
|
||||
char szResponseBody[1024];
|
||||
snprintf(szResponseBody, 1024, "<html><head><title>%s</title></head><body>Error: %s</body></html>", szErrCode, szErrCode);
|
||||
int iPageContentLen = strlen(szResponseBody);
|
||||
|
||||
char szResponseHeader[1024];
|
||||
snprintf(szResponseHeader, 1024, RESPONSE_HEADER, szErrCode, iPageContentLen, Util::VersionRevision());
|
||||
|
||||
// Send the response answer
|
||||
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
|
||||
m_pConnection->Send(szResponseBody, iPageContentLen);
|
||||
}
|
||||
|
||||
void WebProcessor::SendRedirectResponse(const char* szURL)
|
||||
{
|
||||
const char* REDIRECT_RESPONSE_HEADER =
|
||||
"HTTP/1.0 301 Moved Permanently\r\n"
|
||||
"Location: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Server: nzbget-%s\r\n"
|
||||
"\r\n";
|
||||
char szResponseHeader[1024];
|
||||
snprintf(szResponseHeader, 1024, REDIRECT_RESPONSE_HEADER, szURL, Util::VersionRevision());
|
||||
|
||||
// Send the response answer
|
||||
debug("ResponseHeader=%s", szResponseHeader);
|
||||
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
|
||||
}
|
||||
|
||||
void WebProcessor::SendBodyResponse(const char* szBody, int iBodyLen, const char* szContentType)
|
||||
{
|
||||
const char* RESPONSE_HEADER =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
|
||||
"Access-Control-Allow-Origin: %s\r\n"
|
||||
"Access-Control-Allow-Credentials: true\r\n"
|
||||
"Access-Control-Max-Age: 86400\r\n"
|
||||
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
|
||||
"Content-Length: %i\r\n"
|
||||
"%s" // Content-Type: xxx
|
||||
"%s" // Content-Encoding: gzip
|
||||
"Server: nzbget-%s\r\n"
|
||||
"\r\n";
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
char *szGBuf = NULL;
|
||||
bool bGZip = m_bGZip && iBodyLen > MAX_UNCOMPRESSED_SIZE;
|
||||
if (bGZip)
|
||||
{
|
||||
unsigned int iOutLen = ZLib::GZipLen(iBodyLen);
|
||||
szGBuf = (char*)malloc(iOutLen);
|
||||
int iGZippedLen = ZLib::GZip(szBody, iBodyLen, szGBuf, iOutLen);
|
||||
if (iGZippedLen > 0 && iGZippedLen < iBodyLen)
|
||||
{
|
||||
szBody = szGBuf;
|
||||
iBodyLen = iGZippedLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(szGBuf);
|
||||
szGBuf = NULL;
|
||||
bGZip = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
bool bGZip = false;
|
||||
#endif
|
||||
|
||||
char szContentTypeHeader[1024];
|
||||
if (szContentType)
|
||||
{
|
||||
snprintf(szContentTypeHeader, 1024, "Content-Type: %s\r\n", szContentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
szContentTypeHeader[0] = '\0';
|
||||
}
|
||||
|
||||
char szResponseHeader[1024];
|
||||
snprintf(szResponseHeader, 1024, RESPONSE_HEADER,
|
||||
m_szOrigin ? m_szOrigin : "",
|
||||
iBodyLen, szContentTypeHeader,
|
||||
bGZip ? "Content-Encoding: gzip\r\n" : "",
|
||||
Util::VersionRevision());
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
|
||||
m_pConnection->Send(szBody, iBodyLen);
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
if (szGBuf)
|
||||
{
|
||||
free(szGBuf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebProcessor::SendFileResponse(const char* szFilename)
|
||||
{
|
||||
debug("serving file: %s", szFilename);
|
||||
|
||||
char *szBody;
|
||||
int iBodyLen;
|
||||
if (!Util::LoadFileIntoBuffer(szFilename, &szBody, &iBodyLen))
|
||||
{
|
||||
SendErrorResponse(ERR_HTTP_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
// "LoadFileIntoBuffer" adds a trailing NULL, which we don't need here
|
||||
iBodyLen--;
|
||||
|
||||
SendBodyResponse(szBody, iBodyLen, DetectContentType(szFilename));
|
||||
|
||||
free(szBody);
|
||||
}
|
||||
|
||||
const char* WebProcessor::DetectContentType(const char* szFilename)
|
||||
{
|
||||
if (const char *szExt = strrchr(szFilename, '.'))
|
||||
{
|
||||
if (!strcasecmp(szExt, ".css"))
|
||||
{
|
||||
return "text/css";
|
||||
}
|
||||
else if (!strcasecmp(szExt, ".html"))
|
||||
{
|
||||
return "text/html";
|
||||
}
|
||||
else if (!strcasecmp(szExt, ".js"))
|
||||
{
|
||||
return "application/javascript";
|
||||
}
|
||||
else if (!strcasecmp(szExt, ".png"))
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
else if (!strcasecmp(szExt, ".jpeg"))
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
else if (!strcasecmp(szExt, ".gif"))
|
||||
{
|
||||
return "image/gif";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
67
WebServer.h
Normal file
67
WebServer.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WEBSERVER_H
|
||||
#define WEBSERVER_H
|
||||
|
||||
#include "Connection.h"
|
||||
|
||||
class WebProcessor
|
||||
{
|
||||
public:
|
||||
enum EHttpMethod
|
||||
{
|
||||
hmPost,
|
||||
hmGet,
|
||||
hmOptions
|
||||
};
|
||||
|
||||
private:
|
||||
Connection* m_pConnection;
|
||||
char* m_szRequest;
|
||||
char* m_szUrl;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
bool m_bGZip;
|
||||
char* m_szOrigin;
|
||||
|
||||
void Dispatch();
|
||||
void SendAuthResponse();
|
||||
void SendOptionsResponse();
|
||||
void SendErrorResponse(const char* szErrCode);
|
||||
void SendFileResponse(const char* szFilename);
|
||||
void SendBodyResponse(const char* szBody, int iBodyLen, const char* szContentType);
|
||||
void SendRedirectResponse(const char* szURL);
|
||||
const char* DetectContentType(const char* szFilename);
|
||||
|
||||
public:
|
||||
WebProcessor();
|
||||
~WebProcessor();
|
||||
void Execute();
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetUrl(const char* szUrl);
|
||||
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
};
|
||||
|
||||
#endif
|
||||
1165
XmlRpc.cpp
1165
XmlRpc.cpp
File diff suppressed because it is too large
Load Diff
89
XmlRpc.h
89
XmlRpc.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -27,19 +27,7 @@
|
||||
#define XMLRPC_H
|
||||
|
||||
#include "Connection.h"
|
||||
|
||||
class StringBuilder
|
||||
{
|
||||
private:
|
||||
char* m_szBuffer;
|
||||
int m_iBufferSize;
|
||||
int m_iUsedSize;
|
||||
public:
|
||||
StringBuilder();
|
||||
~StringBuilder();
|
||||
void Append(const char* szStr);
|
||||
const char* GetBuffer() { return m_szBuffer; }
|
||||
};
|
||||
#include "Util.h"
|
||||
|
||||
class XmlCommand;
|
||||
|
||||
@@ -61,28 +49,28 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
Connection* m_pConnection;
|
||||
const char* m_szClientIP;
|
||||
char* m_szRequest;
|
||||
const char* m_szContentType;
|
||||
ERpcProtocol m_eProtocol;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
char* m_szUrl;
|
||||
StringBuilder m_cResponse;
|
||||
|
||||
void Dispatch();
|
||||
void SendAuthResponse();
|
||||
void SendResponse(const char* szResponse, const char* szCallbackFunc, bool bFault);
|
||||
XmlCommand* CreateCommand(const char* szMethodName);
|
||||
void MutliCall();
|
||||
void BuildResponse(const char* szResponse, const char* szCallbackFunc, bool bFault);
|
||||
|
||||
public:
|
||||
XmlRpcProcessor();
|
||||
~XmlRpcProcessor();
|
||||
void Execute();
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetProtocol(ERpcProtocol eProtocol) { m_eProtocol = eProtocol; }
|
||||
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
void SetUrl(const char* szUrl);
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
void SetRequest(char* szRequest) { m_szRequest = szRequest; }
|
||||
const char* GetResponse() { return m_cResponse.GetBuffer(); }
|
||||
const char* GetContentType() { return m_szContentType; }
|
||||
static bool IsRpcRequest(const char* szUrl);
|
||||
};
|
||||
|
||||
class XmlCommand
|
||||
@@ -96,7 +84,7 @@ protected:
|
||||
XmlRpcProcessor::ERpcProtocol m_eProtocol;
|
||||
XmlRpcProcessor::EHttpMethod m_eHttpMethod;
|
||||
|
||||
void BuildErrorResponse(int iErrCode, const char* szErrText);
|
||||
void BuildErrorResponse(int iErrCode, const char* szErrText, ...);
|
||||
void BuildBoolResponse(bool bOK);
|
||||
void AppendResponse(const char* szPart);
|
||||
bool IsJson();
|
||||
@@ -106,6 +94,7 @@ protected:
|
||||
bool NextParamAsStr(char** szValueBuf);
|
||||
const char* BoolToStr(bool bValue);
|
||||
char* EncodeStr(const char* szStr);
|
||||
void DecodeStr(char* szStr);
|
||||
|
||||
public:
|
||||
XmlCommand();
|
||||
@@ -151,12 +140,24 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScheduleResumeXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ReloadXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
@@ -223,6 +224,12 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ClearLogXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScanXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
@@ -235,4 +242,40 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DownloadUrlXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UrlQueueXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LoadConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SaveConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ConfigTemplatesXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
22
config.h.in
22
config.h.in
@@ -6,6 +6,9 @@
|
||||
/* Define to 1 to not use curses */
|
||||
#undef DISABLE_CURSES
|
||||
|
||||
/* Define to 1 to disable gzip-support */
|
||||
#undef DISABLE_GZIP
|
||||
|
||||
/* Define to 1 to disable smart par-verification and restoration */
|
||||
#undef DISABLE_PARCHECK
|
||||
|
||||
@@ -64,11 +67,17 @@
|
||||
/* Define to 1 to use OpenSSL library for TLS/SSL-support. */
|
||||
#undef HAVE_OPENSSL
|
||||
|
||||
/* Define to 1 if libpar2 has recent bugfixes-patch (version 2) */
|
||||
#undef HAVE_PAR2_BUGFIXES_V2
|
||||
|
||||
/* Define to 1 if libpar2 supports cancelling (needs a special patch) */
|
||||
#undef HAVE_PAR2_CANCEL
|
||||
|
||||
/* Define to 1 if stat64 is supported */
|
||||
#undef HAVE_STAT64
|
||||
/* Define to 1 if you have the <regex.h> header file. */
|
||||
#undef HAVE_REGEX_H
|
||||
|
||||
/* Define to 1 if spinlocks are supported */
|
||||
#undef HAVE_SPINLOCK
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
@@ -115,6 +124,9 @@
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 to install an empty signal handler for SIGCHLD */
|
||||
#undef SIGCHLD_HANDLER
|
||||
|
||||
/* Determine what socket length (socklen_t) data type is */
|
||||
#undef SOCKLEN_T
|
||||
|
||||
@@ -123,3 +135,9 @@
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
159
configure.ac
159
configure.ac
@@ -2,34 +2,18 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 0.7.0, hugbug@users.sourceforge.net)
|
||||
AM_INIT_AUTOMAKE(nzbget, 0.7.0)
|
||||
AC_INIT(nzbget, 11.0, hugbug@users.sourceforge.net)
|
||||
AC_CANONICAL_SYSTEM
|
||||
AM_INIT_AUTOMAKE(nzbget, 11.0)
|
||||
AC_CONFIG_SRCDIR([nzbget.cpp])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
|
||||
|
||||
dnl
|
||||
dnl Architecture check.
|
||||
dnl
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
|
||||
dnl
|
||||
dnl Set default library path, if not specified in environment variable "LIBPREF".
|
||||
dnl
|
||||
if test "$LIBPREF" = ""; then
|
||||
case "$host" in
|
||||
*-linux*)
|
||||
LIBPREF="/usr"
|
||||
;;
|
||||
*-freebsd*)
|
||||
LIBPREF="/usr/local"
|
||||
;;
|
||||
*-solaris*)
|
||||
LIBPREF="/usr"
|
||||
;;
|
||||
esac
|
||||
LIBPREF="/usr"
|
||||
fi
|
||||
|
||||
|
||||
@@ -52,6 +36,7 @@ dnl
|
||||
dnl Checks for header files.
|
||||
dnl
|
||||
AC_CHECK_HEADERS(sys/prctl.h)
|
||||
AC_CHECK_HEADERS(regex.h)
|
||||
|
||||
|
||||
dnl
|
||||
@@ -71,10 +56,9 @@ AC_CHECK_FUNC(getopt_long,
|
||||
|
||||
|
||||
dnl
|
||||
dnl stat64
|
||||
dnl use 64-Bits for file sizes
|
||||
dnl
|
||||
AC_CHECK_FUNC(stat64,
|
||||
[AC_DEFINE([HAVE_STAT64], 1, [Define to 1 if stat64 is supported])],)
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
|
||||
dnl
|
||||
@@ -158,6 +142,14 @@ if test "$FOUND" = "no"; then
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl cCheck 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
|
||||
@@ -194,7 +186,6 @@ dnl
|
||||
AC_ARG_WITH(libxml2_includes,
|
||||
[AS_HELP_STRING([--with-libxml2-includes=DIR], [libxml2 include directory])],
|
||||
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
|
||||
[CFLAGS="${CFLAGS} -I${withval}"]
|
||||
[INCVAL="yes"],
|
||||
[INCVAL="no"])
|
||||
AC_ARG_WITH(libxml2_libraries,
|
||||
@@ -204,9 +195,8 @@ AC_ARG_WITH(libxml2_libraries,
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES(libxml2, libxml-2.0,
|
||||
[LDFLAGS="${LDFLAGS} $libxml2_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"]
|
||||
[CFLAGS="${CFLAGS} $libxml2_CFLAGS"])
|
||||
[LIBS="${LIBS} $libxml2_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"])
|
||||
fi
|
||||
AC_CHECK_HEADER(libxml/tree.h,,
|
||||
AC_MSG_ERROR("libxml2 header files not found"))
|
||||
@@ -230,7 +220,6 @@ if test "$USECURSES" = "yes"; then
|
||||
[AS_HELP_STRING([--with-libcurses-includes=DIR], [libcurses include directory])],
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
AC_ARG_WITH(libcurses_libraries,
|
||||
[AS_HELP_STRING([--with-libcurses-libraries=DIR], [libcurses library directory])],
|
||||
[LIBVAL="$withval"])
|
||||
@@ -290,7 +279,7 @@ if test "$ENABLEPARCHECK" = "yes"; then
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES(libsigc, sigc++-2.0,
|
||||
[LDFLAGS="${LDFLAGS} $libsigc_LIBS"]
|
||||
[LIBS="${LIBS} $libsigc_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libsigc_CFLAGS"])
|
||||
fi
|
||||
|
||||
@@ -345,6 +334,32 @@ if test "$ENABLEPARCHECK" = "yes"; then
|
||||
AC_MSG_RESULT([[yes]])
|
||||
AC_DEFINE([HAVE_PAR2_CANCEL], 1, [Define to 1 if libpar2 supports cancelling (needs a special patch)]),
|
||||
AC_MSG_RESULT([[no]]))
|
||||
|
||||
dnl
|
||||
dnl check if libpar2 has recent bugfixes-patch
|
||||
dnl
|
||||
AC_MSG_CHECKING(whether libpar2 has recent bugfixes-patch (version 2))
|
||||
AC_TRY_COMPILE(
|
||||
[#include <libpar2/par2cmdline.h>]
|
||||
[#include <libpar2/par2repairer.h>]
|
||||
[ class Repairer : public Par2Repairer { void test() { BugfixesPatchVersion2(); } }; ],
|
||||
[],
|
||||
AC_MSG_RESULT([[yes]])
|
||||
PAR2PATCHV2=yes
|
||||
AC_DEFINE([HAVE_PAR2_BUGFIXES_V2], 1, [Define to 1 if libpar2 has recent bugfixes-patch (version 2)]),
|
||||
AC_MSG_RESULT([[no]])
|
||||
PAR2PATCHV2=no)
|
||||
|
||||
if test "$PAR2PATCHV2" = "no" ; then
|
||||
AC_ARG_ENABLE(libpar2-bugfixes-check,
|
||||
[AS_HELP_STRING([--disable-libpar2-bugfixes-check], [do not check if libpar2 has recent bugfixes-patch applied])],
|
||||
[ PAR2PATCHCHECK=$enableval ],
|
||||
[ PAR2PATCHCHECK=yes] )
|
||||
if test "$PAR2PATCHCHECK" = "yes"; then
|
||||
AC_ERROR([Your version of libpar2 doesn't include the recent bugfixes-patch (version 2, updated Dec 3, 2012). Please patch libpar2 with the patches supplied with NZBGet (see README for details). If you cannot patch libpar2, you can use configure parameter --disable-libpar2-bugfixes-check to suppress the check. Please note however that in this case the program may crash during par-check/repair. The patch is highly recommended!])
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
AC_DEFINE([DISABLE_PARCHECK],1,[Define to 1 to disable smart par-verification and restoration])
|
||||
fi
|
||||
@@ -374,12 +389,11 @@ if test "$USETLS" = "yes"; then
|
||||
[AS_HELP_STRING([--with-libgnutls-includes=DIR], [GnuTLS include directory])],
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
AC_ARG_WITH(libgnutls_libraries,
|
||||
[AS_HELP_STRING([--with-libgnutls-libraries=DIR], [GnuTLS library directory])],
|
||||
[LIBVAL="$withval"])
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
|
||||
AC_CHECK_HEADER(gnutls/gnutls.h,
|
||||
FOUND=yes
|
||||
TLSHEADERS=yes,
|
||||
@@ -404,18 +418,22 @@ if test "$USETLS" = "yes"; then
|
||||
fi
|
||||
|
||||
if test "$TLSLIB" = "OpenSSL" -o "$TLSLIB" = ""; then
|
||||
INCVAL="${LIBPREF}/include"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
AC_ARG_WITH(openssl_includes,
|
||||
[AS_HELP_STRING([--with-openssl-includes=DIR], [OpenSSL include directory])],
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
|
||||
[INCVAL="yes"],
|
||||
[INCVAL="no"])
|
||||
AC_ARG_WITH(openssl_libraries,
|
||||
[AS_HELP_STRING([--with-openssl-libraries=DIR], [OpenSSL library directory])],
|
||||
[LIBVAL="$withval"])
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
[LDFLAGS="${LDFLAGS} -L${withval}"]
|
||||
[LIBVAL="yes"],
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES(openssl, openssl,
|
||||
[LIBS="${LIBS} $openssl_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $openssl_CFLAGS"])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(openssl/ssl.h,
|
||||
FOUND=yes
|
||||
TLSHEADERS=yes,
|
||||
@@ -424,8 +442,10 @@ if test "$USETLS" = "yes"; then
|
||||
AC_MSG_ERROR([Couldn't find OpenSSL headers (ssl.h)])
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
AC_SEARCH_LIBS([SSL_library_init], [ssl],
|
||||
FOUND=yes,
|
||||
AC_SEARCH_LIBS([CRYPTO_set_locking_callback], [crypto],
|
||||
AC_SEARCH_LIBS([SSL_library_init], [ssl],
|
||||
FOUND=yes,
|
||||
FOUND=no),
|
||||
FOUND=no)
|
||||
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; then
|
||||
AC_MSG_ERROR([Couldn't find OpenSSL library])
|
||||
@@ -449,6 +469,53 @@ else
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl checks for zlib includes and libraries.
|
||||
dnl
|
||||
AC_MSG_CHECKING(whether to use gzip)
|
||||
AC_ARG_ENABLE(gzip,
|
||||
[AS_HELP_STRING([--disable-gzip], [disable gzip-compression/decompression (removes dependency from zlib-library)])],
|
||||
[USEZLIB=$enableval],
|
||||
[USEZLIB=yes] )
|
||||
AC_MSG_RESULT($USEZLIB)
|
||||
if test "$USEZLIB" = "yes"; then
|
||||
INCVAL="${LIBPREF}/include"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
AC_ARG_WITH(zlib_includes,
|
||||
[AS_HELP_STRING([--with-zlib-includes=DIR], [zlib include directory])],
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
AC_ARG_WITH(zlib_libraries,
|
||||
[AS_HELP_STRING([--with-zlib-libraries=DIR], [zlib library directory])],
|
||||
[LIBVAL="$withval"])
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
AC_CHECK_HEADER(zlib.h,,
|
||||
AC_MSG_ERROR("zlib header files not found"))
|
||||
AC_SEARCH_LIBS([deflateBound], [z], ,
|
||||
AC_MSG_ERROR("zlib library not found"))
|
||||
else
|
||||
AC_DEFINE([DISABLE_GZIP],1,[Define to 1 to disable gzip-support])
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl Some Linux systems require an empty signal handler for SIGCHLD
|
||||
dnl in order for exit codes to be correctly delivered to parent process.
|
||||
dnl Some 32-Bit BSD systems however may not function properly if the handler is installed.
|
||||
dnl The default behavior is to install the handler.
|
||||
dnl
|
||||
AC_MSG_CHECKING(whether to use an empty SIGCHLD handler)
|
||||
AC_ARG_ENABLE(sigchld-handler,
|
||||
[AS_HELP_STRING([--disable-sigchld-handler], [do not use sigchld-handler (the disabling may be neccessary on 32-Bit BSD)])],
|
||||
[SIGCHLDHANDLER=$enableval],
|
||||
[SIGCHLDHANDLER=yes])
|
||||
AC_MSG_RESULT($SIGCHLDHANDLER)
|
||||
if test "$SIGCHLDHANDLER" = "yes"; then
|
||||
AC_DEFINE([SIGCHLD_HANDLER], 1, [Define to 1 to install an empty signal handler for SIGCHLD])
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl Debugging. Default: no
|
||||
dnl
|
||||
@@ -545,15 +612,5 @@ dnl
|
||||
fi
|
||||
|
||||
|
||||
dnl Substitute flags.
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CPPFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(TAR)
|
||||
AC_SUBST(AR)
|
||||
AC_SUBST(ADDSRCS)
|
||||
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
|
||||
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
|
||||
--- ../libpar2-0.2-original/par2repairer.cpp 2006-01-20 18:25:20.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.cpp 2008-02-06 12:02:53.226050300 +0100
|
||||
@@ -78,6 +78,7 @@
|
||||
+++ ../libpar2-0.2/par2repairer.cpp 2012-11-30 14:23:31.000000000 +0100
|
||||
@@ -76,10 +76,11 @@
|
||||
++sf;
|
||||
}
|
||||
|
||||
delete mainpacket;
|
||||
delete creatorpacket;
|
||||
@@ -9,7 +11,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
|
||||
|
||||
@@ -1261,7 +1262,7 @@
|
||||
Result Par2Repairer::PreProcess(const CommandLine &commandline)
|
||||
{
|
||||
@@ -1259,11 +1260,11 @@
|
||||
string path;
|
||||
string name;
|
||||
DiskFile::SplitFilename(filename, path, name);
|
||||
|
||||
cout << "Target: \"" << name << "\" - missing." << endl;
|
||||
@@ -18,12 +24,37 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1804,7 +1805,7 @@
|
||||
++sf;
|
||||
}
|
||||
@@ -1802,11 +1803,11 @@
|
||||
<< "\" - no data found."
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
- sig_done.emit(name,count,sourcefile->GetVerificationPacket()->BlockCount());
|
||||
+ sig_done.emit(name,count, sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
|
||||
+ sig_done.emit(name,count, count>0 && sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
|
||||
sig_progress.emit(1000.0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find out how much data we have found
|
||||
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.h ../libpar2-0.2/par2repairer.h
|
||||
--- ../libpar2-0.2-original/par2repairer.h 2006-01-20 00:38:27.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.h 2012-11-30 14:24:46.000000000 +0100
|
||||
@@ -34,10 +34,15 @@
|
||||
sigc::signal<void, std::string> sig_filename;
|
||||
sigc::signal<void, double> sig_progress;
|
||||
sigc::signal<void, ParHeaders*> sig_headers;
|
||||
sigc::signal<void, std::string, int, int> sig_done;
|
||||
|
||||
+ // This method allows to determine whether libpar2 includes the patches
|
||||
+ // ("libpar2-0.2-bugfixes.patch") submitted to libpar2 project.
|
||||
+ // Use the method in configure scripts for detection.
|
||||
+ void BugfixesPatchVersion2() { }
|
||||
+
|
||||
protected:
|
||||
// Steps in verifying and repairing files:
|
||||
|
||||
// Load packets from the specified file
|
||||
bool LoadPacketsFromFile(string filename);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
|
||||
--- ../libpar2-0.2-original/par2repairer.cpp 2008-10-26 19:54:33.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.cpp 2008-10-29 10:24:48.000000000 +0100
|
||||
@@ -52,6 +52,8 @@
|
||||
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
|
||||
--- ../libpar2-0.2-original/par2repairer.cpp 2012-12-03 10:47:04.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.cpp 2012-12-03 10:48:13.000000000 +0100
|
||||
@@ -50,10 +50,12 @@
|
||||
outputbuffer = 0;
|
||||
|
||||
noiselevel = CommandLine::nlNormal;
|
||||
headers = new ParHeaders;
|
||||
alreadyloaded = false;
|
||||
@@ -10,7 +12,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
|
||||
Par2Repairer::~Par2Repairer(void)
|
||||
@@ -406,6 +408,10 @@
|
||||
{
|
||||
delete [] (u8*)inputbuffer;
|
||||
@@ -404,10 +406,14 @@
|
||||
{
|
||||
cout << "Loading: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
|
||||
progress = offset;
|
||||
sig_progress.emit(newfraction);
|
||||
|
||||
@@ -21,7 +27,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,6 +590,11 @@
|
||||
// Attempt to read the next packet header
|
||||
PACKET_HEADER header;
|
||||
@@ -582,10 +588,15 @@
|
||||
if (noiselevel > CommandLine::nlQuiet)
|
||||
cout << "No new packets found" << endl;
|
||||
delete diskfile;
|
||||
}
|
||||
|
||||
@@ -33,7 +43,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -833,9 +844,17 @@
|
||||
// Finish loading a recovery packet
|
||||
bool Par2Repairer::LoadRecoveryPacket(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
|
||||
@@ -831,26 +842,42 @@
|
||||
|
||||
// Load packets from each file that was found
|
||||
for (list<string>::const_iterator s=files->begin(); s!=files->end(); ++s)
|
||||
{
|
||||
LoadPacketsFromFile(*s);
|
||||
@@ -51,7 +65,10 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
|
||||
{
|
||||
@@ -846,9 +865,17 @@
|
||||
string wildcard = name.empty() ? "*.PAR2" : name + ".*.PAR2";
|
||||
list<string> *files = DiskFile::FindFiles(path, wildcard);
|
||||
|
||||
// Load packets from each file that was found
|
||||
for (list<string>::const_iterator s=files->begin(); s!=files->end(); ++s)
|
||||
{
|
||||
LoadPacketsFromFile(*s);
|
||||
@@ -69,7 +86,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -866,9 +893,18 @@
|
||||
}
|
||||
|
||||
@@ -864,13 +891,22 @@
|
||||
// If the filename contains ".par2" anywhere
|
||||
if (string::npos != filename.find(".par2") ||
|
||||
string::npos != filename.find(".PAR2"))
|
||||
{
|
||||
LoadPacketsFromFile(filename);
|
||||
@@ -88,7 +109,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1210,6 +1246,11 @@
|
||||
// Check that the packets are consistent and discard any that are not
|
||||
bool Par2Repairer::CheckPacketConsistency(void)
|
||||
@@ -1208,10 +1244,15 @@
|
||||
|
||||
// Start verifying the files
|
||||
sf = sortedfiles.begin();
|
||||
while (sf != sortedfiles.end())
|
||||
{
|
||||
@@ -100,7 +125,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
// Do we have a source file
|
||||
Par2RepairerSourceFile *sourcefile = *sf;
|
||||
|
||||
@@ -1562,6 +1603,10 @@
|
||||
// What filename does the file use
|
||||
string filename = sourcefile->TargetFileName();
|
||||
@@ -1560,10 +1601,14 @@
|
||||
if (oldfraction != newfraction)
|
||||
{
|
||||
cout << "Scanning: \"" << shortname << "\": " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
|
||||
sig_progress.emit(newfraction);
|
||||
|
||||
@@ -111,7 +140,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1651,6 +1696,11 @@
|
||||
// If we fail to find a match, it might be because it was a duplicate of a block
|
||||
// that we have already found.
|
||||
@@ -1649,10 +1694,15 @@
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +156,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
// Get the Full and 16k hash values of the file
|
||||
filechecksummer.GetFileHashes(hashfull, hash16k);
|
||||
|
||||
@@ -2291,10 +2341,19 @@
|
||||
// Did we make any matches at all
|
||||
if (count > 0)
|
||||
@@ -2289,14 +2339,23 @@
|
||||
if (oldfraction != newfraction)
|
||||
{
|
||||
cout << "Repairing: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
|
||||
sig_progress.emit(newfraction);
|
||||
|
||||
@@ -143,7 +180,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
++inputblock;
|
||||
++inputindex;
|
||||
}
|
||||
@@ -2348,9 +2407,18 @@
|
||||
}
|
||||
else
|
||||
@@ -2346,13 +2405,22 @@
|
||||
if (oldfraction != newfraction)
|
||||
{
|
||||
cout << "Processing: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
|
||||
sig_progress.emit(newfraction);
|
||||
|
||||
@@ -162,7 +203,11 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
++copyblock;
|
||||
++inputblock;
|
||||
}
|
||||
@@ -2362,6 +2430,11 @@
|
||||
}
|
||||
|
||||
@@ -2360,10 +2428,15 @@
|
||||
if (lastopenfile != NULL)
|
||||
{
|
||||
lastopenfile->Close();
|
||||
}
|
||||
|
||||
@@ -174,10 +219,14 @@ diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.c
|
||||
if (noiselevel > CommandLine::nlQuiet)
|
||||
cout << "Writing recovered data\r";
|
||||
|
||||
diff -aud ../libpar2-0.2-original/par2repairer.h ../libpar2-0.2/par2repairer.h
|
||||
--- ../libpar2-0.2-original/par2repairer.h 2006-01-20 00:38:27.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.h 2008-10-26 19:01:08.000000000 +0100
|
||||
@@ -183,6 +183,7 @@
|
||||
// For each output block that has been recomputed
|
||||
vector<DataBlock*>::iterator outputblock = outputblocks.begin();
|
||||
diff -aud -U 5 ../libpar2-0.2-with-bugfixes-patch/par2repairer.h ../libpar2-0.2/par2repairer.h
|
||||
--- ../libpar2-0.2-original/par2repairer.h 2012-12-03 10:47:04.000000000 +0100
|
||||
+++ ../libpar2-0.2/par2repairer.h 2012-12-03 10:48:13.000000000 +0100
|
||||
@@ -186,8 +186,9 @@
|
||||
|
||||
u64 progress; // How much data has been processed.
|
||||
u64 totaldata; // Total amount of data to be processed.
|
||||
u64 totalsize; // Total data size
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ rem
|
||||
rem Batch file to start nzbget shell
|
||||
rem
|
||||
rem Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
|
||||
rem Copyright (C) 2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
rem Copyright (C) 2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
rem
|
||||
rem This program is free software; you can redistribute it and/or modify
|
||||
rem it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@ rem GNU General Public License for more details.
|
||||
rem
|
||||
rem You should have received a copy of the GNU General Public License
|
||||
rem along with this program; if not, write to the Free Software
|
||||
rem Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
rem Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
rem
|
||||
|
||||
rem ####################### Usage instructions #######################
|
||||
|
||||
1123
nzbget.conf
Normal file
1123
nzbget.conf
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,866 +0,0 @@
|
||||
# Sample configuration file for nzbget
|
||||
#
|
||||
# On POSIX put this file to one of the following locations:
|
||||
# ~/.nzbget
|
||||
# /etc/nzbget.conf
|
||||
# /usr/etc/nzbget.conf
|
||||
# /usr/local/etc/nzbget.conf
|
||||
# /opt/etc/nzbget.conf
|
||||
#
|
||||
# On Windows put this file in program's directory.
|
||||
#
|
||||
# You can also put the file into any location, if you specify the path to it
|
||||
# using switch "-c", e.g:
|
||||
# nzbget -c /home/user/myconig.txt
|
||||
|
||||
# For quick start change the option MAINDIR and configure one news-server
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PATHS ###
|
||||
|
||||
# Root directory for all related tasks.
|
||||
#
|
||||
# MAINDIR is a variable and therefore starts with "$".
|
||||
# On POSIX you can use "~" as alias for home directory (e.g. "~/download").
|
||||
# On Windows use absolute paths (e.g. "C:\Download").
|
||||
$MAINDIR=~/download
|
||||
|
||||
# Destination-directory to store the downloaded files.
|
||||
DestDir=${MAINDIR}/dst
|
||||
|
||||
# Directory to monitor for incoming nzb-jobs.
|
||||
#
|
||||
# Can have subdirectories.
|
||||
# A nzb-file queued from a subdirectory will be automatically assigned to
|
||||
# category with the directory-name.
|
||||
NzbDir=${MAINDIR}/nzb
|
||||
|
||||
# Directory to store download queue.
|
||||
QueueDir=${MAINDIR}/queue
|
||||
|
||||
# Directory to store temporary files.
|
||||
TempDir=${MAINDIR}/tmp
|
||||
|
||||
# Lock-file for daemon-mode, POSIX only.
|
||||
#
|
||||
# If the option is not empty, nzbget creates the file and writes process-id
|
||||
# (PID) into it. That info can be used in shell scripts.
|
||||
LockFile=/tmp/nzbget.lock
|
||||
|
||||
# Where to store log file, if it needs to be created.
|
||||
#
|
||||
# NOTE: See also option <CreateLog>.
|
||||
LogFile=${DestDir}/nzbget.log
|
||||
|
||||
|
||||
##############################################################################
|
||||
### NEWS-SERVERS ###
|
||||
|
||||
# This section defines which servers nzbget should connect to.
|
||||
|
||||
# Level of newsserver (0-99).
|
||||
#
|
||||
# The servers will be ordered by their level, i.e. nzbget will at
|
||||
# first try to download an article from the level-0-server.
|
||||
# If that server fails, nzbget proceeds with the level-1-server, etc.
|
||||
# A good idea is surely to put your major download-server at level 0
|
||||
# and your fill-servers at levels 1,2,...
|
||||
#
|
||||
# NOTE: Do not leave out a level in your server-list and start with level 0.
|
||||
#
|
||||
# NOTE: Several servers with the same level may be used, they will have
|
||||
# the same priority.
|
||||
Server1.Level=0
|
||||
|
||||
# Host name of newsserver.
|
||||
Server1.Host=my1.newsserver.com
|
||||
|
||||
# Port to connect to (1-65535).
|
||||
Server1.Port=119
|
||||
|
||||
# User name to use for authentication.
|
||||
Server1.Username=user
|
||||
|
||||
# Password to use for authentication.
|
||||
Server1.Password=pass
|
||||
|
||||
# Server requires "Join Group"-command (yes, no).
|
||||
Server1.JoinGroup=yes
|
||||
|
||||
# Encrypted server connection (TLS/SSL) (yes, no).
|
||||
Server1.Encryption=no
|
||||
|
||||
# Maximal number of simultaneous connections to this server (0-999).
|
||||
Server1.Connections=4
|
||||
|
||||
# Second server, on level 0.
|
||||
|
||||
#Server2.Level=0
|
||||
#Server2.Host=my2.newsserver.com
|
||||
#Server2.Port=119
|
||||
#Server2.Username=me
|
||||
#Server2.Password=mypass
|
||||
#Server2.JoinGroup=yes
|
||||
#Server2.Connections=4
|
||||
|
||||
# Third server, on level 1.
|
||||
|
||||
#Server3.Level=1
|
||||
#Server3.Host=fills.newsserver.com
|
||||
#Server3.Port=119
|
||||
#Server3.Username=me2
|
||||
#Server3.Password=mypass2
|
||||
#Server3.JoinGroup=yes
|
||||
#Server3.Connections=1
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PERMISSIONS ###
|
||||
|
||||
# User name for daemon-mode, POSIX only.
|
||||
#
|
||||
# Set the user that the daemon normally runs at (POSIX in daemon-mode only).
|
||||
# Set $MAINDIR with an absolute path to be sure where it will write.
|
||||
# This allows nzbget daemon to be launched in rc.local (at boot), and
|
||||
# download items as a specific user id.
|
||||
#
|
||||
# NOTE: This option has effect only if the program was started from
|
||||
# root-account, otherwise it is ignored and the daemon runs under
|
||||
# current user id.
|
||||
DaemonUserName=root
|
||||
|
||||
# Specify default umask (affects file permissions) for newly created
|
||||
# files, POSIX only (000-1000).
|
||||
#
|
||||
# The value should be written in octal form (the same as for "umask" shell
|
||||
# command).
|
||||
# Empty value or value "1000" disable the setting of umask-mode; current
|
||||
# umask-mode (set via shell) is used in this case.
|
||||
UMask=1000
|
||||
|
||||
|
||||
##############################################################################
|
||||
### INCOMING NZBS ###
|
||||
|
||||
# Create subdirectory with category-name in destination-directory (yes, no).
|
||||
AppendCategoryDir=yes
|
||||
|
||||
# Create subdirectory with nzb-filename in destination-directory (yes, no).
|
||||
AppendNzbDir=yes
|
||||
|
||||
# How often incoming-directory (option <NzbDir>) must be checked for new
|
||||
# nzb-files (seconds).
|
||||
#
|
||||
# Value "0" disables the check.
|
||||
NzbDirInterval=5
|
||||
|
||||
# How old nzb-file should at least be for it to be loaded to queue (seconds).
|
||||
#
|
||||
# Nzbget checks if nzb-file was not modified in last few seconds, defined by
|
||||
# this option. That safety interval prevents the loading of files, which
|
||||
# were not yet completely saved to disk, for example if they are still being
|
||||
# downloaded in web-browser.
|
||||
NzbDirFileAge=60
|
||||
|
||||
# Automatic merging of nzb-files with the same filename (yes, no).
|
||||
#
|
||||
# A typical scenario: you put nzb-file into incoming directory, nzbget adds
|
||||
# file to queue. You find out, that the file doesn't have par-files. You
|
||||
# find required par-files, put nzb-file with the par-files into incoming
|
||||
# directory, nzbget adds it to queue as a separate group. You want the second
|
||||
# file to be merged with the first for parchecking to work properly. With
|
||||
# option "MergeNzb" nzbget can merge files automatically. You only need to
|
||||
# save the second file under the same filename as the first one.
|
||||
MergeNzb=no
|
||||
|
||||
# Set path to program, that must be executed before any file in incoming
|
||||
# directory (option <NzbDir>) is processed.
|
||||
#
|
||||
# Example: "NzbProcess=~/nzbprocess.sh".
|
||||
#
|
||||
# That program can unpack archives which were put in incoming directory, make
|
||||
# filename cleanup, assign category and post-processing parameters to nzb-file
|
||||
# or do something else.
|
||||
#
|
||||
# NZBGet passes following arguments to nzbprocess-program as environment
|
||||
# variables:
|
||||
# NZBNP_DIRECTORY - path to directory, where file is located. It is a directory
|
||||
# specified by the option <NzbDir> or a subdirectory;
|
||||
# NZBNP_FILENAME - name of file to be processed;
|
||||
#
|
||||
# In addition to these arguments nzbget passes all
|
||||
# nzbget.conf-options to postprocess-program as environment variables. These
|
||||
# variables have prefix "NZBOP_" and are written in UPPER CASE. For Example
|
||||
# option "ParRepair" is passed as environment variable "NZBOP_PARREPAIR".
|
||||
# The dots in option names are replaced with underscores, for example
|
||||
# "SERVER1_HOST". For options with predefined possible values (yes/no, etc.)
|
||||
# the values are passed always in lower case.
|
||||
#
|
||||
# The nzbprocess-script can assign category or post-processing parameters
|
||||
# to current nzb-file by printing special messages into standard output
|
||||
# (which is processed by NZBGet).
|
||||
#
|
||||
# To assign category use following syntax:
|
||||
# echo "[NZB] CATEGORY=my category";
|
||||
#
|
||||
# To assign post-processing parameters:
|
||||
# echo "[NZB] NZBPR_myvar=my value";
|
||||
#
|
||||
# The prefix "NZBPR_" will be removed. In this example a post-processing
|
||||
# parameter with name "myvar" and value "my value" will be associated
|
||||
# with nzb-file.
|
||||
#
|
||||
# The nzbprocess-script can delete processed file, rename it or move somewhere.
|
||||
# After the calling of the script the file will be either added to queue
|
||||
# (if it was an nzb-file) or renamed by adding the extension ".processed".
|
||||
#
|
||||
# NOTE: Files with extensions ".processed", ".queued" and ".error" are skipped
|
||||
# during the directory scanning.
|
||||
#
|
||||
# NOTE: Files with extension ".nzb_processed" are not passed to
|
||||
# NzbProcess-script before adding to queue. This feature allows
|
||||
# NzbProcess-script to prevent the scanning of nzb-files extracted from
|
||||
# archives, if they were already processed by the script.
|
||||
NzbProcess=
|
||||
|
||||
# Check for duplicate files (yes, no).
|
||||
#
|
||||
# If this option is enabled the program checks by adding of a new nzb-file:
|
||||
# 1) if nzb-file contains duplicate entries. This check aims on detecting
|
||||
# of reposted files (if first file was not fully uploaded);
|
||||
# If the program find two files with identical names, only the
|
||||
# biggest of these files will be added to queue;
|
||||
# 2) if download queue already contains file with the same name;
|
||||
# 3) if destination file on disk already exists.
|
||||
# In last two cases: if the file exists it will not be added to queue;
|
||||
#
|
||||
# If this option is disabled, all files are downloaded and duplicate files
|
||||
# are renamed to "filename_duplicate1".
|
||||
# Existing files are never deleted or overwritten.
|
||||
DupeCheck=no
|
||||
|
||||
|
||||
##############################################################################
|
||||
### DOWNLOAD QUEUE ###
|
||||
|
||||
# Save download queue to disk (yes, no).
|
||||
#
|
||||
# This allows to reload it on next start.
|
||||
SaveQueue=yes
|
||||
|
||||
# Reload download queue on start, if it exists (yes, no).
|
||||
ReloadQueue=yes
|
||||
|
||||
# Reload Post-processor-queue on start, if it exists (yes, no).
|
||||
#
|
||||
# For this option to work the options <SaveQueue> and <ReloadQueue> must
|
||||
# be also enabled.
|
||||
ReloadPostQueue=yes
|
||||
|
||||
# Reuse articles saved in temp-directory from previous program start (yes, no).
|
||||
#
|
||||
# This allows to continue download of file, if program was exited before
|
||||
# the file was completed.
|
||||
ContinuePartial=yes
|
||||
|
||||
# Visibly rename broken files on download appending "_broken" (yes, no).
|
||||
#
|
||||
# Do not activate this option if par-check is enabled.
|
||||
RenameBroken=no
|
||||
|
||||
# Decode articles (yes, no).
|
||||
#
|
||||
# yes - decode articles using internal decoder (supports yEnc and UU formats);
|
||||
# no - the articles will not be decoded and joined. External programs
|
||||
# (like "uudeview") can be used to decode and join downloaded articles.
|
||||
# Also useful for debugging to look at article's source text.
|
||||
Decode=yes
|
||||
|
||||
# Write decoded articles directly into destination output file (yes, no).
|
||||
#
|
||||
# With this option enabled the program at first creates the output
|
||||
# destination file with required size (total size of all articles),
|
||||
# then writes on the fly decoded articles directly to the file
|
||||
# without creating of any temporary files, even for decoded articles.
|
||||
# This may results in major performance improvement, but this highly
|
||||
# depends on OS and file system.
|
||||
#
|
||||
# Can improve performance on a very fast internet connections,
|
||||
# but you need to test if it works in your case.
|
||||
#
|
||||
# INFO: Tests showed, that on Linux with EXT3-partition activating of
|
||||
# this option results in up to 20% better performance, but on Windows with NTFS
|
||||
# or Linux with FAT32-partitions the performance were decreased.
|
||||
# The possible reason is that on EXT3-partition Linux can create large files
|
||||
# very fast (if the content of file does not need to be initialized),
|
||||
# but Windows on NTFS-partition and also Linux on FAT32-partition need to
|
||||
# initialize created large file with nulls, resulting in a big performance
|
||||
# degradation.
|
||||
#
|
||||
# NOTE: for testing try to download few big files (with total size 500-1000MB)
|
||||
# and measure required time. Do not rely on the program's speed indicator.
|
||||
#
|
||||
# NOTE: if both options <DirectWrite> and <ContinuePartial> are enabled,
|
||||
# the program will still create empty articles-files in temp-directory. They
|
||||
# are used to continue download of file on a next program start. To minimize
|
||||
# disk-io it is recommended to disable option <ContinuePartial>, if
|
||||
# <DirectWrite> is enabled. Especially on a fast connections (where you
|
||||
# would want to activate <DirectWrite>) it should not be a problem to
|
||||
# redownload an interrupted file.
|
||||
DirectWrite=no
|
||||
|
||||
# Check CRC of downloaded and decoded articles (yes, no).
|
||||
#
|
||||
# Normally this option should be enabled for better detecting of download
|
||||
# errors. However checking of CRC needs about the same CPU time as
|
||||
# decoding of articles. On a fast connections with slow CPUs disabling of
|
||||
# CPU-check may slightly improve performance (if CPU is a limiting factor).
|
||||
CrcCheck=yes
|
||||
|
||||
# How much retries should be attempted if a download error occurs (0-99).
|
||||
Retries=4
|
||||
|
||||
# Set the interval between retries (seconds).
|
||||
RetryInterval=10
|
||||
|
||||
# Redownload article if CRC-check fails (yes, no).
|
||||
#
|
||||
# Helps to minimize number of broken files, but may be effective
|
||||
# only if you have multiple download servers (even from the same provider
|
||||
# but from different locations (e.g. europe, usa)).
|
||||
# In any case the option increases your traffic.
|
||||
# For slow connections loading of extra par-blocks may be more effective
|
||||
# The option <CrcCheck> must be enabled for option <RetryOnCrcError> to work.
|
||||
RetryOnCrcError=no
|
||||
|
||||
# Set connection timeout (seconds).
|
||||
ConnectionTimeout=60
|
||||
|
||||
# Timeout until a download-thread should be killed (seconds).
|
||||
#
|
||||
# This can help on hanging downloads, but is dangerous.
|
||||
# Do not use small values!
|
||||
TerminateTimeout=600
|
||||
|
||||
# Set the (approximate) maximum number of allowed threads (0-999).
|
||||
#
|
||||
# Sometimes under certain circumstances the program may create way to many
|
||||
# download threads. Most of them are in wait-state. That is not bad,
|
||||
# but threads are usually a limited resource. If a program creates to many
|
||||
# of them, operating system may kill it. The option <ThreadLimit> prevents that.
|
||||
#
|
||||
# NOTE: the number of threads is not the same as the number of connections
|
||||
# opened to NNTP-servers. Do not use the option <ThreadLimit> to limit the
|
||||
# number of connections. Use the appropriate options <ServerX.Connections>
|
||||
# instead.
|
||||
#
|
||||
# NOTE: the actual number of created threads can be slightly larger as
|
||||
# defined by the option. Important threads may be created even if the
|
||||
# number of threads is exceeded. The option prevents only the creation of
|
||||
# additional download threads.
|
||||
#
|
||||
# NOTE: in most cases you should leave the default value "100" unchanged.
|
||||
# However you may increase that value if you need more than 90 connections
|
||||
# (that's very unlikely) or decrease the value if the OS does not allow so
|
||||
# many threads. But the most OSes should not have problems with 100 threads.
|
||||
ThreadLimit=100
|
||||
|
||||
# Set the maximum download rate on program start (kilobytes/sec).
|
||||
#
|
||||
# Value "0" means no speed control.
|
||||
# The download rate can be changed later via remote calls.
|
||||
DownloadRate=0
|
||||
|
||||
# Set the size of memory buffer used by writing the articles (bytes).
|
||||
#
|
||||
# Bigger values decrease disk-io, but increase memory usage.
|
||||
# Value "0" causes an OS-dependent default value to be used.
|
||||
# With value "-1" (which means "max/auto") the program sets the size of
|
||||
# buffer according to the size of current article (typically less than 500K).
|
||||
#
|
||||
# NOTE: the value must be written in bytes, do not use postfixes "K" or "M".
|
||||
#
|
||||
# NOTE: to calculate the memory usage multiply WriteBufferSize by max number
|
||||
# of connections, configured in section "NEWS-SERVERS".
|
||||
#
|
||||
# NOTE: typical article's size not exceed 500000 bytes, so using bigger values
|
||||
# (like several megabytes) will just waste memory.
|
||||
#
|
||||
# NOTE: for desktop computers with large amount of memory value "-1" (max/auto)
|
||||
# is recommended, but for computers with very low memory (routers, NAS)
|
||||
# value "0" (default OS-dependent size) could be better alternative.
|
||||
#
|
||||
# NOTE: write-buffer is managed by OS (system libraries) and therefore
|
||||
# the effect of the option is highly OS-dependent.
|
||||
WriteBufferSize=0
|
||||
|
||||
# Pause if disk space gets below this value (megabytes).
|
||||
#
|
||||
# Value "0" disables the check.
|
||||
# Only the disk space on the drive with <DestDir> is checked.
|
||||
# The drive with <TempDir> is not checked.
|
||||
DiskSpace=250
|
||||
|
||||
# Delete already downloaded files from disk, if the download of nzb-file was
|
||||
# cancelled (nzb-file was deleted from queue) (yes, no).
|
||||
#
|
||||
# NOTE: nzbget does not delete files in a case if all remaining files in
|
||||
# queue are par-files. That prevents the accidental deletion if the option
|
||||
# <ParCleanupQueue> is disabled or if the program was interrupted during
|
||||
# parcheck and later restarted without reloading of post queue (option
|
||||
# <ReloadPostQueue> disabled).
|
||||
DeleteCleanupDisk=no
|
||||
|
||||
# Keep the history of downloaded nzb-files (days).
|
||||
#
|
||||
# Value "0" disables the history.
|
||||
#
|
||||
# NOTE: when a collection having paused files is added to history all remaining
|
||||
# files are moved from download queue to a list of parked files. It holds files
|
||||
# which could be required later if the collection will be moved back to
|
||||
# download queue for downloading of remaining files. The parked files still
|
||||
# consume some amount of memory and disk space. If the collection was downloaded
|
||||
# and successfully par-checked or postprocessed it is recommended to discard the
|
||||
# unneeded parked files before adding the collection to history. For par2-files
|
||||
# that can be achieved with the option <ParCleanupQueue>.
|
||||
KeepHistory=1
|
||||
|
||||
##############################################################################
|
||||
### LOGGING ###
|
||||
|
||||
# Create log file (yes, no).
|
||||
CreateLog=yes
|
||||
|
||||
# Delete log file upon server start (only in server-mode) (yes, no).
|
||||
ResetLog=no
|
||||
|
||||
# How error messages must be printed (screen, log, both, none).
|
||||
ErrorTarget=both
|
||||
|
||||
# How warning messages must be printed (screen, log, both, none).
|
||||
WarningTarget=both
|
||||
|
||||
# How info messages must be printed (screen, log, both, none).
|
||||
InfoTarget=both
|
||||
|
||||
# How detail messages must be printed (screen, log, both, none).
|
||||
DetailTarget=both
|
||||
|
||||
# How debug messages must be printed (screen, log, both, none).
|
||||
#
|
||||
# Debug-messages can be printed only if the program was compiled in
|
||||
# debug-mode: "./configure --enable-debug".
|
||||
DebugTarget=both
|
||||
|
||||
# Set the default message-kind for output received from process-scripts
|
||||
# (PostProcess, NzbProcess, TaskX.Process) (none, detail, info, warning,
|
||||
# error, debug).
|
||||
#
|
||||
# NZBGet checks if the line written by the script to stdout or stderr starts
|
||||
# with special character-sequence, determining the message-kind, e.g.:
|
||||
# [INFO] bla-bla.
|
||||
# [DETAIL] bla-bla.
|
||||
# [WARNING] bla-bla.
|
||||
# [ERROR] bla-bla.
|
||||
# [DEBUG] bla-bla.
|
||||
#
|
||||
# If the message-kind was detected the text is added to log with detected type.
|
||||
# Otherwise the message becomes the default kind, specified in this option.
|
||||
ProcessLogKind=detail
|
||||
|
||||
# Number of messages stored in buffer and available for remote
|
||||
# clients (messages).
|
||||
LogBufferSize=1000
|
||||
|
||||
# Create a log of all broken files (yes ,no).
|
||||
#
|
||||
# It is a text file placed near downloaded files, which contains
|
||||
# the names of broken files.
|
||||
CreateBrokenLog=yes
|
||||
|
||||
# Create memory dump (core-file) on abnormal termination, Linux only (yes, no).
|
||||
#
|
||||
# Core-files are very helpful for debugging.
|
||||
#
|
||||
# NOTE: core-files may contain sensible data, like your login/password to
|
||||
# newsserver etc.
|
||||
DumpCore=no
|
||||
|
||||
# See also option <LogFile> in section "PATHS"
|
||||
|
||||
|
||||
##############################################################################
|
||||
### DISPLAY (TERMINAL) ###
|
||||
|
||||
# Set screen-outputmode (loggable, colored, curses).
|
||||
#
|
||||
# loggable - only messages will be printed to standard output;
|
||||
# colored - prints messages (with simple coloring for messages categories)
|
||||
# and download progress info; uses escape-sequences to move cursor;
|
||||
# curses - advanced interactive interface with the ability to edit
|
||||
# download queue and various output option.
|
||||
OutputMode=curses
|
||||
|
||||
# Shows NZB-Filename in file list in curses-outputmode (yes, no).
|
||||
#
|
||||
# This option controls the initial state of curses-frontend,
|
||||
# it can be switched on/off in run-time with Z-key.
|
||||
CursesNzbName=yes
|
||||
|
||||
# Show files in groups (NZB-files) in queue list in curses-outputmode (yes, no).
|
||||
#
|
||||
# This option controls the initial state of curses-frontend,
|
||||
# it can be switched on/off in run-time with G-key.
|
||||
CursesGroup=no
|
||||
|
||||
# Show timestamps in message list in curses-outputmode (yes, no).
|
||||
#
|
||||
# This option controls the initial state of curses-frontend,
|
||||
# it can be switched on/off in run-time with T-key.
|
||||
CursesTime=no
|
||||
|
||||
# Update interval for Frontend-output in console mode or remote client
|
||||
# mode (milliseconds).
|
||||
#
|
||||
# Min value 25. Bigger values reduce CPU usage (especially in curses-outputmode)
|
||||
# and network traffic in remote-client mode.
|
||||
UpdateInterval=200
|
||||
|
||||
|
||||
##############################################################################
|
||||
### CLIENT/SERVER COMMUNICATION ###
|
||||
|
||||
# IP on which the server listen and which client uses to contact the server.
|
||||
#
|
||||
# It could be dns-hostname or ip-address (more effective since does not
|
||||
# require dns-lookup).
|
||||
# If you want the server to listen to all interfaces, use "0.0.0.0".
|
||||
ServerIp=127.0.0.1
|
||||
|
||||
# Port which the server & client use (1-65535).
|
||||
ServerPort=6789
|
||||
|
||||
# Password which the server & client use.
|
||||
ServerPassword=tegbzn6789
|
||||
|
||||
# See also option <LogBufferSize> in section "LOGGING"
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PAR CHECK/REPAIR ###
|
||||
|
||||
# How many par2-files to load (none, all, one).
|
||||
#
|
||||
# none - all par2-files must be automatically paused;
|
||||
# all - all par2-files must be downloaded;
|
||||
# one - only one main par2-file must be dowloaded and other must be paused.
|
||||
# Paused files remain in queue and can be unpaused by parchecker when needed.
|
||||
LoadPars=one
|
||||
|
||||
# Automatic par-verification (yes, no).
|
||||
#
|
||||
# To download only needed par2-files (smart par-files loading) set also
|
||||
# the option <LoadPars> to "one". If option <LoadPars> is set to "all",
|
||||
# all par2-files will be downloaded before verification and repair starts.
|
||||
# The option <RenameBroken> must be set to "no", otherwise the par-checker
|
||||
# may not find renamed files and fail.
|
||||
ParCheck=no
|
||||
|
||||
# Automatic par-repair (yes, no).
|
||||
#
|
||||
# If option <ParCheck> is enabled and <ParRepair> is not, the program
|
||||
# only verifies downloaded files and downloads needed par2-files, but does
|
||||
# not start repair-process. This is useful if the server does not have
|
||||
# enough CPU power, since repairing of large files may take too much
|
||||
# resources and time on a slow computers.
|
||||
# This option has effect only if the option <ParCheck> is enabled.
|
||||
ParRepair=yes
|
||||
|
||||
# Use only par2-files with matching names (yes, no).
|
||||
#
|
||||
# If par-check needs extra par-blocks it searches for par2-files
|
||||
# in download queue, which can be unpaused and used for restore.
|
||||
# These par2-files should have the same base name as the main par2-file,
|
||||
# currently loaded in par-checker. Sometimes extra par files (especially if
|
||||
# they were uploaded by a different poster) have not matching names.
|
||||
# Normally par-checker does not use these files, but you can allow it
|
||||
# to use these files by setting <StrictParName> to "no".
|
||||
# This has however a side effect: if NZB-file contains more than one collection
|
||||
# of files (with different par-sets), par-checker may download par-files from
|
||||
# a wrong collection. This increases you traffic (but not harm par-check).
|
||||
#
|
||||
# NOTE: par-checker always uses only par-files added from the same NZB-file
|
||||
# and the option <StrictParName> does not change this behavior.
|
||||
StrictParName=yes
|
||||
|
||||
# Maximum allowed time for par-repair (minutes).
|
||||
#
|
||||
# Value "0" means unlimited.
|
||||
#
|
||||
# If you use nzbget on a very slow computer like NAS-device, it may be good to
|
||||
# limit the time allowed for par-repair. Nzbget calculates the estimated time
|
||||
# required for par-repair. If the estimated value exceeds the limit defined
|
||||
# here, nzbget cancels the repair.
|
||||
#
|
||||
# To avoid a false cancellation nzbget compares the estimated time with
|
||||
# <ParTimeLimit> after the first 5 minutes of repairing, when the calculated
|
||||
# estimated time is more or less accurate. But in a case if <ParTimeLimit> is
|
||||
# set to a value smaller than 5 minutes, the comparison is made after the first
|
||||
# whole minute.
|
||||
#
|
||||
# NOTE: the option limits only the time required for repairing. It doesn't
|
||||
# affect the first stage of parcheck - verification of files. However the
|
||||
# verification speed is constant, it doesn't depend on files integrity and
|
||||
# therefore it is not necessary to limit the time needed for the first stage.
|
||||
#
|
||||
# NOTE: this option requires an extended version of libpar2 (the original
|
||||
# version doesn't support the cancelling of repairing). Please refer to
|
||||
# nzbget's README for info on how to apply a patch to libpar2.
|
||||
ParTimeLimit=0
|
||||
|
||||
# Pause download queue during check/repair (yes, no).
|
||||
#
|
||||
# Enable the option to give CPU more time for par-check/repair. That helps
|
||||
# to speed up check/repair on slow CPUs with fast connection (e.g. NAS-devices).
|
||||
#
|
||||
# NOTE: if parchecker needs additional par-files it temporary unpauses queue.
|
||||
#
|
||||
# NOTE: See also option <PostPauseQueue>.
|
||||
ParPauseQueue=no
|
||||
|
||||
# Cleanup download queue after successful check/repair (yes, no).
|
||||
#
|
||||
# Enable this option for automatic deletion of unneeded (paused) par-files
|
||||
# from download queue after successful check/repair.
|
||||
ParCleanupQueue=yes
|
||||
|
||||
# Delete source nzb-file after successful check/repair (yes, no).
|
||||
#
|
||||
# Enable this option for automatic deletion of nzb-file from incoming directory
|
||||
# after successful check/repair.
|
||||
NzbCleanupDisk=no
|
||||
|
||||
|
||||
##############################################################################
|
||||
### POSTPROCESSING ###
|
||||
|
||||
# Set path to program, that must be executed after the download of nzb-file
|
||||
# or one collection in nzb-file (if par-check enabled and nzb-file contains
|
||||
# multiple collections; see note below for the definition of "collection")
|
||||
# is completed and possibly par-checked/repaired.
|
||||
#
|
||||
# Example: "PostProcess=~/postprocess-example.sh".
|
||||
#
|
||||
# NZBGet passes following arguments to postprocess-program as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file;
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
# 1 = checked and failed to repair;
|
||||
# 2 = checked and successfully repaired;
|
||||
# 3 = checked and can be repaired but repair is disabled;
|
||||
# NZBPP_NZBCOMPLETED - state of nzb-job:
|
||||
# 0 = there are more collections in this nzb-file queued;
|
||||
# 1 = this was the last collection in nzb-file;
|
||||
# NZBPP_PARFAILED - indication of failed par-jobs for current nzb-file:
|
||||
# 0 = no failed par-jobs;
|
||||
# 1 = current par-job or any of the previous par-jobs for
|
||||
# the same nzb-files failed;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string).
|
||||
#
|
||||
# If nzb-file has associated postprocess-parameters (which can be set using
|
||||
# subcommand <O> of command <-E>, for example: nzbget -E G O "myvar=hello !" 10)
|
||||
# or using XML-/JSON-RPC (for example via web-interface), they are also passed
|
||||
# as environment variables. These variables have prefix "NZBPR_" in their names.
|
||||
# For example, pp-parameter "myvar" will be passed as environment
|
||||
# variable "NZBPR_myvar".
|
||||
#
|
||||
# In addition to arguments and postprocess-parameters nzbget passes all
|
||||
# nzbget.conf-options to postprocess-program as environment variables. These
|
||||
# variables have prefix "NZBOP_" and are written in UPPER CASE. For Example
|
||||
# option "ParRepair" is passed as environment variable "NZBOP_PARREPAIR".
|
||||
# The dots in option names are replaced with underscores, for example
|
||||
# "SERVER1_HOST". For options with predefined possible values (yes/no, etc.)
|
||||
# the values are passed always in lower case.
|
||||
#
|
||||
# Return value: nzbget processes the exit code returned by the script:
|
||||
# 91 - request nzbget to do par-check/repair for current collection in the
|
||||
# current nzb-file;
|
||||
# 92 - request nzbget to do par-check/repair for all collections in the
|
||||
# current nzb-file;
|
||||
# 93 - post-process successful (status = SUCCESS);
|
||||
# 94 - post-process failed (status = FAILURE);
|
||||
# 95 - post-process skipped (status = NONE);
|
||||
# All other return codes are interpreted as "status unknown".
|
||||
#
|
||||
# The return value is used to display the status of post-processing in
|
||||
# a history view. In addition to status one or more text messages can be
|
||||
# passed to history using a special prefix "[HISTORY]" by printing messages
|
||||
# to standard output. For example:
|
||||
# echo "[ERROR] [HISTORY] Unpack failed, not enough disk space";
|
||||
#
|
||||
# NOTE: The parameter NZBPP_NZBCOMPLETED is very important and MUST be checked
|
||||
# even in the simplest scripts.
|
||||
# If par-check is enabled and nzb-file contains more than one collection
|
||||
# of files the postprocess-program is called after each collection is completed
|
||||
# and par-checked. If you want to unpack files or clean up the directory
|
||||
# (delete par-files, etc.) there are two possibilities, when you can do this:
|
||||
# 1) you parse NZBPP_PARFILENAME to find out the base name of collection and
|
||||
# clean up only files from this collection (not reliable, because par-files
|
||||
# sometimes have different names than rar-files);
|
||||
# 2) or you just check the parameters NZBPP_NZBCOMPLETED and NZBPP_PARFAILED
|
||||
# and do the processing, only if NZBPP_NZBCOMPLETED is set to "1" (which
|
||||
# means, that this was the last collection in nzb-file and all files
|
||||
# are now completed) and NZBPP_PARFAILED is set to "0" (no failed par-jobs);
|
||||
#
|
||||
# NOTE: the term "collection" in the above description actually means
|
||||
# "par-set". To determine what "collections" are present in nzb-file nzbget
|
||||
# looks for par-sets. If any collection of files within nzb-file does
|
||||
# not have any par-files, this collection will not be detected.
|
||||
# For example, for nzb-file containing three collections but only two par-sets,
|
||||
# the postprocess will be called two times - after processing of each par-set.
|
||||
#
|
||||
# NOTE: if nzbget doesn't find any collections it calls PostProcess once
|
||||
# with empty string for parameter NZBPP_PARFILENAME;
|
||||
#
|
||||
# NOTE: the using of special return values (91 and 92) for requesting of
|
||||
# par-check/repair allows to organize the delayed parcheck. To do that:
|
||||
# 1) set options: LoadPars=one, ParCheck=no, ParRepair=yes;
|
||||
# 2) in post-process-script check the parameter NZBPP_PARSTATUS. If it is "0",
|
||||
# that means, the script is called for the first time. Try to unpack files.
|
||||
# If unpack fails, exit the script with exit code for par-check/repair;
|
||||
# 3) nzbget will start par-check/repair. After that it calls the script again;
|
||||
# 4) on second pass the parameter NZBPP_PARSTATUS will have value
|
||||
# greater than "0". If it is "2" ("checked and successfully repaired")
|
||||
# you can try unpack again.
|
||||
#
|
||||
# NOTE: an example script for unrarring is provided within distribution
|
||||
# in file "postprocess-example.sh".
|
||||
PostProcess=
|
||||
|
||||
# Allow multiple post-processing for the same nzb-file (yes, no).
|
||||
#
|
||||
# After the post-processing (par-check and call of a postprocess-script) is
|
||||
# completed, nzbget adds the nzb-file to a list of completed-jobs. The nzb-file
|
||||
# stays in the list until the last file from that nzb-file is deleted from
|
||||
# the download queue (it occurs straight away if the par-check was successful
|
||||
# and the option <ParCleanupQueue> is enabled).
|
||||
# That means, if a paused file from a nzb-collection becomes unpaused
|
||||
# (manually or from a post-process-script) after the collection was already
|
||||
# postprocessed nzbget will not post-process nzb-file again.
|
||||
# This prevents the unwanted multiple post-processings of the same nzb-file.
|
||||
# But it might be needed if the par-check/-repair are performed not directly
|
||||
# by nzbget but from a post-process-script.
|
||||
#
|
||||
# NOTE: enable this option only if you were advised to do that by the author
|
||||
# of the post-process-script.
|
||||
#
|
||||
# NOTE: by enabling <AllowReProcess> you should disable the option <ParCheck>
|
||||
# to prevent multiple par-checking.
|
||||
AllowReProcess=no
|
||||
|
||||
# Pause download queue during executing of postprocess-script (yes, no).
|
||||
#
|
||||
# Enable the option to give CPU more time for postprocess-script. That helps
|
||||
# to speed up postprocess on slow CPUs with fast connection (e.g. NAS-devices).
|
||||
#
|
||||
# NOTE: See also option <ParPauseQueue>.
|
||||
PostPauseQueue=no
|
||||
|
||||
|
||||
##############################################################################
|
||||
### SCHEDULER ###
|
||||
|
||||
# This section defines scheduler commands.
|
||||
# For each command create a set of options <TaskX.Time>, <TaskX.Command>,
|
||||
# <TaskX.WeekDays> and <TaskX.DownloadRate>.
|
||||
# The following example shows how to throttle downloads in the daytime
|
||||
# by 100 KB/s and download at full speed overnights:
|
||||
|
||||
# Time to execute the command (HH:MM).
|
||||
#
|
||||
# Multiple comma-separated values are accepted.
|
||||
# Asterix as hours-part means "every hour".
|
||||
#
|
||||
# Examples: "08:00", "00:00,06:00,12:00,18:00", "*:00", "*:00,*:30".
|
||||
#Task1.Time=08:00
|
||||
|
||||
# Week days to execute the command (1-7).
|
||||
#
|
||||
# Comma separated list of week days numbers.
|
||||
# 1 is Monday.
|
||||
# Character '-' may be used to define ranges.
|
||||
#
|
||||
# Examples: "1-7", "1-5", "5,6", "1-5, 7".
|
||||
#Task1.WeekDays=1-7
|
||||
|
||||
# Command to be executed (PauseDownload, UnpauseDownload, PauseScan,
|
||||
# UnpauseScan, DownloadRate, Process).
|
||||
#
|
||||
# Possible commands:
|
||||
# PauseDownload - pauses download;
|
||||
# UnpauseDownload - resumes download;
|
||||
# PauseScan - pauses scan of incoming nzb-directory;
|
||||
# UnpauseScan - resumes scan of incoming nzb-directory;
|
||||
# DownloadRate - sets download rate in KB/s;
|
||||
# Process - executes external program.
|
||||
#Task1.Command=DownloadRate
|
||||
|
||||
# Download rate to be set if the command is "DownloadRate" (kilobytes/sec).
|
||||
#
|
||||
# Value "0" means no speed control.
|
||||
#
|
||||
# If the option <TaskX.Command> is not set to "DownloadRate" this option
|
||||
# is ignored and can be omitted.
|
||||
#Task1.DownloadRate=100
|
||||
|
||||
# Path to the porgram to execute if the command is "Process".
|
||||
#
|
||||
# Example: "Task1.Process=/home/user/fetch-nzb.sh".
|
||||
#
|
||||
# If the option <TaskX.Command> is not set to "Process" this option
|
||||
# is ignored and can be omitted.
|
||||
#
|
||||
# NOTE: it's allowed to add parameters to command line. If filename or
|
||||
# any parameter contains spaces it must be surrounded with single quotation
|
||||
# marks. If filename/parameter contains single quotation marks, each of them
|
||||
# must be replaced with two single quotation marks and the resulting filename/
|
||||
# parameter must be surrounded with single quotation marks.
|
||||
# Example: '/home/user/download/my scripts/task process.sh' 'world''s fun'.
|
||||
# In this example one parameter (world's fun) is passed to the script
|
||||
# (task process.sh).
|
||||
#Task1.Process=
|
||||
|
||||
#Task2.Time=20:00
|
||||
#Task2.WeekDays=1-7
|
||||
#Task2.Command=DownloadRate
|
||||
#Task2.DownloadRate=0
|
||||
|
||||
|
||||
##############################################################################
|
||||
## PERFORMANCE ##
|
||||
|
||||
# On a very fast connection and slow CPU and/or drive the following
|
||||
# settings may improve performance:
|
||||
# 1) Disable par-checking and -repairing ("ParCheck=no"). VERY important,
|
||||
# because par-checking/repairing needs a lot of CPU-power and
|
||||
# significantly increases disk usage;
|
||||
# 2) Try to activate option <DirectWrite> ("DirectWrite=yes"), especially
|
||||
# if you use EXT3-partitions;
|
||||
# 3) Disable option <CrcCheck> ("CrcCheck=no");
|
||||
# 4) Disable option <ContinuePartial> ("ContinuePartial=no");
|
||||
# 5) Do not limit download rate ("DownloadRate=0"), because the bandwidth
|
||||
# throttling eats some CPU time;
|
||||
# 6) Disable logging for detail- and debug-messages ("DetailTarget=none",
|
||||
# "DebugTarget=none");
|
||||
# 7) Run the program in daemon (Posix) or service (Windows) mode and use
|
||||
# remote client for short periods of time needed for controlling of
|
||||
# download process on server. Daemon/Service mode eats less CPU
|
||||
# resources than console server mode due to not updating the screen.
|
||||
# 8) Increase the value of option <WriteBufferSize> or better set it to
|
||||
# "-1" (max/auto) if you have spare 5-20 MB of memory.
|
||||
272
nzbget.cpp
272
nzbget.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -66,6 +66,7 @@
|
||||
#include "ColoredFrontend.h"
|
||||
#include "NCursesFrontend.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "UrlCoordinator.h"
|
||||
#include "RemoteServer.h"
|
||||
#include "RemoteClient.h"
|
||||
#include "MessageBase.h"
|
||||
@@ -73,13 +74,16 @@
|
||||
#include "PrePostProcessor.h"
|
||||
#include "ParChecker.h"
|
||||
#include "Scheduler.h"
|
||||
#include "Scanner.h"
|
||||
#include "Util.h"
|
||||
#ifdef WIN32
|
||||
#include "NTService.h"
|
||||
#endif
|
||||
|
||||
// Prototypes
|
||||
void Run();
|
||||
void RunMain();
|
||||
void Run(bool bReload);
|
||||
void Reload();
|
||||
void Cleanup();
|
||||
void ProcessClientRequest();
|
||||
#ifndef WIN32
|
||||
@@ -101,14 +105,20 @@ Thread* g_pFrontend = NULL;
|
||||
Options* g_pOptions = NULL;
|
||||
ServerPool* g_pServerPool = NULL;
|
||||
QueueCoordinator* g_pQueueCoordinator = NULL;
|
||||
UrlCoordinator* g_pUrlCoordinator = NULL;
|
||||
RemoteServer* g_pRemoteServer = NULL;
|
||||
RemoteServer* g_pRemoteSecureServer = NULL;
|
||||
DownloadSpeedMeter* g_pDownloadSpeedMeter = NULL;
|
||||
DownloadQueueHolder* g_pDownloadQueueHolder = NULL;
|
||||
Log* g_pLog = NULL;
|
||||
PrePostProcessor* g_pPrePostProcessor = NULL;
|
||||
DiskState* g_pDiskState = NULL;
|
||||
Scheduler* g_pScheduler = NULL;
|
||||
char* (*szEnvironmentVariables)[] = NULL;
|
||||
Scanner* g_pScanner = NULL;
|
||||
int g_iArgumentCount;
|
||||
char* (*g_szEnvironmentVariables)[] = NULL;
|
||||
char* (*g_szArguments)[] = NULL;
|
||||
bool g_bReloading = true;
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
@@ -137,17 +147,67 @@ int main(int argc, char *argv[], char *argp[])
|
||||
DisableCout();
|
||||
#endif
|
||||
|
||||
g_iArgumentCount = argc;
|
||||
g_szArguments = (char*(*)[])argv;
|
||||
g_szEnvironmentVariables = (char*(*)[])argp;
|
||||
|
||||
#ifdef WIN32
|
||||
for (int i=0; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-D"))
|
||||
{
|
||||
StartService(RunMain);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RunMain();
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _DEBUG
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RunMain()
|
||||
{
|
||||
// we need to save and later restore current directory each time
|
||||
// the program is reloaded (RPC-Method "reload") in order for
|
||||
// config to properly load in a case relative paths are used
|
||||
// in command line
|
||||
char szCurDir[MAX_PATH + 1];
|
||||
Util::GetCurrentDirectory(szCurDir, sizeof(szCurDir));
|
||||
|
||||
bool bReload = false;
|
||||
while (g_bReloading)
|
||||
{
|
||||
g_bReloading = false;
|
||||
Util::SetCurrentDirectory(szCurDir);
|
||||
Run(bReload);
|
||||
bReload = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Run(bool bReload)
|
||||
{
|
||||
g_pLog = new Log();
|
||||
|
||||
debug("nzbget %s", Util::VersionRevision());
|
||||
|
||||
if (!bReload)
|
||||
{
|
||||
Thread::Init();
|
||||
}
|
||||
|
||||
g_pServerPool = new ServerPool();
|
||||
g_pScheduler = new Scheduler();
|
||||
Thread::Init();
|
||||
|
||||
debug("Reading options");
|
||||
g_pOptions = new Options(argc, argv);
|
||||
szEnvironmentVariables = (char*(*)[])argp;
|
||||
g_pOptions = new Options(g_iArgumentCount, *g_szArguments);
|
||||
|
||||
#ifndef WIN32
|
||||
if (g_pOptions->GetUMask() < 01000)
|
||||
@@ -170,7 +230,10 @@ int main(int argc, char *argv[], char *argp[])
|
||||
#ifdef WIN32
|
||||
info("nzbget %s service-mode", Util::VersionRevision());
|
||||
#else
|
||||
Daemonize();
|
||||
if (!bReload)
|
||||
{
|
||||
Daemonize();
|
||||
}
|
||||
info("nzbget %s daemon-mode", Util::VersionRevision());
|
||||
#endif
|
||||
}
|
||||
@@ -183,6 +246,11 @@ int main(int argc, char *argv[], char *argp[])
|
||||
info("nzbget %s remote-mode", Util::VersionRevision());
|
||||
}
|
||||
|
||||
if (!bReload)
|
||||
{
|
||||
Connection::Init();
|
||||
}
|
||||
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
g_pServerPool->InitConnections();
|
||||
@@ -191,13 +259,7 @@ int main(int argc, char *argv[], char *argp[])
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (g_pOptions->GetDaemonMode())
|
||||
{
|
||||
StartService(Run);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#ifndef WIN32
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
if (g_pOptions->GetDumpCore())
|
||||
{
|
||||
@@ -206,19 +268,6 @@ int main(int argc, char *argv[], char *argp[])
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Run();
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _DEBUG
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
#ifndef WIN32
|
||||
InstallSignalHandlers();
|
||||
#ifdef DEBUG
|
||||
@@ -228,9 +277,6 @@ void Run()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Connection::Init(g_pOptions->GetTLS() && !g_pOptions->GetRemoteClientMode() &&
|
||||
(g_pOptions->GetClientOperation() == Options::opClientNoOperation));
|
||||
|
||||
// client request
|
||||
if (g_pOptions->GetClientOperation() != Options::opClientNoOperation)
|
||||
@@ -246,18 +292,27 @@ void Run()
|
||||
g_pQueueCoordinator = new QueueCoordinator();
|
||||
g_pDownloadSpeedMeter = g_pQueueCoordinator;
|
||||
g_pDownloadQueueHolder = g_pQueueCoordinator;
|
||||
|
||||
g_pUrlCoordinator = new UrlCoordinator();
|
||||
}
|
||||
|
||||
// Setup the network-server
|
||||
if (g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pRemoteServer = new RemoteServer();
|
||||
g_pRemoteServer = new RemoteServer(false);
|
||||
g_pRemoteServer->Start();
|
||||
|
||||
if (g_pOptions->GetSecureControl())
|
||||
{
|
||||
g_pRemoteSecureServer = new RemoteServer(true);
|
||||
g_pRemoteSecureServer->Start();
|
||||
}
|
||||
}
|
||||
|
||||
// Creating PrePostProcessor
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
g_pScanner = new Scanner();
|
||||
g_pPrePostProcessor = new PrePostProcessor();
|
||||
}
|
||||
|
||||
@@ -292,7 +347,7 @@ void Run()
|
||||
// Standalone-mode
|
||||
if (!g_pOptions->GetServerMode())
|
||||
{
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromFile(g_pOptions->GetArgFilename(), g_pOptions->GetCategory() ? g_pOptions->GetCategory() : "");
|
||||
NZBFile* pNZBFile = NZBFile::Create(g_pOptions->GetArgFilename(), g_pOptions->GetAddCategory() ? g_pOptions->GetAddCategory() : "");
|
||||
if (!pNZBFile)
|
||||
{
|
||||
abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A");
|
||||
@@ -308,18 +363,28 @@ void Run()
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->Start();
|
||||
g_pUrlCoordinator->Start();
|
||||
g_pPrePostProcessor->Start();
|
||||
|
||||
// enter main program-loop
|
||||
while (g_pQueueCoordinator->IsRunning() || g_pPrePostProcessor->IsRunning())
|
||||
while (g_pQueueCoordinator->IsRunning() ||
|
||||
g_pUrlCoordinator->IsRunning() ||
|
||||
g_pPrePostProcessor->IsRunning())
|
||||
{
|
||||
if (!g_pOptions->GetServerMode() && !g_pQueueCoordinator->HasMoreJobs() && !g_pPrePostProcessor->HasMoreJobs())
|
||||
if (!g_pOptions->GetServerMode() &&
|
||||
!g_pQueueCoordinator->HasMoreJobs() &&
|
||||
!g_pUrlCoordinator->HasMoreJobs() &&
|
||||
!g_pPrePostProcessor->HasMoreJobs())
|
||||
{
|
||||
// Standalone-mode: download completed
|
||||
if (!g_pQueueCoordinator->IsStopped())
|
||||
{
|
||||
g_pQueueCoordinator->Stop();
|
||||
}
|
||||
if (!g_pUrlCoordinator->IsStopped())
|
||||
{
|
||||
g_pUrlCoordinator->Stop();
|
||||
}
|
||||
if (!g_pPrePostProcessor->IsStopped())
|
||||
{
|
||||
g_pPrePostProcessor->Stop();
|
||||
@@ -330,6 +395,7 @@ void Run()
|
||||
|
||||
// main program-loop is terminated
|
||||
debug("QueueCoordinator stopped");
|
||||
debug("UrlCoordinator stopped");
|
||||
debug("PrePostProcessor stopped");
|
||||
}
|
||||
|
||||
@@ -351,7 +417,25 @@ void Run()
|
||||
}
|
||||
debug("RemoteServer stopped");
|
||||
}
|
||||
|
||||
|
||||
if (g_pRemoteSecureServer)
|
||||
{
|
||||
debug("stopping RemoteSecureServer");
|
||||
g_pRemoteSecureServer->Stop();
|
||||
int iMaxWaitMSec = 1000;
|
||||
while (g_pRemoteSecureServer->IsRunning() && iMaxWaitMSec > 0)
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
iMaxWaitMSec -= 100;
|
||||
}
|
||||
if (g_pRemoteSecureServer->IsRunning())
|
||||
{
|
||||
debug("Killing RemoteSecureServer");
|
||||
g_pRemoteSecureServer->Kill();
|
||||
}
|
||||
debug("RemoteSecureServer stopped");
|
||||
}
|
||||
|
||||
// Stop Frontend
|
||||
if (g_pFrontend)
|
||||
{
|
||||
@@ -377,15 +461,15 @@ void ProcessClientRequest()
|
||||
switch (g_pOptions->GetClientOperation())
|
||||
{
|
||||
case Options::opClientRequestListFiles:
|
||||
Client->RequestServerList(true, false);
|
||||
Client->RequestServerList(true, false, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestListGroups:
|
||||
Client->RequestServerList(false, true);
|
||||
Client->RequestServerList(false, true, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestListStatus:
|
||||
Client->RequestServerList(false, false);
|
||||
Client->RequestServerList(false, false, NULL);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestDownloadPause:
|
||||
@@ -414,7 +498,8 @@ void ProcessClientRequest()
|
||||
|
||||
case Options::opClientRequestEditQueue:
|
||||
Client->RequestServerEditQueue((eRemoteEditAction)g_pOptions->GetEditQueueAction(), g_pOptions->GetEditQueueOffset(),
|
||||
g_pOptions->GetEditQueueText(), g_pOptions->GetEditQueueIDList(), g_pOptions->GetEditQueueIDCount(), true);
|
||||
g_pOptions->GetEditQueueText(), g_pOptions->GetEditQueueIDList(), g_pOptions->GetEditQueueIDCount(),
|
||||
g_pOptions->GetEditQueueNameList(), (eRemoteMatchMode)g_pOptions->GetMatchMode(), true);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestLog:
|
||||
@@ -425,8 +510,12 @@ void ProcessClientRequest()
|
||||
Client->RequestServerShutdown();
|
||||
break;
|
||||
|
||||
case Options::opClientRequestReload:
|
||||
Client->RequestServerReload();
|
||||
break;
|
||||
|
||||
case Options::opClientRequestDownload:
|
||||
Client->RequestServerDownload(g_pOptions->GetArgFilename(), g_pOptions->GetCategory(), g_pOptions->GetAddTop());
|
||||
Client->RequestServerDownload(g_pOptions->GetArgFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
|
||||
break;
|
||||
|
||||
case Options::opClientRequestVersion:
|
||||
@@ -441,8 +530,12 @@ void ProcessClientRequest()
|
||||
Client->RequestWriteLog(g_pOptions->GetWriteLogKind(), g_pOptions->GetLastArg());
|
||||
break;
|
||||
|
||||
case Options::opClientRequestScan:
|
||||
Client->RequestScan();
|
||||
case Options::opClientRequestScanAsync:
|
||||
Client->RequestScan(false);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestScanSync:
|
||||
Client->RequestScan(true);
|
||||
break;
|
||||
|
||||
case Options::opClientRequestPostPause:
|
||||
@@ -465,6 +558,14 @@ void ProcessClientRequest()
|
||||
Client->RequestHistory();
|
||||
break;
|
||||
|
||||
case Options::opClientRequestDownloadUrl:
|
||||
Client->RequestServerDownloadUrl(g_pOptions->GetLastArg(), g_pOptions->GetAddNZBFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
|
||||
break;
|
||||
|
||||
case Options::opClientRequestUrlQueue:
|
||||
Client->RequestUrlQueue();
|
||||
break;
|
||||
|
||||
case Options::opClientNoOperation:
|
||||
break;
|
||||
}
|
||||
@@ -474,7 +575,10 @@ void ProcessClientRequest()
|
||||
|
||||
void ExitProc()
|
||||
{
|
||||
info("Stopping, please wait...");
|
||||
if (!g_bReloading)
|
||||
{
|
||||
info("Stopping, please wait...");
|
||||
}
|
||||
if (g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
if (g_pFrontend)
|
||||
@@ -489,11 +593,19 @@ void ExitProc()
|
||||
{
|
||||
debug("Stopping QueueCoordinator");
|
||||
g_pQueueCoordinator->Stop();
|
||||
g_pUrlCoordinator->Stop();
|
||||
g_pPrePostProcessor->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Reload()
|
||||
{
|
||||
g_bReloading = true;
|
||||
info("Reloading...");
|
||||
ExitProc();
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef DEBUG
|
||||
typedef void(*sighandler)(int);
|
||||
@@ -522,22 +634,10 @@ void SignalProc(int iSignal)
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
case SIGPIPE:
|
||||
// ignoring
|
||||
break;
|
||||
|
||||
case SIGSEGV:
|
||||
signal(SIGSEGV, SIG_DFL); // Reset the signal handler
|
||||
PrintBacktrace();
|
||||
break;
|
||||
|
||||
default:
|
||||
// printf("Signal %i received\n", iSignal);
|
||||
if (SignalProcList[iSignal - 1])
|
||||
{
|
||||
SignalProcList[iSignal - 1](iSignal);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -546,15 +646,14 @@ void InstallSignalHandlers()
|
||||
{
|
||||
signal(SIGINT, SignalProc);
|
||||
signal(SIGTERM, SignalProc);
|
||||
signal(SIGCHLD, SignalProc);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#ifdef DEBUG
|
||||
SignalProcList.clear();
|
||||
for (int i = 1; i <= 32; i++)
|
||||
{
|
||||
SignalProcList.push_back((sighandler)signal(i, SignalProc));
|
||||
}
|
||||
signal(SIGWINCH, SIG_DFL);
|
||||
signal(SIGSEGV, SignalProc);
|
||||
#endif
|
||||
#ifdef SIGCHLD_HANDLER
|
||||
// it could be necessary on some systems to activate a handler for SIGCHLD
|
||||
// however it make troubles on other systems and is deactivated by default
|
||||
signal(SIGCHLD, SignalProc);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -619,13 +718,13 @@ void Cleanup()
|
||||
{
|
||||
debug("Cleaning up global objects");
|
||||
|
||||
debug("Deleting QueueCoordinator");
|
||||
if (g_pQueueCoordinator)
|
||||
debug("Deleting UrlCoordinator");
|
||||
if (g_pUrlCoordinator)
|
||||
{
|
||||
delete g_pQueueCoordinator;
|
||||
g_pQueueCoordinator = NULL;
|
||||
delete g_pUrlCoordinator;
|
||||
g_pUrlCoordinator = NULL;
|
||||
}
|
||||
debug("QueueCoordinator deleted");
|
||||
debug("UrlCoordinator deleted");
|
||||
|
||||
debug("Deleting RemoteServer");
|
||||
if (g_pRemoteServer)
|
||||
@@ -635,12 +734,25 @@ void Cleanup()
|
||||
}
|
||||
debug("RemoteServer deleted");
|
||||
|
||||
debug("Deleting RemoteSecureServer");
|
||||
if (g_pRemoteSecureServer)
|
||||
{
|
||||
delete g_pRemoteSecureServer;
|
||||
g_pRemoteSecureServer = NULL;
|
||||
}
|
||||
debug("RemoteSecureServer deleted");
|
||||
|
||||
debug("Deleting PrePostProcessor");
|
||||
if (g_pPrePostProcessor)
|
||||
{
|
||||
delete g_pPrePostProcessor;
|
||||
g_pPrePostProcessor = NULL;
|
||||
}
|
||||
if (g_pScanner)
|
||||
{
|
||||
delete g_pScanner;
|
||||
g_pScanner = NULL;
|
||||
}
|
||||
debug("PrePostProcessor deleted");
|
||||
|
||||
debug("Deleting Frontend");
|
||||
@@ -651,6 +763,14 @@ void Cleanup()
|
||||
}
|
||||
debug("Frontend deleted");
|
||||
|
||||
debug("Deleting QueueCoordinator");
|
||||
if (g_pQueueCoordinator)
|
||||
{
|
||||
delete g_pQueueCoordinator;
|
||||
g_pQueueCoordinator = NULL;
|
||||
}
|
||||
debug("QueueCoordinator deleted");
|
||||
|
||||
debug("Deleting DiskState");
|
||||
if (g_pDiskState)
|
||||
{
|
||||
@@ -662,7 +782,7 @@ void Cleanup()
|
||||
debug("Deleting Options");
|
||||
if (g_pOptions)
|
||||
{
|
||||
if (g_pOptions->GetDaemonMode())
|
||||
if (g_pOptions->GetDaemonMode() && !g_bReloading)
|
||||
{
|
||||
info("Deleting lock file");
|
||||
remove(g_pOptions->GetLockFile());
|
||||
@@ -688,9 +808,11 @@ void Cleanup()
|
||||
}
|
||||
debug("Scheduler deleted");
|
||||
|
||||
Connection::Final();
|
||||
|
||||
Thread::Final();
|
||||
if (!g_bReloading)
|
||||
{
|
||||
Connection::Final();
|
||||
Thread::Final();
|
||||
}
|
||||
|
||||
debug("Global objects cleaned up");
|
||||
|
||||
@@ -722,14 +844,14 @@ void Daemonize()
|
||||
/* Drop user if there is one, and we were run as root */
|
||||
if ( getuid() == 0 || geteuid() == 0 )
|
||||
{
|
||||
struct passwd *pw = getpwnam(g_pOptions->GetDaemonUserName());
|
||||
struct passwd *pw = getpwnam(g_pOptions->GetDaemonUsername());
|
||||
if (pw)
|
||||
{
|
||||
fchown(lfp, pw->pw_uid, pw->pw_gid); /* change owner of lock file */
|
||||
setgroups( 0, (const gid_t*) 0 ); /* Set aux groups to null. */
|
||||
setgid(pw->pw_gid); /* Set primary group. */
|
||||
/* Try setting aux groups correctly - not critical if this fails. */
|
||||
initgroups( g_pOptions->GetDaemonUserName(),pw->pw_gid);
|
||||
initgroups( g_pOptions->GetDaemonUsername(),pw->pw_gid);
|
||||
/* Finally, set uid. */
|
||||
setuid(pw->pw_uid);
|
||||
}
|
||||
|
||||
10
nzbget.h
10
nzbget.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
@@ -37,6 +37,8 @@
|
||||
#define fdopen _fdopen
|
||||
#define ctime_r(timep, buf, bufsize) ctime_s(buf, bufsize, timep)
|
||||
#define localtime_r(time, tm) localtime_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)
|
||||
#define int32_t __int32
|
||||
#define mkdir(dir, flags) _mkdir(dir)
|
||||
#define rmdir _rmdir
|
||||
@@ -50,11 +52,15 @@
|
||||
#define usleep(usec) Sleep((usec) / 1000)
|
||||
#define gettimeofday(tm, ignore) _ftime(tm)
|
||||
#define socklen_t int
|
||||
#define SHUT_WR 0x01
|
||||
#define SHUT_RDWR 0x02
|
||||
#define PATH_SEPARATOR '\\'
|
||||
#define ALT_PATH_SEPARATOR '/'
|
||||
#define LINE_ENDING "\r\n"
|
||||
#define pid_t int
|
||||
#ifndef FSCTL_SET_SPARSE
|
||||
#define FSCTL_SET_SPARSE 590020
|
||||
#endif
|
||||
|
||||
#pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||
|
||||
274
nzbget.kdevelop
274
nzbget.kdevelop
@@ -1,274 +0,0 @@
|
||||
<?xml version = '1.0'?>
|
||||
<kdevelop>
|
||||
<general>
|
||||
<author>gnu</author>
|
||||
<email/>
|
||||
<version>0.3.0</version>
|
||||
<projectmanagement>KDevAutoProject</projectmanagement>
|
||||
<primarylanguage>C++</primarylanguage>
|
||||
<keywords>
|
||||
<keyword>C++</keyword>
|
||||
<keyword>Code</keyword>
|
||||
</keywords>
|
||||
<ignoreparts>
|
||||
<part>kdevabbrev</part>
|
||||
<part>kdevbookmarks</part>
|
||||
<part>kdevsnippet</part>
|
||||
<part>kdevctags2</part>
|
||||
<part>kdevdoxygen</part>
|
||||
<part>kdevkonsoleview</part>
|
||||
<part>kdevfilegroups</part>
|
||||
<part>kdevfilelist</part>
|
||||
<part>kdevfileview</part>
|
||||
<part>kdevdistpart</part>
|
||||
<part>kdevopenwith</part>
|
||||
<part>kdevregexptest</part>
|
||||
<part>kdevscripting</part>
|
||||
<part>kdevfilter</part>
|
||||
<part>kdevtexttools</part>
|
||||
</ignoreparts>
|
||||
<projectdirectory>.</projectdirectory>
|
||||
<absoluteprojectpath>false</absoluteprojectpath>
|
||||
<description/>
|
||||
<projectname>nzbget</projectname>
|
||||
<defaultencoding/>
|
||||
<versioncontrol>kdevsubversion</versioncontrol>
|
||||
</general>
|
||||
<kdevautoproject>
|
||||
<general>
|
||||
<activetarget>src/nzbget</activetarget>
|
||||
<useconfiguration>default</useconfiguration>
|
||||
</general>
|
||||
<run>
|
||||
<mainprogram>/home/user/nzbget/nzbget</mainprogram>
|
||||
<terminal>false</terminal>
|
||||
<directoryradio>executable</directoryradio>
|
||||
<customdirectory>/</customdirectory>
|
||||
<programargs/>
|
||||
<autocompile>true</autocompile>
|
||||
<envvars/>
|
||||
<globaldebugarguments></globaldebugarguments>
|
||||
<globalcwd>/home/user/nzbget</globalcwd>
|
||||
<useglobalprogram>true</useglobalprogram>
|
||||
<autoinstall>false</autoinstall>
|
||||
<autokdesu>false</autokdesu>
|
||||
</run>
|
||||
<configurations>
|
||||
<default>
|
||||
<envvars/>
|
||||
<configargs>--enable-debug</configargs>
|
||||
<builddir/>
|
||||
<topsourcedir/>
|
||||
<cppflags/>
|
||||
<ldflags/>
|
||||
<ccompiler>kdevgccoptions</ccompiler>
|
||||
<cxxcompiler>kdevgppoptions</cxxcompiler>
|
||||
<f77compiler>kdevpgf77options</f77compiler>
|
||||
<ccompilerbinary/>
|
||||
<cxxcompilerbinary/>
|
||||
<f77compilerbinary/>
|
||||
<cflags/>
|
||||
<cxxflags/>
|
||||
<f77flags/>
|
||||
</default>
|
||||
</configurations>
|
||||
<make>
|
||||
<envvars>
|
||||
<envvar value="1" name="WANT_AUTOCONF_2_5" />
|
||||
<envvar value="1" name="WANT_AUTOMAKE_1_6" />
|
||||
</envvars>
|
||||
<abortonerror>true</abortonerror>
|
||||
<runmultiplejobs>false</runmultiplejobs>
|
||||
<numberofjobs>1</numberofjobs>
|
||||
<dontact>false</dontact>
|
||||
<makebin/>
|
||||
<prio>0</prio>
|
||||
</make>
|
||||
</kdevautoproject>
|
||||
<kdevdoctreeview>
|
||||
<ignoretocs>
|
||||
<toc>ada</toc>
|
||||
<toc>ada_bugs_gcc</toc>
|
||||
<toc>bash</toc>
|
||||
<toc>bash_bugs</toc>
|
||||
<toc>clanlib</toc>
|
||||
<toc>w3c-dom-level2-html</toc>
|
||||
<toc>fortran_bugs_gcc</toc>
|
||||
<toc>gnome1</toc>
|
||||
<toc>gnustep</toc>
|
||||
<toc>gtk</toc>
|
||||
<toc>gtk_bugs</toc>
|
||||
<toc>haskell</toc>
|
||||
<toc>haskell_bugs_ghc</toc>
|
||||
<toc>java_bugs_gcc</toc>
|
||||
<toc>java_bugs_sun</toc>
|
||||
<toc>kde2book</toc>
|
||||
<toc>opengl</toc>
|
||||
<toc>pascal_bugs_fp</toc>
|
||||
<toc>php</toc>
|
||||
<toc>php_bugs</toc>
|
||||
<toc>perl</toc>
|
||||
<toc>perl_bugs</toc>
|
||||
<toc>python</toc>
|
||||
<toc>python_bugs</toc>
|
||||
<toc>qt-kdev3</toc>
|
||||
<toc>ruby</toc>
|
||||
<toc>ruby_bugs</toc>
|
||||
<toc>sdl</toc>
|
||||
<toc>w3c-svg</toc>
|
||||
<toc>sw</toc>
|
||||
<toc>w3c-uaag10</toc>
|
||||
<toc>wxwidgets_bugs</toc>
|
||||
</ignoretocs>
|
||||
<ignoreqt_xml>
|
||||
<toc>Guide to the Qt Translation Tools</toc>
|
||||
<toc>Qt Assistant Manual</toc>
|
||||
<toc>Qt Designer Manual</toc>
|
||||
<toc>Qt Reference Documentation</toc>
|
||||
<toc>qmake User Guide</toc>
|
||||
</ignoreqt_xml>
|
||||
<ignoredoxygen>
|
||||
<toc>KDE Libraries (Doxygen)</toc>
|
||||
</ignoredoxygen>
|
||||
</kdevdoctreeview>
|
||||
<kdevfilecreate>
|
||||
<filetypes/>
|
||||
<useglobaltypes>
|
||||
<type ext="cpp" />
|
||||
<type ext="h" />
|
||||
</useglobaltypes>
|
||||
</kdevfilecreate>
|
||||
<kdevfileview>
|
||||
<groups>
|
||||
<group pattern="*.h" name="Header files" />
|
||||
<group pattern="*.cpp" name="Source files" />
|
||||
<hidenonprojectfiles>false</hidenonprojectfiles>
|
||||
<hidenonlocation>false</hidenonlocation>
|
||||
</groups>
|
||||
<tree>
|
||||
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
|
||||
<hidenonprojectfiles>false</hidenonprojectfiles>
|
||||
</tree>
|
||||
</kdevfileview>
|
||||
<kdevdocumentation>
|
||||
<projectdoc>
|
||||
<docsystem>Doxygen Documentation Collection</docsystem>
|
||||
<docurl>nzbget.tag</docurl>
|
||||
<usermanualurl/>
|
||||
</projectdoc>
|
||||
</kdevdocumentation>
|
||||
<substmap>
|
||||
<APPNAME>nzbget</APPNAME>
|
||||
<APPNAMELC>nzbget</APPNAMELC>
|
||||
<APPNAMESC>Nzbget</APPNAMESC>
|
||||
<APPNAMEUC>NZBGET</APPNAMEUC>
|
||||
<AUTHOR>gnu</AUTHOR>
|
||||
<EMAIL/>
|
||||
<LICENSE>GPL</LICENSE>
|
||||
<LICENSEFILE>COPYING</LICENSEFILE>
|
||||
<VERSION>0.3.0</VERSION>
|
||||
<YEAR>2007</YEAR>
|
||||
<dest>/home/user/nzbget-0.3.0/nzbget</dest>
|
||||
</substmap>
|
||||
<cppsupportpart>
|
||||
<filetemplates>
|
||||
<interfacesuffix>.h</interfacesuffix>
|
||||
<implementationsuffix>.cpp</implementationsuffix>
|
||||
</filetemplates>
|
||||
</cppsupportpart>
|
||||
<kdevcppsupport>
|
||||
<qt>
|
||||
<used>false</used>
|
||||
<version>3</version>
|
||||
<root></root>
|
||||
<includestyle>3</includestyle>
|
||||
<designerintegration>EmbeddedKDevDesigner</designerintegration>
|
||||
<qmake></qmake>
|
||||
<designer></designer>
|
||||
<designerpluginpaths/>
|
||||
</qt>
|
||||
<codecompletion>
|
||||
<includeGlobalFunctions>true</includeGlobalFunctions>
|
||||
<includeTypes>true</includeTypes>
|
||||
<includeEnums>true</includeEnums>
|
||||
<includeTypedefs>false</includeTypedefs>
|
||||
<automaticCodeCompletion>false</automaticCodeCompletion>
|
||||
<automaticArgumentsHint>false</automaticArgumentsHint>
|
||||
<automaticHeaderCompletion>true</automaticHeaderCompletion>
|
||||
<codeCompletionDelay>250</codeCompletionDelay>
|
||||
<argumentsHintDelay>400</argumentsHintDelay>
|
||||
<headerCompletionDelay>250</headerCompletionDelay>
|
||||
<showOnlyAccessibleItems>false</showOnlyAccessibleItems>
|
||||
<completionBoxItemOrder>0</completionBoxItemOrder>
|
||||
<howEvaluationContextMenu>true</howEvaluationContextMenu>
|
||||
<showCommentWithArgumentHint>false</showCommentWithArgumentHint>
|
||||
<statusBarTypeEvaluation>false</statusBarTypeEvaluation>
|
||||
<namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
|
||||
<processPrimaryTypes>true</processPrimaryTypes>
|
||||
<processFunctionArguments>false</processFunctionArguments>
|
||||
<preProcessAllHeaders>false</preProcessAllHeaders>
|
||||
<parseMissingHeaders>false</parseMissingHeaders>
|
||||
<resolveIncludePaths>true</resolveIncludePaths>
|
||||
<alwaysParseInBackground>true</alwaysParseInBackground>
|
||||
<usePermanentCaching>true</usePermanentCaching>
|
||||
<alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
|
||||
<includePaths>.;</includePaths>
|
||||
</codecompletion>
|
||||
<creategettersetter>
|
||||
<prefixGet/>
|
||||
<prefixSet>set</prefixSet>
|
||||
<prefixVariable>m_,_</prefixVariable>
|
||||
<parameterName>theValue</parameterName>
|
||||
<inlineGet>true</inlineGet>
|
||||
<inlineSet>true</inlineSet>
|
||||
</creategettersetter>
|
||||
<references/>
|
||||
<splitheadersource>
|
||||
<enabled>false</enabled>
|
||||
<synchronize>true</synchronize>
|
||||
<orientation>Vertical</orientation>
|
||||
</splitheadersource>
|
||||
</kdevcppsupport>
|
||||
<kdevdebugger>
|
||||
<general>
|
||||
<programargs>--standalone /home/user/.nzbget/nzb/t1.nzb</programargs>
|
||||
<gdbpath/>
|
||||
<dbgshell/>
|
||||
<configGdbScript/>
|
||||
<runShellScript/>
|
||||
<runGdbScript/>
|
||||
<breakonloadinglibs>true</breakonloadinglibs>
|
||||
<separatetty>true</separatetty>
|
||||
<floatingtoolbar>false</floatingtoolbar>
|
||||
</general>
|
||||
<display>
|
||||
<staticmembers>false</staticmembers>
|
||||
<demanglenames>true</demanglenames>
|
||||
<outputradix>10</outputradix>
|
||||
</display>
|
||||
</kdevdebugger>
|
||||
<dist>
|
||||
<custom>false</custom>
|
||||
<bzip>false</bzip>
|
||||
<archname/>
|
||||
<appname>nzbget</appname>
|
||||
<version>0.2.4</version>
|
||||
<release/>
|
||||
<vendor/>
|
||||
<licence/>
|
||||
<summary/>
|
||||
<group/>
|
||||
<packager/>
|
||||
<description/>
|
||||
<changelog/>
|
||||
<devpackage>false</devpackage>
|
||||
<docspackage>false</docspackage>
|
||||
<appicon>false</appicon>
|
||||
<arch>0</arch>
|
||||
<genHTML>false</genHTML>
|
||||
<useRPM>false</useRPM>
|
||||
<ftpkde>false</ftpkde>
|
||||
<appskde>false</appskde>
|
||||
<url/>
|
||||
</dist>
|
||||
</kdevelop>
|
||||
@@ -38,7 +38,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@@ -58,7 +58,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0d.lib par2d.lib libgnutls-26.lib libgcrypt-11.lib $(NOINHERIT)"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0d.lib par2d.lib libgnutls-26.lib libgcrypt-11.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
@@ -112,7 +112,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
@@ -131,7 +131,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib libgnutls-26.lib libgcrypt-11.lib $(NOINHERIT)"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib libgnutls-26.lib libgcrypt-11.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
LinkIncremental="0"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
@@ -187,7 +187,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;DISABLE_TLS"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;DISABLE_TLS"
|
||||
ExceptionHandling="1"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
@@ -206,7 +206,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib $(NOINHERIT)"
|
||||
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib regex.lib zlib.lib $(NOINHERIT)"
|
||||
LinkIncremental="0"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
@@ -335,14 +335,6 @@
|
||||
RelativePath=".\NCursesFrontend.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\NetAddress.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\NetAddress.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\NewsServer.cpp"
|
||||
>
|
||||
@@ -399,6 +391,14 @@
|
||||
RelativePath=".\Options.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParCoordinator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParCoordinator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParChecker.cpp"
|
||||
>
|
||||
@@ -407,6 +407,14 @@
|
||||
RelativePath=".\ParChecker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParRenamer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParRenamer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PrePostProcessor.cpp"
|
||||
>
|
||||
@@ -495,6 +503,22 @@
|
||||
RelativePath=".\TLS.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Unpack.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Unpack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\UrlCoordinator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\UrlCoordinator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Util.cpp"
|
||||
>
|
||||
@@ -503,6 +527,22 @@
|
||||
RelativePath=".\Util.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WebDownloader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WebDownloader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WebServer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WebServer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\win32.h"
|
||||
>
|
||||
|
||||
58
nzbgetd
58
nzbgetd
@@ -3,7 +3,7 @@
|
||||
# Script used to start and stop the nzbget usenet service
|
||||
#
|
||||
# Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
|
||||
# Copyright (C) 2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2009-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -17,48 +17,47 @@
|
||||
#
|
||||
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
# --- CONFIGURATION -----------------------------------------------
|
||||
# Location of the nzbget executable
|
||||
export NZBGET_BINARY="/usr/local/bin/nzbget"
|
||||
NZBGET_BINARY="/usr/local/bin/nzbget"
|
||||
|
||||
# Additional options, e. g. config file location:
|
||||
# NZBGET_OPTS="-c /mnt/hdd/tools/nzbget/conf/nzbget.conf"
|
||||
NZBGET_OPTS=""
|
||||
# -----------------------------------------------------------------
|
||||
# start/stop section
|
||||
|
||||
execCommand() {
|
||||
"$NZBGET_BINARY" $@
|
||||
sleep 1 # allows prompt to return
|
||||
}
|
||||
|
||||
start() {
|
||||
execCommand "--daemon"
|
||||
}
|
||||
|
||||
stop() {
|
||||
execCommand "--quit"
|
||||
}
|
||||
|
||||
status() {
|
||||
execCommand "--log 5"
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
if [ -z "$1" ] ; then
|
||||
case `echo "$0" | sed 's:^.*/\(.*\):\1:g'` in
|
||||
S??*) rc="start" ;;
|
||||
K??*) rc="stop" ;;
|
||||
*) rc="usage" ;;
|
||||
esac
|
||||
else
|
||||
rc="$1"
|
||||
fi
|
||||
|
||||
case "$rc" in
|
||||
start)
|
||||
start
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -D
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -Q
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -Q
|
||||
sleep 10 # since stop is backgrounded
|
||||
start
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -D
|
||||
;;
|
||||
status)
|
||||
"$NZBGET_BINARY" $NZBGET_OPTS -L S
|
||||
;;
|
||||
pstatus)
|
||||
retval=$(pgrep -l -f "$NZBGET_BINARY --daemon" > /dev/null ; echo $?)
|
||||
retval=$(pgrep -l -f nzbget > /dev/null ; echo $?)
|
||||
if [ "$retval" = "0" ] ; then
|
||||
echo " ------- nzbget *is* running -------"
|
||||
ps -Ho user,pid,cmd:32,pcpu -C nzbget
|
||||
@@ -68,11 +67,8 @@ case "$1" in
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
istatus)
|
||||
status
|
||||
;;
|
||||
*)
|
||||
echo "Usage $0 {start|stop|restart|pstatus|istatus}"
|
||||
echo "Usage: $0 {start|stop|restart|status|pstatus|usage}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Template configuration file for postprocessing script "postprocess-example.sh".
|
||||
# Please refer to "postprocess-example.sh" for usage instructions.
|
||||
|
||||
##############################################################################
|
||||
### PATHS ###
|
||||
|
||||
# Set the full path to unrar if it is not in your PATH.
|
||||
UnrarCmd=unrar
|
||||
|
||||
|
||||
##############################################################################
|
||||
### OPTIONS ###
|
||||
|
||||
# Delete rar-files after unpacking (yes, no).
|
||||
DeleteRarFiles=yes
|
||||
|
||||
# Rename img-files to iso (yes, no).
|
||||
RenameIMG=yes
|
||||
|
||||
# Joint TS-files (yes, no).
|
||||
JoinTS=no
|
||||
|
||||
##############################################################################
|
||||
### POSTPROCESSING-PARAMETERS ###
|
||||
|
||||
# This section defines parameters, which can be set for each nzb-file
|
||||
# individually using either web-interface or command line.
|
||||
# Example command line for setting parameter "password" to value "123" for
|
||||
# nzb-file with id=2:
|
||||
# nzbget -E G O Password=123 2
|
||||
|
||||
# Perform postprocessing (yes, no).
|
||||
#
|
||||
# Set to "no" to skip postprocessing for this nzb-file.
|
||||
PostProcess=yes
|
||||
|
||||
# Password for encrypted posts.
|
||||
#
|
||||
# If the post requires a password for unpacking.
|
||||
Password=
|
||||
|
||||
# Destination directory.
|
||||
#
|
||||
# NOTE: NZBGet must have write-access-rights for that directory.
|
||||
DestDir=
|
||||
@@ -1,326 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Example postprocessing script for NZBGet
|
||||
#
|
||||
# Copyright (C) 2008 Peter Roubos <peterroubos@hotmail.com>
|
||||
# Copyright (C) 2008 Otmar Werner
|
||||
# Copyright (C) 2008-2009 Andrei Prygounkov <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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
#
|
||||
|
||||
####################### Usage instructions #######################
|
||||
# o Script will unrar downloaded rar files, join ts-files and rename img-files
|
||||
# to iso.
|
||||
#
|
||||
# o To use this script with nzbget set the option "PostProcess" in
|
||||
# nzbget configuration file to point to this script file. E.g.:
|
||||
# PostProcess=/home/user/nzbget/nzbget-postprocess.sh
|
||||
#
|
||||
# o The script needs a configuration file. An example configuration file
|
||||
# is provided in file "postprocess-example.conf". Put the configuration file
|
||||
# into the directory where nzbget's configuration file (nzbget.conf) or where
|
||||
# this script itself is located. Then edit the configuration file in any
|
||||
# text editor to adjust the settings.
|
||||
#
|
||||
# o You can also edit the script's configuration via web-interface (requires
|
||||
# NZBGetWeb 1.4 or later). Set the options "PostProcessConfigFile" and
|
||||
# "PostProcessConfigTemplate" to point to "postprocess-example.conf"
|
||||
# (including full path). The both options are under the section
|
||||
# "CONFIGURATION OF POSTPROCESSING-SCRIPT" in NZBGetWeb.
|
||||
#
|
||||
# o There are few options, which can be ajdusted for each nzb-file
|
||||
# individually. To view/edit them in web-interface click on a spanner icon
|
||||
# near the name of nzb-file.
|
||||
#
|
||||
# o The script supports the feature called "delayed par-check".
|
||||
# That means it can try to unpack downloaded files without par-checking
|
||||
# them fisrt. Only if unpack fails, the script schedules par-check,
|
||||
# then unpacks again.
|
||||
# To use delayed par-check set following options in nzbget configuration file:
|
||||
# ParCheck=no
|
||||
# ParRepair=yes
|
||||
# LoadPars=one (or) LoadPars=all
|
||||
#
|
||||
# o If you want to par-check/repair all files before trying to unpack them,
|
||||
# set option "ParCheck=yes".
|
||||
#
|
||||
####################### End of Usage instructions #######################
|
||||
|
||||
|
||||
# NZBGet passes following arguments to postprocess-programm as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file;
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
# 1 = checked and failed to repair;
|
||||
# 2 = checked and successfully repaired;
|
||||
# 3 = checked and can be repaired but repair is disabled;
|
||||
# NZBPP_NZBCOMPLETED - state of nzb-job:
|
||||
# 0 = there are more collections in this nzb-file queued;
|
||||
# 1 = this was the last collection in nzb-file;
|
||||
# NZBPP_PARFAILED - indication of failed par-jobs for current nzb-file:
|
||||
# 0 = no failed par-jobs;
|
||||
# 1 = current par-job or any of the previous par-jobs for
|
||||
# the same nzb-files failed;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string).
|
||||
|
||||
|
||||
# Name of script's configuration file
|
||||
SCRIPT_CONFIG_FILE="postprocess-example.conf"
|
||||
|
||||
# Exit codes
|
||||
POSTPROCESS_PARCHECK_CURRENT=91
|
||||
POSTPROCESS_PARCHECK_ALL=92
|
||||
POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_ERROR=94
|
||||
POSTPROCESS_NONE=95
|
||||
|
||||
# Check if the script is called from nzbget
|
||||
if [ "$NZBPP_DIRECTORY" = "" -o "$NZBOP_CONFIGFILE" = "" ]; then
|
||||
echo "*** NZBGet post-process script ***"
|
||||
echo "This script is supposed to be called from nzbget (0.7.0 or later)."
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Check if postprocessing was disabled in postprocessing parameters
|
||||
# (for current nzb-file) via web-interface or via command line with
|
||||
# "nzbget -E G O PostProcess=no <ID>"
|
||||
if [ "$NZBPR_PostProcess" = "no" ]; then
|
||||
echo "[WARNING] Post-Process: Postprocessing disabled for this nzb-file, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
echo "[INFO] Post-Process: Post-process script successfully started"
|
||||
|
||||
# Determine the location of configuration file (it must be stored in
|
||||
# the directory with nzbget.conf or in this script's directory).
|
||||
ConfigDir="${NZBOP_CONFIGFILE%/*}"
|
||||
ScriptConfigFile="$ConfigDir/$SCRIPT_CONFIG_FILE"
|
||||
if [ ! -f "$ScriptConfigFile" ]; then
|
||||
ConfigDir="${0%/*}"
|
||||
ScriptConfigFile="$ConfigDir/$SCRIPT_CONFIG_FILE"
|
||||
fi
|
||||
if [ ! -f "$ScriptConfigFile" ]; then
|
||||
echo "[ERROR] Post-Process: Configuration file $ScriptConfigFile not found, exiting"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Readg configuration file
|
||||
while read line; do eval "$line"; done < $ScriptConfigFile
|
||||
|
||||
# Check nzbget.conf options
|
||||
BadConfig=0
|
||||
|
||||
if [ "$NZBOP_ALLOWREPROCESS" = "yes" ]; then
|
||||
echo "[ERROR] Post-Process: Please disable option \"AllowReProcess\" in nzbget configuration file"
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$NZBOP_LOADPARS" = "none" ]; then
|
||||
echo "[ERROR] Post-Process: Please set option \"LoadPars\" to \"One\" or \"All\" in nzbget configuration file"
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$NZBOP_PARREPAIR" = "no" ]; then
|
||||
echo "[ERROR] Post-Process: Please set option \"ParRepair\" to \"Yes\" in nzbget configuration file"
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$BadConfig" -eq 1 ]; then
|
||||
echo "[ERROR] Post-Process: Existing because of not compatible nzbget configuration"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Check if all collections in nzb-file were downloaded
|
||||
if [ ! "$NZBPP_NZBCOMPLETED" -eq 1 ]; then
|
||||
echo "[INFO] Post-Process: Not the last collection in nzb-file, exiting"
|
||||
exit $POSTPROCESS_SUCCESS
|
||||
fi
|
||||
|
||||
# Check par status
|
||||
if [ "$NZBPP_PARSTATUS" -eq 1 -o "$NZBPP_PARSTATUS" -eq 3 -o "$NZBPP_PARFAILED" -eq 1 ]; then
|
||||
if [ "$NZBPP_PARSTATUS" -eq 3 ]; then
|
||||
echo "[WARNING] Post-Process: Par-check successful, but Par-repair disabled, exiting"
|
||||
else
|
||||
echo "[WARNING] Post-Process: Par-check failed, exiting"
|
||||
fi
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Check if destination directory exists (important for reprocessing of history items)
|
||||
if [ ! -d "$NZBPP_DIRECTORY" ]; then
|
||||
echo "[ERROR] Post-Process: Nothing to post-process: destination directory $NZBPP_DIRECTORY doesn't exist"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
cd "$NZBPP_DIRECTORY"
|
||||
|
||||
# If not just repaired and file "_brokenlog.txt" exists, the collection is damaged
|
||||
# exiting with returning code $POSTPROCESS_PARCHECK_ALL to request par-repair
|
||||
if [ ! "$NZBPP_PARSTATUS" -eq 2 ]; then
|
||||
if [ -f "_brokenlog.txt" ]; then
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Brokenlog found, requesting par-repair"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# All checks done, now processing the files
|
||||
|
||||
# Flag indicates that something was unrared
|
||||
Unrared=0
|
||||
|
||||
# Unrar the files (if any) to the temporary directory, if there are no rar files this will do nothing
|
||||
if (ls *.rar >/dev/null 2>&1); then
|
||||
|
||||
# Check if unrar exists
|
||||
$UnrarCmd >/dev/null 2>&1
|
||||
if [ "$?" -eq 127 ]; then
|
||||
echo "[ERROR] Post-Process: Unrar not found. Set the path to unrar in script's configuration"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Make a temporary directory to store the unrarred files
|
||||
ExtractedDirExists=0
|
||||
if [ -d extracted ]; then
|
||||
ExtractedDirExists=1
|
||||
else
|
||||
mkdir extracted
|
||||
fi
|
||||
|
||||
echo "[INFO] Post-Process: Unraring"
|
||||
rarpasswordparam=""
|
||||
if [ "$NZBPR_Password" != "" ]; then
|
||||
rarpasswordparam="-p$NZBPR_Password"
|
||||
fi
|
||||
|
||||
$UnrarCmd x -y -p- "$rarpasswordparam" -o+ "*.rar" ./extracted/
|
||||
if [ "$?" -eq 3 ]; then
|
||||
echo "[ERROR] Post-Process: Unrar failed"
|
||||
if [ "$ExtractedDirExists" -eq 0 ]; then
|
||||
rm -R extracted
|
||||
fi
|
||||
# for delayed par-check/-repair at least one par-file must be already downloaded
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Requesting par-repair"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
Unrared=1
|
||||
|
||||
# Remove the rar files
|
||||
if [ "$DeleteRarFiles" = "yes" ]; then
|
||||
echo "[INFO] Post-Process: Deleting rar-files"
|
||||
rm *.r[0-9][0-9] >/dev/null 2>&1
|
||||
rm *.rar >/dev/null 2>&1
|
||||
rm *.s[0-9][0-9] >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Go to the temp directory and try to unrar again.
|
||||
# If there are any rars inside the extracted rars then these will no also be unrarred
|
||||
cd extracted
|
||||
if (ls *.rar >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Unraring (second pass)"
|
||||
$UnrarCmd x -y -p- -o+ "*.rar"
|
||||
|
||||
if [ "$?" -eq 3 ]; then
|
||||
echo "[INFO] Post-Process: Unrar (second pass) failed"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Delete the Rar files
|
||||
if [ "$DeleteRarFiles" = "yes" ]; then
|
||||
echo "[INFO] Post-Process: Deleting rar-files (second pass)"
|
||||
rm *.r[0-9][0-9] >/dev/null 2>&1
|
||||
rm *.rar >/dev/null 2>&1
|
||||
rm *.s[0-9][0-9] >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Move everything back to the Download folder
|
||||
mv * ..
|
||||
cd ..
|
||||
rmdir extracted
|
||||
fi
|
||||
|
||||
# If download contains only nzb-files move them into nzb-directory
|
||||
# for further download
|
||||
# Check if command "wc" exists
|
||||
wc -l . >/dev/null 2>&1
|
||||
if [ "$?" -ne 127 ]; then
|
||||
AllFilesCount=`ls -1 2>/dev/null | wc -l`
|
||||
NZBFilesCount=`ls -1 *.nzb 2>/dev/null | wc -l`
|
||||
if [ "$AllFilesCount" -eq "$NZBFilesCount" ]; then
|
||||
echo "[INFO] Moving downloaded nzb-files into incoming nzb-directory for further download"
|
||||
mv *.nzb $NZBOP_NZBDIR
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
echo "[INFO] Post-Process: Cleaning up"
|
||||
chmod -R a+rw .
|
||||
rm *.nzb >/dev/null 2>&1
|
||||
rm *.sfv >/dev/null 2>&1
|
||||
rm *.1 >/dev/null 2>&1
|
||||
rm _brokenlog.txt >/dev/null 2>&1
|
||||
if [ "$Unrared" -eq 1 ]; then
|
||||
# Delete par2-file only if there were files for unpacking.
|
||||
rm *.[pP][aA][rR]2 >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$JoinTS" = "yes" ]; then
|
||||
# Join any split .ts files if they are named xxxx.0000.ts xxxx.0001.ts
|
||||
# They will be joined together to a file called xxxx.0001.ts
|
||||
if (ls *.ts >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Joining ts-files"
|
||||
tsname=`find . -name "*0001.ts" |awk -F/ '{print $NF}'`
|
||||
cat *0???.ts > ./$tsname
|
||||
fi
|
||||
|
||||
# Remove all the split .ts files
|
||||
echo "[INFO] Post-Process: Deleting source ts-files"
|
||||
rm *0???.ts >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$RenameIMG" = "yes" ]; then
|
||||
# Rename img file to iso
|
||||
# It will be renamed to .img.iso so you can see that it has been renamed
|
||||
if (ls *.img >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Renaming img-files to iso"
|
||||
imgname=`find . -name "*.img" |awk -F/ '{print $NF}'`
|
||||
mv $imgname $imgname.iso
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if destination directory was set in postprocessing parameters
|
||||
# (for current nzb-file) via web-interface or via command line with
|
||||
# "nzbget -E G O DestDir=/new/path <ID>"
|
||||
if [ "$NZBPR_DestDir" != "" ]; then
|
||||
mkdir $NZBPR_DestDir
|
||||
mv * $NZBPR_DestDir >/dev/null 2>&1
|
||||
cd ..
|
||||
rmdir $NZBPP_DIRECTORY
|
||||
fi
|
||||
|
||||
# All OK, requesting cleaning up of download queue
|
||||
exit $POSTPROCESS_SUCCESS
|
||||
218
ppscripts/EMail.py
Executable file
218
ppscripts/EMail.py
Executable file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# E-Mail post-processing script for NZBGet
|
||||
#
|
||||
# Copyright (C) 2013 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$
|
||||
#
|
||||
|
||||
|
||||
##############################################################################
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
|
||||
# Send E-Mail notification.
|
||||
#
|
||||
# This script sends E-Mail notification when the job is done.
|
||||
#
|
||||
# NOTE: This script requires Python to be installed on your system.
|
||||
|
||||
##############################################################################
|
||||
### OPTIONS ###
|
||||
|
||||
# Email address you want this email to be sent from.
|
||||
#From="NZBGet" <myaccount@gmail.com>
|
||||
|
||||
# Email address you want this email to be sent to.
|
||||
#To=myaccount@gmail.com
|
||||
|
||||
# SMTP server host.
|
||||
#Server=smtp.gmail.com
|
||||
|
||||
# SMTP server port (1-65535).
|
||||
#Port=25
|
||||
|
||||
# Secure communication using TLS/SSL (yes, no).
|
||||
#Encryption=yes
|
||||
|
||||
# SMTP server user name, if required.
|
||||
#Username=myaccount
|
||||
|
||||
# SMTP server password, if required.
|
||||
#Password=mypass
|
||||
|
||||
# Append list of files to the message (yes, no).
|
||||
#
|
||||
# Add the list of downloaded files (the content of destination directory).
|
||||
#FileList=yes
|
||||
|
||||
# Append broken-log to the message (yes, no).
|
||||
#
|
||||
# Add the content of file _brokenlog.txt. This file contains the list of damaged
|
||||
# files and the result of par-check/repair. For successful downloads the broken-log
|
||||
# is usually deleted by cleanup-script and therefore is not sent.
|
||||
#BrokenLog=yes
|
||||
|
||||
# Append post-processing log to the message (Always, Never, OnFailure).
|
||||
#
|
||||
# Add the post-processing log of active job.
|
||||
#PostProcessLog=OnFailure
|
||||
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
##############################################################################
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
try:
|
||||
from xmlrpclib import ServerProxy # python 2
|
||||
except ImportError:
|
||||
from xmlrpc.client import ServerProxy # python 3
|
||||
|
||||
# Exit codes used by NZBGet
|
||||
POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_ERROR=94
|
||||
|
||||
# Check if the script is called from nzbget 11.0 or later
|
||||
if not 'NZBOP_SCRIPTDIR' in os.environ:
|
||||
print('*** NZBGet post-processing script ***')
|
||||
print('This script is supposed to be called from nzbget (11.0 or later).')
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
print('[DETAIL] Script successfully started')
|
||||
sys.stdout.flush()
|
||||
|
||||
required_options = ('NZBPO_FROM', 'NZBPO_TO', 'NZBPO_SERVER', 'NZBPO_PORT', 'NZBPO_ENCRYPTION',
|
||||
'NZBPO_USERNAME', 'NZBPO_PASSWORD', 'NZBPO_FILELIST', 'NZBPO_BROKENLOG', 'NZBPO_POSTPROCESSLOG')
|
||||
for optname in required_options:
|
||||
if (not optname in os.environ):
|
||||
print('[ERROR] Option %s is missing in configuration file. Please check script settings' % optname[6:])
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
# Check par and unpack status for errors.
|
||||
success=False
|
||||
if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_UNPACKSTATUS'] == '1':
|
||||
subject = 'Failure for "%s"' % (os.environ['NZBPP_NZBNAME'])
|
||||
text = 'Download of "%s" has failed.' % (os.environ['NZBPP_NZBNAME'])
|
||||
elif os.environ['NZBPP_PARSTATUS'] == '4':
|
||||
subject = 'Damaged for "%s"' % (os.environ['NZBPP_NZBNAME'])
|
||||
text = 'Download of "%s" requires par-repair.' % (os.environ['NZBPP_NZBNAME'])
|
||||
else:
|
||||
subject = 'Success for "%s"' % (os.environ['NZBPP_NZBNAME'])
|
||||
text = 'Download of "%s" has successfully completed.' % (os.environ['NZBPP_NZBNAME'])
|
||||
success=True
|
||||
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check is disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
# 1 = checked and failed to repair;
|
||||
# 2 = checked and successfully repaired;
|
||||
# 3 = checked and can be repaired but repair is disabled.
|
||||
# 4 = par-check needed but skipped (option ParCheck=manual);
|
||||
parStatus = { '0': 'skipped', '1': 'failed', '2': 'repaired', '3': 'repairable', '4': 'manual' }
|
||||
text += '\nPar-Status: %s' % parStatus[os.environ['NZBPP_PARSTATUS']]
|
||||
|
||||
# NZBPP_UNPACKSTATUS - result of unpack:
|
||||
# 0 = unpack is disabled or was skipped due to nzb-file
|
||||
# properties or due to errors during par-check;
|
||||
# 1 = unpack failed;
|
||||
# 2 = unpack successful.
|
||||
unpackStatus = { '0': 'skipped', '1': 'failed', '2': 'success' }
|
||||
text += '\nUnpack-Status: %s' % unpackStatus[os.environ['NZBPP_UNPACKSTATUS']]
|
||||
|
||||
# add list of downloaded files
|
||||
if os.environ['NZBPO_FILELIST'] == 'yes':
|
||||
text += '\n\nFiles:'
|
||||
for dirname, dirnames, filenames in os.walk(os.environ['NZBPP_DIRECTORY']):
|
||||
for filename in filenames:
|
||||
text += '\n' + os.path.join(dirname, filename)[len(os.environ['NZBPP_DIRECTORY']) + 1:]
|
||||
|
||||
# add _brokenlog.txt (if exists)
|
||||
if os.environ['NZBPO_BROKENLOG'] == 'yes':
|
||||
brokenlog = '%s/_brokenlog.txt' % os.environ['NZBPP_DIRECTORY']
|
||||
if os.path.exists(brokenlog):
|
||||
text += '\n\nBrokenlog:\n' + open(brokenlog, 'r').read().strip()
|
||||
|
||||
# add post-processing log
|
||||
if os.environ['NZBPO_POSTPROCESSLOG'] == 'Always' or \
|
||||
(os.environ['NZBPO_POSTPROCESSLOG'] == 'OnFailure' and not success):
|
||||
# To get the post-processing log we connect to NZBGet via XML-RPC
|
||||
# and call method "postqueue", which returns the list of post-processing job.
|
||||
# The first item in the list is current job. This item has a field 'Log',
|
||||
# containing an array of log-entries.
|
||||
# For more info visit http://nzbget.sourceforge.net/RPC_API_reference
|
||||
|
||||
# First we need to know connection info: host, port and password of NZBGet server.
|
||||
# NZBGet passes all configuration options to post-processing script as
|
||||
# environment variables.
|
||||
host = os.environ['NZBOP_CONTROLIP'];
|
||||
port = os.environ['NZBOP_CONTROLPORT'];
|
||||
username = os.environ['NZBOP_CONTROLUSERNAME'];
|
||||
password = os.environ['NZBOP_CONTROLPASSWORD'];
|
||||
|
||||
if host == '0.0.0.0': host = '127.0.0.1'
|
||||
|
||||
# Build an URL for XML-RPC requests
|
||||
rpcUrl = 'http://%s:%s@%s:%s/xmlrpc' % (username, password, host, port);
|
||||
|
||||
# Create remote server object
|
||||
server = ServerProxy(rpcUrl)
|
||||
|
||||
# Call remote method 'postqueue'. The only parameter tells how many log-entries to return as maximum.
|
||||
postqueue = server.postqueue(10000)
|
||||
|
||||
# Get field 'Log' from the first post-processing job
|
||||
log = postqueue[0]['Log']
|
||||
|
||||
# Now iterate through entries and save them to message text
|
||||
if len(log) > 0:
|
||||
text += '\n\nPost-processing log:';
|
||||
for entry in log:
|
||||
text += '\n%s\t%s\t%s' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text'])
|
||||
|
||||
# Create message
|
||||
msg = MIMEText(text)
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = os.environ['NZBPO_FROM']
|
||||
msg['To'] = os.environ['NZBPO_TO']
|
||||
|
||||
# Send message
|
||||
print('[DETAIL] Sending E-Mail')
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
smtp = smtplib.SMTP(os.environ['NZBPO_SERVER'], os.environ['NZBPO_PORT'])
|
||||
|
||||
if os.environ['NZBPO_ENCRYPTION'] == 'yes':
|
||||
smtp.starttls()
|
||||
|
||||
if os.environ['NZBPO_USERNAME'] != '' and os.environ['NZBPO_PASSWORD'] != '':
|
||||
smtp.login(os.environ['NZBPO_USERNAME'], os.environ['NZBPO_PASSWORD'])
|
||||
|
||||
smtp.sendmail(os.environ['NZBPO_FROM'], os.environ['NZBPO_TO'], msg.as_string())
|
||||
|
||||
smtp.quit()
|
||||
except Exception as err:
|
||||
print('[ERROR] %s' % err)
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
# All OK, returning exit status 'POSTPROCESS_SUCCESS' (int <93>) to let NZBGet know
|
||||
# that our script has successfully completed.
|
||||
sys.exit(POSTPROCESS_SUCCESS)
|
||||
100
ppscripts/Logger.py
Executable file
100
ppscripts/Logger.py
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Logger post-processing script for NZBGet
|
||||
#
|
||||
# Copyright (C) 2013 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$
|
||||
#
|
||||
|
||||
|
||||
##############################################################################
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
|
||||
# Save post-processing log into a file.
|
||||
#
|
||||
# This script saves post-processing log of nzb-file into file
|
||||
# _postprocesslog.txt in the destination directory.
|
||||
#
|
||||
# NOTE: This script requires Python to be installed on your system.
|
||||
|
||||
### NZBGET POST-PROCESSING SCRIPT ###
|
||||
##############################################################################
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
try:
|
||||
from xmlrpclib import ServerProxy # python 2
|
||||
except ImportError:
|
||||
from xmlrpc.client import ServerProxy # python 3
|
||||
|
||||
# Exit codes used by NZBGet
|
||||
POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_NONE=95
|
||||
POSTPROCESS_ERROR=94
|
||||
|
||||
# Check if the script is called from nzbget 11.0 or later
|
||||
if not 'NZBOP_SCRIPTDIR' in os.environ:
|
||||
print('*** NZBGet post-processing script ***')
|
||||
print('This script is supposed to be called from nzbget (11.0 or later).')
|
||||
sys.exit(POSTPROCESS_ERROR)
|
||||
|
||||
if not os.path.exists(os.environ['NZBPP_DIRECTORY']):
|
||||
print('Destination directory doesn\'t exist, exiting')
|
||||
sys.exit(POSTPROCESS_NONE)
|
||||
|
||||
# To get the post-processing log we connect to NZBGet via XML-RPC
|
||||
# and call method "postqueue", which returns the list of post-processing job.
|
||||
# The first item in the list is current job. This item has a field 'Log',
|
||||
# containing an array of log-entries.
|
||||
# For more info visit http://nzbget.sourceforge.net/RPC_API_reference
|
||||
|
||||
# First we need to know connection info: host, port and password of NZBGet server.
|
||||
# NZBGet passes all configuration options to post-processing script as
|
||||
# environment variables.
|
||||
host = os.environ['NZBOP_CONTROLIP'];
|
||||
port = os.environ['NZBOP_CONTROLPORT'];
|
||||
username = os.environ['NZBOP_CONTROLUSERNAME'];
|
||||
password = os.environ['NZBOP_CONTROLPASSWORD'];
|
||||
|
||||
if host == '0.0.0.0': host = '127.0.0.1'
|
||||
|
||||
# Build an URL for XML-RPC requests
|
||||
rpcUrl = 'http://%s:%s@%s:%s/xmlrpc' % (username, password, host, port);
|
||||
|
||||
# Create remote server object
|
||||
server = ServerProxy(rpcUrl)
|
||||
|
||||
# Call remote method 'postqueue'. The only parameter tells how many log-entries to return as maximum.
|
||||
postqueue = server.postqueue(10000)
|
||||
|
||||
# Get field 'Log' from the first post-processing job
|
||||
log = postqueue[0]['Log']
|
||||
|
||||
# Now iterate through entries and save them to the output file
|
||||
if len(log) > 0:
|
||||
f = open('%s/_postprocesslog.txt' % os.environ['NZBPP_DIRECTORY'], 'wb')
|
||||
for entry in log:
|
||||
f.write((u'%s\t%s\t%s\n' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text'])).encode('utf8'))
|
||||
f.close()
|
||||
|
||||
# All OK, returning exit status 'POSTPROCESS_SUCCESS' (int <93>) to let NZBGet know
|
||||
# that our script has successfully completed.
|
||||
sys.exit(POSTPROCESS_SUCCESS)
|
||||
2136
webui/config.js
Normal file
2136
webui/config.js
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user