Compare commits

...

1 Commits
master ... v9.1

Author SHA1 Message Date
Andrey Prygunkov
99bd29f631 version 9.1 2013-03-30 20:43:04 +00:00
73 changed files with 3802 additions and 5553 deletions

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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())

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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
View File

@@ -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

View File

@@ -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);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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;
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
};

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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)
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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())

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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();
};

View File

@@ -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()

View File

@@ -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);

View File

@@ -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 \

View File

@@ -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@

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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)

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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

View File

@@ -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++;
}
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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();

View File

@@ -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();

View File

@@ -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
View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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);
}

View File

@@ -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

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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();

View File

@@ -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();

View File

@@ -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();

1824
TLS.cpp
View File

File diff suppressed because it is too large Load Diff

204
TLS.h
View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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
View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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");

View File

@@ -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
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for nzbget 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

View File

@@ -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

View File

@@ -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=

View File

@@ -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

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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 '/'

View File

@@ -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"
>

View File

@@ -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, '&amp;');
// 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;

View File

@@ -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;
}
}

View File

@@ -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 = [];

View File

@@ -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')

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -172,14 +172,6 @@ var Util = (new function($)
.replace(/>/g, '&gt;');
}
this.textToAttr = function(str)
{
return str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
this.setMenuMark = function(menu, data)
{
// remove marks from all items

View File

@@ -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