mirror of
https://github.com/nzbget/nzbget.git
synced 2025-12-26 15:47:44 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99bd29f631 |
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -110,27 +110,12 @@ void ArticleDownloader::SetInfoName(const char * v)
|
||||
m_szInfoName = strdup(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* How server management (for one particular article) works:
|
||||
- there is a list of failed servers which is initially empty;
|
||||
- level is initially 0;
|
||||
void ArticleDownloader::SetStatus(EStatus eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
Notify(NULL);
|
||||
}
|
||||
|
||||
<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");
|
||||
@@ -144,44 +129,59 @@ void ArticleDownloader::Run()
|
||||
{
|
||||
// file exists from previous program's start
|
||||
detail("Article %s already downloaded, skipping", m_szInfoName);
|
||||
FreeConnection(true);
|
||||
SetStatus(adFinished);
|
||||
Notify(NULL);
|
||||
FreeConnection(true);
|
||||
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 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())
|
||||
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();
|
||||
|
||||
Status = adFailed;
|
||||
|
||||
SetStatus(adWaiting);
|
||||
while (!IsStopped() && !m_pConnection)
|
||||
{
|
||||
m_pConnection = g_pServerPool->GetConnection(iLevel, pWantServer, &failedServers);
|
||||
m_pConnection = g_pServerPool->GetConnection(level);
|
||||
usleep(5 * 1000);
|
||||
}
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
if (IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
pLastServer = m_pConnection->GetNewsServer();
|
||||
|
||||
m_pConnection->SetSuppressErrors(false);
|
||||
|
||||
// test connection
|
||||
@@ -189,8 +189,7 @@ void ArticleDownloader::Run()
|
||||
if (bConnected && !IsStopped())
|
||||
{
|
||||
// Okay, we got a Connection. Now start downloading.
|
||||
detail("Downloading %s @ server%i (%s)", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
detail("Downloading %s @ %s", m_szInfoName, m_pConnection->GetHost());
|
||||
Status = Download();
|
||||
}
|
||||
|
||||
@@ -201,6 +200,9 @@ void ArticleDownloader::Run()
|
||||
m_pConnection->Disconnect();
|
||||
bConnected = false;
|
||||
Status = adFailed;
|
||||
#ifdef THREADCONNECT_WORKAROUND
|
||||
iRemainedConnectRetries--;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -210,37 +212,28 @@ 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 || Status == adNotFound);
|
||||
FreeConnection(Status == adFinished);
|
||||
}
|
||||
}
|
||||
|
||||
if (Status == adFinished || Status == adFatalError)
|
||||
#ifdef THREADCONNECT_WORKAROUND
|
||||
else
|
||||
{
|
||||
iRemainedConnectRetries--;
|
||||
}
|
||||
|
||||
if (iRemainedConnectRetries == 0)
|
||||
{
|
||||
debug("Can't connect from this thread, retry later from another");
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
pWantServer = NULL;
|
||||
|
||||
if (bConnected && Status == adFailed)
|
||||
{
|
||||
iRemainedRetries--;
|
||||
}
|
||||
|
||||
if (!bConnected || (Status == adFailed && iRemainedRetries > 1))
|
||||
{
|
||||
pWantServer = pLastServer;
|
||||
}
|
||||
|
||||
if (Status == adNotFound || Status == adCrcError || (Status == adFailed && iRemainedRetries == 0))
|
||||
{
|
||||
failedServers.push_back(pLastServer);
|
||||
}
|
||||
|
||||
if (pWantServer && !IsStopped() &&
|
||||
if (((Status == adFailed) || (Status == adCrcError && g_pOptions->GetRetryOnCrcError())) &&
|
||||
(iRemainedDownloadRetries > 1 || !bConnected) && !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) &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
@@ -248,68 +241,62 @@ void ArticleDownloader::Run()
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
}
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
}
|
||||
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
if (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pWantServer)
|
||||
if (IsStopped())
|
||||
{
|
||||
// if all servers from current level were tried, increase level
|
||||
// if all servers from all levels were tried, break the loop with failure status
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Status == adFinished) || (Status == adFatalError) ||
|
||||
(Status == adCrcError && !g_pOptions->GetRetryOnCrcError()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bool bAllServersOnLevelFailed = true;
|
||||
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
LevelStatus[level] = Status;
|
||||
|
||||
if (bAllServersOnLevelFailed)
|
||||
bool bAllLevelNotFound = true;
|
||||
for (int lev = 0; lev <= iMaxLevel; lev++)
|
||||
{
|
||||
if (LevelStatus[lev] != adNotFound)
|
||||
{
|
||||
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;
|
||||
}
|
||||
bAllLevelNotFound = false;
|
||||
break;
|
||||
}
|
||||
|
||||
iRemainedRetries = iRetries;
|
||||
}
|
||||
if (bAllLevelNotFound)
|
||||
{
|
||||
if (iMaxLevel > 0)
|
||||
{
|
||||
warn("Article %s @ all servers failed: Article not found", m_szInfoName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// do not count connect-errors, only article- and group-errors
|
||||
if (bConnected)
|
||||
{
|
||||
level++;
|
||||
if (level > iMaxLevel)
|
||||
{
|
||||
level = 0;
|
||||
}
|
||||
iRemainedDownloadRetries--;
|
||||
}
|
||||
}
|
||||
|
||||
FreeConnection(Status == adFinished);
|
||||
|
||||
free(LevelStatus);
|
||||
|
||||
if (m_bDuplicate)
|
||||
{
|
||||
Status = adFinished;
|
||||
@@ -320,19 +307,19 @@ void ArticleDownloader::Run()
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
Status = adRetry;
|
||||
}
|
||||
|
||||
if (Status == adFailed)
|
||||
{
|
||||
warn("Download %s failed", m_szInfoName);
|
||||
if (IsStopped())
|
||||
{
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Download %s failed", m_szInfoName);
|
||||
}
|
||||
}
|
||||
|
||||
SetStatus(Status);
|
||||
Notify(NULL);
|
||||
|
||||
debug("Exiting ArticleDownloader-loop");
|
||||
}
|
||||
@@ -420,8 +407,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ server%i (%s) failed: Unexpected end of article", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
warn("Article %s @ %s failed: Unexpected end of article", m_szInfoName, m_pConnection->GetHost());
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
@@ -455,8 +441,7 @@ 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 @ server%i (%s) failed: Wrong message-id, expected %s, returned %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
warn("Article %s @ %s failed: Wrong message-id, expected %s, returned %s", m_szInfoName, m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
@@ -484,8 +469,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
|
||||
if (!bEnd && Status == adRunning && !IsStopped())
|
||||
{
|
||||
warn("Article %s @ server%i (%s) failed: article incomplete", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
warn("Article %s @ %s failed: article incomplete", m_szInfoName, m_pConnection->GetHost());
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
@@ -512,21 +496,18 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ server%i (%s) failed, %s: Connection closed by remote host", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment);
|
||||
warn("Article %s @ %s failed, %s: Connection closed by remote host", m_szInfoName, m_pConnection->GetHost(), szComment);
|
||||
}
|
||||
return adConnectError;
|
||||
}
|
||||
else if (m_pConnection->GetAuthError() || !strncmp(szResponse, "400", 3) || !strncmp(szResponse, "499", 3))
|
||||
{
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adConnectError;
|
||||
}
|
||||
else if (!strncmp(szResponse, "41", 2) || !strncmp(szResponse, "42", 2) || !strncmp(szResponse, "43", 2))
|
||||
{
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szResponse, "2", 1))
|
||||
@@ -537,8 +518,7 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
else
|
||||
{
|
||||
// unknown error, no special handling
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
@@ -629,8 +609,9 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
{
|
||||
pb += 6; //=strlen(" size=")
|
||||
long iArticleFilesize = atol(pb);
|
||||
if (!CreateOutputFile(iArticleFilesize))
|
||||
if (!Util::CreateSparseFile(m_szOutputFilename, iArticleFilesize))
|
||||
{
|
||||
error("Could not create file %s!", m_szOutputFilename);
|
||||
return false;
|
||||
}
|
||||
m_pFileInfo->SetOutputInitialized(true);
|
||||
@@ -673,33 +654,6 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* creates output file and subdirectores */
|
||||
bool ArticleDownloader::CreateOutputFile(int iSize)
|
||||
{
|
||||
// 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;
|
||||
strncpy(szDestDir, m_szOutputFilename, iMaxlen < 1024 ? iMaxlen : 1024-1);
|
||||
szDestDir[iMaxlen] = '\0';
|
||||
|
||||
if (!Util::ForceDirectories(szDestDir))
|
||||
{
|
||||
error("Could not create directory %s! Errcode: %i", szDestDir, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Util::CreateSparseFile(m_szOutputFilename, iSize))
|
||||
{
|
||||
error("Could not create file %s!", m_szOutputFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
{
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
|
||||
@@ -1031,23 +985,6 @@ 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;
|
||||
strncpy(szOldDestDir, m_szOutputFilename, iMaxlen < 1024 ? iMaxlen : 1024-1);
|
||||
szOldDestDir[iMaxlen] = '\0';
|
||||
if (Util::DirEmpty(szOldDestDir))
|
||||
{
|
||||
debug("Deleting old dir: %s", szOldDestDir);
|
||||
rmdir(szOldDestDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDirectWrite || g_pOptions->GetContinuePartial())
|
||||
|
||||
@@ -42,7 +42,6 @@ public:
|
||||
{
|
||||
adUndefined,
|
||||
adRunning,
|
||||
adWaiting,
|
||||
adFinished,
|
||||
adFailed,
|
||||
adRetry,
|
||||
@@ -77,11 +76,9 @@ private:
|
||||
EStatus Download();
|
||||
bool Write(char* szLine, int iLen);
|
||||
bool PrepareFile(char* szLine);
|
||||
bool CreateOutputFile(int iSize);
|
||||
EStatus DecodeCheck();
|
||||
void FreeConnection(bool bKeepConnected);
|
||||
EStatus CheckResponse(const char* szResponse, const char* szComment);
|
||||
void SetStatus(EStatus eStatus) { m_eStatus = eStatus; }
|
||||
|
||||
public:
|
||||
ArticleDownloader();
|
||||
@@ -90,6 +87,7 @@ 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();
|
||||
@@ -113,7 +111,7 @@ class DownloadSpeedMeter
|
||||
{
|
||||
public:
|
||||
virtual ~DownloadSpeedMeter() {};
|
||||
virtual int CalcCurrentDownloadSpeed() = 0;
|
||||
virtual float CalcCurrentDownloadSpeed() = 0;
|
||||
virtual void AddSpeedReading(int iBytes) = 0;
|
||||
};
|
||||
|
||||
|
||||
284
BinRpc.cpp
284
BinRpc.cpp
@@ -89,27 +89,29 @@ const unsigned int g_iMessageRequestSizes[] =
|
||||
//*****************************************************************
|
||||
// BinProcessor
|
||||
|
||||
BinRpcProcessor::BinRpcProcessor()
|
||||
{
|
||||
m_MessageBase.m_iSignature = (int)NZBMESSAGE_SIGNATURE;
|
||||
}
|
||||
|
||||
void BinRpcProcessor::Execute()
|
||||
{
|
||||
// Read the first package which needs to be a request
|
||||
if (!m_pConnection->Recv(((char*)&m_MessageBase) + sizeof(m_MessageBase.m_iSignature), sizeof(m_MessageBase) - sizeof(m_MessageBase.m_iSignature)))
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetControlPort(), m_szClientIP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetControlPassword()))
|
||||
{
|
||||
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetControlPort(), m_szClientIP);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_pConnection->GetRemoteAddr());
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_szClientIP);
|
||||
|
||||
Dispatch();
|
||||
}
|
||||
@@ -200,7 +202,7 @@ void BinRpcProcessor::Dispatch()
|
||||
|
||||
if (command)
|
||||
{
|
||||
command->SetConnection(m_pConnection);
|
||||
command->SetSocket(m_iSocket);
|
||||
command->SetMessageBase(&m_MessageBase);
|
||||
command->Execute();
|
||||
delete command;
|
||||
@@ -222,8 +224,8 @@ void BinCommand::SendBoolResponse(bool bSuccess, const char* szText)
|
||||
BoolResponse.m_iTrailingDataLength = htonl(iTextLen);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &BoolResponse, sizeof(BoolResponse));
|
||||
m_pConnection->Send((char*)szText, iTextLen);
|
||||
send(m_iSocket, (char*) &BoolResponse, sizeof(BoolResponse), 0);
|
||||
send(m_iSocket, (char*)szText, iTextLen, 0);
|
||||
}
|
||||
|
||||
bool BinCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
@@ -232,7 +234,8 @@ bool BinCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
iSize -= sizeof(SNZBRequestBase);
|
||||
if (iSize > 0)
|
||||
{
|
||||
if (!m_pConnection->Recv(((char*)pBuffer) + sizeof(SNZBRequestBase), iSize))
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)pBuffer) + sizeof(SNZBRequestBase), iSize, 0);
|
||||
if (iBytesReceived != iSize)
|
||||
{
|
||||
error("invalid request");
|
||||
return false;
|
||||
@@ -249,8 +252,6 @@ void PauseUnpauseBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetResumeTime(0);
|
||||
|
||||
switch (ntohl(PauseUnpauseRequest.m_iAction))
|
||||
{
|
||||
case eRemotePauseUnpauseActionDownload:
|
||||
@@ -281,7 +282,7 @@ void SetDownloadRateBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate));
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate) / 1024.0f);
|
||||
SendBoolResponse(true, "Rate-Command completed successfully");
|
||||
}
|
||||
|
||||
@@ -342,44 +343,57 @@ void DownloadBinCommand::Execute()
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(DownloadRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
|
||||
if (!m_pConnection->Recv(pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength)))
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
error("invalid request");
|
||||
free(pRecvBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
int iPriority = ntohl(DownloadRequest.m_iPriority);
|
||||
bool bAddPaused = ntohl(DownloadRequest.m_bAddPaused);
|
||||
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
||||
|
||||
if (pNZBFile)
|
||||
{
|
||||
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
||||
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->SetPriority(iPriority);
|
||||
pFileInfo->SetPaused(bAddPaused);
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, ntohl(DownloadRequest.m_bAddFirst));
|
||||
delete pNZBFile;
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Collection %s added to queue", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
else
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Download Request failed for %s", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(false, tmp);
|
||||
int iPriority = ntohl(DownloadRequest.m_iPriority);
|
||||
bool bAddPaused = ntohl(DownloadRequest.m_bAddPaused);
|
||||
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
||||
|
||||
if (pNZBFile)
|
||||
{
|
||||
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
||||
|
||||
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, ntohl(DownloadRequest.m_bAddFirst));
|
||||
delete pNZBFile;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
free(pRecvBuffer);
|
||||
@@ -592,11 +606,11 @@ void ListBinCommand::Execute()
|
||||
if (htonl(ListRequest.m_bServerState))
|
||||
{
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
ListResponse.m_iDownloadRate = htonl(g_pQueueCoordinator->CalcCurrentDownloadSpeed());
|
||||
ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024));
|
||||
Util::SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
ListResponse.m_iDownloadLimit = htonl(g_pOptions->GetDownloadRate());
|
||||
ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024));
|
||||
ListResponse.m_bDownloadPaused = htonl(g_pOptions->GetPauseDownload());
|
||||
ListResponse.m_bDownload2Paused = htonl(g_pOptions->GetPauseDownload2());
|
||||
ListResponse.m_bPostPaused = htonl(g_pOptions->GetPausePostProcess());
|
||||
@@ -619,12 +633,12 @@ void ListBinCommand::Execute()
|
||||
}
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &ListResponse, sizeof(ListResponse));
|
||||
send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
@@ -710,12 +724,12 @@ void LogBinCommand::Execute()
|
||||
LogResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &LogResponse, sizeof(LogResponse));
|
||||
send(m_iSocket, (char*) &LogResponse, sizeof(LogResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -746,13 +760,24 @@ void EditQueueBinCommand::Execute()
|
||||
}
|
||||
|
||||
char* pBuf = (char*)malloc(iBufLength);
|
||||
|
||||
if (!m_pConnection->Recv(pBuf, iBufLength))
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
char* pBufPtr = pBuf;
|
||||
int NeedBytes = iBufLength;
|
||||
int iResult = 0;
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
error("invalid request");
|
||||
free(pBuf);
|
||||
return;
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
bool bOK = NeedBytes == 0;
|
||||
|
||||
if (iNrIDEntries <= 0 && iNrNameEntries <= 0)
|
||||
{
|
||||
@@ -760,44 +785,45 @@ void EditQueueBinCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
char* szText = iTextLen > 0 ? pBuf : NULL;
|
||||
int32_t* pIDs = (int32_t*)(pBuf + iTextLen);
|
||||
char* pNames = (pBuf + iTextLen + iNrIDEntries * sizeof(int32_t));
|
||||
|
||||
IDList cIDList;
|
||||
NameList cNameList;
|
||||
|
||||
if (iNrIDEntries > 0)
|
||||
if (bOK)
|
||||
{
|
||||
cIDList.reserve(iNrIDEntries);
|
||||
for (int i = 0; i < iNrIDEntries; i++)
|
||||
char* szText = iTextLen > 0 ? pBuf : NULL;
|
||||
int32_t* pIDs = (int32_t*)(pBuf + iTextLen);
|
||||
char* pNames = (pBuf + iTextLen + iNrIDEntries * sizeof(int32_t));
|
||||
|
||||
IDList cIDList;
|
||||
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++)
|
||||
if (iNrNameEntries > 0)
|
||||
{
|
||||
cNameList.push_back(pNames);
|
||||
pNames += strlen(pNames) + 1;
|
||||
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(
|
||||
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);
|
||||
if (iAction < eRemoteEditActionPostMoveOffset)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
free(pBuf);
|
||||
@@ -900,12 +926,12 @@ void PostQueueBinCommand::Execute()
|
||||
PostQueueResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
send(m_iSocket, (char*) &PostQueueResponse, sizeof(PostQueueResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -920,36 +946,50 @@ void WriteLogBinCommand::Execute()
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(WriteLogRequest.m_iTrailingDataLength) + 1);
|
||||
|
||||
if (!m_pConnection->Recv(pRecvBuffer, ntohl(WriteLogRequest.m_iTrailingDataLength)))
|
||||
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)
|
||||
{
|
||||
error("invalid request");
|
||||
free(pRecvBuffer);
|
||||
return;
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
bool OK = true;
|
||||
switch ((Message::EKind)ntohl(WriteLogRequest.m_iKind))
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
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;
|
||||
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");
|
||||
}
|
||||
SendBoolResponse(OK, OK ? "Message added to log" : "Invalid message-kind");
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
@@ -1052,12 +1092,12 @@ void HistoryBinCommand::Execute()
|
||||
HistoryResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
send(m_iSocket, (char*) &HistoryResponse, sizeof(HistoryResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -1162,12 +1202,12 @@ void UrlQueueBinCommand::Execute()
|
||||
UrlQueueResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
m_pConnection->Send((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
|
||||
send(m_iSocket, (char*) &UrlQueueResponse, sizeof(UrlQueueResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
12
BinRpc.h
12
BinRpc.h
@@ -33,21 +33,23 @@
|
||||
class BinRpcProcessor
|
||||
{
|
||||
private:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase m_MessageBase;
|
||||
Connection* m_pConnection;
|
||||
const char* m_szClientIP;
|
||||
|
||||
void Dispatch();
|
||||
|
||||
public:
|
||||
BinRpcProcessor();
|
||||
void Execute();
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetSignature(int iSignature) { m_MessageBase.m_iSignature = iSignature; }
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
};
|
||||
|
||||
class BinCommand
|
||||
{
|
||||
protected:
|
||||
Connection* m_pConnection;
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
@@ -56,7 +58,7 @@ protected:
|
||||
public:
|
||||
virtual ~BinCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; }
|
||||
};
|
||||
|
||||
|
||||
168
ChangeLog
168
ChangeLog
@@ -1,161 +1,13 @@
|
||||
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.1:
|
||||
- added full par-scan feature needed to par-check/repair files which
|
||||
were renamed after creation of par-files:
|
||||
- new option <ParScan> to activate full par-scan (always or automatic);
|
||||
- the automatic full par-scan activates if missing files are detected
|
||||
during par-check, this avoids unnecessary full scan for normal
|
||||
(not renamed) par sets;
|
||||
- replaced a browser error message when trying to add local files
|
||||
in IE9 with a better message dialog;
|
||||
- improved the post-processing script to better handle renamed rar-files.
|
||||
|
||||
nzbget-9.0:
|
||||
- changed version naming scheme by removing the leading zero: current
|
||||
|
||||
@@ -74,11 +74,11 @@ void ColoredFrontend::PrintStatus()
|
||||
char tmp[1024];
|
||||
char timeString[100];
|
||||
timeString[0] = '\0';
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
|
||||
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
|
||||
long long remain_sec = m_lRemainingSize / ((long long)(fCurrentDownloadSpeed * 1024));
|
||||
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_iDownloadLimit > 0)
|
||||
if (m_fDownloadLimit > 0.0f)
|
||||
{
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", m_fDownloadLimit);
|
||||
}
|
||||
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, (iCurrentDownloadSpeed >= 10*1024 ? 0 : 1), (float)iCurrentDownloadSpeed / 1024.0,
|
||||
m_iThreadCount, (fCurrentDownloadSpeed >= 10 ? 0 : 1), fCurrentDownloadSpeed,
|
||||
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
|
||||
m_bPauseDownload || m_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
|
||||
szDownloadLimit, szControlSeq);
|
||||
|
||||
254
Connection.cpp
254
Connection.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -54,15 +54,18 @@
|
||||
#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()
|
||||
{
|
||||
debug("Initializing global connection data");
|
||||
@@ -84,7 +87,18 @@ void Connection::Init()
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
TLSSocket::Init();
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -103,7 +117,11 @@ void Connection::Final()
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
TLSSocket::Final();
|
||||
if (bTLSLibInitialized)
|
||||
{
|
||||
debug("Finalizing TLS library");
|
||||
tls_lib_deinit();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -120,15 +138,15 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
|
||||
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_pTLSSocket = NULL;
|
||||
m_pTLS = NULL;
|
||||
m_bTLSError = false;
|
||||
#endif
|
||||
|
||||
@@ -138,23 +156,22 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
|
||||
}
|
||||
}
|
||||
|
||||
Connection::Connection(SOCKET iSocket, bool bTLS)
|
||||
Connection::Connection(SOCKET iSocket, bool bAutoClose)
|
||||
{
|
||||
debug("Creating Connection");
|
||||
|
||||
m_szHost = NULL;
|
||||
m_iPort = 0;
|
||||
m_bTLS = bTLS;
|
||||
m_szCipher = NULL;
|
||||
m_bTLS = false;
|
||||
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_pTLSSocket = NULL;
|
||||
m_bTLSError = false;
|
||||
m_pTLS = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -162,46 +179,23 @@ Connection::~Connection()
|
||||
{
|
||||
debug("Destroying Connection");
|
||||
|
||||
Disconnect();
|
||||
|
||||
if (m_szHost)
|
||||
{
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szCipher)
|
||||
if (m_bAutoClose)
|
||||
{
|
||||
free(m_szCipher);
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
free(m_szReadBuf);
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_pTLSSocket)
|
||||
if (m_pTLS)
|
||||
{
|
||||
delete m_pTLSSocket;
|
||||
free(m_pTLS);
|
||||
}
|
||||
#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");
|
||||
@@ -276,27 +270,18 @@ int Connection::WriteLine(const char* pBuffer)
|
||||
return iRes;
|
||||
}
|
||||
|
||||
bool Connection::Send(const char* pBuffer, int iSize)
|
||||
int Connection::Send(const char* pBuffer, int iSize)
|
||||
{
|
||||
debug("Sending data");
|
||||
|
||||
if (m_eStatus != csConnected)
|
||||
{
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int iBytesSent = 0;
|
||||
while (iBytesSent < iSize)
|
||||
{
|
||||
int iRes = send(m_iSocket, pBuffer + iBytesSent, iSize-iBytesSent, 0);
|
||||
if (iRes <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
iBytesSent += iRes;
|
||||
}
|
||||
int iRes = send(m_iSocket, pBuffer, iSize, 0);
|
||||
|
||||
return true;
|
||||
return iRes;
|
||||
}
|
||||
|
||||
char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
@@ -311,27 +296,21 @@ char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
return res;
|
||||
}
|
||||
|
||||
Connection* Connection::Accept()
|
||||
SOCKET Connection::Accept()
|
||||
{
|
||||
debug("Accepting connection");
|
||||
|
||||
if (m_eStatus != csListening)
|
||||
{
|
||||
return NULL;
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
SOCKET iRes = DoAccept();
|
||||
if (iRes == INVALID_SOCKET)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Connection* pCon = new Connection(iRes, m_bTLS);
|
||||
|
||||
return pCon;
|
||||
return iRes;
|
||||
}
|
||||
|
||||
int Connection::TryRecv(char* pBuffer, int iSize)
|
||||
int Connection::Recv(char* pBuffer, int iSize)
|
||||
{
|
||||
debug("Receiving data");
|
||||
|
||||
@@ -347,7 +326,7 @@ int Connection::TryRecv(char* pBuffer, int iSize)
|
||||
return iReceived;
|
||||
}
|
||||
|
||||
bool Connection::Recv(char * pBuffer, int iSize)
|
||||
bool Connection::RecvAll(char * pBuffer, int iSize)
|
||||
{
|
||||
debug("Receiving data (full buffer)");
|
||||
|
||||
@@ -407,7 +386,6 @@ bool Connection::DoConnect()
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -418,28 +396,15 @@ 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;
|
||||
@@ -460,13 +425,18 @@ bool Connection::DoConnect()
|
||||
int res = connect(m_iSocket , (struct sockaddr *) & sSocketAddress, sizeof(sSocketAddress));
|
||||
if (res == -1)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
// Connection failed
|
||||
closesocket(m_iSocket);
|
||||
m_iSocket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
{
|
||||
ReportError("Connection to %s failed", m_szHost, true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int MSecVal = m_iTimeout * 1000;
|
||||
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&MSecVal, sizeof(MSecVal));
|
||||
@@ -478,11 +448,11 @@ bool Connection::DoConnect()
|
||||
#endif
|
||||
if (err != 0)
|
||||
{
|
||||
ReportError("Socket initialization failed for %s", m_szHost, true, 0);
|
||||
ReportError("setsockopt failed", NULL, true, 0);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_bTLS && !StartTLS(true, NULL, NULL))
|
||||
if (m_bTLS && !StartTLS())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -497,11 +467,14 @@ 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;
|
||||
@@ -682,7 +655,7 @@ int Connection::DoBind()
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(m_iSocket, 100) < 0)
|
||||
if (listen(m_iSocket, 10) < 0)
|
||||
{
|
||||
ReportError("Listen on socket failed for %s", m_szHost, true, 0);
|
||||
return -1;
|
||||
@@ -693,7 +666,7 @@ int Connection::DoBind()
|
||||
|
||||
SOCKET Connection::DoAccept()
|
||||
{
|
||||
SOCKET iSocket = accept(m_iSocket, NULL, NULL);
|
||||
SOCKET iSocket = accept(GetSocket(), NULL, NULL);
|
||||
|
||||
if (iSocket == INVALID_SOCKET && m_eStatus != csCancelled)
|
||||
{
|
||||
@@ -736,9 +709,14 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
{
|
||||
#ifdef WIN32
|
||||
int ErrCode = WSAGetLastError();
|
||||
char szErrMsg[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrCode, 0, szErrMsg, 1024, NULL);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
if (m_bSuppressErrors)
|
||||
{
|
||||
debug("%s: ErrNo %i", szErrPrefix, ErrCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("%s: ErrNo %i", szErrPrefix, ErrCode);
|
||||
}
|
||||
#else
|
||||
const char *szErrMsg = NULL;
|
||||
int ErrCode = herrno;
|
||||
@@ -751,7 +729,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);
|
||||
@@ -760,6 +738,7 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
{
|
||||
error("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -775,40 +754,71 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
bool Connection::StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile)
|
||||
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()
|
||||
{
|
||||
debug("Starting TLS");
|
||||
|
||||
if (m_pTLSSocket)
|
||||
if (m_pTLS)
|
||||
{
|
||||
delete m_pTLSSocket;
|
||||
free(m_pTLS);
|
||||
}
|
||||
|
||||
m_pTLSSocket = new TLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher);
|
||||
m_pTLSSocket->SetSuppressErrors(m_bSuppressErrors);
|
||||
m_pTLS = malloc(sizeof(tls_t));
|
||||
tls_t* pTLS = (tls_t*)m_pTLS;
|
||||
memset(pTLS, 0, sizeof(tls_t));
|
||||
tls_clear(pTLS);
|
||||
|
||||
return m_pTLSSocket->Start();
|
||||
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;
|
||||
}
|
||||
|
||||
void Connection::CloseTLS()
|
||||
{
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
m_pTLSSocket->Close();
|
||||
delete m_pTLSSocket;
|
||||
m_pTLSSocket = NULL;
|
||||
}
|
||||
tls_close((tls_t*)m_pTLS);
|
||||
free(m_pTLS);
|
||||
m_pTLS = NULL;
|
||||
}
|
||||
|
||||
int Connection::recv(SOCKET s, char* buf, int len, int flags)
|
||||
{
|
||||
int iReceived = 0;
|
||||
size_t iReceived = 0;
|
||||
|
||||
if (m_pTLSSocket)
|
||||
if (m_pTLS)
|
||||
{
|
||||
m_bTLSError = false;
|
||||
iReceived = m_pTLSSocket->Recv(buf, len);
|
||||
if (iReceived < 0)
|
||||
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"))
|
||||
{
|
||||
m_bTLSError = true;
|
||||
return -1;
|
||||
@@ -823,23 +833,22 @@ int Connection::recv(SOCKET s, char* buf, int len, int flags)
|
||||
|
||||
int Connection::send(SOCKET s, const char* buf, int len, int flags)
|
||||
{
|
||||
int iSent = 0;
|
||||
|
||||
if (m_pTLSSocket)
|
||||
if (m_pTLS)
|
||||
{
|
||||
m_bTLSError = false;
|
||||
iSent = m_pTLSSocket->Send(buf, len);
|
||||
if (iSent < 0)
|
||||
char* szErrStr;
|
||||
int iRes = tls_putbuf((tls_t*)m_pTLS, buf, len, &szErrStr);
|
||||
if (!CheckTLSResult(iRes, szErrStr, "Could not send to TLS-socket: %s"))
|
||||
{
|
||||
m_bTLSError = true;
|
||||
return -1;
|
||||
}
|
||||
return iSent;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
iSent = ::send(s, buf, len, flags);
|
||||
return iSent;
|
||||
int iRet = ::send(s, buf, len, flags);
|
||||
return iRet;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -893,20 +902,3 @@ 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;
|
||||
}
|
||||
|
||||
32
Connection.h
32
Connection.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -32,9 +32,6 @@
|
||||
#include "Thread.h"
|
||||
#endif
|
||||
#endif
|
||||
#ifndef DISABLE_TLS
|
||||
#include "TLS.h"
|
||||
#endif
|
||||
|
||||
class Connection
|
||||
{
|
||||
@@ -46,22 +43,22 @@ public:
|
||||
csListening,
|
||||
csCancelled
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
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;
|
||||
char m_szRemoteAddr[20];
|
||||
bool m_bAutoClose;
|
||||
#ifndef DISABLE_TLS
|
||||
TLSSocket* m_pTLSSocket;
|
||||
void* m_pTLS;
|
||||
static bool bTLSLibInitialized;
|
||||
bool m_bTLSError;
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
@@ -70,7 +67,6 @@ 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();
|
||||
@@ -82,6 +78,7 @@ protected:
|
||||
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();
|
||||
@@ -89,32 +86,31 @@ protected:
|
||||
|
||||
public:
|
||||
Connection(const char* szHost, int iPort, bool bTLS);
|
||||
Connection(SOCKET iSocket, bool bAutoClose);
|
||||
virtual ~Connection();
|
||||
static void Init();
|
||||
static void Final();
|
||||
bool Connect();
|
||||
bool Disconnect();
|
||||
int Bind();
|
||||
bool Send(const char* pBuffer, int iSize);
|
||||
bool Recv(char* pBuffer, int iSize);
|
||||
int TryRecv(char* pBuffer, int iSize);
|
||||
int Send(const char* pBuffer, int iSize);
|
||||
int Recv(char* pBuffer, int iSize);
|
||||
bool RecvAll(char* pBuffer, int iSize);
|
||||
char* ReadLine(char* pBuffer, int iSize, int* pBytesRead);
|
||||
void ReadBuffer(char** pBuffer, int *iBufLen);
|
||||
int WriteLine(const char* pBuffer);
|
||||
Connection* Accept();
|
||||
SOCKET Accept();
|
||||
void Cancel();
|
||||
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);
|
||||
SOCKET GetSocket() { return m_iSocket; }
|
||||
void SetTimeout(int iTimeout) { m_iTimeout = iTimeout; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetSuppressErrors(bool bSuppressErrors);
|
||||
void SetSuppressErrors(bool bSuppressErrors) { m_bSuppressErrors = bSuppressErrors; }
|
||||
bool GetSuppressErrors() { return m_bSuppressErrors; }
|
||||
const char* GetRemoteAddr();
|
||||
#ifndef DISABLE_TLS
|
||||
bool StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile);
|
||||
bool StartTLS();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
108
DiskState.cpp
108
DiskState.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -82,7 +82,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 21);
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 16);
|
||||
|
||||
// save nzb-infos
|
||||
SaveNZBList(pDownloadQueue, outfile);
|
||||
@@ -136,7 +136,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
int iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (iFormatVersion < 3 || iFormatVersion > 21)
|
||||
if (iFormatVersion < 3 || iFormatVersion > 16)
|
||||
{
|
||||
error("Could not load diskstate due to file version mismatch");
|
||||
fclose(infile);
|
||||
@@ -152,7 +152,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
if (iFormatVersion >= 7)
|
||||
{
|
||||
// load post-queue
|
||||
if (!LoadPostQueue(pDownloadQueue, infile, iFormatVersion)) goto error;
|
||||
if (!LoadPostQueue(pDownloadQueue, infile)) goto error;
|
||||
}
|
||||
else if (iFormatVersion < 7 && g_pOptions->GetReloadPostQueue())
|
||||
{
|
||||
@@ -203,9 +203,9 @@ void DiskState::SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetQueuedFilename());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetName());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetCategory());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetPostProcess());
|
||||
fprintf(outfile, "%i,%i,%i,%i,%i\n", (int)pNZBInfo->GetParStatus(), (int)pNZBInfo->GetUnpackStatus(), (int)pNZBInfo->GetScriptStatus(), (int)pNZBInfo->GetMoveStatus(), (int)pNZBInfo->GetRenameStatus());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetUnpackCleanedUpDisk());
|
||||
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", pNZBInfo->GetFileCount());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetParkedFileCount());
|
||||
|
||||
@@ -298,52 +298,23 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
|
||||
int iPostProcess;
|
||||
if (fscanf(infile, "%i\n", &iPostProcess) != 1) goto error;
|
||||
pNZBInfo->SetPostProcess((bool)iPostProcess);
|
||||
pNZBInfo->SetPostProcess(iPostProcess == 1);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 8 && iFormatVersion < 18)
|
||||
if (iFormatVersion >= 8)
|
||||
{
|
||||
int iParStatus;
|
||||
if (fscanf(infile, "%i\n", &iParStatus) != 1) goto error;
|
||||
pNZBInfo->SetParStatus((NZBInfo::EParStatus)iParStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 9 && iFormatVersion < 18)
|
||||
if (iFormatVersion >= 9)
|
||||
{
|
||||
int iScriptStatus;
|
||||
if (fscanf(infile, "%i\n", &iScriptStatus) != 1) goto error;
|
||||
pNZBInfo->SetScriptStatus((NZBInfo::EScriptStatus)iScriptStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 18)
|
||||
{
|
||||
int iParStatus, iUnpackStatus, iScriptStatus, iMoveStatus = 0, iRenameStatus = 0;
|
||||
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->SetScriptStatus((NZBInfo::EScriptStatus)iScriptStatus);
|
||||
pNZBInfo->SetMoveStatus((NZBInfo::EMoveStatus)iMoveStatus);
|
||||
pNZBInfo->SetRenameStatus((NZBInfo::ERenameStatus)iRenameStatus);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -438,8 +409,8 @@ void DiskState::SaveFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
if (!pFileInfo->GetDeleted())
|
||||
{
|
||||
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pFileInfo->GetNZBInfo());
|
||||
fprintf(outfile, "%i,%i,%i,%i,%i,%i\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused(),
|
||||
(int)pFileInfo->GetTime(), pFileInfo->GetPriority(), (int)pFileInfo->GetExtraPriority());
|
||||
fprintf(outfile, "%i,%i,%i,%i,%i\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused(),
|
||||
(int)pFileInfo->GetTime(), pFileInfo->GetPriority());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,12 +425,8 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
{
|
||||
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)
|
||||
int iPriority = 0;
|
||||
if (iFormatVersion >= 14)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime, &iPriority) != 5) goto error;
|
||||
}
|
||||
@@ -484,7 +451,6 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
|
||||
pFileInfo->SetPaused(paused);
|
||||
pFileInfo->SetTime(iTime);
|
||||
pFileInfo->SetPriority(iPriority);
|
||||
pFileInfo->SetExtraPriority(iExtraPriority != 0);
|
||||
pFileInfo->SetNZBInfo(pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1));
|
||||
pFileQueue->push_back(pFileInfo);
|
||||
}
|
||||
@@ -632,14 +598,14 @@ 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->GetParStatus(), (int)pPostInfo->GetUnpackStatus(), (int)pPostInfo->GetStage());
|
||||
fprintf(outfile, "%i,%i,%i,%i\n", iNZBIndex, (int)pPostInfo->GetParCheck(),
|
||||
(int)pPostInfo->GetParStatus(), (int)pPostInfo->GetStage());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetInfoName());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetParFilename());
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
{
|
||||
debug("Loading post-queue from disk");
|
||||
|
||||
@@ -652,29 +618,15 @@ bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int i
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
PostInfo* pPostInfo = NULL;
|
||||
unsigned int iNZBIndex, iParCheck, iParStatus = 0, iUnpackStatus = 0, iStage;
|
||||
if (iFormatVersion < 19)
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iParCheck, &iParStatus, &iStage) != 4) goto error;
|
||||
if (!iParCheck)
|
||||
{
|
||||
iParStatus = PostInfo::psSkipped;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iParStatus, &iUnpackStatus, &iStage) != 4) 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++;
|
||||
unsigned int iNZBIndex, iParCheck, iParStatus, iStage;
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iParCheck, &iParStatus, &iStage) != 4) goto error;
|
||||
|
||||
if (!bSkipPostQueue)
|
||||
{
|
||||
pPostInfo = new PostInfo();
|
||||
pPostInfo->SetNZBInfo(pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1));
|
||||
pPostInfo->SetParCheck(iParCheck);
|
||||
pPostInfo->SetParStatus((PostInfo::EParStatus)iParStatus);
|
||||
pPostInfo->SetUnpackStatus((PostInfo::EUnpackStatus)iUnpackStatus);
|
||||
pPostInfo->SetStage((PostInfo::EStage)iStage);
|
||||
}
|
||||
|
||||
@@ -819,11 +771,11 @@ bool DiskState::LoadOldPostQueue(DownloadQueue* pDownloadQueue)
|
||||
}
|
||||
}
|
||||
|
||||
int iParCheck;
|
||||
if (fscanf(infile, "%i\n", &iParCheck) != 1) goto error; // ParCheck
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParCheck(iIntValue);
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParStatus(iParCheck ? (PostInfo::EParStatus)iIntValue : PostInfo::psSkipped);
|
||||
pPostInfo->SetParStatus((PostInfo::EParStatus)iIntValue);
|
||||
|
||||
if (iFormatVersion < 7)
|
||||
{
|
||||
@@ -1066,7 +1018,7 @@ bool DiskState::DiscardDownloadQueue()
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
int iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (3 <= iFormatVersion && iFormatVersion <= 21)
|
||||
if (3 <= iFormatVersion && iFormatVersion <= 16)
|
||||
{
|
||||
// skip nzb-infos
|
||||
int size = 0;
|
||||
@@ -1089,22 +1041,14 @@ bool DiskState::DiscardDownloadQueue()
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // category
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // postprocess
|
||||
}
|
||||
if (iFormatVersion >= 8 && iFormatVersion < 18)
|
||||
if (iFormatVersion >= 8)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ParStatus
|
||||
}
|
||||
if (iFormatVersion >= 9 && iFormatVersion < 18)
|
||||
if (iFormatVersion >= 9)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ScriptStatus
|
||||
}
|
||||
if (iFormatVersion >= 18)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ParStatus, UnpackStatus, ScriptStatus
|
||||
}
|
||||
if (iFormatVersion >= 19)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // UnpackCleanedUpDisk
|
||||
}
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // file count
|
||||
if (iFormatVersion >= 10)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -39,7 +39,7 @@ 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, int iFormatVersion);
|
||||
bool LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile);
|
||||
bool LoadOldPostQueue(DownloadQueue* pDownloadQueue);
|
||||
void SaveUrlQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadUrlQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
|
||||
107
DownloadInfo.cpp
107
DownloadInfo.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -130,15 +130,11 @@ NZBInfo::NZBInfo()
|
||||
m_lSize = 0;
|
||||
m_iRefCount = 0;
|
||||
m_bPostProcess = false;
|
||||
m_eRenameStatus = rsNone;
|
||||
m_eParStatus = psNone;
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eMoveStatus = msNone;
|
||||
m_eParStatus = prNone;
|
||||
m_eScriptStatus = srNone;
|
||||
m_bDeleted = false;
|
||||
m_bParCleanup = false;
|
||||
m_bCleanupDisk = false;
|
||||
m_bUnpackCleanedUpDisk = false;
|
||||
m_szQueuedFilename = strdup("");
|
||||
m_Owner = NULL;
|
||||
m_Messages.clear();
|
||||
@@ -290,59 +286,43 @@ void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int i
|
||||
}
|
||||
|
||||
void NZBInfo::BuildDestDirName()
|
||||
{
|
||||
char szDestDir[1024];
|
||||
|
||||
if (strlen(g_pOptions->GetInterDir()) == 0)
|
||||
{
|
||||
BuildFinalDirName(szDestDir, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szDestDir, 1024, "%s%s", g_pOptions->GetInterDir(), GetName());
|
||||
szDestDir[1024-1] = '\0';
|
||||
}
|
||||
|
||||
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)
|
||||
char szCategory[1024];
|
||||
bool bHasCategory = m_szCategory && m_szCategory[0] != '\0';
|
||||
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
|
||||
{
|
||||
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);
|
||||
strncpy(szCategory, m_szCategory, 1024);
|
||||
szCategory[1024 - 1] = '\0';
|
||||
Util::MakeValidFilename(szCategory, '_', true);
|
||||
}
|
||||
|
||||
if (g_pOptions->GetAppendNZBDir())
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s", szFinalDirBuf, GetName());
|
||||
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s%c%s", g_pOptions->GetDestDir(), szCategory, PATH_SEPARATOR, GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szBuffer, 1024, "%s%s", g_pOptions->GetDestDir(), GetName());
|
||||
}
|
||||
szBuffer[1024-1] = '\0';
|
||||
strncpy(szFinalDirBuf, szBuffer, iBufSize);
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
SetDestDir(szBuffer);
|
||||
}
|
||||
|
||||
void NZBInfo::SetParameter(const char* szName, const char* szValue)
|
||||
@@ -368,8 +348,9 @@ void NZBInfo::AppendMessage(Message::EKind eKind, time_t tTime, const char * szT
|
||||
tTime = time(NULL);
|
||||
}
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
m_Messages.push_back(pMessage);
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
@@ -459,7 +440,6 @@ FileInfo::FileInfo()
|
||||
m_Groups.clear();
|
||||
m_szSubject = NULL;
|
||||
m_szFilename = NULL;
|
||||
m_szOutputFilename = NULL;
|
||||
m_bFilenameConfirmed = false;
|
||||
m_lSize = 0;
|
||||
m_lRemainingSize = 0;
|
||||
@@ -470,7 +450,6 @@ FileInfo::FileInfo()
|
||||
m_bOutputInitialized = false;
|
||||
m_pNZBInfo = NULL;
|
||||
m_iPriority = 0;
|
||||
m_bExtraPriority = false;
|
||||
m_iActiveDownloads = 0;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
@@ -488,10 +467,6 @@ FileInfo::~ FileInfo()
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
|
||||
for (Groups::iterator it = m_Groups.begin(); it != m_Groups.end() ;it++)
|
||||
{
|
||||
@@ -564,15 +539,6 @@ void FileInfo::UnlockOutputFile()
|
||||
m_mutexOutputFile.Unlock();
|
||||
}
|
||||
|
||||
void FileInfo::SetOutputFilename(const char* szOutputFilename)
|
||||
{
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
m_szOutputFilename = strdup(szOutputFilename);
|
||||
}
|
||||
|
||||
bool FileInfo::IsDupe(const char* szFilename)
|
||||
{
|
||||
char fileName[1024];
|
||||
@@ -625,11 +591,9 @@ PostInfo::PostInfo()
|
||||
m_szInfoName = NULL;
|
||||
m_bWorking = false;
|
||||
m_bDeleted = false;
|
||||
m_eRenameStatus = rsNone;
|
||||
m_bParCheck = false;
|
||||
m_eParStatus = psNone;
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eRequestParCheck = rpNone;
|
||||
m_bRequestParRename = false;
|
||||
m_eScriptStatus = srNone;
|
||||
m_szProgressLabel = strdup("");
|
||||
m_iFileProgress = 0;
|
||||
@@ -637,7 +601,7 @@ PostInfo::PostInfo()
|
||||
m_tStartTime = 0;
|
||||
m_tStageTime = 0;
|
||||
m_eStage = ptQueued;
|
||||
m_pPostThread = NULL;
|
||||
m_pScriptThread = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDMessageGen = 0;
|
||||
m_iIDGen++;
|
||||
@@ -715,8 +679,9 @@ void PostInfo::UnlockMessages()
|
||||
|
||||
void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -91,10 +91,8 @@ private:
|
||||
bool m_bFilenameConfirmed;
|
||||
int m_iCompleted;
|
||||
bool m_bOutputInitialized;
|
||||
char* m_szOutputFilename;
|
||||
Mutex m_mutexOutputFile;
|
||||
int m_iPriority;
|
||||
bool m_bExtraPriority;
|
||||
int m_iActiveDownloads;
|
||||
|
||||
static int m_iIDGen;
|
||||
@@ -130,15 +128,11 @@ 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) { m_iActiveDownloads = iActiveDownloads; }
|
||||
};
|
||||
@@ -214,29 +208,12 @@ class NZBInfoList;
|
||||
class NZBInfo
|
||||
{
|
||||
public:
|
||||
enum ERenameStatus
|
||||
{
|
||||
rsNone,
|
||||
rsSkipped,
|
||||
rsFailure,
|
||||
rsSuccess
|
||||
};
|
||||
|
||||
enum EParStatus
|
||||
{
|
||||
psNone,
|
||||
psSkipped,
|
||||
psFailure,
|
||||
psSuccess,
|
||||
psRepairPossible
|
||||
};
|
||||
|
||||
enum EUnpackStatus
|
||||
{
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess
|
||||
prNone,
|
||||
prFailure,
|
||||
prRepairPossible,
|
||||
prSuccess
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
@@ -247,13 +224,6 @@ public:
|
||||
srSuccess
|
||||
};
|
||||
|
||||
enum EMoveStatus
|
||||
{
|
||||
msNone,
|
||||
msFailure,
|
||||
msSuccess
|
||||
};
|
||||
|
||||
typedef std::vector<char*> Files;
|
||||
typedef std::deque<Message*> Messages;
|
||||
|
||||
@@ -269,16 +239,12 @@ private:
|
||||
long long m_lSize;
|
||||
Files m_completedFiles;
|
||||
bool m_bPostProcess;
|
||||
ERenameStatus m_eRenameStatus;
|
||||
EParStatus m_eParStatus;
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
EMoveStatus m_eMoveStatus;
|
||||
char* m_szQueuedFilename;
|
||||
bool m_bDeleted;
|
||||
bool m_bParCleanup;
|
||||
bool m_bCleanupDisk;
|
||||
bool m_bUnpackCleanedUpDisk;
|
||||
NZBInfoList* m_Owner;
|
||||
NZBParameterList m_ppParameters;
|
||||
Mutex m_mutexLog;
|
||||
@@ -311,19 +277,12 @@ 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; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; }
|
||||
void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; }
|
||||
EMoveStatus GetMoveStatus() { return m_eMoveStatus; }
|
||||
void SetMoveStatus(EMoveStatus eMoveStatus) { m_eMoveStatus = eMoveStatus; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
void SetScriptStatus(EScriptStatus eScriptStatus) { m_eScriptStatus = eScriptStatus; }
|
||||
const char* GetQueuedFilename() { return m_szQueuedFilename; }
|
||||
@@ -334,8 +293,6 @@ public:
|
||||
void SetParCleanup(bool bParCleanup) { m_bParCleanup = bParCleanup; }
|
||||
bool GetCleanupDisk() { return m_bCleanupDisk; }
|
||||
void SetCleanupDisk(bool bCleanupDisk) { m_bCleanupDisk = bCleanupDisk; }
|
||||
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)
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
@@ -363,25 +320,13 @@ public:
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
ptRenaming,
|
||||
ptUnpacking,
|
||||
ptMoving,
|
||||
ptExecutingScript,
|
||||
ptFinished
|
||||
};
|
||||
|
||||
enum ERenameStatus
|
||||
{
|
||||
rsNone,
|
||||
rsSkipped,
|
||||
rsFailure,
|
||||
rsSuccess
|
||||
};
|
||||
|
||||
enum EParStatus
|
||||
{
|
||||
psNone,
|
||||
psSkipped,
|
||||
psFailure,
|
||||
psSuccess,
|
||||
psRepairPossible
|
||||
@@ -394,14 +339,6 @@ public:
|
||||
rpAll
|
||||
};
|
||||
|
||||
enum EUnpackStatus
|
||||
{
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
{
|
||||
srNone,
|
||||
@@ -419,19 +356,17 @@ private:
|
||||
char* m_szInfoName;
|
||||
bool m_bWorking;
|
||||
bool m_bDeleted;
|
||||
ERenameStatus m_eRenameStatus;
|
||||
bool m_bParCheck;
|
||||
EParStatus m_eParStatus;
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
ERequestParCheck m_eRequestParCheck;
|
||||
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_pPostThread;
|
||||
Thread* m_pScriptThread;
|
||||
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
@@ -465,21 +400,17 @@ public:
|
||||
void SetWorking(bool bWorking) { m_bWorking = bWorking; }
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
|
||||
ERenameStatus GetRenameStatus() { return m_eRenameStatus; }
|
||||
void SetRenameStatus(ERenameStatus eRenameStatus) { m_eRenameStatus = eRenameStatus; }
|
||||
bool GetParCheck() { return m_bParCheck; }
|
||||
void SetParCheck(bool bParCheck) { m_bParCheck = bParCheck; }
|
||||
EParStatus GetParStatus() { return m_eParStatus; }
|
||||
void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; }
|
||||
void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; }
|
||||
ERequestParCheck GetRequestParCheck() { return m_eRequestParCheck; }
|
||||
void SetRequestParCheck(ERequestParCheck eRequestParCheck) { m_eRequestParCheck = eRequestParCheck; }
|
||||
bool GetRequestParRename() { return m_bRequestParRename; }
|
||||
void SetRequestParRename(bool bRequestParRename) { m_bRequestParRename = bRequestParRename; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
void SetScriptStatus(EScriptStatus eScriptStatus) { m_eScriptStatus = eScriptStatus; }
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
Thread* GetPostThread() { return m_pPostThread; }
|
||||
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
|
||||
Thread* GetScriptThread() { return m_pScriptThread; }
|
||||
void SetScriptThread(Thread* pScriptThread) { m_pScriptThread = pScriptThread; }
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
};
|
||||
|
||||
39
Frontend.cpp
39
Frontend.cpp
@@ -63,11 +63,11 @@ Frontend::Frontend()
|
||||
m_iNeededLogEntries = 0;
|
||||
m_bSummary = false;
|
||||
m_bFileList = false;
|
||||
m_iCurrentDownloadSpeed = 0;
|
||||
m_fCurrentDownloadSpeed = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_bPauseDownload = false;
|
||||
m_bPauseDownload2 = false;
|
||||
m_iDownloadLimit = 0;
|
||||
m_fDownloadLimit = 0;
|
||||
m_iThreadCount = 0;
|
||||
m_iPostJobCount = 0;
|
||||
m_iUpTimeSec = 0;
|
||||
@@ -96,11 +96,11 @@ bool Frontend::PrepareData()
|
||||
{
|
||||
if (m_bSummary)
|
||||
{
|
||||
m_iCurrentDownloadSpeed = g_pQueueCoordinator->CalcCurrentDownloadSpeed();
|
||||
m_fCurrentDownloadSpeed = g_pQueueCoordinator->CalcCurrentDownloadSpeed();
|
||||
m_lRemainingSize = g_pQueueCoordinator->CalcRemainingSize();
|
||||
m_bPauseDownload = g_pOptions->GetPauseDownload();
|
||||
m_bPauseDownload2 = g_pOptions->GetPauseDownload2();
|
||||
m_iDownloadLimit = g_pOptions->GetDownloadRate();
|
||||
m_fDownloadLimit = g_pOptions->GetDownloadRate();
|
||||
m_iThreadCount = Thread::GetThreadCount();
|
||||
PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue();
|
||||
m_iPostJobCount = pPostQueue->size();
|
||||
@@ -182,7 +182,6 @@ void Frontend::ServerPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pOptions->SetResumeTime(0);
|
||||
if (bSecondRegister)
|
||||
{
|
||||
g_pOptions->SetPauseDownload2(bPause);
|
||||
@@ -194,15 +193,15 @@ void Frontend::ServerPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
}
|
||||
}
|
||||
|
||||
void Frontend::ServerSetDownloadRate(int iRate)
|
||||
void Frontend::ServerSetDownloadRate(float fRate)
|
||||
{
|
||||
if (IsRemoteMode())
|
||||
{
|
||||
RequestSetDownloadRate(iRate);
|
||||
RequestSetDownloadRate(fRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pOptions->SetDownloadRate(iRate);
|
||||
g_pOptions->SetDownloadRate(fRate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,15 +261,15 @@ bool Frontend::RequestMessages()
|
||||
LogRequest.m_iIDFrom = 0;
|
||||
}
|
||||
|
||||
if (!connection.Send((char*)(&LogRequest), sizeof(LogRequest)))
|
||||
if (connection.Send((char*)(&LogRequest), sizeof(LogRequest)) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now listen for the returned log
|
||||
SNZBLogResponse LogResponse;
|
||||
bool bRead = connection.Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = connection.Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (iResponseLen != sizeof(LogResponse) ||
|
||||
(int)ntohl(LogResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(LogResponse.m_MessageBase.m_iStructSize) != sizeof(LogResponse))
|
||||
{
|
||||
@@ -281,7 +280,7 @@ bool Frontend::RequestMessages()
|
||||
if (ntohl(LogResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(LogResponse.m_iTrailingDataLength));
|
||||
if (!connection.Recv(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
if (!connection.RecvAll(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -326,15 +325,15 @@ bool Frontend::RequestFileList()
|
||||
ListRequest.m_bFileList = htonl(m_bFileList);
|
||||
ListRequest.m_bServerState = htonl(m_bSummary);
|
||||
|
||||
if (!connection.Send((char*)(&ListRequest), sizeof(ListRequest)))
|
||||
if (connection.Send((char*)(&ListRequest), sizeof(ListRequest)) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBListResponse ListResponse;
|
||||
bool bRead = connection.Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = connection.Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (iResponseLen != sizeof(ListResponse) ||
|
||||
(int)ntohl(ListResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(ListResponse.m_MessageBase.m_iStructSize) != sizeof(ListResponse))
|
||||
{
|
||||
@@ -345,7 +344,7 @@ bool Frontend::RequestFileList()
|
||||
if (ntohl(ListResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(ListResponse.m_iTrailingDataLength));
|
||||
if (!connection.Recv(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
if (!connection.RecvAll(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -359,8 +358,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_iCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate);
|
||||
m_iDownloadLimit = ntohl(ListResponse.m_iDownloadLimit);
|
||||
m_fCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate) / 1024.0f;
|
||||
m_fDownloadLimit = ntohl(ListResponse.m_iDownloadLimit) / 1024.0f;
|
||||
m_iThreadCount = ntohl(ListResponse.m_iThreadCount);
|
||||
m_iPostJobCount = ntohl(ListResponse.m_iPostJobCount);
|
||||
m_iUpTimeSec = ntohl(ListResponse.m_iUpTimeSec);
|
||||
@@ -391,11 +390,11 @@ bool Frontend::RequestPauseUnpause(bool bPause, bool bSecondRegister)
|
||||
return client.RequestServerPauseUnpause(bPause, bSecondRegister ? eRemotePauseUnpauseActionDownload2 : eRemotePauseUnpauseActionDownload);
|
||||
}
|
||||
|
||||
bool Frontend::RequestSetDownloadRate(int iRate)
|
||||
bool Frontend::RequestSetDownloadRate(float fRate)
|
||||
{
|
||||
RemoteClient client;
|
||||
client.SetVerbose(false);
|
||||
return client.RequestServerSetDownloadRate(iRate);
|
||||
return client.RequestServerSetDownloadRate(fRate);
|
||||
}
|
||||
|
||||
bool Frontend::RequestDumpDebug()
|
||||
|
||||
@@ -50,11 +50,11 @@ protected:
|
||||
int m_iUpdateInterval;
|
||||
|
||||
// summary
|
||||
int m_iCurrentDownloadSpeed;
|
||||
float m_fCurrentDownloadSpeed;
|
||||
long long m_lRemainingSize;
|
||||
bool m_bPauseDownload;
|
||||
bool m_bPauseDownload2;
|
||||
int m_iDownloadLimit;
|
||||
float m_fDownloadLimit;
|
||||
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(int iRate);
|
||||
bool RequestSetDownloadRate(int iRate);
|
||||
void ServerSetDownloadRate(float fRate);
|
||||
bool RequestSetDownloadRate(float fRate);
|
||||
void ServerDumpDebug();
|
||||
bool RequestDumpDebug();
|
||||
bool ServerEditQueue(QueueEditor::EEditAction eAction, int iOffset, int iEntry);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-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
|
||||
@@ -28,13 +28,13 @@ nzbget_SOURCES = \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.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 \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.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 WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
UrlCoordinator.cpp UrlCoordinator.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd nzbget-postprocess.sh \
|
||||
|
||||
28
Makefile.in
28
Makefile.in
@@ -17,7 +17,7 @@
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-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
|
||||
@@ -89,16 +89,14 @@ am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
Frontend.$(OBJEXT) Log.$(OBJEXT) LoggableFrontend.$(OBJEXT) \
|
||||
NCursesFrontend.$(OBJEXT) NNTPConnection.$(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) \
|
||||
Options.$(OBJEXT) ParChecker.$(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) WebDownloader.$(OBJEXT) \
|
||||
WebServer.$(OBJEXT) UrlCoordinator.$(OBJEXT) Unpack.$(OBJEXT) \
|
||||
nzbget.$(OBJEXT)
|
||||
WebServer.$(OBJEXT) UrlCoordinator.$(OBJEXT) nzbget.$(OBJEXT)
|
||||
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
|
||||
nzbget_LDADD = $(LDADD)
|
||||
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
|
||||
@@ -143,13 +141,16 @@ DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_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@
|
||||
@@ -227,8 +228,6 @@ 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@
|
||||
@@ -248,13 +247,13 @@ nzbget_SOURCES = \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.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 \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.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 WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
UrlCoordinator.cpp UrlCoordinator.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd nzbget-postprocess.sh \
|
||||
@@ -444,8 +443,6 @@ distclean-compile:
|
||||
@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@
|
||||
@@ -457,7 +454,6 @@ 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@
|
||||
|
||||
@@ -613,10 +613,10 @@ void NCursesFrontend::PrintStatus()
|
||||
char timeString[100];
|
||||
timeString[0] = '\0';
|
||||
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
|
||||
long long remain_sec = (long long)(m_lRemainingSize / (fCurrentDownloadSpeed * 1024));
|
||||
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_iDownloadLimit > 0)
|
||||
if (m_fDownloadLimit > 0.0f)
|
||||
{
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", (float)m_iDownloadLimit / 1024.0);
|
||||
sprintf(szDownloadLimit, ", Limit %.0f KB/s", m_fDownloadLimit);
|
||||
}
|
||||
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, (iCurrentDownloadSpeed >= 10*1024 ? 0 : 1), (float)iCurrentDownloadSpeed / 1024.0,
|
||||
m_iThreadCount, (fCurrentDownloadSpeed >= 10 ? 0 : 1), fCurrentDownloadSpeed,
|
||||
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
|
||||
m_bPauseDownload || m_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
|
||||
m_bPauseDownload || m_bPauseDownload2 ?
|
||||
@@ -1065,15 +1065,15 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
|
||||
|
||||
char szTime[100];
|
||||
szTime[0] = '\0';
|
||||
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
|
||||
float fCurrentDownloadSpeed = m_bStandBy ? 0 : m_fCurrentDownloadSpeed;
|
||||
if (pGroupInfo->GetPausedSize() > 0 && lUnpausedRemainingSize == 0)
|
||||
{
|
||||
snprintf(szTime, 100, "[paused]");
|
||||
Util::FormatFileSize(szRemaining, sizeof(szRemaining), pGroupInfo->GetRemainingSize());
|
||||
}
|
||||
else if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
else if (fCurrentDownloadSpeed > 0.0 && !(m_bPauseDownload || m_bPauseDownload2))
|
||||
{
|
||||
long long remain_sec = (long long)(lUnpausedRemainingSize / iCurrentDownloadSpeed);
|
||||
long long remain_sec = (long long)(lUnpausedRemainingSize / (fCurrentDownloadSpeed * 1024));
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
@@ -1448,7 +1448,7 @@ void NCursesFrontend::UpdateInput(int initialKey)
|
||||
// Enter
|
||||
else if (iKey == 10 || iKey == 13)
|
||||
{
|
||||
ServerSetDownloadRate(m_iInputValue * 1024);
|
||||
ServerSetDownloadRate((float)m_iInputValue);
|
||||
m_eInputMode = eNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ NNTPConnection::NNTPConnection(NewsServer* pNewsServer) : Connection(pNewsServer
|
||||
m_szActiveGroup = NULL;
|
||||
m_szLineBuf = (char*)malloc(CONNECTION_LINEBUFFER_SIZE);
|
||||
m_bAuthError = false;
|
||||
SetCipher(pNewsServer->GetCipher());
|
||||
}
|
||||
|
||||
NNTPConnection::~NNTPConnection()
|
||||
@@ -128,7 +127,7 @@ 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", GetHost(), false, 0);
|
||||
ReportError("Authorization for %s failed: Connection closed by remote host.", GetHost(), true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,7 +170,7 @@ 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", GetHost(), false, 0);
|
||||
ReportError("Authorization for %s failed: Connection closed by remote host.", GetHost(), true, 0);
|
||||
return false;
|
||||
}
|
||||
else if (!strncmp(answer, "2", 1))
|
||||
@@ -243,7 +242,7 @@ bool NNTPConnection::DoConnect()
|
||||
|
||||
if (!answer)
|
||||
{
|
||||
ReportError("Connection to %s failed: Connection closed by remote host", GetHost(), false, 0);
|
||||
ReportError("Connection to %s failed: Connection closed by remote host.", GetHost(), true, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,23 +38,29 @@
|
||||
#include "nzbget.h"
|
||||
#include "NewsServer.h"
|
||||
|
||||
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::NewsServer(const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS, int iMaxConnections, int iLevel)
|
||||
{
|
||||
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;
|
||||
m_szHost = szHost ? strdup(szHost) : NULL;
|
||||
m_szUser = szUser ? strdup(szUser) : NULL;
|
||||
m_szPassword = szPass ? strdup(szPass) : NULL;
|
||||
m_szCipher = szCipher ? strdup(szCipher) : NULL;
|
||||
|
||||
if (szHost)
|
||||
{
|
||||
m_szHost = strdup(szHost);
|
||||
}
|
||||
if (szUser)
|
||||
{
|
||||
m_szUser = strdup(szUser);
|
||||
}
|
||||
if (szPass)
|
||||
{
|
||||
m_szPassword = strdup(szPass);
|
||||
}
|
||||
}
|
||||
|
||||
NewsServer::~NewsServer()
|
||||
@@ -71,8 +77,4 @@ NewsServer::~NewsServer()
|
||||
{
|
||||
free(m_szPassword);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
}
|
||||
|
||||
10
NewsServer.h
10
NewsServer.h
@@ -30,8 +30,6 @@
|
||||
class NewsServer
|
||||
{
|
||||
private:
|
||||
int m_iID;
|
||||
int m_iGroup;
|
||||
char* m_szHost;
|
||||
int m_iPort;
|
||||
char* m_szUser;
|
||||
@@ -40,24 +38,18 @@ private:
|
||||
int m_iLevel;
|
||||
bool m_bJoinGroup;
|
||||
bool m_bTLS;
|
||||
char* m_szCipher;
|
||||
|
||||
public:
|
||||
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(const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS, int iMaxConnections, int iLevel);
|
||||
~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
|
||||
|
||||
270
Options.cpp
270
Options.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -97,7 +97,6 @@ static const char* OPTION_APPDIR = "AppDir";
|
||||
static const char* OPTION_VERSION = "Version";
|
||||
static const char* OPTION_MAINDIR = "MainDir";
|
||||
static const char* OPTION_DESTDIR = "DestDir";
|
||||
static const char* OPTION_INTERDIR = "InterDir";
|
||||
static const char* OPTION_TEMPDIR = "TempDir";
|
||||
static const char* OPTION_QUEUEDIR = "QueueDir";
|
||||
static const char* OPTION_NZBDIR = "NzbDir";
|
||||
@@ -115,10 +114,6 @@ static const char* OPTION_RENAMEBROKEN = "RenameBroken";
|
||||
static const char* OPTION_CONTROLIP = "ControlIp";
|
||||
static const char* OPTION_CONTROLPORT = "ControlPort";
|
||||
static const char* OPTION_CONTROLPASSWORD = "ControlPassword";
|
||||
static const char* OPTION_SECURECONTROL = "SecureControl";
|
||||
static const char* OPTION_SECUREPORT = "SecurePort";
|
||||
static const char* OPTION_SECURECERT = "SecureCert";
|
||||
static const char* OPTION_SECUREKEY = "SecureKey";
|
||||
static const char* OPTION_CONNECTIONTIMEOUT = "ConnectionTimeout";
|
||||
static const char* OPTION_SAVEQUEUE = "SaveQueue";
|
||||
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
|
||||
@@ -153,6 +148,7 @@ static const char* OPTION_CURSESNZBNAME = "CursesNzbName";
|
||||
static const char* OPTION_CURSESTIME = "CursesTime";
|
||||
static const char* OPTION_CURSESGROUP = "CursesGroup";
|
||||
static const char* OPTION_CRCCHECK = "CrcCheck";
|
||||
static const char* OPTION_RETRYONCRCERROR = "RetryOnCrcError";
|
||||
static const char* OPTION_THREADLIMIT = "ThreadLimit";
|
||||
static const char* OPTION_DIRECTWRITE = "DirectWrite";
|
||||
static const char* OPTION_WRITEBUFFERSIZE = "WriteBufferSize";
|
||||
@@ -171,16 +167,10 @@ static const char* OPTION_MERGENZB = "MergeNzb";
|
||||
static const char* OPTION_PARTIMELIMIT = "ParTimeLimit";
|
||||
static const char* OPTION_KEEPHISTORY = "KeepHistory";
|
||||
static const char* OPTION_ACCURATERATE = "AccurateRate";
|
||||
static const char* OPTION_UNPACK = "Unpack";
|
||||
static const char* OPTION_UNPACKCLEANUPDISK = "UnpackCleanupDisk";
|
||||
static const char* OPTION_UNRARCMD = "UnrarCmd";
|
||||
static const char* OPTION_SEVENZIPCMD = "SevenZipCmd";
|
||||
static const char* OPTION_UNPACKPAUSEQUEUE = "UnpackPauseQueue";
|
||||
|
||||
// obsolete options
|
||||
static const char* OPTION_POSTLOGKIND = "PostLogKind";
|
||||
static const char* OPTION_NZBLOGKIND = "NZBLogKind";
|
||||
static const char* OPTION_RETRYONCRCERROR = "RetryOnCrcError";
|
||||
static const char* OPTION_POSTLOGKIND = "PostLogKind";
|
||||
static const char* OPTION_NZBLOGKIND = "NZBLogKind";
|
||||
|
||||
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable", "enabled", "disabled" };
|
||||
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||
@@ -261,9 +251,9 @@ Options::OptEntries::~OptEntries()
|
||||
}
|
||||
}
|
||||
|
||||
Options::OptEntry* Options::OptEntries::FindOption(const char* szName)
|
||||
Options::OptEntry* Options::OptEntries::FindOption(const char* optname)
|
||||
{
|
||||
if (!szName)
|
||||
if (!optname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -271,7 +261,7 @@ Options::OptEntry* Options::OptEntries::FindOption(const char* szName)
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
OptEntry* pOptEntry = *it;
|
||||
if (!strcasecmp(pOptEntry->GetName(), szName))
|
||||
if (!strcasecmp(pOptEntry->GetName(), optname))
|
||||
{
|
||||
return pOptEntry;
|
||||
}
|
||||
@@ -281,52 +271,6 @@ Options::OptEntry* Options::OptEntries::FindOption(const char* szName)
|
||||
}
|
||||
|
||||
|
||||
Options::Category::Category(const char* szName, const char* szDestDir)
|
||||
{
|
||||
m_szName = strdup(szName);
|
||||
m_szDestDir = szDestDir ? strdup(szDestDir) : NULL;
|
||||
}
|
||||
|
||||
Options::Category::~Category()
|
||||
{
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
}
|
||||
|
||||
Options::Categories::~Categories()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
Options::Category* Options::Categories::FindCategory(const char* szName)
|
||||
{
|
||||
if (!szName)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
Category* pCategory = *it;
|
||||
if (!strcasecmp(pCategory->GetName(), szName))
|
||||
{
|
||||
return pCategory;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Options::Options(int argc, char* argv[])
|
||||
{
|
||||
m_bConfigErrors = false;
|
||||
@@ -336,7 +280,6 @@ Options::Options(int argc, char* argv[])
|
||||
m_bConfigInitialized = false;
|
||||
m_szConfigFilename = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_szInterDir = NULL;
|
||||
m_szTempDir = NULL;
|
||||
m_szQueueDir = NULL;
|
||||
m_szNzbDir = NULL;
|
||||
@@ -353,7 +296,7 @@ Options::Options(int argc, char* argv[])
|
||||
m_bPauseScan = false;
|
||||
m_bCreateBrokenLog = false;
|
||||
m_bResetLog = false;
|
||||
m_iDownloadRate = 0;
|
||||
m_fDownloadRate = 0;
|
||||
m_iEditQueueAction = 0;
|
||||
m_pEditQueueIDList = NULL;
|
||||
m_iEditQueueIDCount = 0;
|
||||
@@ -380,13 +323,9 @@ Options::Options(int argc, char* argv[])
|
||||
m_bDupeCheck = false;
|
||||
m_iRetries = 0;
|
||||
m_iRetryInterval = 0;
|
||||
m_iControlPort = 0;
|
||||
m_szControlPort = 0;
|
||||
m_szControlIP = NULL;
|
||||
m_szControlPassword = NULL;
|
||||
m_bSecureControl = false;
|
||||
m_iSecurePort = 0;
|
||||
m_szSecureCert = NULL;
|
||||
m_szSecureKey = NULL;
|
||||
m_szLockFile = NULL;
|
||||
m_szDaemonUserName = NULL;
|
||||
m_eOutputMode = omLoggable;
|
||||
@@ -415,6 +354,7 @@ Options::Options(int argc, char* argv[])
|
||||
m_bCursesTime = false;
|
||||
m_bCursesGroup = false;
|
||||
m_bCrcCheck = false;
|
||||
m_bRetryOnCrcError = false;
|
||||
m_bDirectWrite = false;
|
||||
m_iThreadLimit = 0;
|
||||
m_iWriteBufferSize = 0;
|
||||
@@ -436,12 +376,6 @@ Options::Options(int argc, char* argv[])
|
||||
m_iKeepHistory = 0;
|
||||
m_bAccurateRate = false;
|
||||
m_EMatchMode = mmID;
|
||||
m_tResumeTime = 0;
|
||||
m_bUnpack = false;
|
||||
m_bUnpackCleanupDisk = false;
|
||||
m_szUnrarCmd = NULL;
|
||||
m_szSevenZipCmd = NULL;
|
||||
m_bUnpackPauseQueue = false;
|
||||
|
||||
// Option "ConfigFile" will be initialized later, but we want
|
||||
// to see it at the top of option list, so we add it first
|
||||
@@ -493,7 +427,6 @@ Options::Options(int argc, char* argv[])
|
||||
}
|
||||
|
||||
InitOptions();
|
||||
CheckOptions();
|
||||
|
||||
if (!m_bPrintOptions)
|
||||
{
|
||||
@@ -501,8 +434,8 @@ Options::Options(int argc, char* argv[])
|
||||
}
|
||||
|
||||
InitServers();
|
||||
InitCategories();
|
||||
InitScheduler();
|
||||
CheckOptions();
|
||||
|
||||
if (m_bPrintOptions)
|
||||
{
|
||||
@@ -530,10 +463,6 @@ Options::~Options()
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szInterDir)
|
||||
{
|
||||
free(m_szInterDir);
|
||||
}
|
||||
if (m_szTempDir)
|
||||
{
|
||||
free(m_szTempDir);
|
||||
@@ -574,14 +503,6 @@ Options::~Options()
|
||||
{
|
||||
free(m_szControlPassword);
|
||||
}
|
||||
if (m_szSecureCert)
|
||||
{
|
||||
free(m_szSecureCert);
|
||||
}
|
||||
if (m_szSecureKey)
|
||||
{
|
||||
free(m_szSecureKey);
|
||||
}
|
||||
if (m_szLogFile)
|
||||
{
|
||||
free(m_szLogFile);
|
||||
@@ -618,14 +539,6 @@ Options::~Options()
|
||||
{
|
||||
free(m_szAddNZBFilename);
|
||||
}
|
||||
if (m_szUnrarCmd)
|
||||
{
|
||||
free(m_szUnrarCmd);
|
||||
}
|
||||
if (m_szSevenZipCmd)
|
||||
{
|
||||
free(m_szSevenZipCmd);
|
||||
}
|
||||
|
||||
for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++)
|
||||
{
|
||||
@@ -659,33 +572,6 @@ void Options::ConfigError(const char* msg, ...)
|
||||
m_bConfigErrors = true;
|
||||
}
|
||||
|
||||
void Options::ConfigWarn(const char* msg, ...)
|
||||
{
|
||||
char tmp2[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vsnprintf(tmp2, 1024, msg, ap);
|
||||
tmp2[1024-1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
printf("%s(%i): %s\n", Util::BaseFileName(m_szConfigFilename), m_iConfigLine, tmp2);
|
||||
warn("%s(%i): %s", Util::BaseFileName(m_szConfigFilename), m_iConfigLine, tmp2);
|
||||
}
|
||||
|
||||
void Options::LocateOptionSrcPos(const char *szOptionName)
|
||||
{
|
||||
OptEntry* pOptEntry = FindOption(szOptionName);
|
||||
if (pOptEntry)
|
||||
{
|
||||
m_iConfigLine = pOptEntry->GetLineNo();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iConfigLine = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Options::InitDefault()
|
||||
{
|
||||
#ifdef WIN32
|
||||
@@ -695,7 +581,6 @@ void Options::InitDefault()
|
||||
#endif
|
||||
SetOption(OPTION_TEMPDIR, "${MainDir}/tmp");
|
||||
SetOption(OPTION_DESTDIR, "${MainDir}/dst");
|
||||
SetOption(OPTION_INTERDIR, "");
|
||||
SetOption(OPTION_QUEUEDIR, "${MainDir}/queue");
|
||||
SetOption(OPTION_NZBDIR, "${MainDir}/nzb");
|
||||
SetOption(OPTION_LOCKFILE, "${MainDir}/nzbget.lock");
|
||||
@@ -711,10 +596,6 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_CONTROLIP, "0.0.0.0");
|
||||
SetOption(OPTION_CONTROLPASSWORD, "tegbzn6789");
|
||||
SetOption(OPTION_CONTROLPORT, "6789");
|
||||
SetOption(OPTION_SECURECONTROL, "no");
|
||||
SetOption(OPTION_SECUREPORT, "6791");
|
||||
SetOption(OPTION_SECURECERT, "");
|
||||
SetOption(OPTION_SECUREKEY, "");
|
||||
SetOption(OPTION_CONNECTIONTIMEOUT, "60");
|
||||
SetOption(OPTION_SAVEQUEUE, "yes");
|
||||
SetOption(OPTION_RELOADQUEUE, "yes");
|
||||
@@ -750,6 +631,7 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_CURSESTIME, "no");
|
||||
SetOption(OPTION_CURSESGROUP, "no");
|
||||
SetOption(OPTION_CRCCHECK, "yes");
|
||||
SetOption(OPTION_RETRYONCRCERROR, "no");
|
||||
SetOption(OPTION_THREADLIMIT, "100");
|
||||
SetOption(OPTION_DIRECTWRITE, "yes");
|
||||
SetOption(OPTION_WRITEBUFFERSIZE, "0");
|
||||
@@ -768,16 +650,6 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_PARTIMELIMIT, "0");
|
||||
SetOption(OPTION_KEEPHISTORY, "7");
|
||||
SetOption(OPTION_ACCURATERATE, "no");
|
||||
SetOption(OPTION_UNPACK, "no");
|
||||
SetOption(OPTION_UNPACKCLEANUPDISK, "no");
|
||||
#ifdef WIN32
|
||||
SetOption(OPTION_UNRARCMD, "unrar.exe");
|
||||
SetOption(OPTION_SEVENZIPCMD, "7z.exe");
|
||||
#else
|
||||
SetOption(OPTION_UNRARCMD, "unrar");
|
||||
SetOption(OPTION_SEVENZIPCMD, "7z");
|
||||
#endif
|
||||
SetOption(OPTION_UNPACKPAUSEQUEUE, "no");
|
||||
}
|
||||
|
||||
void Options::InitOptFile()
|
||||
@@ -891,7 +763,6 @@ void Options::CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, b
|
||||
void Options::InitOptions()
|
||||
{
|
||||
CheckDir(&m_szDestDir, OPTION_DESTDIR, false, true);
|
||||
CheckDir(&m_szInterDir, OPTION_INTERDIR, true, true);
|
||||
CheckDir(&m_szTempDir, OPTION_TEMPDIR, false, true);
|
||||
CheckDir(&m_szQueueDir, OPTION_QUEUEDIR, false, true);
|
||||
CheckDir(&m_szWebDir, OPTION_WEBDIR, true, false);
|
||||
@@ -901,21 +772,16 @@ void Options::InitOptions()
|
||||
m_szNZBAddedProcess = strdup(GetOption(OPTION_NZBADDEDPROCESS));
|
||||
m_szControlIP = strdup(GetOption(OPTION_CONTROLIP));
|
||||
m_szControlPassword = strdup(GetOption(OPTION_CONTROLPASSWORD));
|
||||
m_szSecureCert = strdup(GetOption(OPTION_SECURECERT));
|
||||
m_szSecureKey = strdup(GetOption(OPTION_SECUREKEY));
|
||||
m_szLockFile = strdup(GetOption(OPTION_LOCKFILE));
|
||||
m_szDaemonUserName = strdup(GetOption(OPTION_DAEMONUSERNAME));
|
||||
m_szLogFile = strdup(GetOption(OPTION_LOGFILE));
|
||||
m_szUnrarCmd = strdup(GetOption(OPTION_UNRARCMD));
|
||||
m_szSevenZipCmd = strdup(GetOption(OPTION_SEVENZIPCMD));
|
||||
|
||||
m_iDownloadRate = (int)(ParseFloatValue(OPTION_DOWNLOADRATE) * 1024);
|
||||
m_fDownloadRate = ParseFloatValue(OPTION_DOWNLOADRATE);
|
||||
m_iConnectionTimeout = ParseIntValue(OPTION_CONNECTIONTIMEOUT, 10);
|
||||
m_iTerminateTimeout = ParseIntValue(OPTION_TERMINATETIMEOUT, 10);
|
||||
m_iRetries = ParseIntValue(OPTION_RETRIES, 10);
|
||||
m_iRetryInterval = ParseIntValue(OPTION_RETRYINTERVAL, 10);
|
||||
m_iControlPort = ParseIntValue(OPTION_CONTROLPORT, 10);
|
||||
m_iSecurePort = ParseIntValue(OPTION_SECUREPORT, 10);
|
||||
m_szControlPort = ParseIntValue(OPTION_CONTROLPORT, 10);
|
||||
m_iUrlConnections = ParseIntValue(OPTION_URLCONNECTIONS, 10);
|
||||
m_iLogBufferSize = ParseIntValue(OPTION_LOGBUFFERSIZE, 10);
|
||||
m_iUMask = ParseIntValue(OPTION_UMASK, 8);
|
||||
@@ -949,6 +815,7 @@ void Options::InitOptions()
|
||||
m_bCursesTime = (bool)ParseEnumValue(OPTION_CURSESTIME, BoolCount, BoolNames, BoolValues);
|
||||
m_bCursesGroup = (bool)ParseEnumValue(OPTION_CURSESGROUP, BoolCount, BoolNames, BoolValues);
|
||||
m_bCrcCheck = (bool)ParseEnumValue(OPTION_CRCCHECK, BoolCount, BoolNames, BoolValues);
|
||||
m_bRetryOnCrcError = (bool)ParseEnumValue(OPTION_RETRYONCRCERROR, BoolCount, BoolNames, BoolValues);
|
||||
m_bDirectWrite = (bool)ParseEnumValue(OPTION_DIRECTWRITE, BoolCount, BoolNames, BoolValues);
|
||||
m_bParCleanupQueue = (bool)ParseEnumValue(OPTION_PARCLEANUPQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
m_bDecode = (bool)ParseEnumValue(OPTION_DECODE, BoolCount, BoolNames, BoolValues);
|
||||
@@ -960,10 +827,6 @@ void Options::InitOptions()
|
||||
m_bDeleteCleanupDisk = (bool)ParseEnumValue(OPTION_DELETECLEANUPDISK, BoolCount, BoolNames, BoolValues);
|
||||
m_bMergeNzb = (bool)ParseEnumValue(OPTION_MERGENZB, BoolCount, BoolNames, BoolValues);
|
||||
m_bAccurateRate = (bool)ParseEnumValue(OPTION_ACCURATERATE, BoolCount, BoolNames, BoolValues);
|
||||
m_bSecureControl = (bool)ParseEnumValue(OPTION_SECURECONTROL, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpack = (bool)ParseEnumValue(OPTION_UNPACK, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpackCleanupDisk = (bool)ParseEnumValue(OPTION_UNPACKCLEANUPDISK, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpackPauseQueue = (bool)ParseEnumValue(OPTION_UNPACKPAUSEQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
|
||||
const char* OutputModeNames[] = { "loggable", "logable", "log", "colored", "color", "ncurses", "curses" };
|
||||
const int OutputModeValues[] = { omLoggable, omLoggable, omLoggable, omColored, omColored, omNCurses, omNCurses };
|
||||
@@ -1319,7 +1182,7 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
break;
|
||||
case 'R':
|
||||
m_eClientOperation = opClientRequestSetRate;
|
||||
m_iSetRate = (int)(atof(optarg)*1024);
|
||||
m_fSetRate = (float)atof(optarg);
|
||||
break;
|
||||
case 'B':
|
||||
if (!strcasecmp(optarg, "dump"))
|
||||
@@ -1890,9 +1753,6 @@ void Options::InitServers()
|
||||
sprintf(optname, "Server%i.Level", n);
|
||||
const char* nlevel = GetOption(optname);
|
||||
|
||||
sprintf(optname, "Server%i.Group", n);
|
||||
const char* ngroup = GetOption(optname);
|
||||
|
||||
sprintf(optname, "Server%i.Host", n);
|
||||
const char* nhost = GetOption(optname);
|
||||
|
||||
@@ -1907,7 +1767,7 @@ void Options::InitServers()
|
||||
|
||||
sprintf(optname, "Server%i.JoinGroup", n);
|
||||
const char* njoingroup = GetOption(optname);
|
||||
bool bJoinGroup = false;
|
||||
bool bJoinGroup = true;
|
||||
if (njoingroup)
|
||||
{
|
||||
bJoinGroup = (bool)ParseEnumValue(optname, BoolCount, BoolNames, BoolValues);
|
||||
@@ -1929,14 +1789,11 @@ void Options::InitServers()
|
||||
m_bTLS |= bTLS;
|
||||
}
|
||||
|
||||
sprintf(optname, "Server%i.Cipher", n);
|
||||
const char* ncipher = GetOption(optname);
|
||||
|
||||
sprintf(optname, "Server%i.Connections", n);
|
||||
const char* nconnections = GetOption(optname);
|
||||
|
||||
bool definition = nlevel || ngroup || nhost || nport || nusername || npassword || nconnections || njoingroup || ntls || ncipher;
|
||||
bool completed = nhost && nport && nconnections;
|
||||
bool definition = nlevel || nhost || nport || nusername || npassword || nconnections || njoingroup || ntls;
|
||||
bool completed = nlevel && nhost && nport && nconnections;
|
||||
|
||||
if (!definition)
|
||||
{
|
||||
@@ -1945,10 +1802,8 @@ void Options::InitServers()
|
||||
|
||||
if (completed)
|
||||
{
|
||||
NewsServer* pNewsServer = new NewsServer(n, nhost, atoi(nport), nusername, npassword,
|
||||
bJoinGroup, bTLS, ncipher, atoi((char*)nconnections),
|
||||
nlevel ? atoi((char*)nlevel) : 0,
|
||||
ngroup ? atoi((char*)ngroup) : 0);
|
||||
NewsServer* pNewsServer = new NewsServer(nhost, atoi(nport), nusername, npassword,
|
||||
bJoinGroup, bTLS, atoi((char*)nconnections), atoi((char*)nlevel));
|
||||
g_pServerPool->AddServer(pNewsServer);
|
||||
}
|
||||
else
|
||||
@@ -1962,53 +1817,6 @@ void Options::InitServers()
|
||||
g_pServerPool->SetTimeout(GetConnectionTimeout());
|
||||
}
|
||||
|
||||
void Options::InitCategories()
|
||||
{
|
||||
int n = 1;
|
||||
while (true)
|
||||
{
|
||||
char optname[128];
|
||||
|
||||
sprintf(optname, "Category%i.Name", n);
|
||||
const char* nname = GetOption(optname);
|
||||
|
||||
char destdiroptname[128];
|
||||
sprintf(destdiroptname, "Category%i.DestDir", n);
|
||||
const char* ndestdir = GetOption(destdiroptname);
|
||||
|
||||
bool definition = nname || ndestdir;
|
||||
bool completed = nname && strlen(nname) > 0;
|
||||
|
||||
if (!definition)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (completed)
|
||||
{
|
||||
char* szDestDir = NULL;
|
||||
if (ndestdir && ndestdir[0] != '\0')
|
||||
{
|
||||
CheckDir(&szDestDir, destdiroptname, false, true);
|
||||
}
|
||||
|
||||
Category* pCategory = new Category(nname, szDestDir);
|
||||
m_Categories.push_back(pCategory);
|
||||
|
||||
if (szDestDir)
|
||||
{
|
||||
free(szDestDir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigError("Category definition not complete for \"Category%i\"", n);
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void Options::InitScheduler()
|
||||
{
|
||||
int n = 1;
|
||||
@@ -2103,6 +1911,7 @@ void Options::InitScheduler()
|
||||
if (!ParseTime(pTime, &iHours, &iMinutes))
|
||||
{
|
||||
ConfigError("Invalid value for option \"Task%i.Time\": \"%s\"", n, pTime);
|
||||
bOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2112,13 +1921,13 @@ void Options::InitScheduler()
|
||||
{
|
||||
for (int iEveryHour = 0; iEveryHour < 24; iEveryHour++)
|
||||
{
|
||||
Scheduler::Task* pTask = new Scheduler::Task(iEveryHour, iMinutes, iWeekDays, eCommand, iDownloadRate * 1024, szProcess);
|
||||
Scheduler::Task* pTask = new Scheduler::Task(iEveryHour, iMinutes, iWeekDays, eCommand, iDownloadRate, szProcess);
|
||||
g_pScheduler->AddTask(pTask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Scheduler::Task* pTask = new Scheduler::Task(iHours, iMinutes, iWeekDays, eCommand, iDownloadRate * 1024, szProcess);
|
||||
Scheduler::Task* pTask = new Scheduler::Task(iHours, iMinutes, iWeekDays, eCommand, iDownloadRate, szProcess);
|
||||
g_pScheduler->AddTask(pTask);
|
||||
}
|
||||
}
|
||||
@@ -2342,8 +2151,7 @@ bool Options::ValidateOptionName(const char * optname)
|
||||
(!strcasecmp(p, ".level") || !strcasecmp(p, ".host") ||
|
||||
!strcasecmp(p, ".port") || !strcasecmp(p, ".username") ||
|
||||
!strcasecmp(p, ".password") || !strcasecmp(p, ".joingroup") ||
|
||||
!strcasecmp(p, ".encryption") || !strcasecmp(p, ".connections") ||
|
||||
!strcasecmp(p, ".cipher") || !strcasecmp(p, ".group")))
|
||||
!strcasecmp(p, ".encryption") || !strcasecmp(p, ".connections")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2364,21 +2172,16 @@ bool Options::ValidateOptionName(const char * optname)
|
||||
{
|
||||
char* p = (char*)optname + 8;
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".destdir")))
|
||||
if (p && (!strcasecmp(p, ".name")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// print a warning message for obsolete options
|
||||
// suppress abort on obsolete options; print a warning message instead
|
||||
if (!strcasecmp(optname, OPTION_POSTLOGKIND) || !strcasecmp(optname, OPTION_NZBLOGKIND))
|
||||
{
|
||||
ConfigWarn("Option \"%s\" is obsolete, use \"%s\" instead", optname, OPTION_PROCESSLOGKIND);
|
||||
return true;
|
||||
}
|
||||
if (!strcasecmp(optname, OPTION_RETRYONCRCERROR))
|
||||
{
|
||||
ConfigWarn("Option \"%s\" is obsolete, ignored", optname);
|
||||
ConfigError("Option \"%s\" is obsolete, use \"%s\" instead", optname, OPTION_PROCESSLOGKIND);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2390,7 +2193,6 @@ void Options::CheckOptions()
|
||||
#ifdef DISABLE_PARCHECK
|
||||
if (m_bParCheck)
|
||||
{
|
||||
LocateOptionSrcPos(OPTION_PARCHECK);
|
||||
ConfigError("Invalid value for option \"%s\": program was compiled without parcheck-support", OPTION_PARCHECK);
|
||||
}
|
||||
#endif
|
||||
@@ -2398,30 +2200,14 @@ void Options::CheckOptions()
|
||||
#ifdef DISABLE_CURSES
|
||||
if (m_eOutputMode == omNCurses)
|
||||
{
|
||||
LocateOptionSrcPos(OPTION_OUTPUTMODE);
|
||||
ConfigError("Invalid value for option \"%s\": program was compiled without curses-support", OPTION_OUTPUTMODE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DISABLE_TLS
|
||||
if (m_bSecureControl)
|
||||
{
|
||||
LocateOptionSrcPos(OPTION_SECURECONTROL);
|
||||
ConfigError("Invalid value for option \"%s\": program was compiled without TLS/SSL-support", OPTION_SECURECONTROL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_bDecode)
|
||||
{
|
||||
m_bDirectWrite = false;
|
||||
}
|
||||
|
||||
if (m_bUnpack && m_bAllowReProcess)
|
||||
{
|
||||
LocateOptionSrcPos(OPTION_ALLOWREPROCESS);
|
||||
ConfigError("Options \"%s\" and \"%s\" cannot be both active at the same time", OPTION_UNPACK, OPTION_ALLOWREPROCESS);
|
||||
m_bAllowReProcess = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Options::ParseFileIDList(int argc, char* argv[], int optind)
|
||||
|
||||
70
Options.h
70
Options.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -28,7 +28,6 @@
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
#include "Thread.h"
|
||||
|
||||
class Options
|
||||
@@ -147,40 +146,16 @@ public:
|
||||
|
||||
typedef std::vector<char*> NameList;
|
||||
|
||||
class Category
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szDestDir;
|
||||
|
||||
public:
|
||||
Category(const char* szName, const char* szDestDir);
|
||||
~Category();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
};
|
||||
|
||||
typedef std::vector<Category*> CategoriesBase;
|
||||
|
||||
class Categories: public CategoriesBase
|
||||
{
|
||||
public:
|
||||
~Categories();
|
||||
Category* FindCategory(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;
|
||||
@@ -205,11 +180,7 @@ private:
|
||||
bool m_bDupeCheck;
|
||||
char* m_szControlIP;
|
||||
char* m_szControlPassword;
|
||||
int m_iControlPort;
|
||||
bool m_bSecureControl;
|
||||
int m_iSecurePort;
|
||||
char* m_szSecureCert;
|
||||
char* m_szSecureKey;
|
||||
int m_szControlPort;
|
||||
char* m_szLockFile;
|
||||
char* m_szDaemonUserName;
|
||||
EOutputMode m_eOutputMode;
|
||||
@@ -236,6 +207,7 @@ private:
|
||||
bool m_bCursesTime;
|
||||
bool m_bCursesGroup;
|
||||
bool m_bCrcCheck;
|
||||
bool m_bRetryOnCrcError;
|
||||
int m_iThreadLimit;
|
||||
bool m_bDirectWrite;
|
||||
int m_iWriteBufferSize;
|
||||
@@ -255,11 +227,6 @@ private:
|
||||
int m_iParTimeLimit;
|
||||
int m_iKeepHistory;
|
||||
bool m_bAccurateRate;
|
||||
bool m_bUnpack;
|
||||
bool m_bUnpackCleanupDisk;
|
||||
char* m_szUnrarCmd;
|
||||
char* m_szSevenZipCmd;
|
||||
bool m_bUnpackPauseQueue;
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool m_bServerMode;
|
||||
@@ -280,7 +247,7 @@ private:
|
||||
char* m_szLastArg;
|
||||
bool m_bPrintOptions;
|
||||
bool m_bAddTop;
|
||||
int m_iSetRate;
|
||||
float m_fSetRate;
|
||||
int m_iLogLines;
|
||||
int m_iWriteLogKind;
|
||||
bool m_bTestBacktrace;
|
||||
@@ -290,9 +257,8 @@ private:
|
||||
bool m_bPauseDownload2;
|
||||
bool m_bPausePostProcess;
|
||||
bool m_bPauseScan;
|
||||
int m_iDownloadRate;
|
||||
float m_fDownloadRate;
|
||||
EClientOperation m_eClientOperation;
|
||||
time_t m_tResumeTime;
|
||||
|
||||
void InitDefault();
|
||||
void InitOptFile();
|
||||
@@ -301,7 +267,6 @@ private:
|
||||
void InitPostConfig();
|
||||
void InitFileArg(int argc, char* argv[]);
|
||||
void InitServers();
|
||||
void InitCategories();
|
||||
void InitScheduler();
|
||||
void CheckOptions();
|
||||
void PrintUsage(char* com);
|
||||
@@ -321,8 +286,6 @@ private:
|
||||
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 ConvertOldOptionName(char *szOption, int iBufLen);
|
||||
|
||||
public:
|
||||
@@ -337,7 +300,6 @@ public:
|
||||
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; }
|
||||
@@ -362,11 +324,7 @@ public:
|
||||
bool GetDupeCheck() { return m_bDupeCheck; }
|
||||
const char* GetControlIP() { return m_szControlIP; }
|
||||
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; }
|
||||
int GetControlPort() { return m_szControlPort; }
|
||||
const char* GetLockFile() { return m_szLockFile; }
|
||||
const char* GetDaemonUserName() { return m_szDaemonUserName; }
|
||||
EOutputMode GetOutputMode() { return m_eOutputMode; }
|
||||
@@ -392,6 +350,7 @@ 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; }
|
||||
@@ -411,13 +370,6 @@ public:
|
||||
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; }
|
||||
|
||||
Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); }
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool GetServerMode() { return m_bServerMode; }
|
||||
@@ -438,7 +390,7 @@ public:
|
||||
int GetAddPriority() { return m_iAddPriority; }
|
||||
char* GetAddNZBFilename() { return m_szAddNZBFilename; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
int GetSetRate() { return m_iSetRate; }
|
||||
float GetSetRate() { return m_fSetRate; }
|
||||
int GetLogLines() { return m_iLogLines; }
|
||||
int GetWriteLogKind() { return m_iWriteLogKind; }
|
||||
bool GetTestBacktrace() { return m_bTestBacktrace; }
|
||||
@@ -452,10 +404,8 @@ public:
|
||||
bool GetPausePostProcess() const { return m_bPausePostProcess; }
|
||||
void SetPauseScan(bool bPauseScan) { m_bPauseScan = bPauseScan; }
|
||||
bool GetPauseScan() const { return m_bPauseScan; }
|
||||
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; }
|
||||
void SetDownloadRate(float fRate) { m_fDownloadRate = fRate; }
|
||||
float GetDownloadRate() const { return m_fDownloadRate; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -85,6 +85,8 @@ Result Repairer::PreProcess(const char *szParFilename)
|
||||
BugfixesPatchVersion2();
|
||||
#endif
|
||||
|
||||
bool bFullScan = true;
|
||||
|
||||
if (g_pOptions->GetParScan() == Options::psFull)
|
||||
{
|
||||
char szWildcardParam[1024];
|
||||
@@ -121,36 +123,6 @@ Result Repairer::Process(bool 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");
|
||||
@@ -163,6 +135,7 @@ ParChecker::ParChecker()
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_iExtraFiles = 0;
|
||||
m_iMissingFiles = 0;
|
||||
m_bVerifyingExtraFiles = false;
|
||||
m_bCancelled = false;
|
||||
m_eStage = ptLoadingPars;
|
||||
@@ -235,6 +208,7 @@ void ParChecker::Run()
|
||||
m_eStage = ptLoadingPars;
|
||||
m_iProcessedFiles = 0;
|
||||
m_iExtraFiles = 0;
|
||||
m_iMissingFiles = 0;
|
||||
m_bVerifyingExtraFiles = false;
|
||||
m_bCancelled = false;
|
||||
|
||||
@@ -291,8 +265,9 @@ void ParChecker::Run()
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
|
||||
if (!IsStopped() && pRepairer->missingfilecount > 0 && g_pOptions->GetParScan() == Options::psAuto && AddMissingFiles())
|
||||
if (!IsStopped() && m_iMissingFiles > 0 && g_pOptions->GetParScan() == Options::psAuto && AddAllFiles())
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
@@ -481,7 +456,7 @@ bool ParChecker::CheckSplittedFragments()
|
||||
{
|
||||
bool bFragmentsAdded = false;
|
||||
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
@@ -508,7 +483,7 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
szBasename[-1] = '\0';
|
||||
int iBaseLen = strlen(szBasename);
|
||||
|
||||
std::list<CommandLine::ExtraFile> extrafiles;
|
||||
list<CommandLine::ExtraFile> extrafiles;
|
||||
|
||||
DirBrowser dir(szDirectory);
|
||||
while (const char* filename = dir.Next())
|
||||
@@ -547,9 +522,9 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
return bFragmentsAdded;
|
||||
}
|
||||
|
||||
bool ParChecker::AddMissingFiles()
|
||||
bool ParChecker::AddAllFiles()
|
||||
{
|
||||
info("Performing extra par-scan for %s", m_szInfoName);
|
||||
info("Performing full par-scan for %s", m_szInfoName);
|
||||
|
||||
char szDirectory[1024];
|
||||
strncpy(szDirectory, m_szParFilename, 1024);
|
||||
@@ -562,7 +537,7 @@ bool ParChecker::AddMissingFiles()
|
||||
}
|
||||
szBasename[-1] = '\0';
|
||||
|
||||
std::list<CommandLine::ExtraFile*> extrafiles;
|
||||
list<CommandLine::ExtraFile> extrafiles;
|
||||
|
||||
DirBrowser dir(szDirectory);
|
||||
while (const char* filename = dir.Next())
|
||||
@@ -586,49 +561,20 @@ bool ParChecker::AddMissingFiles()
|
||||
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
|
||||
fullfilename[1024-1] = '\0';
|
||||
|
||||
extrafiles.push_back(new CommandLine::ExtraFile(fullfilename, Util::FileSize(fullfilename)));
|
||||
CommandLine::ExtraFile extrafile(fullfilename, Util::FileSize(fullfilename));
|
||||
extrafiles.push_back(extrafile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
bFilesAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
|
||||
m_bVerifyingExtraFiles = false;
|
||||
|
||||
// free any remaining objects
|
||||
for (std::list<CommandLine::ExtraFile*>::iterator it = extrafiles.begin(); it != extrafiles.end() ;it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
return bFilesAdded;
|
||||
@@ -713,7 +659,7 @@ void ParChecker::signal_done(std::string str, int available, int total)
|
||||
{
|
||||
bool bFileExists = true;
|
||||
|
||||
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
@@ -732,6 +678,7 @@ void ParChecker::signal_done(std::string str, int available, int total)
|
||||
else
|
||||
{
|
||||
warn("File %s with %i block(s) is missing", str.c_str(), total);
|
||||
m_iMissingFiles++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ private:
|
||||
int m_iProcessedFiles;
|
||||
int m_iFilesToRepair;
|
||||
int m_iExtraFiles;
|
||||
int m_iMissingFiles;
|
||||
bool m_bVerifyingExtraFiles;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
@@ -79,7 +80,7 @@ private:
|
||||
bool LoadMorePars();
|
||||
bool CheckSplittedFragments();
|
||||
bool AddSplittedFragments(const char* szFilename);
|
||||
bool AddMissingFiles();
|
||||
bool AddAllFiles();
|
||||
void signal_filename(std::string str);
|
||||
void signal_progress(double progress);
|
||||
void signal_done(std::string str, int available, int total);
|
||||
|
||||
@@ -1,768 +0,0 @@
|
||||
/*
|
||||
* 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 <fstream>
|
||||
#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::PostParRenamer::UpdateProgress()
|
||||
{
|
||||
m_pOwner->UpdateParRenameProgress();
|
||||
}
|
||||
#endif
|
||||
|
||||
ParCoordinator::ParCoordinator()
|
||||
{
|
||||
debug("Creating ParCoordinator");
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_ParCheckerObserver.m_pOwner = this;
|
||||
m_ParChecker.Attach(&m_ParCheckerObserver);
|
||||
m_ParChecker.m_pOwner = this;
|
||||
|
||||
m_ParRenamerObserver.m_pOwner = this;
|
||||
m_ParRenamer.Attach(&m_ParRenamerObserver);
|
||||
m_ParRenamer.m_pOwner = this;
|
||||
|
||||
m_bStopped = false;
|
||||
|
||||
const char* szPostScript = g_pOptions->GetPostProcess();
|
||||
m_bPostScript = szPostScript && strlen(szPostScript) > 0;
|
||||
#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,
|
||||
(g_pOptions->GetLoadPars() == Options::lpOne ||
|
||||
(g_pOptions->GetLoadPars() == Options::lpNone && g_pOptions->GetParCheck()))
|
||||
? QueueEditor::eaGroupPauseExtraPars : QueueEditor::eaGroupPauseAllPars,
|
||||
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)
|
||||
{
|
||||
info("Checking pars for %s", pPostInfo->GetInfoName());
|
||||
m_eCurrentJob = jkParCheck;
|
||||
m_ParChecker.SetPostInfo(pPostInfo);
|
||||
m_ParChecker.SetParFilename(pPostInfo->GetParFilename());
|
||||
m_ParChecker.SetInfoName(pPostInfo->GetInfoName());
|
||||
pPostInfo->SetWorking(true);
|
||||
m_ParChecker.Start();
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void ParCoordinator::StartParRenameJob(PostInfo* pPostInfo)
|
||||
{
|
||||
info("Checking renamed files for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
m_eCurrentJob = jkParRename;
|
||||
m_ParRenamer.SetPostInfo(pPostInfo);
|
||||
m_ParRenamer.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
|
||||
m_ParRenamer.SetInfoName(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::ParCheckerUpdate(Subject* Caller, void* Aspect)
|
||||
{
|
||||
if (m_ParChecker.GetStatus() == ParChecker::psFinished ||
|
||||
m_ParChecker.GetStatus() == ParChecker::psFailed)
|
||||
{
|
||||
char szPath[1024];
|
||||
strncpy(szPath, m_ParChecker.GetParFilename(), 1024);
|
||||
szPath[1024-1] = '\0';
|
||||
if (char* p = strrchr(szPath, PATH_SEPARATOR)) *p = '\0';
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", szPath, (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
|
||||
if (!m_ParChecker.GetRepairNotNeeded() || Util::FileExists(szBrokenLogName))
|
||||
{
|
||||
FILE* file = fopen(szBrokenLogName, "ab");
|
||||
if (file)
|
||||
{
|
||||
if (m_ParChecker.GetStatus() == ParChecker::psFailed)
|
||||
{
|
||||
if (m_ParChecker.GetCancelled())
|
||||
{
|
||||
fprintf(file, "Repair cancelled for %s\n", m_ParChecker.GetInfoName());
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "Repair failed for %s: %s\n", m_ParChecker.GetInfoName(), m_ParChecker.GetErrMsg() ? m_ParChecker.GetErrMsg() : "");
|
||||
}
|
||||
}
|
||||
else if (m_ParChecker.GetRepairNotNeeded())
|
||||
{
|
||||
fprintf(file, "Repair not needed for %s\n", m_ParChecker.GetInfoName());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_pOptions->GetParRepair())
|
||||
{
|
||||
fprintf(file, "Successfully repaired %s\n", m_ParChecker.GetInfoName());
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "Repair possible for %s\n", m_ParChecker.GetInfoName());
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not open file %s", szBrokenLogName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
|
||||
pPostInfo->SetWorking(false);
|
||||
if (pPostInfo->GetDeleted())
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
|
||||
// Update ParStatus by NZBInfo (accumulate result)
|
||||
if (m_ParChecker.GetStatus() == ParChecker::psFailed && !m_ParChecker.GetCancelled())
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psFailure);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
|
||||
}
|
||||
else if (m_ParChecker.GetStatus() == ParChecker::psFinished &&
|
||||
(g_pOptions->GetParRepair() || m_ParChecker.GetRepairNotNeeded()))
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psSuccess);
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSuccess);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psRepairPossible);
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psRepairPossible);
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
info("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())
|
||||
{
|
||||
info("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()
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = pDownloadQueue->GetPostQueue()->front();
|
||||
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);
|
||||
warn("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::ParRenamerUpdate(Subject* Caller, void* Aspect)
|
||||
{
|
||||
if (m_ParRenamer.GetStatus() == ParRenamer::psFinished ||
|
||||
m_ParRenamer.GetStatus() == ParRenamer::psFailed)
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
|
||||
pPostInfo->SetWorking(false);
|
||||
if (pPostInfo->GetDeleted())
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
|
||||
// Update ParStatus by NZBInfo
|
||||
if (m_ParRenamer.GetStatus() == ParRenamer::psFailed && !m_ParRenamer.GetCancelled())
|
||||
{
|
||||
pPostInfo->SetRenameStatus(PostInfo::rsFailure);
|
||||
pPostInfo->GetNZBInfo()->SetRenameStatus(NZBInfo::rsFailure);
|
||||
}
|
||||
else if (m_ParRenamer.GetStatus() == ParRenamer::psFinished)
|
||||
{
|
||||
pPostInfo->SetRenameStatus(PostInfo::rsSuccess);
|
||||
pPostInfo->GetNZBInfo()->SetRenameStatus(NZBInfo::rsSuccess);
|
||||
}
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void ParCoordinator::UpdateParRenameProgress()
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
PostInfo* pPostInfo = pDownloadQueue->GetPostQueue()->front();
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
143
ParCoordinator.h
143
ParCoordinator.h
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* 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 "Observer.h"
|
||||
#include "DownloadInfo.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
#include "ParRenamer.h"
|
||||
#endif
|
||||
|
||||
class ParCoordinator
|
||||
{
|
||||
private:
|
||||
#ifndef DISABLE_PARCHECK
|
||||
class ParCheckerObserver: public Observer
|
||||
{
|
||||
public:
|
||||
ParCoordinator* m_pOwner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->ParCheckerUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
class PostParChecker: public ParChecker
|
||||
{
|
||||
private:
|
||||
ParCoordinator* m_pOwner;
|
||||
PostInfo* m_pPostInfo;
|
||||
protected:
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
virtual void UpdateProgress();
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_pPostInfo; }
|
||||
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
|
||||
|
||||
friend class ParCoordinator;
|
||||
};
|
||||
|
||||
class ParRenamerObserver: public Observer
|
||||
{
|
||||
public:
|
||||
ParCoordinator* m_pOwner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->ParRenamerUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
class PostParRenamer: public ParRenamer
|
||||
{
|
||||
private:
|
||||
ParCoordinator* m_pOwner;
|
||||
PostInfo* m_pPostInfo;
|
||||
protected:
|
||||
virtual void UpdateProgress();
|
||||
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;
|
||||
ParCheckerObserver m_ParCheckerObserver;
|
||||
bool m_bStopped;
|
||||
bool m_bPostScript;
|
||||
PostParRenamer m_ParRenamer;
|
||||
ParRenamerObserver m_ParRenamerObserver;
|
||||
EJobKind m_eCurrentJob;
|
||||
|
||||
protected:
|
||||
virtual bool PauseDownload() = 0;
|
||||
virtual bool UnpauseDownload() = 0;
|
||||
#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
|
||||
void ParCheckerUpdate(Subject* Caller, void* Aspect);
|
||||
void ParRenamerUpdate(Subject* Caller, void* Aspect);
|
||||
void CheckPauseState(PostInfo* pPostInfo);
|
||||
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 UpdateParCheckProgress();
|
||||
void UpdateParRenameProgress();
|
||||
void StartParCheckJob(PostInfo* pPostInfo);
|
||||
void StartParRenameJob(PostInfo* pPostInfo);
|
||||
void Stop();
|
||||
bool Cancel();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
323
ParRenamer.cpp
323
ParRenamer.cpp
@@ -1,323 +0,0 @@
|
||||
/*
|
||||
* 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 <ctype.h>
|
||||
#include <fstream>
|
||||
#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 = psUnknown;
|
||||
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::SetStatus(EStatus eStatus)
|
||||
{
|
||||
m_eStatus = eStatus;
|
||||
Notify(NULL);
|
||||
}
|
||||
|
||||
void ParRenamer::Cancel()
|
||||
{
|
||||
m_bCancelled = true;
|
||||
}
|
||||
|
||||
void ParRenamer::Run()
|
||||
{
|
||||
Cleanup();
|
||||
m_bCancelled = false;
|
||||
m_iRenamedCount = 0;
|
||||
|
||||
SetStatus(psUnknown);
|
||||
|
||||
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)
|
||||
{
|
||||
warn("Renaming cancelled for %s", m_szInfoName);
|
||||
SetStatus(psFailed);
|
||||
}
|
||||
else if (m_iRenamedCount > 0)
|
||||
{
|
||||
info("Successfully renamed %i file(s) for %s", m_iRenamedCount, m_szInfoName);
|
||||
SetStatus(psFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Could not rename any files for %s", m_szInfoName);
|
||||
SetStatus(psFailed);
|
||||
}
|
||||
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
warn("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)
|
||||
{
|
||||
error("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)
|
||||
{
|
||||
error("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))
|
||||
{
|
||||
info("Renaming %s to %s", Util::BaseFileName(szFilename), pFileHash->GetFilename());
|
||||
if (Util::MoveFile(szFilename, szDstFilename))
|
||||
{
|
||||
m_iRenamedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not rename %s to %s", szFilename, szDstFilename);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
97
ParRenamer.h
97
ParRenamer.h
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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 "Observer.h"
|
||||
|
||||
class ParRenamer : public Thread, public Subject
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
psUnknown,
|
||||
psFailed,
|
||||
psFinished
|
||||
};
|
||||
|
||||
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() {}
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -32,7 +32,10 @@
|
||||
#include "Observer.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Scanner.h"
|
||||
#include "ParCoordinator.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
#endif
|
||||
|
||||
class PrePostProcessor : public Thread
|
||||
{
|
||||
@@ -49,26 +52,48 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
class QueueCoordinatorObserver: public Observer
|
||||
{
|
||||
public:
|
||||
PrePostProcessor* m_pOwner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->QueueCoordinatorUpdate(Caller, Aspect); }
|
||||
PrePostProcessor* owner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { owner->QueueCoordinatorUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
class PostParCoordinator: public ParCoordinator
|
||||
#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
|
||||
{
|
||||
private:
|
||||
PrePostProcessor* m_pOwner;
|
||||
PrePostProcessor* m_Owner;
|
||||
PostInfo* m_pPostInfo;
|
||||
protected:
|
||||
virtual bool PauseDownload() { return m_pOwner->PauseDownload(); }
|
||||
virtual bool UnpauseDownload() { return m_pOwner->UnpauseDownload(); }
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
virtual void UpdateProgress();
|
||||
public:
|
||||
PostInfo* GetPostInfo() { return m_pPostInfo; }
|
||||
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
|
||||
|
||||
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;
|
||||
@@ -76,27 +101,28 @@ private:
|
||||
bool m_bSchedulerPause;
|
||||
bool m_bPostPause;
|
||||
Scanner m_Scanner;
|
||||
const char* m_szPauseReason;
|
||||
|
||||
bool IsNZBFileCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
|
||||
bool bIgnorePausedPars, bool bCheckPostQueue, bool bAllowOnlyOneDeleted);
|
||||
void CheckPostQueue();
|
||||
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartProcessJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartScriptJob(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 CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bParCheck, bool bUnpackOrScript, bool bAddTop);
|
||||
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);
|
||||
@@ -105,8 +131,20 @@ private:
|
||||
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();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -127,7 +127,7 @@ void QueueCoordinator::Run()
|
||||
{
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
NNTPConnection* pConnection = g_pServerPool->GetConnection(0, NULL, NULL);
|
||||
NNTPConnection* pConnection = g_pServerPool->GetConnection(0);
|
||||
if (pConnection)
|
||||
{
|
||||
// start download for next article
|
||||
@@ -297,26 +297,25 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
/*
|
||||
* NOTE: see note to "AddSpeedReading"
|
||||
*/
|
||||
int QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
float QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
{
|
||||
if (m_bStandBy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
if (iTimeDiff == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_iSpeedTotalBytes / iTimeDiff;
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
if (iTimeDiff == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
float fSpeed = m_iSpeedTotalBytes / 1024.0f / iTimeDiff;
|
||||
return fSpeed;
|
||||
}
|
||||
|
||||
void QueueCoordinator::AddSpeedReading(int iBytes)
|
||||
{
|
||||
time_t tCurTime = time(NULL);
|
||||
int iNowSlot = (int)tCurTime / SPEEDMETER_SLOTSIZE;
|
||||
int iNowSlot = (int)time(NULL) / SPEEDMETER_SLOTSIZE;
|
||||
|
||||
if (g_pOptions->GetAccurateRate())
|
||||
{
|
||||
@@ -327,45 +326,33 @@ void QueueCoordinator::AddSpeedReading(int iBytes)
|
||||
#endif
|
||||
}
|
||||
|
||||
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];
|
||||
while (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];
|
||||
|
||||
//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];
|
||||
//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];
|
||||
|
||||
//Now reset.
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] = 0;
|
||||
m_iSpeedTime[m_iSpeedBytesIndex] = iNowSlot;
|
||||
}
|
||||
//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;
|
||||
if (m_iSpeedTotalBytes == 0)
|
||||
{
|
||||
m_iSpeedStartTime = iNowSlot;
|
||||
}
|
||||
m_iSpeedBytes[m_iSpeedBytesIndex] += iBytes;
|
||||
m_iSpeedTotalBytes += iBytes;
|
||||
m_iAllBytes += iBytes;
|
||||
|
||||
if (g_pOptions->GetAccurateRate())
|
||||
@@ -380,16 +367,14 @@ void QueueCoordinator::AddSpeedReading(int iBytes)
|
||||
|
||||
void QueueCoordinator::ResetSpeedStat()
|
||||
{
|
||||
time_t tCurTime = time(NULL);
|
||||
m_iSpeedStartTime = (int)tCurTime / SPEEDMETER_SLOTSIZE;
|
||||
m_iSpeedStartTime = (int)time(NULL) / 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_tSpeedCorrection = tCurTime;
|
||||
m_iSpeedTotalBytes = 0;
|
||||
}
|
||||
|
||||
long long QueueCoordinator::CalcRemainingSize()
|
||||
@@ -461,9 +446,6 @@ bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArtic
|
||||
// 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()");
|
||||
|
||||
bool bOK = false;
|
||||
@@ -484,10 +466,7 @@ bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArtic
|
||||
FileInfo* pFileInfo1 = *it;
|
||||
if ((!pCheckedFiles || !pCheckedFiles[iNum]) &&
|
||||
!pFileInfo1->GetPaused() && !pFileInfo1->GetDeleted() &&
|
||||
(!pFileInfo ||
|
||||
(pFileInfo1->GetExtraPriority() == pFileInfo->GetExtraPriority() &&
|
||||
pFileInfo1->GetPriority() > pFileInfo->GetPriority()) ||
|
||||
(pFileInfo1->GetExtraPriority() > pFileInfo->GetExtraPriority())))
|
||||
(!pFileInfo || (pFileInfo1->GetPriority() > pFileInfo->GetPriority())))
|
||||
{
|
||||
pFileInfo = pFileInfo1;
|
||||
iFileNum = iNum;
|
||||
@@ -576,22 +555,8 @@ void QueueCoordinator::BuildArticleFilename(ArticleDownloader* pArticleDownloade
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
{
|
||||
pFileInfo->LockOutputFile();
|
||||
|
||||
if (pFileInfo->GetOutputFilename())
|
||||
{
|
||||
strncpy(name, pFileInfo->GetOutputFilename(), 1024);
|
||||
name[1024-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(name, 1024, "%s%c%i.out.tmp", pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, pFileInfo->GetID());
|
||||
name[1024-1] = '\0';
|
||||
pFileInfo->SetOutputFilename(name);
|
||||
}
|
||||
|
||||
pFileInfo->UnlockOutputFile();
|
||||
|
||||
snprintf(name, 1024, "%s%i.out", g_pOptions->GetTempDir(), pFileInfo->GetID());
|
||||
name[1024-1] = '\0';
|
||||
pArticleDownloader->SetOutputFilename(name);
|
||||
}
|
||||
}
|
||||
@@ -767,9 +732,12 @@ void QueueCoordinator::DiscardDiskFile(FileInfo* pFileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pOptions->GetDirectWrite() && pFileInfo->GetOutputFilename())
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
{
|
||||
remove(pFileInfo->GetOutputFilename());
|
||||
char name[1024];
|
||||
snprintf(name, 1024, "%s%i.out", g_pOptions->GetTempDir(), pFileInfo->GetID());
|
||||
name[1024-1] = '\0';
|
||||
remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,7 +774,7 @@ void QueueCoordinator::LogDebugInfo()
|
||||
|
||||
debug(" SpeedMeter");
|
||||
debug(" ----------");
|
||||
float fSpeed = (float)(CalcCurrentDownloadSpeed() / 1024.0);
|
||||
float fSpeed = CalcCurrentDownloadSpeed();
|
||||
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
|
||||
debug(" Speed: %f", fSpeed);
|
||||
debug(" SpeedStartTime: %i", m_iSpeedStartTime);
|
||||
@@ -839,7 +807,8 @@ void QueueCoordinator::LogDebugInfo()
|
||||
|
||||
void QueueCoordinator::ResetHangingDownloads()
|
||||
{
|
||||
if (g_pOptions->GetTerminateTimeout() == 0 && g_pOptions->GetConnectionTimeout() == 0)
|
||||
const int TimeOut = g_pOptions->GetTerminateTimeout();
|
||||
if (TimeOut == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -850,15 +819,7 @@ void QueueCoordinator::ResetHangingDownloads()
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
|
||||
{
|
||||
ArticleDownloader* pArticleDownloader = *it;
|
||||
|
||||
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() &&
|
||||
if (tm - pArticleDownloader->GetLastUpdateTime() > TimeOut &&
|
||||
pArticleDownloader->GetStatus() == ArticleDownloader::adRunning)
|
||||
{
|
||||
ArticleInfo* pArticleInfo = pArticleDownloader->GetArticleInfo();
|
||||
|
||||
@@ -71,7 +71,6 @@ private:
|
||||
int m_iSpeedTotalBytes;
|
||||
int m_iSpeedTime[SPEEDMETER_SLOTS];
|
||||
int m_iSpeedStartTime;
|
||||
time_t m_tSpeedCorrection;
|
||||
#ifdef HAVE_SPINLOCK
|
||||
SpinLock m_spinlockSpeed;
|
||||
#else
|
||||
@@ -107,7 +106,7 @@ public:
|
||||
|
||||
// statistics
|
||||
long long CalcRemainingSize();
|
||||
virtual int CalcCurrentDownloadSpeed();
|
||||
virtual float CalcCurrentDownloadSpeed();
|
||||
virtual void AddSpeedReading(int iBytes);
|
||||
void CalcStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy);
|
||||
|
||||
|
||||
23
README
23
README
@@ -429,15 +429,14 @@ same computer)
|
||||
Security warning
|
||||
----------------
|
||||
|
||||
NZBGet client communicates with NZBGet server via unsecured socket connections.
|
||||
This makes it vulnerable. Although server checks the password passed by client,
|
||||
this password is still transmitted in unsecured way. For this reason it is
|
||||
highly recommended to configure your firewall to not expose the port used by
|
||||
NZBGet (option <ControlPort>) to WAN.
|
||||
NZBGet communicates via unsecured socket connections. This makes it vulnerable.
|
||||
Although server checks the password passed by client, this password is still
|
||||
transmitted in unsecured way. For this reason it is highly recommended
|
||||
to configure your Firewall to not expose the port used by NZBGet to WAN.
|
||||
|
||||
If you need to control server from WAN it is better to use web-interface via HTTPS
|
||||
or (if you prefer remote commands) connect to server's terminal via SSH (POSIX)
|
||||
or remote desktop (Windows) and then run nzbget-client-commands in this terminal.
|
||||
If you need to control server from WAN it is better to connect to server's
|
||||
terminal via SSH (POSIX) or remote desktop (Windows) and then run
|
||||
nzbget-client-commands in this terminal.
|
||||
|
||||
Post processing scripts
|
||||
-----------------------
|
||||
@@ -506,6 +505,9 @@ 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.
|
||||
|
||||
Module TLS (TLS.c, TLS.h) is based on work by Martin Lambers
|
||||
(marlam@marlam.de).
|
||||
|
||||
=====================================
|
||||
9. Copyright
|
||||
=====================================
|
||||
@@ -524,11 +526,8 @@ Binary distribution for Windows contains code from the following libraries:
|
||||
- libpar2 (http://parchive.sourceforge.net)
|
||||
- libsigc++ (http://libsigc.sourceforge.net)
|
||||
- GnuTLS (http://www.gnu.org/software/gnutls)
|
||||
- zlib (http://www.zlib.net)
|
||||
- regex (http://gnuwin32.sourceforge.net/packages/regex.htm)
|
||||
|
||||
libpar2 is distributed under GPL; libsigc++, GnuTLS and regex - under LGPL;
|
||||
zlib - under zlib license.
|
||||
libpar2 is distributed under GPL; libsigc++ and GnuTLS - under LGPL.
|
||||
|
||||
=====================================
|
||||
10. Contact
|
||||
|
||||
143
RemoteClient.cpp
143
RemoteClient.cpp
@@ -46,7 +46,6 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "RemoteClient.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
@@ -138,21 +137,35 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
SNZBDownloadResponse BoolResponse;
|
||||
memset(&BoolResponse, 0, sizeof(BoolResponse));
|
||||
|
||||
bool bRead = m_pConnection->Recv((char*)&BoolResponse, sizeof(BoolResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*)&BoolResponse, sizeof(BoolResponse));
|
||||
if (iResponseLen != sizeof(BoolResponse) ||
|
||||
(int)ntohl(BoolResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(BoolResponse.m_MessageBase.m_iStructSize) != sizeof(BoolResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int iTextLen = ntohl(BoolResponse.m_iTrailingDataLength);
|
||||
char* buf = (char*)malloc(iTextLen);
|
||||
bRead = m_pConnection->Recv(buf, iTextLen);
|
||||
if (!bRead)
|
||||
iResponseLen = m_pConnection->Recv(buf, iTextLen);
|
||||
if (iResponseLen != iTextLen)
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
@@ -195,7 +208,7 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
}
|
||||
DownloadRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
if (!m_pConnection->Send((char*)(&DownloadRequest), sizeof(DownloadRequest)))
|
||||
if (m_pConnection->Send((char*)(&DownloadRequest), sizeof(DownloadRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
OK = false;
|
||||
@@ -319,7 +332,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
ListRequest.m_szPattern[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
}
|
||||
|
||||
if (!m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)))
|
||||
if (m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -329,12 +342,19 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBListResponse ListResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
if (iResponseLen != sizeof(ListResponse) ||
|
||||
(int)ntohl(ListResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(ListResponse.m_MessageBase.m_iStructSize) != sizeof(ListResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -342,7 +362,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
if (ntohl(ListResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(ListResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(ListResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -680,7 +700,7 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
LogRequest.m_iLines = htonl(iLines);
|
||||
LogRequest.m_iIDFrom = 0;
|
||||
|
||||
if (!m_pConnection->Send((char*)(&LogRequest), sizeof(LogRequest)))
|
||||
if (m_pConnection->Send((char*)(&LogRequest), sizeof(LogRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -690,12 +710,19 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
|
||||
// Now listen for the returned log
|
||||
SNZBLogResponse LogResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
if (iResponseLen != sizeof(LogResponse) ||
|
||||
(int)ntohl(LogResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(LogResponse.m_MessageBase.m_iStructSize) != sizeof(LogResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -703,7 +730,7 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
if (ntohl(LogResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(LogResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(LogResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -766,7 +793,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)))
|
||||
if (m_pConnection->Send((char*)(&PauseUnpauseRequest), sizeof(PauseUnpauseRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -779,15 +806,15 @@ bool RemoteClient::RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAct
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestServerSetDownloadRate(int iRate)
|
||||
bool RemoteClient::RequestServerSetDownloadRate(float fRate)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBSetDownloadRateRequest SetDownloadRateRequest;
|
||||
InitMessageBase(&SetDownloadRateRequest.m_MessageBase, eRemoteRequestSetDownloadRate, sizeof(SetDownloadRateRequest));
|
||||
SetDownloadRateRequest.m_iDownloadRate = htonl(iRate);
|
||||
SetDownloadRateRequest.m_iDownloadRate = htonl((unsigned int)(fRate * 1024));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&SetDownloadRateRequest), sizeof(SetDownloadRateRequest)))
|
||||
if (m_pConnection->Send((char*)(&SetDownloadRateRequest), sizeof(SetDownloadRateRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -807,7 +834,7 @@ bool RemoteClient::RequestServerDumpDebug()
|
||||
SNZBDumpDebugRequest DumpDebugInfo;
|
||||
InitMessageBase(&DumpDebugInfo.m_MessageBase, eRemoteRequestDumpDebug, sizeof(DumpDebugInfo));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&DumpDebugInfo), sizeof(DumpDebugInfo)))
|
||||
if (m_pConnection->Send((char*)(&DumpDebugInfo), sizeof(DumpDebugInfo)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
m_pConnection->Disconnect();
|
||||
@@ -892,7 +919,7 @@ bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset
|
||||
}
|
||||
|
||||
bool OK = false;
|
||||
if (!m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)))
|
||||
if (m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
}
|
||||
@@ -916,7 +943,7 @@ bool RemoteClient::RequestServerShutdown()
|
||||
SNZBShutdownRequest ShutdownRequest;
|
||||
InitMessageBase(&ShutdownRequest.m_MessageBase, eRemoteRequestShutdown, sizeof(ShutdownRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest));
|
||||
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest)) >= 0;
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -937,7 +964,7 @@ bool RemoteClient::RequestServerReload()
|
||||
SNZBReloadRequest ReloadRequest;
|
||||
InitMessageBase(&ReloadRequest.m_MessageBase, eRemoteRequestReload, sizeof(ReloadRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ReloadRequest), sizeof(ReloadRequest));
|
||||
bool OK = m_pConnection->Send((char*)(&ReloadRequest), sizeof(ReloadRequest)) >= 0;
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -958,7 +985,7 @@ bool RemoteClient::RequestServerVersion()
|
||||
SNZBVersionRequest VersionRequest;
|
||||
InitMessageBase(&VersionRequest.m_MessageBase, eRemoteRequestVersion, sizeof(VersionRequest));
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&VersionRequest), sizeof(VersionRequest));
|
||||
bool OK = m_pConnection->Send((char*)(&VersionRequest), sizeof(VersionRequest)) >= 0;
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -979,7 +1006,7 @@ bool RemoteClient::RequestPostQueue()
|
||||
SNZBPostQueueRequest PostQueueRequest;
|
||||
InitMessageBase(&PostQueueRequest.m_MessageBase, eRemoteRequestPostQueue, sizeof(PostQueueRequest));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&PostQueueRequest), sizeof(PostQueueRequest)))
|
||||
if (m_pConnection->Send((char*)(&PostQueueRequest), sizeof(PostQueueRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -989,12 +1016,19 @@ bool RemoteClient::RequestPostQueue()
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBPostQueueResponse PostQueueResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
if (iResponseLen != sizeof(PostQueueResponse) ||
|
||||
(int)ntohl(PostQueueResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(PostQueueResponse.m_MessageBase.m_iStructSize) != sizeof(PostQueueResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1002,7 +1036,7 @@ bool RemoteClient::RequestPostQueue()
|
||||
if (ntohl(PostQueueResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(PostQueueResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(PostQueueResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(PostQueueResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -1027,14 +1061,15 @@ 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) != (int)PostInfo::ptExecutingScript)
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != EXECUTING_SCRIPT)
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(iStageProgress / 10), "%");
|
||||
}
|
||||
|
||||
const char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Unpacking", ", Executing postprocess-script", "" };
|
||||
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);
|
||||
|
||||
printf("[%i] %s%s%s\n", ntohl(pPostQueueAnswer->m_iID), szInfoName, szPostStageName[ntohl(pPostQueueAnswer->m_iStage)], szCompleted);
|
||||
@@ -1062,7 +1097,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)))
|
||||
if (m_pConnection->Send((char*)(&WriteLogRequest), sizeof(WriteLogRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -1083,7 +1118,7 @@ bool RemoteClient::RequestScan(bool bSyncMode)
|
||||
|
||||
ScanRequest.m_bSyncMode = htonl(bSyncMode);
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&ScanRequest), sizeof(ScanRequest));
|
||||
bool OK = m_pConnection->Send((char*)(&ScanRequest), sizeof(ScanRequest)) >= 0;
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -1104,7 +1139,7 @@ bool RemoteClient::RequestHistory()
|
||||
SNZBHistoryRequest HistoryRequest;
|
||||
InitMessageBase(&HistoryRequest.m_MessageBase, eRemoteRequestHistory, sizeof(HistoryRequest));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&HistoryRequest), sizeof(HistoryRequest)))
|
||||
if (m_pConnection->Send((char*)(&HistoryRequest), sizeof(HistoryRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -1114,12 +1149,19 @@ bool RemoteClient::RequestHistory()
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBHistoryResponse HistoryResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*) &HistoryResponse, sizeof(HistoryResponse));
|
||||
if (iResponseLen != sizeof(HistoryResponse) ||
|
||||
(int)ntohl(HistoryResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(HistoryResponse.m_MessageBase.m_iStructSize) != sizeof(HistoryResponse))
|
||||
{
|
||||
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1127,7 +1169,7 @@ bool RemoteClient::RequestHistory()
|
||||
if (ntohl(HistoryResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(HistoryResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(HistoryResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(HistoryResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
@@ -1215,7 +1257,7 @@ bool RemoteClient::RequestServerDownloadUrl(const char* szURL, const char* szNZB
|
||||
}
|
||||
DownloadUrlRequest.m_szNZBFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
|
||||
|
||||
bool OK = m_pConnection->Send((char*)(&DownloadUrlRequest), sizeof(DownloadUrlRequest));
|
||||
bool OK = m_pConnection->Send((char*)(&DownloadUrlRequest), sizeof(DownloadUrlRequest)) >= 0;
|
||||
if (OK)
|
||||
{
|
||||
OK = ReceiveBoolResponse();
|
||||
@@ -1236,7 +1278,7 @@ bool RemoteClient::RequestUrlQueue()
|
||||
SNZBUrlQueueRequest UrlQueueRequest;
|
||||
InitMessageBase(&UrlQueueRequest.m_MessageBase, eRemoteRequestUrlQueue, sizeof(UrlQueueRequest));
|
||||
|
||||
if (!m_pConnection->Send((char*)(&UrlQueueRequest), sizeof(UrlQueueRequest)))
|
||||
if (m_pConnection->Send((char*)(&UrlQueueRequest), sizeof(UrlQueueRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
@@ -1246,12 +1288,19 @@ bool RemoteClient::RequestUrlQueue()
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBUrlQueueResponse UrlQueueResponse;
|
||||
bool bRead = m_pConnection->Recv((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
|
||||
if (!bRead ||
|
||||
int iResponseLen = m_pConnection->Recv((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
|
||||
if (iResponseLen != sizeof(UrlQueueResponse) ||
|
||||
(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");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1259,7 +1308,7 @@ bool RemoteClient::RequestUrlQueue()
|
||||
if (ntohl(UrlQueueResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(UrlQueueResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->Recv(pBuf, ntohl(UrlQueueResponse.m_iTrailingDataLength)))
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(UrlQueueResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
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(int iRate);
|
||||
bool RequestServerSetDownloadRate(float fRate);
|
||||
bool RequestServerDumpDebug();
|
||||
bool RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
|
||||
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-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
|
||||
@@ -47,18 +47,16 @@
|
||||
#include "WebServer.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
//*****************************************************************
|
||||
// RemoteServer
|
||||
|
||||
RemoteServer::RemoteServer(bool bTLS)
|
||||
RemoteServer::RemoteServer()
|
||||
{
|
||||
debug("Creating RemoteServer");
|
||||
|
||||
m_bTLS = bTLS;
|
||||
m_pConnection = NULL;
|
||||
}
|
||||
|
||||
@@ -76,44 +74,25 @@ 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(g_pOptions->GetControlIP(),
|
||||
m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(),
|
||||
m_bTLS);
|
||||
m_pConnection = new Connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
|
||||
m_pConnection->SetTimeout(g_pOptions->GetConnectionTimeout());
|
||||
m_pConnection->SetSuppressErrors(false);
|
||||
bBind = m_pConnection->Bind() == 0;
|
||||
}
|
||||
|
||||
// Accept connections and store the new Connection
|
||||
Connection* pAcceptedConnection = NULL;
|
||||
// Accept connections and store the "new" socket value
|
||||
SOCKET iSocket = INVALID_SOCKET;
|
||||
if (bBind)
|
||||
{
|
||||
pAcceptedConnection = m_pConnection->Accept();
|
||||
iSocket = m_pConnection->Accept();
|
||||
}
|
||||
if (!bBind || pAcceptedConnection == NULL)
|
||||
if (!bBind || iSocket == INVALID_SOCKET)
|
||||
{
|
||||
// Remote server could not bind or accept connection, waiting 1/2 sec and try again
|
||||
if (IsStopped())
|
||||
@@ -128,13 +107,9 @@ void RemoteServer::Run()
|
||||
|
||||
RequestProcessor* commandThread = new RequestProcessor();
|
||||
commandThread->SetAutoDestroy(true);
|
||||
commandThread->SetConnection(pAcceptedConnection);
|
||||
#ifndef DISABLE_TLS
|
||||
commandThread->SetTLS(m_bTLS);
|
||||
#endif
|
||||
commandThread->SetSocket(iSocket);
|
||||
commandThread->Start();
|
||||
}
|
||||
|
||||
if (m_pConnection)
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
@@ -159,32 +134,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;
|
||||
|
||||
m_pConnection->SetSuppressErrors(true);
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
if (m_bTLS && !m_pConnection->StartTLS(false, g_pOptions->GetSecureCert(), g_pOptions->GetSecureKey()))
|
||||
int iSignature = 0;
|
||||
int iBytesReceived = recv(m_iSocket, (char*)&iSignature, sizeof(iSignature), 0);
|
||||
if (iBytesReceived < 0)
|
||||
{
|
||||
debug("Could not establish secure connection to web-client: Start TLS failed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Read the first 4 bytes to determine request type
|
||||
int iSignature = 0;
|
||||
if (!m_pConnection->Recv((char*)&iSignature, 4))
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
#ifdef WIN32
|
||||
ip = inet_ntoa(PeerName.sin_addr);
|
||||
#else
|
||||
inet_ntop(AF_INET, &PeerName.sin_addr, ip, sizeof(ip));
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((int)ntohl(iSignature) == (int)NZBMESSAGE_SIGNATURE)
|
||||
@@ -192,7 +167,9 @@ void RequestProcessor::Run()
|
||||
// binary request received
|
||||
bOK = true;
|
||||
BinRpcProcessor processor;
|
||||
processor.SetConnection(m_pConnection);
|
||||
processor.SetSocket(m_iSocket);
|
||||
processor.SetSignature(iSignature);
|
||||
processor.SetClientIP(ip);
|
||||
processor.Execute();
|
||||
}
|
||||
else if (!strncmp((char*)&iSignature, "POST", 4) ||
|
||||
@@ -200,8 +177,9 @@ void RequestProcessor::Run()
|
||||
!strncmp((char*)&iSignature, "OPTI", 4))
|
||||
{
|
||||
// HTTP request received
|
||||
Connection con(m_iSocket, false);
|
||||
char szBuffer[1024];
|
||||
if (m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
if (con.ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
{
|
||||
WebProcessor::EHttpMethod eHttpMethod = WebProcessor::hmGet;
|
||||
char* szUrl = szBuffer;
|
||||
@@ -223,7 +201,8 @@ void RequestProcessor::Run()
|
||||
debug("url: %s", szUrl);
|
||||
|
||||
WebProcessor processor;
|
||||
processor.SetConnection(m_pConnection);
|
||||
processor.SetConnection(&con);
|
||||
processor.SetClientIP(ip);
|
||||
processor.SetUrl(szUrl);
|
||||
processor.SetHttpMethod(eHttpMethod);
|
||||
processor.Execute();
|
||||
@@ -231,8 +210,15 @@ void RequestProcessor::Run()
|
||||
}
|
||||
}
|
||||
|
||||
if (!bOK)
|
||||
if (!bOK && iBytesReceived > 0)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetControlPort(), ip);
|
||||
}
|
||||
|
||||
if (!bOK && iBytesReceived == 0)
|
||||
{
|
||||
debug("empty request received on port %i from %s", g_pOptions->GetControlPort(), ip);
|
||||
}
|
||||
|
||||
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-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@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
|
||||
@@ -33,11 +33,10 @@
|
||||
class RemoteServer : public Thread
|
||||
{
|
||||
private:
|
||||
bool m_bTLS;
|
||||
Connection* m_pConnection;
|
||||
|
||||
public:
|
||||
RemoteServer(bool bTLS);
|
||||
RemoteServer();
|
||||
~RemoteServer();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
@@ -46,14 +45,11 @@ public:
|
||||
class RequestProcessor : public Thread
|
||||
{
|
||||
private:
|
||||
bool m_bTLS;
|
||||
Connection* m_pConnection;
|
||||
SOCKET m_iSocket;
|
||||
|
||||
public:
|
||||
~RequestProcessor();
|
||||
virtual void Run();
|
||||
void SetTLS(bool bTLS) { m_bTLS = bTLS; }
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -43,16 +43,12 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ScriptController.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
// System global variable holding environments variables
|
||||
extern char** environ;
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern char* (*g_szEnvironmentVariables)[];
|
||||
extern DownloadQueueHolder* g_pDownloadQueueHolder;
|
||||
@@ -218,7 +214,7 @@ void ScriptController::SetEnvVar(const char* szName, const char* szValue)
|
||||
m_environmentStrings.Append(szVar);
|
||||
}
|
||||
|
||||
void ScriptController::PrepareEnvOptions()
|
||||
void ScriptController::PrepareEnvironmentStrings()
|
||||
{
|
||||
Options::OptEntries* pOptEntries = g_pOptions->LockOptEntries();
|
||||
|
||||
@@ -231,7 +227,10 @@ void ScriptController::PrepareEnvOptions()
|
||||
// convert to upper case; replace "." with "_".
|
||||
for (char* szPtr = szVarname; *szPtr; szPtr++)
|
||||
{
|
||||
if (*szPtr == '.') *szPtr = '_';
|
||||
if (*szPtr == '.')
|
||||
{
|
||||
*szPtr = '_';
|
||||
}
|
||||
*szPtr = toupper(*szPtr);
|
||||
}
|
||||
|
||||
@@ -242,40 +241,15 @@ void ScriptController::PrepareEnvOptions()
|
||||
g_pOptions->UnlockOptEntries();
|
||||
}
|
||||
|
||||
void ScriptController::PrepareEnvParameters(NZBInfo* pNZBInfo)
|
||||
{
|
||||
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
char szVarname[1024];
|
||||
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
|
||||
szVarname[1024-1] = '\0';
|
||||
|
||||
// Original name
|
||||
SetEnvVar(szVarname, pParameter->GetValue());
|
||||
|
||||
char szNormVarname[1024];
|
||||
strncpy(szNormVarname, szVarname, sizeof(szVarname));
|
||||
szNormVarname[1024-1] = '\0';
|
||||
|
||||
// replace ".*:" with "_".
|
||||
for (char* szPtr = szNormVarname; *szPtr; szPtr++)
|
||||
{
|
||||
if (*szPtr == '.' || *szPtr == ':' || *szPtr == '*') *szPtr = '_';
|
||||
*szPtr = toupper(*szPtr);
|
||||
}
|
||||
|
||||
// Another env var with normalized name (replaced special chars and converted to upper case)
|
||||
if (strcmp(szVarname, szNormVarname))
|
||||
{
|
||||
SetEnvVar(szNormVarname, pParameter->GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ScriptController::Execute()
|
||||
{
|
||||
PrepareEnvOptions();
|
||||
if (!Util::FileExists(m_szScript))
|
||||
{
|
||||
error("Could not start %s: could not find file %s", m_szInfoName, m_szScript);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PrepareEnvironmentStrings();
|
||||
|
||||
int iExitCode = 0;
|
||||
int pipein;
|
||||
@@ -325,7 +299,8 @@ int ScriptController::Execute()
|
||||
DWORD dwErrCode = GetLastError();
|
||||
char szErrMsg[255];
|
||||
szErrMsg[255-1] = '\0';
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM || FORMAT_MESSAGE_IGNORE_INSERTS || FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
{
|
||||
error("Could not start %s: %s", m_szInfoName, szErrMsg);
|
||||
}
|
||||
@@ -333,10 +308,6 @@ int ScriptController::Execute()
|
||||
{
|
||||
error("Could not start %s: error %i", m_szInfoName, dwErrCode);
|
||||
}
|
||||
if (!Util::FileExists(m_szScript))
|
||||
{
|
||||
error("Could not find file %s", m_szScript);
|
||||
}
|
||||
free(szEnvironmentStrings);
|
||||
return -1;
|
||||
}
|
||||
@@ -399,14 +370,10 @@ int ScriptController::Execute()
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
chdir(m_szWorkingDir);
|
||||
environ = pEnvironmentStrings;
|
||||
execvp(m_szScript, (char* const*)m_szArgs);
|
||||
// NOTE: the text "[ERROR] Could not start " is checked later,
|
||||
// by changing adjust the dependent code below.
|
||||
fprintf(stdout, "[ERROR] Could not start %s: %s", m_szScript, strerror(errno));
|
||||
execve(m_szScript, (char* const*)m_szArgs, (char* const*)pEnvironmentStrings);
|
||||
fprintf(stdout, "[ERROR] Could not start script: %s", strerror(errno));
|
||||
fflush(stdout);
|
||||
_exit(254);
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
// continue the first instance
|
||||
@@ -440,11 +407,9 @@ int ScriptController::Execute()
|
||||
char* buf = (char*)malloc(10240);
|
||||
|
||||
debug("Entering pipe-loop");
|
||||
bool bFirstLine = true;
|
||||
bool bStartError = false;
|
||||
while (!feof(readpipe) && !m_bTerminated)
|
||||
{
|
||||
if (ReadLine(buf, 10240, readpipe))
|
||||
if (fgets(buf, 10240, readpipe))
|
||||
{
|
||||
#ifdef CHILD_WATCHDOG
|
||||
if (!bChildConfirmed)
|
||||
@@ -452,15 +417,9 @@ int ScriptController::Execute()
|
||||
bChildConfirmed = true;
|
||||
pWatchDog->Stop();
|
||||
debug("Child confirmed");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (bFirstLine && !strncmp(buf, "[ERROR] Could not start ", 24))
|
||||
{
|
||||
bStartError = true;
|
||||
}
|
||||
ProcessOutput(buf);
|
||||
bFirstLine = false;
|
||||
}
|
||||
}
|
||||
debug("Exited pipe-loop");
|
||||
@@ -499,10 +458,6 @@ int ScriptController::Execute()
|
||||
if (WIFEXITED(iStatus))
|
||||
{
|
||||
iExitCode = WEXITSTATUS(iStatus);
|
||||
if (iExitCode == 254 && bStartError)
|
||||
{
|
||||
iExitCode = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -548,11 +503,6 @@ void ScriptController::Terminate()
|
||||
debug("Stopped %s", m_szInfoName);
|
||||
}
|
||||
|
||||
bool ScriptController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
return fgets(szBuf, iBufSize, pStream);
|
||||
}
|
||||
|
||||
void ScriptController::ProcessOutput(char* szText)
|
||||
{
|
||||
debug("Processing output received from script");
|
||||
@@ -567,23 +517,23 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
|
||||
if (!strncmp(szText, "[INFO] ", 7))
|
||||
{
|
||||
AddMessage(Message::mkInfo, false, szText + 7);
|
||||
AddMessage(Message::mkInfo, false, g_pOptions->GetInfoTarget(), szText + 7);
|
||||
}
|
||||
else if (!strncmp(szText, "[WARNING] ", 10))
|
||||
{
|
||||
AddMessage(Message::mkWarning, false, szText + 10);
|
||||
AddMessage(Message::mkWarning, false, g_pOptions->GetWarningTarget(), szText + 10);
|
||||
}
|
||||
else if (!strncmp(szText, "[ERROR] ", 8))
|
||||
{
|
||||
AddMessage(Message::mkError, false, szText + 8);
|
||||
AddMessage(Message::mkError, false, g_pOptions->GetErrorTarget(), szText + 8);
|
||||
}
|
||||
else if (!strncmp(szText, "[DETAIL] ", 9))
|
||||
{
|
||||
AddMessage(Message::mkDetail, false, szText + 9);
|
||||
AddMessage(Message::mkDetail, false, g_pOptions->GetDetailTarget(), szText + 9);
|
||||
}
|
||||
else if (!strncmp(szText, "[DEBUG] ", 8))
|
||||
{
|
||||
AddMessage(Message::mkDebug, false, szText + 8);
|
||||
AddMessage(Message::mkDebug, false, g_pOptions->GetDebugTarget(), szText + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -593,23 +543,23 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
break;
|
||||
|
||||
case Options::slDetail:
|
||||
AddMessage(Message::mkDetail, true, szText);
|
||||
AddMessage(Message::mkDetail, true, g_pOptions->GetDetailTarget(), szText);
|
||||
break;
|
||||
|
||||
case Options::slInfo:
|
||||
AddMessage(Message::mkInfo, true, szText);
|
||||
AddMessage(Message::mkInfo, true, g_pOptions->GetInfoTarget(), szText);
|
||||
break;
|
||||
|
||||
case Options::slWarning:
|
||||
AddMessage(Message::mkWarning, true, szText);
|
||||
AddMessage(Message::mkWarning, true, g_pOptions->GetWarningTarget(), szText);
|
||||
break;
|
||||
|
||||
case Options::slError:
|
||||
AddMessage(Message::mkError, true, szText);
|
||||
AddMessage(Message::mkError, true, g_pOptions->GetErrorTarget(), szText);
|
||||
break;
|
||||
|
||||
case Options::slDebug:
|
||||
AddMessage(Message::mkDebug, true, szText);
|
||||
AddMessage(Message::mkDebug, true, g_pOptions->GetDebugTarget(), szText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -617,7 +567,7 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
debug("Processing output received from script - completed");
|
||||
}
|
||||
|
||||
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
|
||||
{
|
||||
switch (eKind)
|
||||
{
|
||||
@@ -643,30 +593,19 @@ void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptController::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
|
||||
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, const char* szScript, bool bNZBFileCompleted, bool bHasFailedParJobs)
|
||||
{
|
||||
char tmp2[1024];
|
||||
info("Executing post-process-script for %s", pPostInfo->GetInfoName());
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
vsnprintf(tmp2, 1024, szFormat, ap);
|
||||
tmp2[1024-1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
AddMessage(eKind, false, tmp2);
|
||||
}
|
||||
|
||||
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, bool bNZBFileCompleted, bool bHasFailedParJobs)
|
||||
{
|
||||
PostScriptController* pScriptController = new PostScriptController();
|
||||
pScriptController->m_pPostInfo = pPostInfo;
|
||||
pScriptController->SetScript(g_pOptions->GetPostProcess());
|
||||
pScriptController->SetScript(szScript);
|
||||
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
|
||||
pScriptController->m_bNZBFileCompleted = bNZBFileCompleted;
|
||||
pScriptController->m_bHasFailedParJobs = bHasFailedParJobs;
|
||||
pScriptController->SetAutoDestroy(false);
|
||||
|
||||
pPostInfo->SetPostThread(pScriptController);
|
||||
pPostInfo->SetScriptThread(pScriptController);
|
||||
|
||||
pScriptController->Start();
|
||||
}
|
||||
@@ -680,16 +619,10 @@ void PostScriptController::Run()
|
||||
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
|
||||
szNZBName[1024-1] = '\0';
|
||||
|
||||
int iParStatus[] = { 0, 0, 1, 2, 3 };
|
||||
char szParStatus[10];
|
||||
snprintf(szParStatus, 10, "%i", iParStatus[g_pOptions->GetAllowReProcess() ? (int)m_pPostInfo->GetParStatus() : (int)m_pPostInfo->GetNZBInfo()->GetParStatus()]);
|
||||
snprintf(szParStatus, 10, "%i", m_pPostInfo->GetParStatus());
|
||||
szParStatus[10-1] = '\0';
|
||||
|
||||
int iUnpackStatus[] = { 0, 0, 1, 2 };
|
||||
char szUnpackStatus[10];
|
||||
snprintf(szUnpackStatus, 10, "%i", g_pOptions->GetAllowReProcess() ? 0 : iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
|
||||
szUnpackStatus[10-1] = '\0';
|
||||
|
||||
char szCollectionCompleted[10];
|
||||
snprintf(szCollectionCompleted, 10, "%i", (int)m_bNZBFileCompleted);
|
||||
szCollectionCompleted[10-1] = '\0';
|
||||
@@ -715,7 +648,7 @@ void PostScriptController::Run()
|
||||
szCategory[1024-1] = '\0';
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "post-process-script for %s", g_pOptions->GetAllowReProcess() ? m_pPostInfo->GetInfoName() : m_pPostInfo->GetNZBInfo()->GetName());
|
||||
snprintf(szInfoName, 1024, "post-process-script for %s", m_pPostInfo->GetInfoName());
|
||||
szInfoName[1024-1] = '\0';
|
||||
SetInfoName(szInfoName);
|
||||
|
||||
@@ -739,30 +672,31 @@ void PostScriptController::Run()
|
||||
SetEnvVar("NZBPP_NZBFILENAME", szNZBFilename);
|
||||
SetEnvVar("NZBPP_PARFILENAME", szParFilename);
|
||||
SetEnvVar("NZBPP_PARSTATUS", szParStatus);
|
||||
SetEnvVar("NZBPP_UNPACKSTATUS", szUnpackStatus);
|
||||
SetEnvVar("NZBPP_NZBCOMPLETED", szCollectionCompleted);
|
||||
SetEnvVar("NZBPP_PARFAILED", szHasFailedParJobs);
|
||||
SetEnvVar("NZBPP_CATEGORY", szCategory);
|
||||
|
||||
PrepareEnvParameters(m_pPostInfo->GetNZBInfo());
|
||||
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
char szVarname[1024];
|
||||
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
|
||||
szVarname[1024-1] = '\0';
|
||||
SetEnvVar(szVarname, pParameter->GetValue());
|
||||
}
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
|
||||
info("Executing post-process-script for %s", g_pOptions->GetAllowReProcess() ? m_pPostInfo->GetInfoName() : szNZBName);
|
||||
|
||||
int iResult = Execute();
|
||||
|
||||
szInfoName[0] = 'P'; // uppercase
|
||||
|
||||
switch (iResult)
|
||||
{
|
||||
case POSTPROCESS_SUCCESS:
|
||||
info("%s successful", szInfoName);
|
||||
info("%s sucessful", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srSuccess);
|
||||
break;
|
||||
|
||||
case POSTPROCESS_ERROR:
|
||||
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
|
||||
info("%s failed", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
|
||||
break;
|
||||
@@ -774,7 +708,7 @@ void PostScriptController::Run()
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
case POSTPROCESS_PARCHECK_ALL:
|
||||
if (m_pPostInfo->GetParStatus() > PostInfo::psSkipped)
|
||||
if (m_pPostInfo->GetParCheck())
|
||||
{
|
||||
error("%s requested par-check/repair for all collections, but they were already checked", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
|
||||
@@ -793,7 +727,7 @@ void PostScriptController::Run()
|
||||
break;
|
||||
|
||||
case POSTPROCESS_PARCHECK_CURRENT:
|
||||
if (m_pPostInfo->GetParStatus() > PostInfo::psSkipped)
|
||||
if (m_pPostInfo->GetParCheck())
|
||||
{
|
||||
error("%s requested par-check/repair for current collection, but it was already checked", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
|
||||
@@ -821,18 +755,26 @@ void PostScriptController::Run()
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
|
||||
{
|
||||
if (!strncmp(szText, "[HISTORY] ", 10))
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szText);
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
|
||||
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (g_pOptions->GetPausePostProcess())
|
||||
{
|
||||
time_t tStageTime = m_pPostInfo->GetStageTime();
|
||||
@@ -912,7 +854,7 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
|
||||
delete pScriptController;
|
||||
}
|
||||
|
||||
void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
|
||||
{
|
||||
if (!strncmp(szText, "[NZB] ", 6))
|
||||
{
|
||||
@@ -948,7 +890,7 @@ void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, co
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szText);
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,7 +927,14 @@ void NZBAddedScriptController::StartScript(DownloadQueue* pDownloadQueue, NZBInf
|
||||
snprintf(buf, 100, "%i", iMaxPriority);
|
||||
pScriptController->SetEnvVar("NZBNA_PRIORITY", buf);
|
||||
|
||||
pScriptController->PrepareEnvParameters(pNZBInfo);
|
||||
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
char szVarname[1024];
|
||||
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
|
||||
szVarname[1024-1] = '\0';
|
||||
pScriptController->SetEnvVar(szVarname, pParameter->GetValue());
|
||||
}
|
||||
|
||||
pScriptController->SetAutoDestroy(true);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -27,7 +27,6 @@
|
||||
#define SCRIPTCONTROLLER_H
|
||||
|
||||
#include <list>
|
||||
#include <fstream>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
@@ -71,15 +70,11 @@ private:
|
||||
pid_t m_hProcess;
|
||||
#endif
|
||||
|
||||
void PrepareEnvOptions();
|
||||
void ProcessOutput(char* szText);
|
||||
void PrepareEnvironmentStrings();
|
||||
|
||||
protected:
|
||||
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, bool bDefaultKind, const char* szText);
|
||||
bool GetTerminated() { return m_bTerminated; }
|
||||
void PrepareEnvParameters(NZBInfo* pNZBInfo);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
|
||||
public:
|
||||
ScriptController();
|
||||
@@ -98,7 +93,7 @@ public:
|
||||
void SetEnvVar(const char* szName, const char* szValue);
|
||||
};
|
||||
|
||||
class PostScriptController : public Thread, public ScriptController
|
||||
class PostScriptController : public Thread, ScriptController
|
||||
{
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
@@ -106,12 +101,13 @@ private:
|
||||
bool m_bHasFailedParJobs;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartScriptJob(PostInfo* pPostInfo, bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
static void StartScriptJob(PostInfo* pPostInfo, const char* szScript,
|
||||
bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
};
|
||||
|
||||
class NZBScriptController : public ScriptController
|
||||
@@ -122,13 +118,13 @@ private:
|
||||
NZBParameterList* m_pParameterList;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
|
||||
public:
|
||||
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory, char** pCategory, int* iPriority, NZBParameterList* pParameterList);
|
||||
};
|
||||
|
||||
class NZBAddedScriptController : public Thread, public ScriptController
|
||||
class NZBAddedScriptController : public Thread, ScriptController
|
||||
{
|
||||
private:
|
||||
char* m_szNZBName;
|
||||
@@ -138,7 +134,7 @@ public:
|
||||
static void StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript);
|
||||
};
|
||||
|
||||
class SchedulerScriptController : public Thread, public ScriptController
|
||||
class SchedulerScriptController : public Thread, ScriptController
|
||||
{
|
||||
public:
|
||||
virtual void Run();
|
||||
|
||||
112
ServerPool.cpp
112
ServerPool.cpp
@@ -38,7 +38,6 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ServerPool.h"
|
||||
@@ -83,119 +82,70 @@ void ServerPool::AddServer(NewsServer* pNewsServer)
|
||||
{
|
||||
debug("Adding server to ServerPool");
|
||||
|
||||
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();
|
||||
m_Servers.push_back(pNewsServer);
|
||||
}
|
||||
|
||||
void ServerPool::InitConnections()
|
||||
{
|
||||
debug("Initializing connections in ServerPool");
|
||||
|
||||
NormalizeLevels();
|
||||
|
||||
m_iMaxLevel = 0;
|
||||
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();
|
||||
}
|
||||
|
||||
if (m_Levels.empty())
|
||||
for (int iLevel = 0; iLevel <= m_iMaxLevel; iLevel++)
|
||||
{
|
||||
warn("No news servers defined, download is not possible");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers)
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel)
|
||||
{
|
||||
PooledConnection* pConnection = NULL;
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
if (iLevel < (int)m_Levels.size() && m_Levels[iLevel] > 0)
|
||||
if (m_Levels[iLevel] > 0)
|
||||
{
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pCandidateConnection = *it;
|
||||
NewsServer* pCandidateServer = pCandidateConnection->GetNewsServer();
|
||||
if (!pCandidateConnection->GetInUse() && pCandidateServer->GetLevel() == iLevel &&
|
||||
(!pWantServer || pCandidateServer == pWantServer ||
|
||||
(pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())))
|
||||
PooledConnection* pConnection1 = *it;
|
||||
if (!pConnection1->GetInUse() && pConnection1->GetNewsServer()->GetLevel() == iLevel)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
// free connection found, take it!
|
||||
pConnection = pConnection1;
|
||||
pConnection->SetInUse(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pConnection)
|
||||
m_Levels[iLevel]--;
|
||||
|
||||
if (!pConnection)
|
||||
{
|
||||
m_Levels[iLevel]--;
|
||||
error("ServerPool: internal error, no free connection found, but there should be one");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +208,7 @@ void ServerPool::LogDebugInfo()
|
||||
debug(" Connections: %i", m_Connections.size());
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
debug(" %s: Level=%i, InUse:%i", (*it)->GetNewsServer()->GetHost(), (*it)->GetNewsServer()->GetLevel(), (int)(*it)->GetInUse());
|
||||
debug(" Connection: Level=%i, InUse:%i", (*it)->GetNewsServer()->GetLevel(), (int)(*it)->GetInUse());
|
||||
}
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
|
||||
10
ServerPool.h
10
ServerPool.h
@@ -36,9 +36,6 @@
|
||||
|
||||
class ServerPool
|
||||
{
|
||||
public:
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
|
||||
private:
|
||||
class PooledConnection : public NNTPConnection
|
||||
{
|
||||
@@ -53,6 +50,7 @@ private:
|
||||
void SetFreeTimeNow() { m_tFreeTime = ::time(NULL); }
|
||||
};
|
||||
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
typedef std::vector<int> Levels;
|
||||
typedef std::vector<PooledConnection*> Connections;
|
||||
|
||||
@@ -63,9 +61,6 @@ private:
|
||||
Mutex m_mutexConnections;
|
||||
int m_iTimeout;
|
||||
|
||||
void NormalizeLevels();
|
||||
static bool CompareServers(NewsServer* pServer1, NewsServer* pServer2);
|
||||
|
||||
public:
|
||||
ServerPool();
|
||||
~ServerPool();
|
||||
@@ -73,8 +68,7 @@ public:
|
||||
void AddServer(NewsServer* pNewsServer);
|
||||
void InitConnections();
|
||||
int GetMaxLevel() { return m_iMaxLevel; }
|
||||
Servers* GetServers() { return &m_Servers; } // Only for read access (no lockings)
|
||||
NNTPConnection* GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers);
|
||||
NNTPConnection* GetConnection(int iLevel);
|
||||
void FreeConnection(NNTPConnection* pConnection, bool bUsed);
|
||||
void CloseUnusedConnections();
|
||||
|
||||
|
||||
204
TLS.h
204
TLS.h
@@ -1,7 +1,13 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,36 +33,180 @@
|
||||
|
||||
#ifndef DISABLE_TLS
|
||||
|
||||
class TLSSocket
|
||||
#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
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
// using "void*" to prevent the including of GnuTLS/OpenSSL header files into TLS.h
|
||||
void* m_pContext;
|
||||
void* m_pSession;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
void ReportError(const char* szErrMsg);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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; }
|
||||
};
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
713
Unpack.cpp
713
Unpack.cpp
@@ -1,713 +0,0 @@
|
||||
/*
|
||||
* 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 <ctype.h>
|
||||
#include <fstream>
|
||||
#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::StartUnpackJob(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';
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && HasBrokenFiles() && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && HasParFiles())
|
||||
{
|
||||
info("%s has broken files", m_szName);
|
||||
RequestParCheck(false);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bUnpack)
|
||||
{
|
||||
CheckArchiveFiles();
|
||||
}
|
||||
|
||||
if (bUnpack && (m_bHasRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles))
|
||||
{
|
||||
SetInfoName(m_szInfoName);
|
||||
SetDefaultLogKind(g_pOptions->GetProcessLogKind());
|
||||
SetWorkingDir(m_szDestDir);
|
||||
|
||||
PrintMessage(Message::mkInfo, "Unpacking %s", m_szName);
|
||||
|
||||
CreateUnpackDir();
|
||||
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
|
||||
if (m_bHasRarFiles)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
ExecuteUnrar();
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipFiles && m_bUnpackOK)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
ExecuteSevenZip(false);
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipMultiFiles && m_bUnpackOK)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
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 && HasParFiles())
|
||||
{
|
||||
RequestParCheck(m_pPostInfo->GetNZBInfo()->GetRenameStatus() <= NZBInfo::rsSkipped);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_pPostInfo->SetUnpackStatus(PostInfo::usSkipped);
|
||||
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] = "*.rar";
|
||||
szArgs[6] = m_szUnpackDir;
|
||||
szArgs[7] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetUnrarCmd());
|
||||
SetDefaultKindPrefix("Unrar: ");
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upUnrar;
|
||||
|
||||
int iExitCode = Execute();
|
||||
m_pPostInfo->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());
|
||||
SetDefaultKindPrefix("7-Zip: ");
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upSevenZip;
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing 7-Zip");
|
||||
int iExitCode = Execute();
|
||||
m_pPostInfo->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->SetUnpackStatus(PostInfo::usSuccess);
|
||||
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() && HasParFiles())
|
||||
{
|
||||
RequestParCheck(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
|
||||
m_pPostInfo->SetUnpackStatus(PostInfo::usFailure);
|
||||
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(PostInfo::rpAll);
|
||||
}
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool UnpackController::HasParFiles()
|
||||
{
|
||||
return ParCoordinator::FindMainPars(m_szDestDir, NULL);
|
||||
}
|
||||
|
||||
bool UnpackController::HasBrokenFiles()
|
||||
{
|
||||
char szBrokenLog[1024];
|
||||
snprintf(szBrokenLog, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_brokenlog.txt");
|
||||
szBrokenLog[1024-1] = '\0';
|
||||
return Util::FileExists(szBrokenLog);
|
||||
}
|
||||
|
||||
void UnpackController::CreateUnpackDir()
|
||||
{
|
||||
if (strlen(g_pOptions->GetInterDir()) > 0 &&
|
||||
!strncmp(m_szDestDir, g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir())))
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szFinalDir, 1024);
|
||||
m_szFinalDir[1024-1] = '\0';
|
||||
Util::ForceDirectories(m_szFinalDir);
|
||||
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';
|
||||
Util::ForceDirectories(m_szUnpackDir);
|
||||
}
|
||||
|
||||
|
||||
void UnpackController::CheckArchiveFiles()
|
||||
{
|
||||
m_bHasRarFiles = false;
|
||||
m_bHasSevenZipFiles = false;
|
||||
m_bHasSevenZipMultiFiles = false;
|
||||
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
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;
|
||||
}
|
||||
if (regExSevenZip.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipFiles = true;
|
||||
}
|
||||
if (regExSevenZipMulti.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipMultiFiles = 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 (!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) && !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, bool bDefaultKind, 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, "Extracting ", 12) &&
|
||||
!strncmp(szText + 12, m_szUnpackDir, strlen(m_szUnpackDir)))
|
||||
{
|
||||
snprintf(szMsgText, 1024, "Extracting %s", szText + 12 + strlen(m_szUnpackDir) + 1);
|
||||
szMsgText[1024-1] = '\0';
|
||||
}
|
||||
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szMsgText);
|
||||
m_pPostInfo->AppendMessage(eKind, szMsgText);
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szMsgText, "Extracting ", 11))
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel(szMsgText);
|
||||
}
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Extracting from ", 16))
|
||||
{
|
||||
const char *szFilename = szText + 16;
|
||||
debug("Filename: %s", szFilename);
|
||||
m_archiveFiles.push_back(strdup(szFilename));
|
||||
m_pPostInfo->SetProgressLabel(szText);
|
||||
}
|
||||
|
||||
if ((m_eUnpacker == upUnrar && !strncmp(szText, "All OK", 6)) ||
|
||||
(m_eUnpacker == upSevenZip && !strncmp(szText, "Everything is Ok", 16)))
|
||||
{
|
||||
m_bAllOKMessageReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::Stop()
|
||||
{
|
||||
debug("Stopping unpack");
|
||||
Thread::Stop();
|
||||
Terminate();
|
||||
}
|
||||
|
||||
|
||||
void MoveController::StartMoveJob(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);
|
||||
|
||||
SetDefaultKindPrefix("Move: ");
|
||||
SetDefaultLogKind(g_pOptions->GetProcessLogKind());
|
||||
|
||||
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()
|
||||
{
|
||||
bool bOK = true;
|
||||
|
||||
bOK = Util::ForceDirectories(m_szDestDir);
|
||||
|
||||
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;
|
||||
}
|
||||
109
Unpack.h
109
Unpack.h
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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_bAllOKMessageReceived;
|
||||
bool m_bNoFilesMessageReceived;
|
||||
bool m_bHasRarFiles;
|
||||
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, bool bDefaultKind, const char* szText);
|
||||
void ExecuteUnrar();
|
||||
void ExecuteSevenZip(bool bMultiVolumes);
|
||||
void Completed();
|
||||
void CreateUnpackDir();
|
||||
bool Cleanup();
|
||||
bool HasParFiles();
|
||||
bool HasBrokenFiles();
|
||||
void CheckArchiveFiles();
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RequestParCheck(bool bRename);
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual ~UnpackController();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartUnpackJob(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 StartMoveJob(PostInfo* pPostInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
40
Util.cpp
40
Util.cpp
@@ -599,42 +599,6 @@ bool Util::CreateDirectory(const char* szDirFilename)
|
||||
return DirectoryExists(szDirFilename);
|
||||
}
|
||||
|
||||
bool Util::RemoveDirectory(const char* szDirFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return ::RemoveDirectory(szDirFilename);
|
||||
#else
|
||||
return remove(szDirFilename) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Util::DeleteDirectoryWithContent(const char* szDirFilename)
|
||||
{
|
||||
bool bOK = true;
|
||||
|
||||
DirBrowser dir(szDirFilename);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDirFilename, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
if (Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
bOK &= DeleteDirectoryWithContent(szFullFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
bOK &= remove(szFullFilename) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bOK && RemoveDirectory(szDirFilename);
|
||||
}
|
||||
|
||||
long long Util::FileSize(const char* szFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
@@ -1145,7 +1109,7 @@ char* WebUtil::JsonEncode(const char* raw)
|
||||
iReqSize++;
|
||||
break;
|
||||
default:
|
||||
if (ch < 0x20 || ch >= 0x80)
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
iReqSize += 6;
|
||||
break;
|
||||
@@ -1197,7 +1161,7 @@ char* WebUtil::JsonEncode(const char* raw)
|
||||
output += 2;
|
||||
break;
|
||||
default:
|
||||
if (ch < 0x20 || ch >= 0x80)
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
sprintf(output, "\\u%04x", ch);
|
||||
output += 6;
|
||||
|
||||
2
Util.h
2
Util.h
@@ -71,8 +71,6 @@ public:
|
||||
static bool FileExists(const char* szFilename);
|
||||
static bool DirectoryExists(const char* szDirFilename);
|
||||
static bool CreateDirectory(const char* szDirFilename);
|
||||
static bool RemoveDirectory(const char* szDirFilename);
|
||||
static bool DeleteDirectoryWithContent(const char* szDirFilename);
|
||||
static bool ForceDirectories(const char* szPath);
|
||||
static bool GetCurrentDirectory(char* szBuffer, int iBufSize);
|
||||
static bool SetCurrentDirectory(const char* szDirFilename);
|
||||
|
||||
@@ -390,7 +390,7 @@ WebDownloader::EStatus WebDownloader::DownloadBody()
|
||||
m_pConnection->ReadBuffer(&szBuffer, &iLen);
|
||||
if (iLen == 0)
|
||||
{
|
||||
iLen = m_pConnection->TryRecv(szLineBuf, LineBufSize);
|
||||
iLen = m_pConnection->Recv(szLineBuf, LineBufSize);
|
||||
szBuffer = szLineBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ static const int MAX_UNCOMPRESSED_SIZE = 500;
|
||||
WebProcessor::WebProcessor()
|
||||
{
|
||||
m_pConnection = NULL;
|
||||
m_szClientIP = NULL;
|
||||
m_szRequest = NULL;
|
||||
m_szUrl = NULL;
|
||||
m_szOrigin = NULL;
|
||||
@@ -93,6 +94,7 @@ void WebProcessor::Execute()
|
||||
|
||||
// reading http header
|
||||
char szBuffer[1024];
|
||||
bool bBody = false;
|
||||
int iContentLen = 0;
|
||||
while (char* p = m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
{
|
||||
@@ -122,6 +124,7 @@ void WebProcessor::Execute()
|
||||
}
|
||||
if (*p == '\0')
|
||||
{
|
||||
bBody = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -196,7 +199,7 @@ void WebProcessor::Execute()
|
||||
if (pw) *pw++ = '\0';
|
||||
if (strcmp(szAuthInfo, "nzbget") || strcmp(pw, g_pOptions->GetControlPassword()))
|
||||
{
|
||||
warn("request received on port %i from %s, but password invalid", g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
|
||||
warn("request received on port %i from %s, but password invalid", g_pOptions->GetControlPort(), m_szClientIP);
|
||||
SendAuthResponse();
|
||||
return;
|
||||
}
|
||||
@@ -207,7 +210,7 @@ void WebProcessor::Execute()
|
||||
m_szRequest = (char*)malloc(iContentLen + 1);
|
||||
m_szRequest[iContentLen] = '\0';
|
||||
|
||||
if (!m_pConnection->Recv(m_szRequest, iContentLen))
|
||||
if (!m_pConnection->RecvAll(m_szRequest, iContentLen))
|
||||
{
|
||||
free(m_szRequest);
|
||||
error("invalid-request: could not read data");
|
||||
@@ -216,7 +219,7 @@ void WebProcessor::Execute()
|
||||
debug("Request=%s", m_szRequest);
|
||||
}
|
||||
|
||||
debug("request received from %s", m_pConnection->GetRemoteAddr());
|
||||
debug("request received from %s", m_szClientIP);
|
||||
|
||||
Dispatch();
|
||||
}
|
||||
@@ -233,6 +236,7 @@ void WebProcessor::Dispatch()
|
||||
{
|
||||
XmlRpcProcessor processor;
|
||||
processor.SetRequest(m_szRequest);
|
||||
processor.SetClientIP(m_szClientIP);
|
||||
processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost);
|
||||
processor.SetUrl(m_szUrl);
|
||||
processor.Execute();
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
|
||||
private:
|
||||
Connection* m_pConnection;
|
||||
const char* m_szClientIP;
|
||||
char* m_szRequest;
|
||||
char* m_szUrl;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
@@ -62,6 +63,7 @@ public:
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetUrl(const char* szUrl);
|
||||
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
146
XmlRpc.cpp
146
XmlRpc.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <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
|
||||
@@ -93,6 +93,7 @@ void StringBuilder::Append(const char* szStr)
|
||||
|
||||
XmlRpcProcessor::XmlRpcProcessor()
|
||||
{
|
||||
m_szClientIP = NULL;
|
||||
m_szRequest = NULL;
|
||||
m_eProtocol = rpUndefined;
|
||||
m_eHttpMethod = hmPost;
|
||||
@@ -415,10 +416,6 @@ XmlCommand* XmlRpcProcessor::CreateCommand(const char* szMethodName)
|
||||
{
|
||||
command = new PauseUnpauseXmlCommand(false, PauseUnpauseXmlCommand::paScan);
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "scheduleresume"))
|
||||
{
|
||||
command = new ScheduleResumeXmlCommand();
|
||||
}
|
||||
else if (!strcasecmp(szMethodName, "history"))
|
||||
{
|
||||
command = new HistoryXmlCommand();
|
||||
@@ -784,8 +781,6 @@ void PauseUnpauseXmlCommand::Execute()
|
||||
|
||||
bool bOK = true;
|
||||
|
||||
g_pOptions->SetResumeTime(0);
|
||||
|
||||
switch (m_eEPauseAction)
|
||||
{
|
||||
case paDownload:
|
||||
@@ -811,28 +806,6 @@ void PauseUnpauseXmlCommand::Execute()
|
||||
BuildBoolResponse(bOK);
|
||||
}
|
||||
|
||||
// bool scheduleresume(int Seconds)
|
||||
void ScheduleResumeXmlCommand::Execute()
|
||||
{
|
||||
if (!CheckSafeMethod())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iSeconds = 0;
|
||||
if (!NextParamAsInt(&iSeconds) || iSeconds < 0)
|
||||
{
|
||||
BuildErrorResponse(2, "Invalid parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
time_t tCurTime = time(NULL);
|
||||
|
||||
g_pOptions->SetResumeTime(tCurTime + iSeconds);
|
||||
|
||||
BuildBoolResponse(true);
|
||||
}
|
||||
|
||||
void ShutdownXmlCommand::Execute()
|
||||
{
|
||||
if (!CheckSafeMethod())
|
||||
@@ -888,7 +861,7 @@ void SetDownloadRateXmlCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetDownloadRate(iRate * 1024);
|
||||
g_pOptions->SetDownloadRate((float)iRate);
|
||||
BuildBoolResponse(true);
|
||||
}
|
||||
|
||||
@@ -896,11 +869,11 @@ void StatusXmlCommand::Execute()
|
||||
{
|
||||
const char* XML_RESPONSE_STATUS_BODY =
|
||||
"<struct>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadedSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>DownloadRate</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>AverageDownloadRate</name><value><i4>%i</i4></value></member>\n"
|
||||
@@ -917,20 +890,18 @@ void StatusXmlCommand::Execute()
|
||||
"<member><name>ServerStandBy</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>PostPaused</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>ScanPaused</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>FreeDiskSpaceLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FreeDiskSpaceHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FreeDiskSpaceLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FreeDiskSpaceHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FreeDiskSpaceMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>ServerTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>ResumeTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"</struct>\n";
|
||||
|
||||
const char* JSON_RESPONSE_STATUS_BODY =
|
||||
"{\n"
|
||||
"\"RemainingSizeLo\" : %u,\n"
|
||||
"\"RemainingSizeHi\" : %u,\n"
|
||||
"\"RemainingSizeLo\" : %i,\n"
|
||||
"\"RemainingSizeHi\" : %i,\n"
|
||||
"\"RemainingSizeMB\" : %i,\n"
|
||||
"\"DownloadedSizeLo\" : %u,\n"
|
||||
"\"DownloadedSizeHi\" : %u,\n"
|
||||
"\"DownloadedSizeLo\" : %i,\n"
|
||||
"\"DownloadedSizeHi\" : %i,\n"
|
||||
"\"DownloadedSizeMB\" : %i,\n"
|
||||
"\"DownloadRate\" : %i,\n"
|
||||
"\"AverageDownloadRate\" : %i,\n"
|
||||
@@ -947,19 +918,17 @@ void StatusXmlCommand::Execute()
|
||||
"\"ServerStandBy\" : %s,\n"
|
||||
"\"PostPaused\" : %s,\n"
|
||||
"\"ScanPaused\" : %s,\n"
|
||||
"\"FreeDiskSpaceLo\" : %u,\n"
|
||||
"\"FreeDiskSpaceHi\" : %u,\n"
|
||||
"\"FreeDiskSpaceMB\" : %i,\n"
|
||||
"\"ServerTime\" : %i,\n"
|
||||
"\"ResumeTime\" : %i\n"
|
||||
"\"FreeDiskSpaceLo\" : %i,\n"
|
||||
"\"FreeDiskSpaceHi\" : %i,\n"
|
||||
"\"FreeDiskSpaceMB\" : %i\n"
|
||||
"}\n";
|
||||
|
||||
unsigned long iRemainingSizeHi, iRemainingSizeLo;
|
||||
int iDownloadRate = (int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed());
|
||||
int iDownloadRate = (int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024);
|
||||
long long iRemainingSize = g_pQueueCoordinator->CalcRemainingSize();
|
||||
Util::SplitInt64(iRemainingSize, &iRemainingSizeHi, &iRemainingSizeLo);
|
||||
int iRemainingMBytes = (int)(iRemainingSize / 1024 / 1024);
|
||||
int iDownloadLimit = (int)(g_pOptions->GetDownloadRate());
|
||||
int iDownloadLimit = (int)(g_pOptions->GetDownloadRate() * 1024);
|
||||
bool bDownloadPaused = g_pOptions->GetPauseDownload();
|
||||
bool bDownload2Paused = g_pOptions->GetPauseDownload2();
|
||||
bool bPostPaused = g_pOptions->GetPausePostProcess();
|
||||
@@ -981,8 +950,6 @@ void StatusXmlCommand::Execute()
|
||||
long long iFreeDiskSpace = Util::FreeDiskSize(g_pOptions->GetDestDir());
|
||||
Util::SplitInt64(iFreeDiskSpace, &iFreeDiskSpaceHi, &iFreeDiskSpaceLo);
|
||||
int iFreeDiskSpaceMB = (int)(iFreeDiskSpace / 1024 / 1024);
|
||||
int iServerTime = time(NULL);
|
||||
int iResumeTime = g_pOptions->GetResumeTime();
|
||||
|
||||
char szContent[2048];
|
||||
snprintf(szContent, 2048, IsJson() ? JSON_RESPONSE_STATUS_BODY : XML_RESPONSE_STATUS_BODY,
|
||||
@@ -991,7 +958,7 @@ void StatusXmlCommand::Execute()
|
||||
iPostJobCount, iPostJobCount, iUrlCount, iUpTimeSec, iDownloadTimeSec,
|
||||
BoolToStr(bDownloadPaused), BoolToStr(bDownloadPaused), BoolToStr(bDownload2Paused),
|
||||
BoolToStr(bServerStandBy), BoolToStr(bPostPaused), BoolToStr(bScanPaused),
|
||||
iFreeDiskSpaceLo, iFreeDiskSpaceHi, iFreeDiskSpaceMB, iServerTime, iResumeTime);
|
||||
iFreeDiskSpaceLo, iFreeDiskSpaceHi, iFreeDiskSpaceMB);
|
||||
szContent[2048-1] = '\0';
|
||||
|
||||
AppendResponse(szContent);
|
||||
@@ -1107,10 +1074,10 @@ void ListFilesXmlCommand::Execute()
|
||||
const char* XML_LIST_ITEM =
|
||||
"<value><struct>\n"
|
||||
"<member><name>ID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PostTime</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FilenameConfirmed</name><value><boolean>%s</boolean></value></member>\n"
|
||||
"<member><name>Paused</name><value><boolean>%s</boolean></value></member>\n"
|
||||
@@ -1129,10 +1096,10 @@ void ListFilesXmlCommand::Execute()
|
||||
const char* JSON_LIST_ITEM =
|
||||
"{\n"
|
||||
"\"ID\" : %i,\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
"\"RemainingSizeLo\" : %u,\n"
|
||||
"\"RemainingSizeHi\" : %u,\n"
|
||||
"\"FileSizeLo\" : %i,\n"
|
||||
"\"FileSizeHi\" : %i,\n"
|
||||
"\"RemainingSizeLo\" : %i,\n"
|
||||
"\"RemainingSizeHi\" : %i,\n"
|
||||
"\"PostTime\" : %i,\n"
|
||||
"\"FilenameConfirmed\" : %s,\n"
|
||||
"\"Paused\" : %s,\n"
|
||||
@@ -1205,14 +1172,14 @@ void ListGroupsXmlCommand::Execute()
|
||||
"<value><struct>\n"
|
||||
"<member><name>FirstID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>LastID</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PausedSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>PausedSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>PausedSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PausedSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>PausedSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingFileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
@@ -1238,14 +1205,14 @@ void ListGroupsXmlCommand::Execute()
|
||||
"{\n"
|
||||
"\"FirstID\" : %i,\n"
|
||||
"\"LastID\" : %i,\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
"\"FileSizeLo\" : %i,\n"
|
||||
"\"FileSizeHi\" : %i,\n"
|
||||
"\"FileSizeMB\" : %i,\n"
|
||||
"\"RemainingSizeLo\" : %u,\n"
|
||||
"\"RemainingSizeHi\" : %u,\n"
|
||||
"\"RemainingSizeLo\" : %i,\n"
|
||||
"\"RemainingSizeHi\" : %i,\n"
|
||||
"\"RemainingSizeMB\" : %i,\n"
|
||||
"\"PausedSizeLo\" : %u,\n"
|
||||
"\"PausedSizeHi\" : %u,\n"
|
||||
"\"PausedSizeLo\" : %i,\n"
|
||||
"\"PausedSizeHi\" : %i,\n"
|
||||
"\"PausedSizeMB\" : %i,\n"
|
||||
"\"FileCount\" : %i,\n"
|
||||
"\"RemainingFileCount\" : %i,\n"
|
||||
@@ -1629,7 +1596,7 @@ void PostQueueXmlCommand::Execute()
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
|
||||
const char* szPostStageName[] = { "QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING", "VERIFYING_REPAIRED", "RENAMING", "UNPACKING", "MOVING", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
const char* szPostStageName[] = { "QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING", "VERIFYING_REPAIRED", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
|
||||
char* xmlNZBNicename = EncodeStr(pPostInfo->GetNZBInfo()->GetName());
|
||||
char* xmlNZBFilename = EncodeStr(pPostInfo->GetNZBInfo()->GetFilename());
|
||||
@@ -1665,11 +1632,12 @@ void PostQueueXmlCommand::Execute()
|
||||
PostInfo::Messages* pMessages = pPostInfo->LockMessages();
|
||||
if (!pMessages->empty())
|
||||
{
|
||||
int iStart = pMessages->size();
|
||||
if (iNrEntries > (int)pMessages->size())
|
||||
{
|
||||
iNrEntries = pMessages->size();
|
||||
}
|
||||
int iStart = pMessages->size() - iNrEntries;
|
||||
iStart = pMessages->size() - iNrEntries;
|
||||
|
||||
int index = 0;
|
||||
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
||||
@@ -1785,11 +1753,9 @@ void HistoryXmlCommand::Execute()
|
||||
"<member><name>DestDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Category</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ParStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UnpackStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>MoveStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ScriptStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileSizeMB</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>FileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
"<member><name>RemainingFileCount</name><value><i4>%i</i4></value></member>\n"
|
||||
@@ -1817,11 +1783,9 @@ void HistoryXmlCommand::Execute()
|
||||
"\"DestDir\" : \"%s\",\n"
|
||||
"\"Category\" : \"%s\",\n"
|
||||
"\"ParStatus\" : \"%s\",\n"
|
||||
"\"UnpackStatus\" : \"%s\",\n"
|
||||
"\"MoveStatus\" : \"%s\",\n"
|
||||
"\"ScriptStatus\" : \"%s\",\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
"\"FileSizeLo\" : %i,\n"
|
||||
"\"FileSizeHi\" : %i,\n"
|
||||
"\"FileSizeMB\" : %i,\n"
|
||||
"\"FileCount\" : %i,\n"
|
||||
"\"RemainingFileCount\" : %i,\n"
|
||||
@@ -1866,9 +1830,7 @@ void HistoryXmlCommand::Execute()
|
||||
"\"Text\" : \"%s\"\n"
|
||||
"}";
|
||||
|
||||
const char* szParStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS", "REPAIR_POSSIBLE" };
|
||||
const char* szUnpackStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS" };
|
||||
const char* szMoveStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
|
||||
const char* szParStatusName[] = { "NONE", "FAILURE", "REPAIR_POSSIBLE", "SUCCESS" };
|
||||
const char* szScriptStatusName[] = { "NONE", "UNKNOWN", "FAILURE", "SUCCESS" };
|
||||
const char* szUrlStatusName[] = { "UNKNOWN", "UNKNOWN", "SUCCESS", "FAILURE", "UNKNOWN" };
|
||||
const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"};
|
||||
@@ -1904,11 +1866,9 @@ void HistoryXmlCommand::Execute()
|
||||
|
||||
snprintf(szItemBuf, szItemBufSize, IsJson() ? JSON_HISTORY_ITEM_START : XML_HISTORY_ITEM_START,
|
||||
pHistoryInfo->GetID(), pHistoryInfo->GetID(), "NZB", xmlNicename, xmlNicename, xmlNZBFilename,
|
||||
xmlDestDir, xmlCategory, szParStatusName[pNZBInfo->GetParStatus()],
|
||||
szUnpackStatusName[pNZBInfo->GetUnpackStatus()], szMoveStatusName[pNZBInfo->GetMoveStatus()],
|
||||
szScriptStatusName[pNZBInfo->GetScriptStatus()],
|
||||
iFileSizeLo, iFileSizeHi, iFileSizeMB, pNZBInfo->GetFileCount(),
|
||||
pNZBInfo->GetParkedFileCount(), pHistoryInfo->GetTime(), "", "");
|
||||
xmlDestDir, xmlCategory, szParStatusName[pNZBInfo->GetParStatus()],
|
||||
szScriptStatusName[pNZBInfo->GetScriptStatus()], iFileSizeLo, iFileSizeHi, iFileSizeMB,
|
||||
pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(), pHistoryInfo->GetTime(), "", "");
|
||||
|
||||
free(xmlDestDir);
|
||||
}
|
||||
@@ -1922,7 +1882,7 @@ void HistoryXmlCommand::Execute()
|
||||
|
||||
snprintf(szItemBuf, szItemBufSize, IsJson() ? JSON_HISTORY_ITEM_START : XML_HISTORY_ITEM_START,
|
||||
pHistoryInfo->GetID(), pHistoryInfo->GetID(), "URL", xmlNicename, xmlNicename, xmlNZBFilename,
|
||||
"", xmlCategory, "", "", "", "", 0, 0, 0, 0, 0, pHistoryInfo->GetTime(), xmlURL,
|
||||
"", xmlCategory, "", "", 0, 0, 0, 0, 0, pHistoryInfo->GetTime(), xmlURL,
|
||||
szUrlStatusName[pUrlInfo->GetStatus()]);
|
||||
|
||||
free(xmlURL);
|
||||
@@ -2279,16 +2239,18 @@ void SaveConfigXmlCommand::Execute()
|
||||
return;
|
||||
}
|
||||
|
||||
const char* szConfigFile = NULL;
|
||||
Options::EDomain eDomain;
|
||||
|
||||
if (!strcasecmp(szDomain, "SERVER"))
|
||||
{
|
||||
eDomain = Options::dmServer;
|
||||
szConfigFile = g_pOptions->GetConfigFilename();
|
||||
}
|
||||
else if (!strcasecmp(szDomain, "POST"))
|
||||
{
|
||||
eDomain = Options::dmPostProcess;
|
||||
const char* szConfigFile = g_pOptions->GetPostConfigFilename();
|
||||
szConfigFile = g_pOptions->GetPostConfigFilename();
|
||||
if (!szConfigFile)
|
||||
{
|
||||
BuildErrorResponse(3, "Post-processing script configuration file is not defined");
|
||||
|
||||
8
XmlRpc.h
8
XmlRpc.h
@@ -61,6 +61,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
const char* m_szClientIP;
|
||||
char* m_szRequest;
|
||||
const char* m_szContentType;
|
||||
ERpcProtocol m_eProtocol;
|
||||
@@ -79,6 +80,7 @@ public:
|
||||
void Execute();
|
||||
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; }
|
||||
@@ -152,12 +154,6 @@ public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScheduleResumeXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
|
||||
273
configure
vendored
273
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 10.0.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 9.1.
|
||||
#
|
||||
# Report bugs to <hugbug@users.sourceforge.net>.
|
||||
#
|
||||
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='nzbget'
|
||||
PACKAGE_TARNAME='nzbget'
|
||||
PACKAGE_VERSION='10.0'
|
||||
PACKAGE_STRING='nzbget 10.0'
|
||||
PACKAGE_VERSION='9.1'
|
||||
PACKAGE_STRING='nzbget 9.1'
|
||||
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
|
||||
|
||||
ac_unique_file="nzbget.cpp"
|
||||
@@ -711,8 +711,9 @@ libxml2_CFLAGS
|
||||
libxml2_LIBS
|
||||
libsigc_CFLAGS
|
||||
libsigc_LIBS
|
||||
openssl_CFLAGS
|
||||
openssl_LIBS
|
||||
CFLAGS
|
||||
AR
|
||||
ADDSRCS
|
||||
LIBOBJS
|
||||
LTLIBOBJS'
|
||||
ac_subst_files=''
|
||||
@@ -730,9 +731,7 @@ PKG_CONFIG
|
||||
libxml2_CFLAGS
|
||||
libxml2_LIBS
|
||||
libsigc_CFLAGS
|
||||
libsigc_LIBS
|
||||
openssl_CFLAGS
|
||||
openssl_LIBS'
|
||||
libsigc_LIBS'
|
||||
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -1235,7 +1234,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures nzbget 10.0 to adapt to many kinds of systems.
|
||||
\`configure' configures nzbget 9.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1306,7 +1305,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of nzbget 10.0:";;
|
||||
short | recursive ) echo "Configuration of nzbget 9.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1383,10 +1382,6 @@ Some influential environment variables:
|
||||
C compiler flags for libsigc, overriding pkg-config
|
||||
libsigc_LIBS
|
||||
linker flags for libsigc, overriding pkg-config
|
||||
openssl_CFLAGS
|
||||
C compiler flags for openssl, overriding pkg-config
|
||||
openssl_LIBS
|
||||
linker flags for openssl, overriding pkg-config
|
||||
|
||||
Use these variables to override the choices made by `configure' or to help
|
||||
it to find libraries and programs with nonstandard names/locations.
|
||||
@@ -1452,7 +1447,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
nzbget configure 10.0
|
||||
nzbget configure 9.1
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1466,7 +1461,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by nzbget $as_me 10.0, which was
|
||||
It was created by nzbget $as_me 9.1, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2262,7 +2257,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=nzbget
|
||||
VERSION=10.0
|
||||
VERSION=9.1
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -5685,6 +5680,7 @@ _ACEOF
|
||||
# Check whether --with-libxml2_includes was given.
|
||||
if test "${with_libxml2_includes+set}" = set; then
|
||||
withval=$with_libxml2_includes; CPPFLAGS="${CPPFLAGS} -I${withval}"
|
||||
CFLAGS="${CFLAGS} -I${withval}"
|
||||
INCVAL="yes"
|
||||
else
|
||||
INCVAL="no"
|
||||
@@ -5929,8 +5925,9 @@ else
|
||||
libxml2_LIBS=$pkg_cv_libxml2_LIBS
|
||||
{ echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6; }
|
||||
LIBS="${LIBS} $libxml2_LIBS"
|
||||
LDFLAGS="${LDFLAGS} $libxml2_LIBS"
|
||||
CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"
|
||||
CFLAGS="${CFLAGS} $libxml2_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
if test "${ac_cv_header_libxml_tree_h+set}" = set; then
|
||||
@@ -6182,6 +6179,7 @@ if test "${with_libcurses_includes+set}" = set; then
|
||||
fi
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
|
||||
# Check whether --with-libcurses_libraries was given.
|
||||
if test "${with_libcurses_libraries+set}" = set; then
|
||||
@@ -6864,7 +6862,7 @@ else
|
||||
libsigc_LIBS=$pkg_cv_libsigc_LIBS
|
||||
{ echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6; }
|
||||
LIBS="${LIBS} $libsigc_LIBS"
|
||||
LDFLAGS="${LDFLAGS} $libsigc_LIBS"
|
||||
CPPFLAGS="${CPPFLAGS} $libsigc_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
@@ -7476,6 +7474,7 @@ if test "${with_libgnutls_includes+set}" = set; then
|
||||
fi
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
|
||||
# Check whether --with-libgnutls_libraries was given.
|
||||
if test "${with_libgnutls_libraries+set}" = set; then
|
||||
@@ -7814,138 +7813,23 @@ _ACEOF
|
||||
fi
|
||||
|
||||
if test "$TLSLIB" = "OpenSSL" -o "$TLSLIB" = ""; then
|
||||
INCVAL="${LIBPREF}/include"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
|
||||
# Check whether --with-openssl_includes was given.
|
||||
if test "${with_openssl_includes+set}" = set; then
|
||||
withval=$with_openssl_includes; CPPFLAGS="${CPPFLAGS} -I${withval}"
|
||||
INCVAL="yes"
|
||||
else
|
||||
INCVAL="no"
|
||||
withval=$with_openssl_includes; INCVAL="$withval"
|
||||
fi
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
|
||||
# Check whether --with-openssl_libraries was given.
|
||||
if test "${with_openssl_libraries+set}" = set; then
|
||||
withval=$with_openssl_libraries; LDFLAGS="${LDFLAGS} -L${withval}"
|
||||
LIBVAL="yes"
|
||||
else
|
||||
LIBVAL="no"
|
||||
withval=$with_openssl_libraries; LIBVAL="$withval"
|
||||
fi
|
||||
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
|
||||
pkg_failed=no
|
||||
{ echo "$as_me:$LINENO: checking for openssl" >&5
|
||||
echo $ECHO_N "checking for openssl... $ECHO_C" >&6; }
|
||||
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$openssl_CFLAGS"; then
|
||||
pkg_cv_openssl_CFLAGS="$openssl_CFLAGS"
|
||||
else
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"openssl\"") >&5
|
||||
($PKG_CONFIG --exists --print-errors "openssl") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; then
|
||||
pkg_cv_openssl_CFLAGS=`$PKG_CONFIG --cflags "openssl" 2>/dev/null`
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$openssl_LIBS"; then
|
||||
pkg_cv_openssl_LIBS="$openssl_LIBS"
|
||||
else
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"openssl\"") >&5
|
||||
($PKG_CONFIG --exists --print-errors "openssl") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; then
|
||||
pkg_cv_openssl_LIBS=`$PKG_CONFIG --libs "openssl" 2>/dev/null`
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
openssl_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "openssl"`
|
||||
else
|
||||
openssl_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "openssl"`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$openssl_PKG_ERRORS" >&5
|
||||
|
||||
{ { echo "$as_me:$LINENO: error: Package requirements (openssl) were not met:
|
||||
|
||||
$openssl_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
Alternatively, you may set the environment variables openssl_CFLAGS
|
||||
and openssl_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
" >&5
|
||||
echo "$as_me: error: Package requirements (openssl) were not met:
|
||||
|
||||
$openssl_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
Alternatively, you may set the environment variables openssl_CFLAGS
|
||||
and openssl_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
elif test $pkg_failed = untried; then
|
||||
{ { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
Alternatively, you may set the environment variables openssl_CFLAGS
|
||||
and openssl_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
|
||||
See \`config.log' for more details." >&5
|
||||
echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
Alternatively, you may set the environment variables openssl_CFLAGS
|
||||
and openssl_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
|
||||
See \`config.log' for more details." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
else
|
||||
openssl_CFLAGS=$pkg_cv_openssl_CFLAGS
|
||||
openssl_LIBS=$pkg_cv_openssl_LIBS
|
||||
{ echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6; }
|
||||
LIBS="${LIBS} $openssl_LIBS"
|
||||
CPPFLAGS="${CPPFLAGS} $openssl_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
if test "${ac_cv_header_openssl_ssl_h+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for openssl/ssl.h" >&5
|
||||
@@ -8091,87 +7975,7 @@ echo "$as_me: error: Couldn't find OpenSSL headers (ssl.h)" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
{ echo "$as_me:$LINENO: checking for library containing CRYPTO_set_locking_callback" >&5
|
||||
echo $ECHO_N "checking for library containing CRYPTO_set_locking_callback... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char CRYPTO_set_locking_callback ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return CRYPTO_set_locking_callback ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' crypto; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_search_CRYPTO_set_locking_callback=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_CRYPTO_set_locking_callback+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_CRYPTO_set_locking_callback=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_CRYPTO_set_locking_callback" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_CRYPTO_set_locking_callback" >&6; }
|
||||
ac_res=$ac_cv_search_CRYPTO_set_locking_callback
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
{ echo "$as_me:$LINENO: checking for library containing SSL_library_init" >&5
|
||||
{ echo "$as_me:$LINENO: checking for library containing SSL_library_init" >&5
|
||||
echo $ECHO_N "checking for library containing SSL_library_init... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_SSL_library_init+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
@@ -8252,10 +8056,6 @@ ac_res=$ac_cv_search_SSL_library_init
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
FOUND=yes
|
||||
else
|
||||
FOUND=no
|
||||
fi
|
||||
|
||||
else
|
||||
FOUND=no
|
||||
fi
|
||||
@@ -8317,6 +8117,7 @@ if test "${with_zlib_includes+set}" = set; then
|
||||
fi
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
|
||||
# Check whether --with-zlib_libraries was given.
|
||||
if test "${with_zlib_libraries+set}" = set; then
|
||||
@@ -8871,6 +8672,15 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
@@ -9283,7 +9093,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by nzbget $as_me 10.0, which was
|
||||
This file was extended by nzbget $as_me 9.1, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -9336,7 +9146,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
nzbget config.status 10.0
|
||||
nzbget config.status 9.1
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
@@ -9610,7 +9420,7 @@ libxml2_CFLAGS!$libxml2_CFLAGS$ac_delim
|
||||
libxml2_LIBS!$libxml2_LIBS$ac_delim
|
||||
libsigc_CFLAGS!$libsigc_CFLAGS$ac_delim
|
||||
libsigc_LIBS!$libsigc_LIBS$ac_delim
|
||||
openssl_CFLAGS!$openssl_CFLAGS$ac_delim
|
||||
CFLAGS!$CFLAGS$ac_delim
|
||||
_ACEOF
|
||||
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
|
||||
@@ -9652,12 +9462,13 @@ _ACEOF
|
||||
ac_delim='%!_!# '
|
||||
for ac_last_try in false false false false false :; do
|
||||
cat >conf$$subs.sed <<_ACEOF
|
||||
openssl_LIBS!$openssl_LIBS$ac_delim
|
||||
AR!$AR$ac_delim
|
||||
ADDSRCS!$ADDSRCS$ac_delim
|
||||
LIBOBJS!$LIBOBJS$ac_delim
|
||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||
_ACEOF
|
||||
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 3; then
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 4; then
|
||||
break
|
||||
elif $ac_last_try; then
|
||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||
|
||||
53
configure.ac
53
configure.ac
@@ -2,9 +2,9 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 10.0, hugbug@users.sourceforge.net)
|
||||
AC_INIT(nzbget, 9.1, hugbug@users.sourceforge.net)
|
||||
AC_CANONICAL_SYSTEM
|
||||
AM_INIT_AUTOMAKE(nzbget, 10.0)
|
||||
AM_INIT_AUTOMAKE(nzbget, 9.1)
|
||||
AC_CONFIG_SRCDIR([nzbget.cpp])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
@@ -187,6 +187,7 @@ 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,
|
||||
@@ -196,8 +197,9 @@ AC_ARG_WITH(libxml2_libraries,
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES(libxml2, libxml-2.0,
|
||||
[LIBS="${LIBS} $libxml2_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"])
|
||||
[LDFLAGS="${LDFLAGS} $libxml2_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"]
|
||||
[CFLAGS="${CFLAGS} $libxml2_CFLAGS"])
|
||||
fi
|
||||
AC_CHECK_HEADER(libxml/tree.h,,
|
||||
AC_MSG_ERROR("libxml2 header files not found"))
|
||||
@@ -221,6 +223,7 @@ 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"])
|
||||
@@ -280,7 +283,7 @@ if test "$ENABLEPARCHECK" = "yes"; then
|
||||
[LIBVAL="no"])
|
||||
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
|
||||
PKG_CHECK_MODULES(libsigc, sigc++-2.0,
|
||||
[LIBS="${LIBS} $libsigc_LIBS"]
|
||||
[LDFLAGS="${LDFLAGS} $libsigc_LIBS"]
|
||||
[CPPFLAGS="${CPPFLAGS} $libsigc_CFLAGS"])
|
||||
fi
|
||||
|
||||
@@ -390,11 +393,12 @@ 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,
|
||||
@@ -419,22 +423,18 @@ 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])],
|
||||
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
|
||||
[INCVAL="yes"],
|
||||
[INCVAL="no"])
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
AC_ARG_WITH(openssl_libraries,
|
||||
[AS_HELP_STRING([--with-openssl-libraries=DIR], [OpenSSL library directory])],
|
||||
[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
|
||||
|
||||
[LIBVAL="$withval"])
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
AC_CHECK_HEADER(openssl/ssl.h,
|
||||
FOUND=yes
|
||||
TLSHEADERS=yes,
|
||||
@@ -443,10 +443,8 @@ if test "$USETLS" = "yes"; then
|
||||
AC_MSG_ERROR([Couldn't find OpenSSL headers (ssl.h)])
|
||||
fi
|
||||
if test "$FOUND" = "yes"; then
|
||||
AC_SEARCH_LIBS([CRYPTO_set_locking_callback], [crypto],
|
||||
AC_SEARCH_LIBS([SSL_library_init], [ssl],
|
||||
FOUND=yes,
|
||||
FOUND=no),
|
||||
AC_SEARCH_LIBS([SSL_library_init], [ssl],
|
||||
FOUND=yes,
|
||||
FOUND=no)
|
||||
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; then
|
||||
AC_MSG_ERROR([Couldn't find OpenSSL library])
|
||||
@@ -486,6 +484,7 @@ if test "$USEZLIB" = "yes"; then
|
||||
[AS_HELP_STRING([--with-zlib-includes=DIR], [zlib include directory])],
|
||||
[INCVAL="$withval"])
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
CFLAGS="${CFLAGS} -I${INCVAL}"
|
||||
AC_ARG_WITH(zlib_libraries,
|
||||
[AS_HELP_STRING([--with-zlib-libraries=DIR], [zlib library directory])],
|
||||
[LIBVAL="$withval"])
|
||||
@@ -621,5 +620,15 @@ 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,10 +1,10 @@
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Template configuration file for post-processing script "nzbget-postprocess.sh".
|
||||
# Template configuration file for postprocessing script "nzbget-postprocess.sh".
|
||||
# Please refer to "nzbget-postprocess.sh" for usage instructions.
|
||||
#
|
||||
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-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
|
||||
@@ -22,29 +22,45 @@
|
||||
#
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
### 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=yes
|
||||
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 "PostProcess" to value "no" for
|
||||
# Example command line for setting parameter "password" to value "123" for
|
||||
# nzb-file with id=2:
|
||||
# nzbget -E G O PostProcess=no 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=
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Copyright (C) 2008 Peter Roubos <peterroubos@hotmail.com>
|
||||
# Copyright (C) 2008 Otmar Werner
|
||||
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-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
|
||||
@@ -25,7 +25,8 @@
|
||||
#
|
||||
|
||||
####################### Usage instructions #######################
|
||||
# o Script will cleanup, join ts-files and rename img-files to iso.
|
||||
# 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.:
|
||||
@@ -40,29 +41,41 @@
|
||||
#
|
||||
# o There are few options, which can be ajdusted for each nzb-file individually.
|
||||
#
|
||||
# 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_NZBNAME - user-friendly name of processed nzb-file as it is displayed
|
||||
# by the program. The file path and extension are removed.
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file. It includes file extension and also
|
||||
# may include full path;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# 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 is disabled or nzb-file does
|
||||
# 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_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.
|
||||
# 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
|
||||
@@ -75,32 +88,31 @@ POSTPROCESS_SUCCESS=93
|
||||
POSTPROCESS_ERROR=94
|
||||
POSTPROCESS_NONE=95
|
||||
|
||||
# Check if the script is called from nzbget 10.0 or later
|
||||
# Check if the script is called from nzbget
|
||||
if [ "$NZBPP_DIRECTORY" = "" -o "$NZBOP_CONFIGFILE" = "" ]; then
|
||||
echo "*** NZBGet post-processing script ***"
|
||||
echo "This script is supposed to be called from nzbget (10.0 or later)."
|
||||
echo "*** NZBGet post-process script ***"
|
||||
echo "This script is supposed to be called from nzbget (0.7.0 or later)."
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
if [ "$NZBOP_UNPACK" = "" ]; then
|
||||
echo "[ERROR] This script requires nzbget version at least 10.0-testing-r555 or 10.0-stable."
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
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: Post-processing disabled for this nzb-file, exiting"
|
||||
echo "[WARNING] Post-Process: Postprocessing disabled for this nzb-file, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
echo "[INFO] Post-Process: Post-processing script successfully started"
|
||||
cd "$NZBPP_DIRECTORY"
|
||||
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).
|
||||
# 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
|
||||
@@ -115,53 +127,38 @@ 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_UNPACK" != "yes" ]; then
|
||||
echo "[ERROR] Post-Process: Please enable option \"Unpack\" in nzbget configuration file"
|
||||
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: Exiting due to incompatible nzbget configuration"
|
||||
echo "[ERROR] Post-Process: Exiting because of not compatible nzbget configuration"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
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 3 ]; then
|
||||
echo "[WARNING] Post-Process: Par-check successful, but Par-repair disabled, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
if [ "$NZBPP_PARSTATUS" -eq 1 ]; then
|
||||
echo "[WARNING] Post-Process: Par-check failed, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
# Check unpack status
|
||||
if [ "$NZBPP_UNPACKSTATUS" -eq 1 ]; then
|
||||
echo "[WARNING] Post-Process: Unpack failed, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
if [ "$NZBPP_UNPACKSTATUS" -eq 0 -a "$NZBPP_PARSTATUS" -ne 2 ]; then
|
||||
# Unpack is disabled or was skipped due to nzb-file properties or due to errors during par-check
|
||||
|
||||
if (ls *.rar *.7z *.7z.??? >/dev/null 2>&1); then
|
||||
echo "[WARNING] Post-Process: Archive files exist but unpack skipped, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
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
|
||||
|
||||
if (ls *.par2 >/dev/null 2>&1); then
|
||||
echo "[WARNING] Post-Process: Unpack skipped and par-check skipped (although par2-files exist), exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
if [ -f "_brokenlog.txt" ]; then
|
||||
echo "[WARNING] Post-Process: _brokenlog.txt exists, download is probably damaged, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
echo "[INFO] Post-Process: Neither archive- nor par2-files found, _brokenlog.txt doesn't exist, considering download successful"
|
||||
fi
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Check if destination directory exists (important for reprocessing of history items)
|
||||
if [ ! -d "$NZBPP_DIRECTORY" ]; then
|
||||
@@ -169,8 +166,111 @@ if [ ! -d "$NZBPP_DIRECTORY" ]; then
|
||||
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 [ "$?" -ne 0 ]; 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 [ "$?" -ne 0 ]; 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 there were nothing to unrar and the download was not par-checked,
|
||||
# we don't know if it's OK. To be sure we force par-check.
|
||||
# In particular that helps with downloads containing renamed rar-files.
|
||||
# The par-repair will rename files to correct names, then we can unpack.
|
||||
if [ "$Unrared" -eq 0 -a "$NZBPP_PARSTATUS" -eq 0 ]; then
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: No rar-files found, requesting par-check"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# If download contains only nzb-files move them into nzb-directory
|
||||
# for further download
|
||||
# Check if command "wc" exists
|
||||
@@ -191,30 +291,33 @@ 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
|
||||
rm *.[pP][aA][rR]2 >/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"
|
||||
echo "[INFO] Post-Process: Joining ts-files"
|
||||
tsname=`find . -name "*0001.ts" |awk -F/ '{print $NF}'`
|
||||
cat *0???.ts > ./$tsname
|
||||
|
||||
# Remove all the split .ts files
|
||||
echo "[INFO] Post-Process: Deleting source ts-files"
|
||||
rm *0???.ts >/dev/null 2>&1
|
||||
fi
|
||||
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"
|
||||
echo "[INFO] Post-Process: Renaming img-files to iso"
|
||||
imgname=`find . -name "*.img" |awk -F/ '{print $NF}'`
|
||||
mv $imgname $imgname.iso
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if destination directory was set in postprocessing parameters
|
||||
|
||||
379
nzbget.conf
379
nzbget.conf
@@ -23,31 +23,11 @@
|
||||
#
|
||||
# On POSIX you can use "~" as alias for home directory (e.g. "~/download").
|
||||
# On Windows use absolute paths (e.g. "C:\Download").
|
||||
MainDir=~/downloads
|
||||
MainDir=~/download
|
||||
|
||||
# Destination directory for downloaded files.
|
||||
#
|
||||
# If you want to distinguish between partially downloaded files and
|
||||
# completed downloads, use also option <InterDir>.
|
||||
# Destination-directory to store downloaded files.
|
||||
DestDir=${MainDir}/dst
|
||||
|
||||
# Directory to store intermediate files.
|
||||
#
|
||||
# If this option is set (not empty) the files are downloaded into
|
||||
# this directory first. After successful download of nzb-file (possibly
|
||||
# after par-repair) the files are moved to destination directory
|
||||
# (option <DestDir>). If download or unpack fail the files remain in
|
||||
# intermediate directory.
|
||||
#
|
||||
# Using of intermediate directory can significantly improve unpack
|
||||
# performance if you can put intermediate directory (option <InterDir>)
|
||||
# and destination directory (option <DestDir>) on separate physical
|
||||
# hard drives.
|
||||
#
|
||||
# NOTE: If the option <InterDir> is set to empty value the downloaded
|
||||
# files are put directly to destination directory (option <DestDir>).
|
||||
InterDir=
|
||||
|
||||
# Directory to monitor for incoming nzb-jobs.
|
||||
#
|
||||
# Can have subdirectories.
|
||||
@@ -59,6 +39,11 @@ NzbDir=${MainDir}/nzb
|
||||
QueueDir=${MainDir}/queue
|
||||
|
||||
# Directory to store temporary files.
|
||||
#
|
||||
# NOTE: When option <DirectWrite> is enabled the temporary directory (option
|
||||
# <TempDir>) must be located on the same partition with destination directory
|
||||
# (option <DestDir>) for better performance. If option <DirectWrite> is disabled
|
||||
# it's better to use different drives for temporary and destination directories.
|
||||
TempDir=${MainDir}/tmp
|
||||
|
||||
# Lock-file for daemon-mode, POSIX only.
|
||||
@@ -81,6 +66,7 @@ LogFile=${DestDir}/nzbget.log
|
||||
# it is also used to serve JSON-/XML-RPC requests.
|
||||
WebDir=
|
||||
|
||||
|
||||
##############################################################################
|
||||
### NEWS-SERVERS ###
|
||||
|
||||
@@ -92,31 +78,21 @@ WebDir=
|
||||
# change the name of Server3 to Server2. Otherwise it will not be properly
|
||||
# read from the config file. Server number doesn't affect its priority (level).
|
||||
|
||||
# Level (priority) of news server (0-99).
|
||||
# Level of newsserver (0-99).
|
||||
#
|
||||
# The servers are ordered by their level. NZBGet first tries to download
|
||||
# an article from one (any) of level-0-servers. If that server fails,
|
||||
# NZBGet tries all other level-0-servers. If all servers fail, it proceeds
|
||||
# with the level-1-servers, etc.
|
||||
# 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,...
|
||||
#
|
||||
# Put your major download servers at level 0 and your fill servers at
|
||||
# levels 1, 2, etc..
|
||||
# NOTE: Do not leave out a level in your server-list and start with level 0.
|
||||
#
|
||||
# Several servers with the same level may be defined, they have
|
||||
# NOTE: Several servers with the same level may be used, they will have
|
||||
# the same priority.
|
||||
Server1.Level=0
|
||||
|
||||
# Group of news server (0-99).
|
||||
#
|
||||
# If you have multiple accounts with same conditions (retention, etc.)
|
||||
# on the same news server, set the same group (greater than 0) for all
|
||||
# of them. If download fails on one news server, NZBGet does not try
|
||||
# other servers from the same group.
|
||||
#
|
||||
# Value "0" means no group defined (default).
|
||||
Server1.Group=0
|
||||
|
||||
# Host name of news server.
|
||||
# Host name of newsserver.
|
||||
Server1.Host=my.newsserver.com
|
||||
|
||||
# Port to connect to (1-65535).
|
||||
@@ -129,7 +105,7 @@ Server1.Username=user
|
||||
Server1.Password=pass
|
||||
|
||||
# Server requires "Join Group"-command (yes, no).
|
||||
Server1.JoinGroup=no
|
||||
Server1.JoinGroup=yes
|
||||
|
||||
# Encrypted server connection (TLS/SSL) (yes, no).
|
||||
#
|
||||
@@ -137,24 +113,6 @@ Server1.JoinGroup=no
|
||||
# accordingly because unsecure and encrypted connections use different ports.
|
||||
Server1.Encryption=no
|
||||
|
||||
# Cipher to use for encrypted server connection.
|
||||
#
|
||||
# By default (when the option is empty) the underlying encryption library
|
||||
# chooses the cipher automatically. To achieve the best performance
|
||||
# however you can manually select a faster cipher.
|
||||
#
|
||||
# See http://nzbget.sourceforge.net/Choosing_a_cipher for details.
|
||||
#
|
||||
# NOTE: One of the fastest cipher is RC4, it also provides strong 128 bit
|
||||
# encryption. To select it use the cipher string "RC4-MD5" (if NZBGet was
|
||||
# configured to use OpenSSL) or "NONE:+VERS-TLS-ALL:+ARCFOUR-128:+RSA:+MD5:+COMP-ALL"
|
||||
# (if NZBGet was configured to use GnuTLS).
|
||||
#
|
||||
# NOTE: You may get a TLS handshake error if the news server does
|
||||
# not support the chosen cipher. You can also get an error "Could not
|
||||
# select cipher for TLS" if the cipher string is not valid.
|
||||
Server1.Cipher=
|
||||
|
||||
# Maximal number of simultaneous connections to this server (0-999).
|
||||
Server1.Connections=4
|
||||
|
||||
@@ -199,9 +157,6 @@ Server1.Connections=4
|
||||
ControlIP=0.0.0.0
|
||||
|
||||
# Port which NZBGet server and remote client use (1-65535).
|
||||
#
|
||||
# NOTE: The communication via this port is not encrypted. For encrypted
|
||||
# communication see option <SecurePort>.
|
||||
ControlPort=6789
|
||||
|
||||
# Password which NZBGet server and remote client use.
|
||||
@@ -210,22 +165,7 @@ ControlPort=6789
|
||||
# and the password defined here.
|
||||
ControlPassword=tegbzn6789
|
||||
|
||||
# Secure control of NZBGet server (yes, no).
|
||||
#
|
||||
# Activate the option if you want to access NZBGet built-in web-server
|
||||
# via HTTPS (web-interface and RPC). You should also provide certificate
|
||||
# and key files, see option <SecureCert> and option <SecureKey>.
|
||||
SecureControl=no
|
||||
|
||||
# Port which NZBGet server and remote client use for encrypted
|
||||
# communication (1-65535).
|
||||
SecurePort=6791
|
||||
|
||||
# Full path to certificate file for encrypted communication.
|
||||
SecureCert=
|
||||
|
||||
# Full path to key file for encrypted communication.
|
||||
SecureKey=
|
||||
# See also option <LogBufferSize> in section "LOGGING"
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -499,29 +439,27 @@ DirectWrite=yes
|
||||
# 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 CPU time. On a fast connection and
|
||||
# slow CPU disabling of CRC-Check may improve performance.
|
||||
# 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 many retries should be attempted if a download error occurs (0-99).
|
||||
#
|
||||
# 1) If download fails because of "article or group not found error" the
|
||||
# program tries another news server.
|
||||
#
|
||||
# 2) If download fails because of interrupted connection, the program
|
||||
# tries the same server again until connection can be established.
|
||||
#
|
||||
# In both cases 1) and 2) option <Retries> is not used.
|
||||
#
|
||||
# If download however fails because of incomplete article, CRC-error or other
|
||||
# error not mentioned above the program tries to redownload the article from
|
||||
# the same news server as many times as defined in option <Retries>. If all
|
||||
# attempts fail the program tries another news server.
|
||||
# How much retries should be attempted if a download error occurs (0-99).
|
||||
Retries=3
|
||||
|
||||
# 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
|
||||
|
||||
@@ -531,7 +469,7 @@ ConnectionTimeout=60
|
||||
# Do not use small values!
|
||||
TerminateTimeout=600
|
||||
|
||||
# Set the (approximate) maximum number of allowed threads (10-999).
|
||||
# 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,
|
||||
@@ -563,19 +501,23 @@ DownloadRate=0
|
||||
# Accurate speed rate calculation (yes, no).
|
||||
#
|
||||
# During downloading using several connections the download threads may
|
||||
# interfere with each other when updating statistical data for speed
|
||||
# meter. This may cause small errors in current download speed reported
|
||||
# by the program. The speed meter recovers automatically from such errors
|
||||
# after max. 30 seconds (time window used for speed calculation).
|
||||
# interfere with each other when updating statistical data for speed meter.
|
||||
# This may cause calculation errors resulting in a wrong download rate
|
||||
# reported by the program. This can be critical especially when using download
|
||||
# rate throttling.
|
||||
#
|
||||
# Enable the option to use thread synchronisation mechanisms in order to
|
||||
# provide absolutely accurate speed calculations.
|
||||
# provide accurate speed calculations.
|
||||
#
|
||||
# NOTE: Thread synchronisation increases CPU load and therefore can
|
||||
# decrease download speed. Do not activate this option on computers with
|
||||
# limited CPU power. Before activating the option it is recommended to
|
||||
# run tests to determine how the option affects the CPU usage and the
|
||||
# download speed on a particular system.
|
||||
# NOTE: The program uses spinlocks if the operating system supports them.
|
||||
# Otherwise it uses mutexes, which are less effective. In any case the thread
|
||||
# synchronisation increases CPU load.
|
||||
#
|
||||
# NOTE: It is recommended to run tests to determine how the option affects
|
||||
# the CPU usage and the download speed on a particular system.
|
||||
#
|
||||
# NOTE: The average (session) download speed is always accurate. It uses
|
||||
# other data for speed calculation and is not affected by this option.
|
||||
AccurateRate=no
|
||||
|
||||
# Set the size of memory buffer used by writing the articles (bytes).
|
||||
@@ -647,19 +589,13 @@ UrlConnections=4
|
||||
|
||||
# Category name.
|
||||
#
|
||||
# Each nzb-file can be assigned to a category.
|
||||
# Each nzb-file can be assigned to a category. If the option <AppendCategoryDir>
|
||||
# is active, the program creates a subdirectory with category name within
|
||||
# destination directory.
|
||||
# Category name is passed to post-processing script and can be used by it
|
||||
# to perform category specific processing.
|
||||
Category1.Name=Movies
|
||||
|
||||
# Destination directory for this category.
|
||||
#
|
||||
# If this option is empty, then the default destination directory
|
||||
# (option <DestDir>) is used. In this case if the option <AppendCategoryDir>
|
||||
# is active, the program creates a subdirectory with category name within
|
||||
# destination directory.
|
||||
Category1.DestDir=
|
||||
|
||||
Category2.Name=Series
|
||||
Category3.Name=Music
|
||||
Category4.Name=Software
|
||||
@@ -778,11 +714,7 @@ UpdateInterval=200
|
||||
# Paused files remain in queue and can be unpaused by parchecker when needed.
|
||||
LoadPars=one
|
||||
|
||||
# Force par-verification (yes, no).
|
||||
#
|
||||
# Force par-check for every download. When set to "no" the par-check is
|
||||
# performed only if the unpacker or the post-processing script detect a
|
||||
# damaged download.
|
||||
# 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",
|
||||
@@ -795,7 +727,7 @@ ParCheck=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 computer does not have
|
||||
# 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.
|
||||
ParRepair=yes
|
||||
@@ -807,15 +739,15 @@ ParRepair=yes
|
||||
# full - scan all files in the directory. This helps if the
|
||||
# files were renamed after creating of par-set.
|
||||
# auto - a limited scan is performed first. If the par-checker
|
||||
# detects missing files, it scans other files in the
|
||||
# directory until all required files are found.
|
||||
# detects missing files, it scans all files in the
|
||||
# directory which were not scanned yet.
|
||||
#
|
||||
# NOTE: for par-check/repair NZBGet uses library libpar2. The last and
|
||||
# widely used version 0.2 of the library has few bugs, sometimes causing
|
||||
# a crash of the program. This is especially true when using "full" or
|
||||
# "auto" par-scan. NZBGet is supplied with patches addressing these
|
||||
# issues. Please apply the patches to libpar2 and recompile it.
|
||||
ParScan=auto
|
||||
ParScan=limited
|
||||
|
||||
# Use only par2-files with matching names (yes, no).
|
||||
#
|
||||
@@ -867,7 +799,7 @@ ParTimeLimit=0
|
||||
# NOTE: If parchecker needs additional par-files it temporarily unpauses
|
||||
# the queue.
|
||||
#
|
||||
# NOTE: See also options <PostPauseQueue> and <UnpackPauseQueue>.
|
||||
# NOTE: See also option <PostPauseQueue>.
|
||||
ParPauseQueue=no
|
||||
|
||||
# Cleanup download queue after successful check/repair (yes, no).
|
||||
@@ -883,110 +815,38 @@ ParCleanupQueue=yes
|
||||
NzbCleanupDisk=no
|
||||
|
||||
|
||||
##############################################################################
|
||||
### UNPACK ###
|
||||
|
||||
# Unpack downloaded nzb-files (yes, no).
|
||||
#
|
||||
# If the download is damaged and could not be repaired using par-files
|
||||
# the unpacking is not performed.
|
||||
#
|
||||
# If the option <ParCheck> is disabled the program will try to unpack
|
||||
# downloaded files first. If the unpacking fails the par-check/repair
|
||||
# is performed and the unpack will be executed again.
|
||||
Unpack=yes
|
||||
|
||||
# Pause download queue during unpack (yes, no).
|
||||
#
|
||||
# Enable the option to give CPU more time for unpacking. That helps
|
||||
# to speed up unpacking on slow CPUs.
|
||||
#
|
||||
# NOTE: See also options <ParPauseQueue> and <PostPauseQueue>.
|
||||
UnpackPauseQueue=no
|
||||
|
||||
# Delete archive files after successful unpacking (yes, no).
|
||||
UnpackCleanupDisk=yes
|
||||
|
||||
# Full path to unrar executable.
|
||||
#
|
||||
# Example: "/usr/bin/unrar".
|
||||
#
|
||||
# If unrar is in your PATH you may leave the path part and set only
|
||||
# the executable name ("unrar" on POSIX or "unrar.exe" on Windows).
|
||||
UnrarCmd=unrar
|
||||
|
||||
# Full path to 7-Zip executable.
|
||||
#
|
||||
# Example: "/usr/bin/7z".
|
||||
#
|
||||
# If 7-Zip binary is in your PATH you may leave the path part and set only
|
||||
# the executable name ("7z" or "7za" on POSIX or "7z.exe" on Windows).
|
||||
SevenZipCmd=7z
|
||||
|
||||
|
||||
##############################################################################
|
||||
### POST-PROCESSING ###
|
||||
|
||||
# Set path to program, that must be executed after the download of nzb-file
|
||||
# is completed and possibly par-checked/repaired and unpacked, depending
|
||||
# on other options.
|
||||
# or one collection in nzb-file is completed and possibly par-checked/repaired.
|
||||
#
|
||||
# Example: "PostProcess=~/nzbget-postprocess.sh".
|
||||
#
|
||||
# NOTE: An example script is provided within distribution in file
|
||||
# "nzbget-postprocess.sh".
|
||||
#
|
||||
# NOTE: Since version 10.0 NZBGet has a built-in support for unpack
|
||||
# (option <Unpack>). In the previous versions unpack was performed by
|
||||
# post-processing scripts. If you use a script created for older NZBGet
|
||||
# version you need to disable the built-in unpack for script to operate
|
||||
# properly.
|
||||
# NOTE: An example script for unrarring is provided within distribution
|
||||
# in file "nzbget-postprocess.sh".
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# If the option <AllowReProcess> is disabled (that's the default setting)
|
||||
# the post-processing script is executed once per nzb-file after
|
||||
# par-check/repair (if needed) and unpacking (if enabled).
|
||||
#
|
||||
# If the option <AllowReProcess> is active the post-processing script is
|
||||
# executed for each collection within nzb-file (for nzb-files having multiple
|
||||
# collections but at least once). Depending on option <ParCheck> the collection
|
||||
# could be already par-checked/repaired or the script could be called without
|
||||
# par-check taken place. In the latest case if the script detects errors
|
||||
# (such as unpack failed) it has an ability to request par-check from
|
||||
# NZBGet. After par-check/repair NZBGet calls the script once again.
|
||||
#
|
||||
# NZBGet passes following arguments to post-processing script as environment
|
||||
# NZBGet passes following arguments to postprocess-program as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
|
||||
# NZBPP_NZBNAME - user-friendly name of processed nzb-file as it is displayed
|
||||
# by the program. The file path and extension are removed.
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file. It includes file extension and also
|
||||
# may include full path;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# 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 is disabled or nzb-file does
|
||||
# 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_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.
|
||||
#
|
||||
# In addition the following arguments are passed if the option <AllowReProcess>
|
||||
# is active:
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# 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_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_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)
|
||||
@@ -1004,14 +864,13 @@ SevenZipCmd=7z
|
||||
# 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);
|
||||
# 91 - request NZBGet to do par-check/repair for current collection in the
|
||||
# current nzb-file. This return code is accepted only if the
|
||||
# option <AllowReProcess> is active;
|
||||
# 92 - request NZBGet to do par-check/repair for all collections (par-sets)
|
||||
# in the current nzb-file.
|
||||
# All other return codes are interpreted as "status unknown".
|
||||
#
|
||||
# The return value is used to display the status of post-processing in
|
||||
@@ -1020,42 +879,62 @@ SevenZipCmd=7z
|
||||
# to standard output. For example:
|
||||
# echo "[ERROR] [HISTORY] Unpack failed, not enough disk space";
|
||||
#
|
||||
# NOTE: If the option <AllowReProcess> is active NZBGet calls the script
|
||||
# for each collection within nzb-file. The term "collection" actually means
|
||||
# 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.
|
||||
# If NZBGet doesn't find any collections it calls PostProcess once
|
||||
# with empty string for parameter NZBPP_PARFILENAME.
|
||||
#
|
||||
# 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.
|
||||
PostProcess=
|
||||
|
||||
# Allow multiple post-processing for the same nzb-file (yes, no).
|
||||
#
|
||||
# NOTE: Enable this option only if you were advised to do that by the author
|
||||
# of the post-processing script.
|
||||
# of the post-process-script.
|
||||
#
|
||||
# NOTE: By enabling <AllowReProcess> you should disable the option <ParCheck>
|
||||
# to prevent multiple par-checking.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# This option affects the post-processing in several ways:
|
||||
# 1) If the option is active the post-processing script (option <PostProcess>)
|
||||
# is called for each collection (par-set) within nzb-file;
|
||||
# 2) The post-processing script may be called multiple times when nzb-file
|
||||
# reaches the state "completely downloaded". This can be needed if
|
||||
# the par-check/-repair is performed by the post-processing script
|
||||
# (instead of relying on NZBGet's built-in par-check-feature).
|
||||
#
|
||||
# NOTE: If the built-in unpacking is active (option <Unpack>) this option
|
||||
# is ignored (as if it were set to "no").
|
||||
#
|
||||
# NOTE: If you develop a script depending on this option you should check
|
||||
# if the option is active when your script is started and generate an
|
||||
# error message if the option is not set correctly. You should also check
|
||||
# the option <Unpack> because if it's active the option <AllowReProcess>
|
||||
# doesn't work too.
|
||||
# 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.
|
||||
AllowReProcess=no
|
||||
|
||||
# Pause download queue during executing of postprocess-script (yes, no).
|
||||
@@ -1063,7 +942,7 @@ AllowReProcess=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 options <ParPauseQueue> and <UnpackPauseQueue>.
|
||||
# NOTE: See also option <ParPauseQueue>.
|
||||
PostPauseQueue=no
|
||||
|
||||
|
||||
@@ -1134,3 +1013,29 @@ PostPauseQueue=no
|
||||
#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 (Linux) or NTFS (Windows);
|
||||
# 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. Disable accurate speed rate
|
||||
# meter ("AccurateRate=no");
|
||||
# 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.
|
||||
|
||||
|
||||
35
nzbget.cpp
35
nzbget.cpp
@@ -106,7 +106,6 @@ 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;
|
||||
@@ -294,14 +293,8 @@ void Run(bool bReload)
|
||||
// Setup the network-server
|
||||
if (g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pRemoteServer = new RemoteServer(false);
|
||||
g_pRemoteServer = new RemoteServer();
|
||||
g_pRemoteServer->Start();
|
||||
|
||||
if (g_pOptions->GetSecureControl())
|
||||
{
|
||||
g_pRemoteSecureServer = new RemoteServer(true);
|
||||
g_pRemoteSecureServer->Start();
|
||||
}
|
||||
}
|
||||
|
||||
// Creating PrePostProcessor
|
||||
@@ -412,24 +405,6 @@ void Run(bool bReload)
|
||||
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)
|
||||
{
|
||||
@@ -728,14 +703,6 @@ 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)
|
||||
{
|
||||
|
||||
1
nzbget.h
1
nzbget.h
@@ -50,7 +50,6 @@
|
||||
#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 '/'
|
||||
|
||||
@@ -391,14 +391,6 @@
|
||||
RelativePath=".\Options.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParCoordinator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParCoordinator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParChecker.cpp"
|
||||
>
|
||||
@@ -407,14 +399,6 @@
|
||||
RelativePath=".\ParChecker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParRenamer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ParRenamer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PrePostProcessor.cpp"
|
||||
>
|
||||
@@ -503,14 +487,6 @@
|
||||
RelativePath=".\TLS.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Unpack.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Unpack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\UrlCoordinator.cpp"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -336,7 +336,6 @@ var Options = (new function($)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this.findOption = findOption;
|
||||
|
||||
function mergeValues(config, values)
|
||||
{
|
||||
@@ -663,9 +662,9 @@ var Config = (new function($)
|
||||
value = option.defvalue;
|
||||
}
|
||||
|
||||
option.formId = section.category + '-' + option.name.replace(/[\.|$|\:|\*]/g, '_');
|
||||
option.formId = section.category + '-' + option.name.replace(/[\.|$]/g, '_');
|
||||
|
||||
var caption = option.caption ? option.caption : option.name;
|
||||
var caption = option.name;
|
||||
if (section.multi)
|
||||
{
|
||||
caption = '<span class="config-multicaption">' + caption.substring(0, caption.indexOf('.') + 1) + '</span>' + caption.substring(caption.indexOf('.') + 1);
|
||||
@@ -714,17 +713,17 @@ var Config = (new function($)
|
||||
var pvalue = option.select[j];
|
||||
if (value && pvalue.toLowerCase() === value.toLowerCase())
|
||||
{
|
||||
html += '<input type="button" class="btn btn-primary" value="' + Util.textToAttr(pvalue) + '" onclick="Config.switchClick(this)">';
|
||||
html += '<input type="button" class="btn btn-primary" value="' + pvalue + '" onclick="Config.switchClick(this)">';
|
||||
valfound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
html += '<input type="button" class="btn" value="' + Util.textToAttr(pvalue) + '" onclick="Config.switchClick(this)">';
|
||||
html += '<input type="button" class="btn" value="' + pvalue + '" onclick="Config.switchClick(this)">';
|
||||
}
|
||||
}
|
||||
if (!valfound)
|
||||
{
|
||||
html += '<input type="button" class="btn btn-primary" value="' + Util.textToAttr(value) + '" onclick="Config.switchClick(this)">';
|
||||
html += '<input type="button" class="btn btn-primary" value="' + value + '" onclick="Config.switchClick(this)">';
|
||||
}
|
||||
|
||||
html +='</div>';
|
||||
@@ -734,26 +733,26 @@ var Config = (new function($)
|
||||
{
|
||||
option.type = 'numeric';
|
||||
html += '<div class="input-append">'+
|
||||
'<input type="text" id="' + option.formId + '" value="' + Util.textToAttr(value) + '" class="editnumeric">'+
|
||||
'<input type="text" id="' + option.formId + '" value="' + value + '" class="editnumeric">'+
|
||||
'<span class="add-on">'+ option.select[0] +'</span>'+
|
||||
'</div>';
|
||||
}
|
||||
else if (option.name.toLowerCase() === 'serverpassword')
|
||||
{
|
||||
option.type = 'password';
|
||||
html += '<input type="password" id="' + option.formId + '" value="' + Util.textToAttr(value) + '" class="editsmall">';
|
||||
html += '<input type="password" id="' + option.formId + '" value="' + value + '" class="editsmall">';
|
||||
}
|
||||
else if (option.name.toLowerCase().indexOf('username') > -1 ||
|
||||
option.name.toLowerCase().indexOf('password') > -1 ||
|
||||
option.name.indexOf('IP') > -1)
|
||||
{
|
||||
option.type = 'text';
|
||||
html += '<input type="text" id="' + option.formId + '" value="' + Util.textToAttr(value) + '" class="editsmall">';
|
||||
html += '<input type="text" id="' + option.formId + '" value="' + value + '" class="editsmall">';
|
||||
}
|
||||
else
|
||||
{
|
||||
option.type = 'text';
|
||||
html += '<input type="text" id="' + option.formId + '" value="' + Util.textToAttr(value) + '" class="editlarge">';
|
||||
html += '<input type="text" id="' + option.formId + '" value="' + value + '" class="editlarge">';
|
||||
}
|
||||
|
||||
if (option.description !== '')
|
||||
@@ -766,10 +765,6 @@ var Config = (new function($)
|
||||
htmldescr = htmldescr.replace(/CLOSETAG/g, '</a>');
|
||||
htmldescr = htmldescr.replace(/&/g, '&');
|
||||
|
||||
// replace URLs
|
||||
var exp = /(http:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
|
||||
htmldescr = htmldescr.replace(exp, "<a href='$1'>$1</a>");
|
||||
|
||||
// highlight first line
|
||||
htmldescr = htmldescr.replace(/\n/, '</span>\n');
|
||||
htmldescr = '<span class="help-option-title">' + htmldescr;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -273,10 +273,7 @@ var Downloads = (new function($)
|
||||
case 'VERIFYING_SOURCES': group.status = 'checking'; break;
|
||||
case 'REPAIRING': group.status = 'repairing'; break;
|
||||
case 'VERIFYING_REPAIRED': group.status = 'verifying'; break;
|
||||
case 'RENAMING': group.status = 'renaming'; break;
|
||||
case 'MOVING': group.status = 'moving'; break;
|
||||
case 'UNPACKING': group.status = 'unpacking'; break;
|
||||
case 'EXECUTING_SCRIPT': group.status = 'processing'; break;
|
||||
case 'EXECUTING_SCRIPT': group.status = 'unpacking'; break;
|
||||
case 'FINISHED': group.status = 'finished'; break;
|
||||
default: group.status = 'error: ' + group.post.Stage; break;
|
||||
}
|
||||
@@ -622,7 +619,7 @@ var DownloadsUI = (new function($)
|
||||
{
|
||||
if (group.post.StageProgress > 0)
|
||||
{
|
||||
return Util.formatTimeLeft(group.post.StageTimeSec / group.post.StageProgress * (1000 - group.post.StageProgress));
|
||||
return Util.formatTimeHMS(group.post.StageTimeSec / group.post.StageProgress * (1000 - group.post.StageProgress));
|
||||
}
|
||||
}
|
||||
else if (!group.paused && Status.status.DownloadRate > 0)
|
||||
@@ -636,29 +633,15 @@ var DownloadsUI = (new function($)
|
||||
this.buildProgressLabel = function(group)
|
||||
{
|
||||
var text = '';
|
||||
if (group.postprocess && !Status.status.PostPaused)
|
||||
if (group.postprocess && !Status.status.PostPaused && group.post.Stage !== 'REPAIRING')
|
||||
{
|
||||
switch (group.post.Stage)
|
||||
if (group.post.Log && group.post.Log.length > 0)
|
||||
{
|
||||
case "REPAIRING":
|
||||
break;
|
||||
case "LOADING_PARS":
|
||||
case "VERIFYING_SOURCES":
|
||||
case "VERIFYING_REPAIRED":
|
||||
case "UNPACKING":
|
||||
case "RENAMING":
|
||||
text = group.post.ProgressLabel;
|
||||
break;
|
||||
case "EXECUTING_SCRIPT":
|
||||
if (group.post.Log && group.post.Log.length > 0)
|
||||
{
|
||||
text = group.post.Log[group.post.Log.length-1].Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
text = group.post.ProgressLabel;
|
||||
}
|
||||
break;
|
||||
text = group.post.Log[group.post.Log.length-1].Text;
|
||||
}
|
||||
else if (group.post.ProgressLabel !== '')
|
||||
{
|
||||
text = group.post.ProgressLabel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -149,7 +149,6 @@ var DownloadsEditDialog = (new function($)
|
||||
table += '<tr><td>Total</td><td class="text-right">' + size + '</td></tr>';
|
||||
table += '<tr><td>Paused</td><td class="text-right">' + unpausedSize + '</td></tr>';
|
||||
table += '<tr><td>Unpaused</td><td class="text-right">' + remaining + '</td></tr>';
|
||||
//table += '<tr><td>Active downloads</td><td class="text-right">' + group.ActiveDownloads + '</td></tr>';
|
||||
table += '<tr><td>Estimated time</td><td class="text-right">' + estimated + '</td></tr>';
|
||||
table += '<tr><td>Files (total/remaining/pars)</td><td class="text-center">' + group.FileCount + ' / ' +
|
||||
group.RemainingFileCount + ' / ' + group.RemainingParCount + '</td></tr>';
|
||||
@@ -183,16 +182,13 @@ var DownloadsEditDialog = (new function($)
|
||||
$DownloadsLogTable.fasttable('update', []);
|
||||
$DownloadsFileTable.fasttable('update', []);
|
||||
|
||||
var postParamConfig = Options.postParamConfig;
|
||||
defineBuiltinParams(postParamConfig);
|
||||
|
||||
Util.show('#DownloadsEdit_NZBNameReadonly', group.postprocess);
|
||||
Util.show('#DownloadsEdit_CancelPPGroup', group.postprocess);
|
||||
Util.show('#DownloadsEdit_DeleteGroup', !group.postprocess);
|
||||
Util.show('#DownloadsEdit_PauseGroup', !group.postprocess);
|
||||
Util.show('#DownloadsEdit_ResumeGroup', false);
|
||||
Util.show('#DownloadsEdit_Save', !group.postprocess);
|
||||
var postParam = postParamConfig && postParamConfig.length > 0;
|
||||
var postParam = Options.postParamConfig && Options.postParamConfig.length > 0;
|
||||
var postLog = group.postprocess && group.post.Log.length > 0;
|
||||
Util.show('#DownloadsEdit_Param', postParam);
|
||||
Util.show('#DownloadsEdit_Log', postLog);
|
||||
@@ -220,7 +216,7 @@ var DownloadsEditDialog = (new function($)
|
||||
|
||||
if (postParam)
|
||||
{
|
||||
postParams = $.extend(true, [], postParamConfig);
|
||||
postParams = $.extend(true, [], Options.postParamConfig);
|
||||
Options.mergeValues(postParams, group.Parameters);
|
||||
var content = Config.buildOptionsContent(postParams[0]);
|
||||
var configData = $('#DownloadsEdit_ParamData');
|
||||
@@ -431,25 +427,6 @@ var DownloadsEditDialog = (new function($)
|
||||
|
||||
/*** TAB: POST-PROCESSING PARAMETERS **************************************************/
|
||||
|
||||
function defineBuiltinParams(postParamConfig)
|
||||
{
|
||||
if (Options.option('Unpack') !== 'yes')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (postParamConfig.length == 0)
|
||||
{
|
||||
postParamConfig.push({category: 'P', postparam: true, options: []});
|
||||
}
|
||||
|
||||
if (!Options.findOption(postParamConfig[0].options, '*Unpack:'))
|
||||
{
|
||||
postParamConfig[0].options.unshift({name: '*Unpack:Password', value: '', defvalue: '', select: [], caption: 'Password', description: 'Unpack-password for encrypted posts.'});
|
||||
postParamConfig[0].options.unshift({name: '*Unpack:', value: '', defvalue: 'yes', select: ['yes', 'no'], caption: 'Unpack', description: 'Set to "no" to disable unpack for this nzb-file.'});
|
||||
}
|
||||
}
|
||||
|
||||
function prepareParamRequest()
|
||||
{
|
||||
var request = [];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -113,29 +113,19 @@ var History = (new function($)
|
||||
{
|
||||
if (hist.Kind === 'NZB')
|
||||
{
|
||||
if (hist.ParStatus == 'FAILURE' || hist.UnpackStatus == 'FAILURE' || hist.MoveStatus == 'FAILURE' || hist.ScriptStatus == 'FAILURE')
|
||||
switch (hist.ScriptStatus)
|
||||
{
|
||||
hist.status = 'failure';
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (hist.ScriptStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'UNKNOWN': hist.status = 'unknown'; break;
|
||||
case 'NONE':
|
||||
switch (hist.UnpackStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'NONE':
|
||||
switch (hist.ParStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'REPAIR_POSSIBLE': hist.status = 'repairable'; break;
|
||||
case 'NONE': hist.status = 'unknown'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'FAILURE': hist.status = 'failure'; break;
|
||||
case 'UNKNOWN': hist.status = 'unknown'; break;
|
||||
case 'NONE':
|
||||
switch (hist.ParStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'REPAIR_POSSIBLE': hist.status = 'repairable'; break;
|
||||
case 'FAILURE': hist.status = 'failure'; break;
|
||||
case 'NONE': hist.status = 'none'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hist.Kind === 'URL')
|
||||
@@ -190,7 +180,7 @@ var History = (new function($)
|
||||
{
|
||||
var hist = item.hist;
|
||||
|
||||
var status = buildStatus(hist.status, '');
|
||||
var status = buildStatus(hist);
|
||||
|
||||
var name = '<a href="#" histid="' + hist.ID + '">' + Util.textToHtml(Util.formatNZBName(hist.Name)) + '</a>';
|
||||
var category = Util.textToHtml(hist.Category);
|
||||
@@ -232,27 +222,16 @@ var History = (new function($)
|
||||
}
|
||||
}
|
||||
|
||||
function buildStatus(status, prefix)
|
||||
function buildStatus(hist)
|
||||
{
|
||||
switch (status)
|
||||
switch (hist.status)
|
||||
{
|
||||
case 'success':
|
||||
case 'SUCCESS':
|
||||
return '<span class="label label-status label-success">' + prefix + 'success</span>';
|
||||
case 'failure':
|
||||
case 'FAILURE':
|
||||
return '<span class="label label-status label-important">' + prefix + 'failure</span>';
|
||||
case 'unknown':
|
||||
case 'UNKNOWN':
|
||||
return '<span class="label label-status label-info">' + prefix + 'unknown</span>';
|
||||
case 'repairable':
|
||||
case 'REPAIR_POSSIBLE':
|
||||
return '<span class="label label-status label-success">' + prefix + 'repairable</span>';
|
||||
case 'none':
|
||||
case 'NONE':
|
||||
return '<span class="label label-status">' + prefix + 'none</span>';
|
||||
default:
|
||||
return '<span class="label label-status">' + prefix + status + '</span>';
|
||||
case 'success': return '<span class="label label-status label-success">success</span>';
|
||||
case 'failure': return '<span class="label label-status label-important">failure</span>';
|
||||
case 'unknown': return '<span class="label label-status label-info">unknown</span>';
|
||||
case 'repairable': return '<span class="label label-status label-success">repairable</span>';
|
||||
case 'none': return '<span class="label label-status">unknown</span>';
|
||||
default: return '<span class="label label-status label-important">internal error(' + hist.status + ')</span>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,18 +358,7 @@ var History = (new function($)
|
||||
|
||||
curHist = hist;
|
||||
|
||||
var status;
|
||||
if (hist.Kind === 'URL')
|
||||
{
|
||||
status = buildStatus(hist.status, '');
|
||||
}
|
||||
else
|
||||
{
|
||||
status = buildStatus(hist.ParStatus, 'Par: ') + ' ' +
|
||||
(Options.option('Unpack') == 'yes' || hist.UnpackStatus != 'NONE' ? buildStatus(hist.UnpackStatus, 'Unpack: ') + ' ' : '') +
|
||||
(hist.MoveStatus === "FAILURE" ? buildStatus(hist.MoveStatus, 'Move: ') + ' ' : "") +
|
||||
buildStatus(hist.ScriptStatus, 'Script: ');
|
||||
}
|
||||
var status = buildStatus(hist);
|
||||
|
||||
$('#HistoryEdit_Title').text(Util.formatNZBName(hist.Name));
|
||||
if (hist.Kind === 'URL')
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@@ -2,7 +2,7 @@
|
||||
<!--
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -101,11 +101,6 @@
|
||||
<li class="divider"></li>
|
||||
<li><a href="#" onclick="Status.pauseClick('download')"><table><tr><td><i class="icon-ok" id="CHSoftPauseDownload"></td><td>Soft-Pause Download</td></tr></table></a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="menu-header">Pause for</li>
|
||||
<li><a href="#" onclick="Status.scheduledPauseClick(30*60)"><table><tr><td></td><td>30 Minutes</td></tr></table></a></li>
|
||||
<li><a href="#" onclick="Status.scheduledPauseClick(3*60*60)"><table><tr><td></td><td>3 Hours</td></tr></table></a></li>
|
||||
<li><a href="#" onclick="Status.scheduledPauseDialogClick()"><table><tr><td></td><td>Custom...</td></tr></table></a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a data-toggle="modal" href="#PauseHelp"><table><tr><td></td><td>Quick Help</td></tr></table></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -114,7 +109,7 @@
|
||||
<!-- SPEED/TIME -->
|
||||
<div id="InfoBlock">
|
||||
<div href="#" onclick="Status.limitDialogClick()" title="Current speed (click to set speed limit)"><i class="icon-plane" id="StatusSpeedIcon"></i> <span id="StatusSpeed">--- KB/s</span></div>
|
||||
<div href="#" onclick="Status.statDialogClick()" title="Remaining time (click for more statistics)"><i class="icon-time" id="StatusTimeIcon"></i> <span id="StatusTime">--h --m</span></div>
|
||||
<div href="#" onclick="Status.statDialogClick()" title="Remaining time (click for more statistics)"><i class="icon-time"></i> <span id="StatusTime">--h --m</span></div>
|
||||
</div>
|
||||
|
||||
<!-- REFRESH MENU -->
|
||||
@@ -446,7 +441,7 @@
|
||||
|
||||
<div id="ConfigInfo">
|
||||
<p>
|
||||
On this page you can review and change settings. When you done with changes click
|
||||
On this page your can review and change settings. When you done with changes click
|
||||
<em><strong>Save all changes</strong></em>, which will save the changes made on all pages.
|
||||
It's not neccessary to save the changes on each page individually.
|
||||
</p>
|
||||
@@ -464,22 +459,16 @@
|
||||
to check at least the option <a class="option" href="#" data-category="S" onclick="Config.scrollToOption(event, this)">MainDir</a> and configure one news server.
|
||||
Any changes of NZBGet settings require a restart or reload (soft-restart) of NZBGet.
|
||||
</p>
|
||||
<p>
|
||||
There are many configuration options affecting performance. If you use
|
||||
NZBGet on a computer with limited capabilities, such as NAS, media player,
|
||||
router, etc. you should take your time to configure NZBGet for best
|
||||
performance - see <a href="http://nzbget.sourceforge.net/Performance_tips">Performance tips</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h4>Post-processing script settings</h4>
|
||||
<p>
|
||||
When NZBGet finishes download
|
||||
of nzb-file it can start a post-processing script for further processing (cleanup, etc.).
|
||||
of nzb-file it can start a post-processing script for further processing (unpacking etc.).
|
||||
You can configure what script must be executed using option <a class="option" href="#" data-category="S" onclick="Config.scrollToOption(event, this)">PostProcess</a>
|
||||
in section <em><strong>POST-PROCESSING</strong></em>.
|
||||
</p>
|
||||
<p>
|
||||
The post-processing script settings are shown on the navigation bar
|
||||
The <em><strong>POST-PROCESSING SCRIPT SETTINGS</strong></em> are shown on the navigation bar
|
||||
only if you have setup a post-processing script and if it has a configuration file. For your convenience
|
||||
NZBGet proivides you with a way to configure the post-processing script options via web-interface.
|
||||
These settings however do not
|
||||
@@ -561,6 +550,8 @@
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>Module TLS (TLS.c, TLS.h) is based on work by Martin Lambers (marlam@marlam.de).</p>
|
||||
|
||||
<h2>Copyright</h2>
|
||||
<p>This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -640,34 +631,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- *** PAUSE FOR X MINUTES ***************************************************** -->
|
||||
|
||||
<div class="modal modal-mini hide" id="ScheduledPauseDialog">
|
||||
<div class="modal-header">
|
||||
<a class="close" href='#' data-dismiss="modal"><i class="icon-close"></i></a>
|
||||
<h3>Temporary Pause</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-horizontal">
|
||||
<fieldset>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="PauseForInputGroup">Pause for</label>
|
||||
<div class="controls" id="PauseForInputGroup">
|
||||
<div class="input-append">
|
||||
<input class="input-mini" id="PauseForInput" size="16" type="text"><span class="add-on">Minutes</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="dialog-transmit hide" style="position:absolute;margin-left:260px;" id="ScheduledPause_Transmit"><img src="img/transmit.gif"></div>
|
||||
<a href="#" class="btn" data-dismiss="modal">Close</a>
|
||||
<a href="#" class="btn btn-primary" onclick="Status.pauseForClick()">Pause</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- *** QUICK HELP: EXPLAINING PAUSE OPTIONS ************************************************************ -->
|
||||
|
||||
<div class="modal hide" id="PauseHelp">
|
||||
@@ -738,13 +701,13 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<div class="modal-bottom-toolbar">
|
||||
<button class="btn" data-tab="DownloadsEdit_FileTab" data-fullscreen="true" id="DownloadsEdit_File" title="File list">Files <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_ParamTab" id="DownloadsEdit_Param" title="Post-processing parameters">PP-Parameters <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_LogTab" data-fullscreen="true" id="DownloadsEdit_Log" title="Post-processing messages">PP-Messages <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_FileTab" data-fullscreen="true" id="DownloadsEdit_File">Files <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_ParamTab" id="DownloadsEdit_Param" title="Post-processing parameters">PP Parameters <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_LogTab" data-fullscreen="true" id="DownloadsEdit_Log" title="Post-processing messages">PP Messages <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1008,6 +971,7 @@
|
||||
<label class="control-label" for="HistoryEdit_Path">Download Path</label>
|
||||
<div class="controls">
|
||||
<span class="uneditable-mulitline-input" id="HistoryEdit_Path"></span>
|
||||
<p class="help-block">Post-processing script may have moved files elsewhere.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
4
webui/lib/bootstrap.css
vendored
4
webui/lib/bootstrap.css
vendored
@@ -1757,7 +1757,7 @@ table .span24 {
|
||||
*margin-right: .3em;
|
||||
line-height: 14px;
|
||||
vertical-align: text-top;
|
||||
/* background-image: url("../img/glyphicons-halflings.png"); */
|
||||
background-image: url("../img/glyphicons-halflings.png");
|
||||
background-position: 14px 14px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@@ -1768,7 +1768,7 @@ table .span24 {
|
||||
}
|
||||
|
||||
.icon-white {
|
||||
/* background-image: url("../img/glyphicons-halflings-white.png"); */
|
||||
background-image: url("../img/glyphicons-halflings-white.png");
|
||||
}
|
||||
|
||||
.icon-glass {
|
||||
|
||||
@@ -49,7 +49,6 @@ var Status = (new function($)
|
||||
var $StatusLeft;
|
||||
var $StatusSpeed;
|
||||
var $StatusSpeedIcon;
|
||||
var $StatusTimeIcon;
|
||||
var $StatusTime;
|
||||
var $StatusURLs;
|
||||
var $PlayBlock;
|
||||
@@ -60,8 +59,6 @@ var Status = (new function($)
|
||||
var $CurSpeedLimitBlock;
|
||||
var $LimitDialog;
|
||||
var $StatDialog;
|
||||
var $ScheduledPauseDialog;
|
||||
var $PauseForInput;
|
||||
|
||||
// State
|
||||
var status;
|
||||
@@ -88,15 +85,12 @@ var Status = (new function($)
|
||||
$StatusLeft = $('#StatusLeft');
|
||||
$StatusSpeed = $('#StatusSpeed');
|
||||
$StatusSpeedIcon = $('#StatusSpeedIcon');
|
||||
$StatusTimeIcon = $('#StatusTimeIcon');
|
||||
$StatusTime = $('#StatusTime');
|
||||
$StatusURLs = $('#StatusURLs');
|
||||
$CurSpeedLimit = $('#CurSpeedLimit');
|
||||
$CurSpeedLimitBlock = $('#CurSpeedLimitBlock');
|
||||
$LimitDialog = $('#LimitDialog');
|
||||
$StatDialog = $('#StatDialog');
|
||||
$ScheduledPauseDialog = $('#ScheduledPauseDialog')
|
||||
$PauseForInput = $('#PauseForInput');
|
||||
|
||||
if (UISettings.setFocus)
|
||||
{
|
||||
@@ -104,10 +98,6 @@ var Status = (new function($)
|
||||
{
|
||||
$('#SpeedLimitInput').focus();
|
||||
});
|
||||
$ScheduledPauseDialog.on('shown', function()
|
||||
{
|
||||
$('#PauseForInput').focus();
|
||||
});
|
||||
}
|
||||
|
||||
$PlayAnimation.hover(function() { $PlayBlock.addClass('hover'); }, function() { $PlayBlock.removeClass('hover'); });
|
||||
@@ -179,11 +169,6 @@ var Status = (new function($)
|
||||
'<span class="label label-status label-success">active</span>')) +
|
||||
'</td></tr>';
|
||||
|
||||
if (status.ResumeTime > 0)
|
||||
{
|
||||
content += '<tr><td>Autoresume</td><td class="text-right">' + Util.formatTimeHMS(status.ResumeTime - status.ServerTime) + '</td></tr>';
|
||||
}
|
||||
|
||||
content += '</tbody>';
|
||||
content += '</table>';
|
||||
|
||||
@@ -203,11 +188,7 @@ var Status = (new function($)
|
||||
if (status.ServerStandBy)
|
||||
{
|
||||
$StatusSpeed.html('--- KB/s');
|
||||
if (status.ResumeTime > 0)
|
||||
{
|
||||
$StatusTime.html(Util.formatTimeLeft(status.ResumeTime - status.ServerTime));
|
||||
}
|
||||
else if (status.RemainingSizeMB > 0 || status.RemainingSizeLo > 0)
|
||||
if (status.RemainingSizeHi > 0 || status.RemainingSizeLo > 0)
|
||||
{
|
||||
if (status.AverageDownloadRate > 0)
|
||||
{
|
||||
@@ -236,11 +217,9 @@ var Status = (new function($)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$StatusSpeedIcon.toggleClass('icon-plane', status.DownloadLimit === 0);
|
||||
$StatusSpeedIcon.toggleClass('icon-truck', status.DownloadLimit !== 0);
|
||||
$StatusTime.toggleClass('scheduled-resume', status.ServerStandBy && status.ResumeTime > 0);
|
||||
$StatusTimeIcon.toggleClass('icon-time', !(status.ServerStandBy && status.ResumeTime > 0));
|
||||
$StatusTimeIcon.toggleClass('icon-time-orange', status.ServerStandBy && status.ResumeTime > 0);
|
||||
}
|
||||
|
||||
function updatePlayButton()
|
||||
@@ -395,34 +374,6 @@ var Status = (new function($)
|
||||
});
|
||||
}
|
||||
|
||||
this.scheduledPauseClick = function(seconds)
|
||||
{
|
||||
RPC.call('pausedownload2', [],
|
||||
function(){RPC.call('pausepost', [],
|
||||
function(){RPC.call('pausescan', [],
|
||||
function(){RPC.call('scheduleresume', [seconds], Refresher.update)})})});
|
||||
}
|
||||
|
||||
this.scheduledPauseDialogClick = function()
|
||||
{
|
||||
$PauseForInput.val('');
|
||||
$ScheduledPauseDialog.modal();
|
||||
}
|
||||
|
||||
this.pauseForClick = function()
|
||||
{
|
||||
var val = $PauseForInput.val();
|
||||
var minutes = parseInt(val);
|
||||
|
||||
if (isNaN(minutes) || minutes <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$ScheduledPauseDialog.modal('hide');
|
||||
this.scheduledPauseClick(minutes * 60);
|
||||
}
|
||||
|
||||
function modalShow()
|
||||
{
|
||||
modalShown = true;
|
||||
|
||||
@@ -254,14 +254,6 @@ body.navfixed.scrolled .navbar-fixed-top .navbar-inner {
|
||||
filter: alpha(opacity=100);
|
||||
}
|
||||
|
||||
#StatusTime.scheduled-resume {
|
||||
color: #F08929;
|
||||
}
|
||||
|
||||
#StatusTime.scheduled-resume:hover {
|
||||
color: #FFA15A;
|
||||
}
|
||||
|
||||
.navbar-inner .btn:hover i {
|
||||
opacity: 1;
|
||||
filter: alpha(opacity=100);
|
||||
@@ -550,10 +542,6 @@ body.navfixed.scrolled .navbar-fixed-top .navbar-inner {
|
||||
background-position: -464px -48px;
|
||||
}
|
||||
|
||||
.icon-time-orange {
|
||||
background-position: -400px -80px;
|
||||
}
|
||||
|
||||
.img-checkmark {
|
||||
background-position: -432px -16px;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* 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
|
||||
@@ -170,13 +170,7 @@ var Upload = (new function($)
|
||||
|
||||
function selectFiles()
|
||||
{
|
||||
var inp = $('#AddDialog_Input');
|
||||
|
||||
// Reset file input control (needed for IE10)
|
||||
inp.wrap('<form>').closest('form').get(0).reset();
|
||||
inp.unwrap();
|
||||
|
||||
inp.click();
|
||||
$('#AddDialog_Input').click();
|
||||
}
|
||||
|
||||
function fileSelectHandler(event)
|
||||
@@ -261,10 +255,10 @@ var Upload = (new function($)
|
||||
}
|
||||
|
||||
var testreader = new FileReader();
|
||||
if (!testreader.readAsBinaryString && !testreader.readAsDataURL)
|
||||
if (!testreader.readAsBinaryString)
|
||||
{
|
||||
$AddDialog.modal('hide');
|
||||
alert("Unfortunately your browser doesn't support neither \"readAsBinaryString\" nor \"readAsDataURL\" functions of FileReader API.\n\nPlease use alternative ways to add files to queue:\nadd via URL or put the files directly into incoming nzb-directory.");
|
||||
alert("Unfortunately your browser doesn't support the function \"readAsBinaryString\" of FileReader API.\n\nPlease use alternative ways to add files to queue:\nadd via URL or put the files directly into incoming nzb-directory.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -315,28 +309,13 @@ var Upload = (new function($)
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (event)
|
||||
{
|
||||
var base64str;
|
||||
if (reader.readAsBinaryString)
|
||||
{
|
||||
base64str = window.btoa(event.target.result);
|
||||
}
|
||||
else
|
||||
{
|
||||
base64str = event.target.result.replace(/^data:[^,]+,/, '');
|
||||
}
|
||||
var base64str = window.btoa(event.target.result);
|
||||
var category = $('#AddDialog_Category').val();
|
||||
var priority = parseInt($('#AddDialog_Priority').val());
|
||||
RPC.call('append', [file.name, category, priority, false, base64str], fileCompleted, fileFailure);
|
||||
};
|
||||
|
||||
if (reader.readAsBinaryString)
|
||||
{
|
||||
reader.readAsBinaryString(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
reader.readAsBinaryString(file);
|
||||
}
|
||||
|
||||
function fileCompleted(result)
|
||||
|
||||
@@ -172,14 +172,6 @@ var Util = (new function($)
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
this.textToAttr = function(str)
|
||||
{
|
||||
return str.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
this.setMenuMark = function(menu, data)
|
||||
{
|
||||
// remove marks from all items
|
||||
|
||||
4
win32.h
4
win32.h
@@ -36,8 +36,6 @@
|
||||
#ifndef DISABLE_TLS
|
||||
/* Define to 1 to use GnuTLS library for TLS/SSL-support */
|
||||
#define HAVE_LIBGNUTLS
|
||||
/* Define to 1 to use OpenSSL library for TLS/SSL-support */
|
||||
//#define HAVE_OPENSSL
|
||||
#endif
|
||||
|
||||
/* Define to the name of macro which returns the name of function being
|
||||
@@ -74,7 +72,7 @@
|
||||
/* Define to 1 if spinlocks are supported */
|
||||
#define HAVE_SPINLOCK
|
||||
|
||||
#define VERSION "10.0"
|
||||
#define VERSION "9.1"
|
||||
|
||||
/* Suppress warnings */
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
Reference in New Issue
Block a user