Compare commits

..

1 Commits

Author SHA1 Message Date
Andrey Prygunkov
ba24945bcd version 0.7.0 2010-04-26 21:21:23 +00:00
123 changed files with 8236 additions and 42893 deletions

View File

@@ -1,4 +1,4 @@
nzbget:
Sven Henkel <sidddy@users.sourceforge.net> (versions 0.1.0 - ?)
Bo Cordes Petersen <placebodk@users.sourceforge.net> (versions ? - 0.2.3)
Andrey Prygunkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)
Andrei Prygounkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -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->GetServer()->GetHost());
Status = Download();
}
@@ -201,6 +200,9 @@ void ArticleDownloader::Run()
m_pConnection->Disconnect();
bConnected = false;
Status = adFailed;
#ifdef THREADCONNECT_WORKAROUND
iRemainedConnectRetries--;
#endif
}
else
{
@@ -210,103 +212,89 @@ 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 > 0))
{
pWantServer = pLastServer;
}
if (pWantServer && !IsStopped() &&
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
{
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
SetStatus(adWaiting);
int msec = 0;
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
{
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 (((Status == adFailed) || (Status == adCrcError && g_pOptions->GetRetryOnCrcError())) &&
(iRemainedDownloadRetries > 1 || !bConnected) && !IsStopped())
{
failedServers.push_back(pLastServer);
// if all servers from current level were tried, increase level
// if all servers from all levels were tried, break the loop with failure status
bool bAllServersOnLevelFailed = true;
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
int msec = 0;
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000))
{
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;
}
}
usleep(100 * 1000);
msec += 100;
}
}
if (bAllServersOnLevelFailed)
if (IsStopped())
{
Status = adFailed;
break;
}
if ((Status == adFinished) || (Status == adFatalError) ||
(Status == adCrcError && !g_pOptions->GetRetryOnCrcError()))
{
break;
}
LevelStatus[level] = Status;
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;
@@ -317,19 +305,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");
}
@@ -417,8 +405,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->GetServer()->GetHost());
}
Status = adFailed;
break;
@@ -452,8 +439,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->GetServer()->GetHost(), m_pArticleInfo->GetMessageID(), p);
Status = adFailed;
break;
}
@@ -481,8 +467,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->GetServer()->GetHost());
Status = adFailed;
}
@@ -509,21 +494,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->GetServer()->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->GetServer()->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->GetServer()->GetHost(), szComment, szResponse);
return adNotFound;
}
else if (!strncmp(szResponse, "2", 1))
@@ -534,8 +516,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->GetServer()->GetHost(), szComment, szResponse);
return adFailed;
}
}
@@ -626,8 +607,9 @@ bool ArticleDownloader::PrepareFile(char* szLine)
{
pb += 6; //=strlen(" size=")
long iArticleFilesize = atol(pb);
if (!CreateOutputFile(iArticleFilesize))
if (!Util::SetFileSize(m_szOutputFilename, iArticleFilesize))
{
error("Could not create file %s!", m_szOutputFilename);
return false;
}
m_pFileInfo->SetOutputInitialized(true);
@@ -670,33 +652,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;
@@ -868,18 +823,11 @@ void ArticleDownloader::CompleteFileParts()
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_pFileInfo->GetOutputInitialized();
char szNZBName[1024];
char szNZBDestDir[1024];
// the locking is needed for accessing the memebers of NZBInfo
g_pDownloadQueueHolder->LockQueue();
strncpy(szNZBName, m_pFileInfo->GetNZBInfo()->GetName(), 1024);
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
g_pDownloadQueueHolder->UnlockQueue();
szNZBName[1024-1] = '\0';
szNZBDestDir[1024-1] = '\0';
char szNZBNiceName[1024];
m_pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
char InfoFilename[1024];
snprintf(InfoFilename, 1024, "%s%c%s", szNZBName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
snprintf(InfoFilename, 1024, "%s%c%s", szNZBNiceName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
InfoFilename[1024-1] = '\0';
if (!g_pOptions->GetDecode())
@@ -895,6 +843,13 @@ void ArticleDownloader::CompleteFileParts()
detail("Joining articles for %s", InfoFilename);
}
char szNZBDestDir[1024];
// the locking is needed for accessing the memebers of NZBInfo
g_pDownloadQueueHolder->LockQueue();
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
g_pDownloadQueueHolder->UnlockQueue();
szNZBDestDir[1024-1] = '\0';
// Ensure the DstDir is created
if (!Util::ForceDirectories(szNZBDestDir))
{
@@ -1028,23 +983,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

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -42,10 +42,10 @@ public:
{
adUndefined,
adRunning,
adWaiting,
adFinished,
adFailed,
adRetry,
adDecodeError,
adCrcError,
adDecoding,
adJoining,
@@ -76,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();
@@ -89,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();
@@ -112,7 +111,7 @@ class DownloadSpeedMeter
{
public:
virtual ~DownloadSpeedMeter() {};
virtual int CalcCurrentDownloadSpeed() = 0;
virtual float CalcCurrentDownloadSpeed() = 0;
virtual void AddSpeedReading(int iBytes) = 0;
};

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -48,23 +48,19 @@
#include "Log.h"
#include "Options.h"
#include "QueueCoordinator.h"
#include "UrlCoordinator.h"
#include "QueueEditor.h"
#include "PrePostProcessor.h"
#include "Util.h"
#include "DownloadInfo.h"
extern Options* g_pOptions;
extern QueueCoordinator* g_pQueueCoordinator;
extern UrlCoordinator* g_pUrlCoordinator;
extern PrePostProcessor* g_pPrePostProcessor;
extern void ExitProc();
extern void Reload();
const char* g_szMessageRequestNames[] =
{ "N/A", "Download", "Pause/Unpause", "List", "Set download rate", "Dump debug",
"Edit queue", "Log", "Quit", "Reload", "Version", "Post-queue", "Write log", "Scan",
"Pause/Unpause postprocessor", "History", "Download URL", "URL-queue" };
"Edit queue", "Log", "Quit", "Version", "Post-queue", "Write log", "Scan",
"Pause/Unpause postprocessor", "History" };
const unsigned int g_iMessageRequestSizes[] =
{ 0,
@@ -76,40 +72,39 @@ const unsigned int g_iMessageRequestSizes[] =
sizeof(SNZBEditQueueRequest),
sizeof(SNZBLogRequest),
sizeof(SNZBShutdownRequest),
sizeof(SNZBReloadRequest),
sizeof(SNZBVersionRequest),
sizeof(SNZBPostQueueRequest),
sizeof(SNZBWriteLogRequest),
sizeof(SNZBScanRequest),
sizeof(SNZBHistoryRequest),
sizeof(SNZBDownloadUrlRequest),
sizeof(SNZBUrlQueueRequest)
sizeof(SNZBHistoryRequest)
};
//*****************************************************************
// 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;
}
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetControlPassword()))
// Make sure this is a nzbget request from a client
if ((int)ntohl(m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE)
{
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetServerPort(), m_szClientIP);
return;
}
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_pConnection->GetRemoteAddr());
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetServerPassword()))
{
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetServerPort(), m_szClientIP);
return;
}
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_szClientIP);
Dispatch();
}
@@ -161,10 +156,6 @@ void BinRpcProcessor::Dispatch()
command = new ShutdownBinCommand();
break;
case eRemoteRequestReload:
command = new ReloadBinCommand();
break;
case eRemoteRequestVersion:
command = new VersionBinCommand();
break;
@@ -185,14 +176,6 @@ void BinRpcProcessor::Dispatch()
command = new HistoryBinCommand();
break;
case eRemoteRequestDownloadUrl:
command = new DownloadUrlBinCommand();
break;
case eRemoteRequestUrlQueue:
command = new UrlQueueBinCommand();
break;
default:
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
break;
@@ -200,7 +183,7 @@ void BinRpcProcessor::Dispatch()
if (command)
{
command->SetConnection(m_pConnection);
command->SetSocket(m_iSocket);
command->SetMessageBase(&m_MessageBase);
command->Execute();
delete command;
@@ -222,8 +205,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 +215,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 +233,6 @@ void PauseUnpauseBinCommand::Execute()
return;
}
g_pOptions->SetResumeTime(0);
switch (ntohl(PauseUnpauseRequest.m_iAction))
{
case eRemotePauseUnpauseActionDownload:
@@ -281,7 +263,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");
}
@@ -294,7 +276,6 @@ void DumpDebugBinCommand::Execute()
}
g_pQueueCoordinator->LogDebugInfo();
g_pUrlCoordinator->LogDebugInfo();
SendBoolResponse(true, "Debug-Command completed successfully");
}
@@ -310,18 +291,6 @@ void ShutdownBinCommand::Execute()
ExitProc();
}
void ReloadBinCommand::Execute()
{
SNZBReloadRequest ReloadRequest;
if (!ReceiveRequest(&ReloadRequest, sizeof(ReloadRequest)))
{
return;
}
SendBoolResponse(true, "Reloading server");
Reload();
}
void VersionBinCommand::Execute()
{
SNZBVersionRequest VersionRequest;
@@ -342,44 +311,46 @@ 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);
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);
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);
@@ -398,24 +369,12 @@ void ListBinCommand::Execute()
ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse));
ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseFileEntry));
ListResponse.m_bRegExValid = 0;
char* buf = NULL;
int bufsize = 0;
if (ntohl(ListRequest.m_bFileList))
{
eRemoteMatchMode eMatchMode = (eRemoteMatchMode)ntohl(ListRequest.m_iMatchMode);
bool bMatchGroup = ntohl(ListRequest.m_bMatchGroup);
const char* szPattern = ListRequest.m_szPattern;
RegEx *pRegEx = NULL;
if (eMatchMode == eRemoteMatchModeRegEx)
{
pRegEx = new RegEx(szPattern);
ListResponse.m_bRegExValid = pRegEx->IsValid();
}
// Make a data structure and copy all the elements of the list into it
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
@@ -427,7 +386,6 @@ void ListBinCommand::Execute()
{
NZBInfo* pNZBInfo = *it;
bufsize += strlen(pNZBInfo->GetFilename()) + 1;
bufsize += strlen(pNZBInfo->GetName()) + 1;
bufsize += strlen(pNZBInfo->GetDestDir()) + 1;
bufsize += strlen(pNZBInfo->GetCategory()) + 1;
bufsize += strlen(pNZBInfo->GetQueuedFilename()) + 1;
@@ -471,17 +429,13 @@ void ListBinCommand::Execute()
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iSizeLo = htonl(iSizeLo);
pListAnswer->m_iSizeHi = htonl(iSizeHi);
pListAnswer->m_bMatch = htonl(bMatchGroup && (!pRegEx || pRegEx->Match(pNZBInfo->GetName())));
pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1);
pListAnswer->m_iNameLen = htonl(strlen(pNZBInfo->GetName()) + 1);
pListAnswer->m_iDestDirLen = htonl(strlen(pNZBInfo->GetDestDir()) + 1);
pListAnswer->m_iCategoryLen = htonl(strlen(pNZBInfo->GetCategory()) + 1);
pListAnswer->m_iQueuedFilenameLen = htonl(strlen(pNZBInfo->GetQueuedFilename()) + 1);
bufptr += sizeof(SNZBListResponseNZBEntry);
strcpy(bufptr, pNZBInfo->GetFilename());
bufptr += ntohl(pListAnswer->m_iFilenameLen);
strcpy(bufptr, pNZBInfo->GetName());
bufptr += ntohl(pListAnswer->m_iNameLen);
strcpy(bufptr, pNZBInfo->GetDestDir());
bufptr += ntohl(pListAnswer->m_iDestDirLen);
strcpy(bufptr, pNZBInfo->GetCategory());
@@ -530,7 +484,7 @@ void ListBinCommand::Execute()
unsigned long iSizeHi, iSizeLo;
FileInfo* pFileInfo = *it;
SNZBListResponseFileEntry* pListAnswer = (SNZBListResponseFileEntry*) bufptr;
pListAnswer->m_iID = htonl(pFileInfo->GetID());
pListAnswer->m_iID = htonl(pFileInfo->GetID());
int iNZBIndex = 0;
for (unsigned int i = 0; i < pDownloadQueue->GetNZBInfoList()->size(); i++)
@@ -543,13 +497,6 @@ void ListBinCommand::Execute()
}
pListAnswer->m_iNZBIndex = htonl(iNZBIndex);
if (pRegEx && !bMatchGroup)
{
char szFilename[MAX_PATH];
snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename()));
pListAnswer->m_bMatch = htonl(pRegEx->Match(szFilename));
}
Util::SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
@@ -558,8 +505,6 @@ void ListBinCommand::Execute()
pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi);
pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed());
pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused());
pListAnswer->m_iActiveDownloads = htonl(pFileInfo->GetActiveDownloads());
pListAnswer->m_iPriority = htonl(pFileInfo->GetPriority());
pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
bufptr += sizeof(SNZBListResponseFileEntry);
@@ -578,11 +523,6 @@ void ListBinCommand::Execute()
g_pQueueCoordinator->UnlockQueue();
if (pRegEx)
{
delete pRegEx;
}
ListResponse.m_iNrTrailingNZBEntries = htonl(iNrNZBEntries);
ListResponse.m_iNrTrailingPPPEntries = htonl(iNrPPPEntries);
ListResponse.m_iNrTrailingFileEntries = htonl(iNrFileEntries);
@@ -592,11 +532,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 +559,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 +650,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);
@@ -729,71 +669,63 @@ void EditQueueBinCommand::Execute()
return;
}
int iNrIDEntries = ntohl(EditQueueRequest.m_iNrTrailingIDEntries);
int iNrNameEntries = ntohl(EditQueueRequest.m_iNrTrailingNameEntries);
int iNameEntriesLen = ntohl(EditQueueRequest.m_iTrailingNameEntriesLen);
int iNrEntries = ntohl(EditQueueRequest.m_iNrTrailingEntries);
int iAction = ntohl(EditQueueRequest.m_iAction);
int iMatchMode = ntohl(EditQueueRequest.m_iMatchMode);
int iOffset = ntohl(EditQueueRequest.m_iOffset);
int iTextLen = ntohl(EditQueueRequest.m_iTextLen);
bool bSmartOrder = ntohl(EditQueueRequest.m_bSmartOrder);
unsigned int iBufLength = ntohl(EditQueueRequest.m_iTrailingDataLength);
if (iNrIDEntries * sizeof(int32_t) + iTextLen + iNameEntriesLen != iBufLength)
if (iNrEntries * sizeof(int32_t) + iTextLen != iBufLength)
{
error("Invalid struct size");
return;
}
if (iNrEntries <= 0)
{
SendBoolResponse(false, "Edit-Command failed: no IDs specified");
return;
}
char* pBuf = (char*)malloc(iBufLength);
if (!m_pConnection->Recv(pBuf, iBufLength))
{
error("invalid request");
free(pBuf);
return;
}
char* szText = NULL;
int32_t* pIDs = NULL;
if (iNrIDEntries <= 0 && iNrNameEntries <= 0)
// Read from the socket until nothing remains
char* pBufPtr = pBuf;
int NeedBytes = iBufLength;
int iResult = 0;
while (NeedBytes > 0)
{
SendBoolResponse(false, "Edit-Command failed: no IDs/Names specified");
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;
char* szText = iTextLen > 0 ? pBuf : NULL;
int32_t* pIDs = (int32_t*)(pBuf + iTextLen);
char* pNames = (pBuf + iTextLen + iNrIDEntries * sizeof(int32_t));
if (bOK)
{
szText = iTextLen > 0 ? pBuf : NULL;
pIDs = (int32_t*)(pBuf + iTextLen);
}
IDList cIDList;
NameList cNameList;
if (iNrIDEntries > 0)
cIDList.reserve(iNrEntries);
for (int i = 0; i < iNrEntries; i++)
{
cIDList.reserve(iNrIDEntries);
for (int i = 0; i < iNrIDEntries; i++)
{
cIDList.push_back(ntohl(pIDs[i]));
}
cIDList.push_back(ntohl(pIDs[i]));
}
if (iNrNameEntries > 0)
{
cNameList.reserve(iNrNameEntries);
for (int i = 0; i < iNrNameEntries; i++)
{
cNameList.push_back(pNames);
pNames += strlen(pNames) + 1;
}
}
bool bOK = false;
if (iAction < eRemoteEditActionPostMoveOffset)
{
bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(
iNrIDEntries > 0 ? &cIDList : NULL,
iNrNameEntries > 0 ? &cNameList : NULL,
(QueueEditor::EMatchMode)iMatchMode, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset, szText);
bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(&cIDList, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset, szText);
}
else
{
@@ -808,13 +740,6 @@ void EditQueueBinCommand::Execute()
}
else
{
#ifndef HAVE_REGEX_H
if ((QueueEditor::EMatchMode)iMatchMode == QueueEditor::mmRegEx)
{
SendBoolResponse(false, "Edit-Command failed: the program was compiled without RegEx-support");
return;
}
#endif
SendBoolResponse(false, "Edit-Command failed");
}
}
@@ -900,12 +825,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 +845,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);
}
@@ -962,10 +901,8 @@ void ScanBinCommand::Execute()
return;
}
bool bSyncMode = ntohl(ScanRequest.m_bSyncMode);
g_pPrePostProcessor->ScanNZBDir(bSyncMode);
SendBoolResponse(true, bSyncMode ? "Scan-Command completed" : "Scan-Command scheduled successfully");
g_pPrePostProcessor->ScanNZBDir();
SendBoolResponse(true, "Scan-Command scheduled successfully");
}
void HistoryBinCommand::Execute()
@@ -989,14 +926,15 @@ void HistoryBinCommand::Execute()
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
// calculate required buffer size for nzbs
int iNrEntries = pDownloadQueue->GetHistoryList()->size();
bufsize += iNrEntries * sizeof(SNZBHistoryResponseEntry);
int iNrNZBEntries = pDownloadQueue->GetHistoryList()->size();
bufsize += iNrNZBEntries * sizeof(SNZBHistoryResponseEntry);
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
char szNicename[1024];
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
bufsize += strlen(szNicename) + 1;
NZBInfo* pNZBInfo = *it;
bufsize += strlen(pNZBInfo->GetFilename()) + 1;
bufsize += strlen(pNZBInfo->GetDestDir()) + 1;
bufsize += strlen(pNZBInfo->GetCategory()) + 1;
bufsize += strlen(pNZBInfo->GetQueuedFilename()) + 1;
// align struct to 4-bytes, needed by ARM-processor (and may be others)
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
}
@@ -1005,42 +943,36 @@ void HistoryBinCommand::Execute()
char* bufptr = buf;
// write nzb entries
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
for (NZBInfoList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
unsigned long iSizeHi, iSizeLo;
NZBInfo* pNZBInfo = *it;
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) bufptr;
pListAnswer->m_iID = htonl(pHistoryInfo->GetID());
pListAnswer->m_iKind = htonl((int)pHistoryInfo->GetKind());
pListAnswer->m_tTime = htonl((int)pHistoryInfo->GetTime());
char szNicename[1024];
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
pListAnswer->m_iNicenameLen = htonl(strlen(szNicename) + 1);
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
{
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
unsigned long iSizeHi, iSizeLo;
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iSizeLo = htonl(iSizeLo);
pListAnswer->m_iSizeHi = htonl(iSizeHi);
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatus());
}
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
{
UrlInfo* pUrlInfo = pHistoryInfo->GetUrlInfo();
pListAnswer->m_iUrlStatus = htonl(pUrlInfo->GetStatus());
}
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iID = htonl(pNZBInfo->GetID());
pListAnswer->m_tTime = htonl((int)pNZBInfo->GetHistoryTime());
pListAnswer->m_iSizeLo = htonl(iSizeLo);
pListAnswer->m_iSizeHi = htonl(iSizeHi);
pListAnswer->m_iFileCount = htonl(pNZBInfo->GetFileCount());
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatus());
pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1);
pListAnswer->m_iDestDirLen = htonl(strlen(pNZBInfo->GetDestDir()) + 1);
pListAnswer->m_iCategoryLen = htonl(strlen(pNZBInfo->GetCategory()) + 1);
pListAnswer->m_iQueuedFilenameLen = htonl(strlen(pNZBInfo->GetQueuedFilename()) + 1);
bufptr += sizeof(SNZBHistoryResponseEntry);
strcpy(bufptr, szNicename);
bufptr += ntohl(pListAnswer->m_iNicenameLen);
strcpy(bufptr, pNZBInfo->GetFilename());
bufptr += ntohl(pListAnswer->m_iFilenameLen);
strcpy(bufptr, pNZBInfo->GetDestDir());
bufptr += ntohl(pListAnswer->m_iDestDirLen);
strcpy(bufptr, pNZBInfo->GetCategory());
bufptr += ntohl(pListAnswer->m_iCategoryLen);
strcpy(bufptr, pNZBInfo->GetQueuedFilename());
bufptr += ntohl(pListAnswer->m_iQueuedFilenameLen);
// align struct to 4-bytes, needed by ARM-processor (and may be others)
if ((size_t)bufptr % 4 > 0)
{
pListAnswer->m_iNicenameLen = htonl(ntohl(pListAnswer->m_iNicenameLen) + 4 - (size_t)bufptr % 4);
pListAnswer->m_iQueuedFilenameLen = htonl(ntohl(pListAnswer->m_iQueuedFilenameLen) + 4 - (size_t)bufptr % 4);
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
bufptr += 4 - (size_t)bufptr % 4;
}
@@ -1048,126 +980,16 @@ void HistoryBinCommand::Execute()
g_pQueueCoordinator->UnlockQueue();
HistoryResponse.m_iNrTrailingEntries = htonl(iNrEntries);
HistoryResponse.m_iNrTrailingEntries = htonl(iNrNZBEntries);
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);
}
free(buf);
}
void DownloadUrlBinCommand::Execute()
{
SNZBDownloadUrlRequest DownloadUrlRequest;
if (!ReceiveRequest(&DownloadUrlRequest, sizeof(DownloadUrlRequest)))
{
return;
}
URL url(DownloadUrlRequest.m_szURL);
if (!url.IsValid())
{
char tmp[1024];
snprintf(tmp, 1024, "Url %s is not valid", DownloadUrlRequest.m_szURL);
tmp[1024-1] = '\0';
SendBoolResponse(true, tmp);
return;
}
UrlInfo* pUrlInfo = new UrlInfo();
pUrlInfo->SetURL(DownloadUrlRequest.m_szURL);
pUrlInfo->SetNZBFilename(DownloadUrlRequest.m_szNZBFilename);
pUrlInfo->SetCategory(DownloadUrlRequest.m_szCategory);
pUrlInfo->SetPriority(ntohl(DownloadUrlRequest.m_iPriority));
pUrlInfo->SetAddTop(ntohl(DownloadUrlRequest.m_bAddFirst));
pUrlInfo->SetAddPaused(ntohl(DownloadUrlRequest.m_bAddPaused));
g_pUrlCoordinator->AddUrlToQueue(pUrlInfo, ntohl(DownloadUrlRequest.m_bAddFirst));
info("Request: Queue url %s", DownloadUrlRequest.m_szURL);
char tmp[1024];
snprintf(tmp, 1024, "Url %s added to queue", DownloadUrlRequest.m_szURL);
tmp[1024-1] = '\0';
SendBoolResponse(true, tmp);
}
void UrlQueueBinCommand::Execute()
{
SNZBUrlQueueRequest UrlQueueRequest;
if (!ReceiveRequest(&UrlQueueRequest, sizeof(UrlQueueRequest)))
{
return;
}
SNZBUrlQueueResponse UrlQueueResponse;
memset(&UrlQueueResponse, 0, sizeof(UrlQueueResponse));
UrlQueueResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
UrlQueueResponse.m_MessageBase.m_iStructSize = htonl(sizeof(UrlQueueResponse));
UrlQueueResponse.m_iEntrySize = htonl(sizeof(SNZBUrlQueueResponseEntry));
char* buf = NULL;
int bufsize = 0;
// Make a data structure and copy all the elements of the list into it
UrlQueue* pUrlQueue = g_pQueueCoordinator->LockQueue()->GetUrlQueue();
int NrEntries = pUrlQueue->size();
// calculate required buffer size
bufsize = NrEntries * sizeof(SNZBUrlQueueResponseEntry);
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
{
UrlInfo* pUrlInfo = *it;
bufsize += strlen(pUrlInfo->GetURL()) + 1;
bufsize += strlen(pUrlInfo->GetNZBFilename()) + 1;
// align struct to 4-bytes, needed by ARM-processor (and may be others)
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
}
buf = (char*) malloc(bufsize);
char* bufptr = buf;
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
{
UrlInfo* pUrlInfo = *it;
SNZBUrlQueueResponseEntry* pUrlQueueAnswer = (SNZBUrlQueueResponseEntry*) bufptr;
pUrlQueueAnswer->m_iID = htonl(pUrlInfo->GetID());
pUrlQueueAnswer->m_iURLLen = htonl(strlen(pUrlInfo->GetURL()) + 1);
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pUrlInfo->GetNZBFilename()) + 1);
bufptr += sizeof(SNZBUrlQueueResponseEntry);
strcpy(bufptr, pUrlInfo->GetURL());
bufptr += ntohl(pUrlQueueAnswer->m_iURLLen);
strcpy(bufptr, pUrlInfo->GetNZBFilename());
bufptr += ntohl(pUrlQueueAnswer->m_iNZBFilenameLen);
// align struct to 4-bytes, needed by ARM-processor (and may be others)
if ((size_t)bufptr % 4 > 0)
{
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(ntohl(pUrlQueueAnswer->m_iNZBFilenameLen) + 4 - (size_t)bufptr % 4);
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
bufptr += 4 - (size_t)bufptr % 4;
}
}
g_pQueueCoordinator->UnlockQueue();
UrlQueueResponse.m_iNrTrailingEntries = htonl(NrEntries);
UrlQueueResponse.m_iTrailingDataLength = htonl(bufsize);
// Send the request answer
m_pConnection->Send((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
// Send the data
if (bufsize > 0)
{
m_pConnection->Send(buf, bufsize);
send(m_iSocket, buf, bufsize, 0);
}
free(buf);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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; }
};
@@ -108,12 +110,6 @@ public:
virtual void Execute();
};
class ReloadBinCommand: public BinCommand
{
public:
virtual void Execute();
};
class VersionBinCommand: public BinCommand
{
public:
@@ -144,16 +140,4 @@ public:
virtual void Execute();
};
class DownloadUrlBinCommand: public BinCommand
{
public:
virtual void Execute();
};
class UrlQueueBinCommand: public BinCommand
{
public:
virtual void Execute();
};
#endif

336
ChangeLog
View File

@@ -1,339 +1,3 @@
nzbget-10.1:
- fixed: articles with decoding errors (incomplete or damaged posts)
caused infinite retry-loop in downloader.
nzbget-10.0:
- added built-in unpack:
- rar and 7-zip formats are supported (via external Unrar and
7-Zip executables);
- new options <Unpack>, <UnpackPauseQueue>, <UnpackCleanupDisk>,
<UnrarCmd>, <SevenZipCmd>;
- web-interface now shows progress and estimated time during
unpack (rar only; for 7-Zip progress is not available due to
limitations of 7-Zip);
- when built-in unpack is enabled, the post-processing script is
called after unpack and possibly par-check/repair (if needed);
- for nzb-files containing multiple collections (par-sets) the
post-processing script is called only once, after the last
par-set;
- new parameter <NZBPP_UNPACKSTATUS> passed to post-processing
script;
- if the option <AllowReProcess> is enabled the post-processing-
script is called after each par-set (as in previous versions);
- example post-processing script updated: removed unrar-code,
added check for unpack status;
- new field <UnpackStatus> in result of RPC-method <history>;
- history-dialog in web-interface shows three status: par-status,
unpack-status, script-status;
- with two built-in special post-processing parameters <*Unpack:>
and <*Unpack:Password> the unpack can be disabled for individual
nzb-file or the password can be set;
- built-in special post-processing parameters can be set via web-
interface on page <PP-Parameters> (when built-in unpack is
enabled);
- added support for HTTPS to the built-in web-server (web-interface and
XML/JSON-RPC):
- new options <SecureControl>, <SecurePort>, <SecureCert> and
<SecureKey>;
- module <TLS.c/h> completely rewritten with support for server-
side sockets, newer versions of GnuTLS, proper thread lockings
in OpenSSL;
- improved the automatic par-scan (option <ParScan=auto>) to
significantly reduce the verify-time in some common cases with renamed
rar-files:
- the extra files are scanned in an optimized order;
- the scan stops when all missings files are found;
- added fast renaming of intentionally misnamed (rar-) files:
- the new renaming algorithm doesn't require full par-scan and
restores original filenames in just a few seconds, even on very
slow computers (NAS, media players, etc.);
- the fast renaming is performed automatically when requested by
the built-in unpacker (option <Unpack> must be active);
- added new option <InterDir> to put intermediate files during download
into a separate directory (instead of storing them directly in
destination directory (option <DestDir>):
- when nzb-file is completely (successfully) downloaded, repaired
(if neccessary) and unpacked the files are moved to destination
directory (option <DestDir> or <CategoryX.DestDir>);
- intermediate directory can significantly improve unpack
performance if it is located on a separate physical hard drive;
- added new option <ServerX.Cipher> to manually select cipher for
encrypted communication with news server:
- manually choosing a faster cipher (such as <RC4>) can
significantly improve performance (if CPU is a limiting factor);
- major improvements in news-server/connection management (main and fill
servers):
- if download of article fails, the program tries all servers of
the same level before trying higher level servers;
- this ensures that fill servers are used only if all main servers
fail;
- this makes the configuring of multiple servers much easier than
before: in most cases the simple configuration of level 0 for
all main servers and level 1 for all fill servers suffices;
- in previous versions the level was increased immediately after
the first tried server of the level failed; to make sure all
main servers were tried before downloading from fill servers it
was required to create complex server configurations with
duplicates; these configurations were still not as effective as
now;
- do not reconnect on <article/group not found> errors since this
doesn't help but unnecessary increases CPU load and network
traffic;
- removed option <RetryOnCrcError>; it's not required anymore;
- new option <ServerX.Group> allows more flexible configuration
of news servers when using multiple accounts on the same server;
with this option it's also possible to imitate the old server
management behavior regarding levels;
- news servers configuration is now less error-prone:
- the option <ServerX.Level> is not required to start from <0> and
when several news servers are configured the Levels can be any
integers - the program sorts the servers and corrects the Levels
to 0,1,2,etc. automatically if needed;
- when option <ServerX.Connections> is set to <0> the server is
ignored (in previous version such a server could cause hanging
when the program was trying to go to the next level);
- if no news servers are defined (or all definitions are invalid)
a warning is printed to inform that the download is not
possible;
- categories can now have their own destination directories; new option
<CategoryX.DestDir>;
- new feature <Pause for X Minutes> in web-interface; new XML-/JSON-RPC
method <scheduleresume>;
- improved the handling of hanging connections: if a connection hangs
longer than defined by option <ConnectionTimeout> the program tries to
gracefully close connection first (this is new); if it still hangs
after <TerminateTimeout> the download thread is terminated as a last
resort (as in previous versions);
- added automatic speed meter recalibration to recover after possible
synchronization errors which can occur when the option <AccurateRate>
is not active; this makes the default (less accurate but fast) speed
meter almost as good as the accurate one; important when speed
throttling is active;
- when the par-checked requests more par-files, they get an extra
priority and are downloaded before other files regardless of their
priorities; this is needed to avoid hanging of par-checker-job if a
file with a higher priority gets added to queue during par-check;
- when post-processing-parameters are passed to the post-processing
script a second version of each parameter with a normalized parameter-
name is passed in addition to the original parameter name; in the
normalized name the special characters <*> and <:> are replaced with
<_> and all characters are passed in upper case; this is important for
internal post-processing-parameters (*Unpack:=yes/no) which include
special characters;
- warning <Non-nzbget request received> now is not printed when the
connection was aborted before the request signature was read;
- changed formatting of remaining time for post-processing to short
format (as used for remaining download time);
- added link to article <Performance tips> to settings tab on web-
interface;
- removed hint <Post-processing script may have moved files elsewhere>
from history dialog since it caused more questions than helped;
- changed default value for option <ServerX.JoinGroup> to <no>; most
news servers nowadays do not require joining the group and many
servers do not keep headers for many groups making the join-command
fail even if the articles still can be successfully downloaded;
- small change in example post-processing script: message <Deleting
source ts-files> are now printed only if ts-files really existed;
- improved configure-script:
- libs which are added via pkgconfig are now put into LIBS instead
of LDFLAGS - improves compatibility with newer Linux linkers;
- OpenSSL libs/includes are now added using pkgconfig to better
handle dependencies;
- additional check for libcrypto (part of OpenSSL) ensures the
library is added to linker command even if pkgconfig is not
used;
- adding of local files via web-interface now works in IE10;
- if an obsolete option is found in the config file a warning is printed
instead of an error and the program is not paused anymore;
- fixed: the reported line numbers for configuration errors were
sometimes inaccurate;
- fixed warning <file glyphicons-halflings.png not found>;
- fixed: some XML-/JSON-RPC methods may return negative values for file
sizes between 2-4GB; this had also influence on web-interface.
- fixed: if an external program (unrar, pp-script, etc.) could not be
started, the execute-function has returned code 255 although the code
-1 were expected in this case; this could break designed post-
processing flow;
- fixed: some characters with codes below 32 were not properly encoded
in JSON-RPC; sometimes output from unrar contained such characters
and could break web-interface;
- fixed: special characters (quotation marks, etc.) in unpack password
and in configuration options were not displayed properly and could be
discarded on saving;
nzbget-9.0:
- changed version naming scheme by removing the leading zero: current
version is now called 9.0 instead of 0.9.0 (it's really the 9th major
version of the program);
- added built-in web-interface:
- completely new designed and written from scratch;
- doesn't require a separate web-server;
- doesn't require PHP;
- 100% Javascript application; the built-in web-server hosts only
static files; the javascript app communicates with NZBGet via
JSON-RPC;
- very efficient usage of server resources (CPU and memory);
- easy installation. Since neither a separate web-server nor PHP
are needed the installation of new web-interface is very easy.
Actually it is performed automatically when you "make install"
or "ipkg install nzbget";
- modern look: better layout, popup dialogs, nice animations,
hi-def icons;
- built-in phone-theme (activates automatically);
- combined view for "currently downloading", "queued", "currently
processing" and "queued for processing";
- renaming of nzb-files;
- multiselect with multiedit or merge of downloads;
- fast paging in the lists (downloads, history, messages);
- search box for filtering in the lists (downloads, history, messages)
and in settings;
- adding nzb-files to download queue was improved in several ways:
- add multiple files at once. The "select files dialog" allows
to select multiple files;
- add files using drag and drop. Just drop the files from your
file manager directly into the web-browser;
- add files via URLs. Put the URL and NZBGet downloads the
nzb-file and adds it to download queue automatically;
- the priority of nzb-file can now be set when adding local-files
or URLs;
- the history can be cleared completely or selected items can be removed;
- file mode is now nzb-file related;
- added the ability to queue URLs:
- the program automatically downloads nzb-files from given URLs
and put them to download queue.
- when multiple URLs are added in a short time, they are put
into a special URL-queue.
- the number of simultaneous URL-downloads are controlled via
new option UrlConnections.
- with the new option ReloadUrlQueue can be controlled if the URL-queue
should be reloaded after the program is restarted (if the URL-queue
was not empty).
- new switch <-U> for remote-command <--append/-A> to queue an URL.
- new subcommand <-U> in the remote command <--list/-L> prints the
current URL-queue.
- if URL-download fails, the URL is moved into history.
- with subcommand <-R> of command <--edit> the failed URL can be
returned to URL-queue for redownload.
- the remote command <--list/-L> for history can now print the infos
for URL history items.
- new XML/JSON-RPC command <appendurl> to add an URL or multiple
URLs for download.
- new XML/JSON-RPC command <urlqueue> returns the items from the
URL-queue.
- the XML/JSON-RPC command <history> was extended to provide
infos about URL history items.
- the URL-queue obeys the pause-state of download queue.
- the URL-downloads support HTTP and HTTPS protocols;
- added new field <name> to nzb-info-object.
- it is initially set to the cleaned up name of the nzb-file.
- the renaming of the group changes this field.
- all RPC-methods related to nzb-object return the new field, the
old field <NZBNicename> is now deprecated.
- the option <MergeNZB> now checks the <name>-field instead of
<nzbfilename> (the latter is not changed when the nzb is renamed).
- new env-var-parameter <NZBPP_NZBNAME> for post-processing script;
- added options <GN> and <FN> for remote command <--edit/-E>. With these
options the name of group or file can be used in edit-command instead
of file ID;
- added support for regular expressions (POSIX ERE Syntax) in remote
commands <--list/-L> and <--edit/-E> using new subcommands <GR> and <FR>;
- improved performance of RPC-command <listgroups>;
- added new command <FileReorder> to RPC-method <editqueue> to set the
order of individual files in the group;
- added gzip-support to built-in web-server (including RPC);
- added processing of http-request <OPTIONS> in RPC-server for better
support of cross domain requests;
- renamed example configuration file and postprocessing script to make
the installation easier;
- improved the automatic installation (<make install>) to install all
necessary files (not only the binary as it was before);
- improved handling of configuration errors: the program now does not
terminate on errors but rather logs all of them and uses default option values;
- added new XML/JSON-RPC methods <config>, <loadconfig> and <saveconfig>;
- with active option <AllowReProcess> the NZB considered completed even if
there are paused non-par-files (the paused non-par-files are treated the
same way as paused par-files): as a result the reprocessable script is called;
- added subcommand <W> to remote command <-S/--scan> to scan synchronously
(wait until scan completed);
- added parameter <SyncMode> to XML/JSON-RPC method <scan>;
- the command <Scan> in web-interface now waits for completing of scan
before reporting the status;
- added remote command <--reload/-O> and JSON/XML-RPC method <reload> to
reload configuration from disk and reintialize the program; the reload
can be performed from web-interface;
- JSON/XML-RPC method <append> extended with parameter <priority>;
- categories available in web-interface are now configured in program
configuration file (nzbget.conf) and can be managed via web-interface
on settings page;
- updated descriptions in example configuration file;
- changes in configuration file:
- renamed options <ServerIP>, <ServerPort> and <ServerPassword> to
<ControlIP>, <ControlPort> and <ControlPassword> to avoid confusion
with news-server options <ServerX.Host>, <ServerX.Port> and
<ServerX.Password>;
- the old option names are still recognized and are automatically
renamed when the configuration is saved from web-interface;
- also renamed option <$MAINDIR> to <MainDir>;
- extended remote command <--append/-A> with optional parameters:
- <T> - adds the file/URL to the top of queue;
- <P> - pauses added files;
- <C category-name> - sets category for added nzb-file/URL;
- <N nzb-name> - sets nzb filename for added URL;
- the old switches <--category/-K> and <--top/-T> are deprecated
but still supported for compatibility;
- renamed subcommand <K> of command <--edit/-E> to <C> (the old
subcommand is still supported for compatibility);
- added new option <NzbAddedProcess> to setup a script called after
a nzb-file is added to queue;
- added debug messages for speed meter;
- improved the startup script <nzbgetd> so it can be directly used in
</etc/init.d> without modifications;
- fixed: after renaming of a group, the new name was not displayed
by remote commands <-L G> and <-C in curses mode>;
- fixed incompatibility with OpenSLL 1.0 (thanks to OpenWRT team
for the patch);
- fixed: RPC-method <log(0, IdFrom)> could return wrong results if
the log was filtered with options <XXXTarget>;
- fixed: free disk space calculated incorrectly on some OSes;
- fixed: unrar failure was not always properly detected causing the
post-processing to delete not yet unpacked rar-files;
- fixed compilation error on recent linux versions;
- fixed compilation error on older systems;
nzbget-0.8.0:
- added priorities; new action <I> for remote command <--edit/-E> to set
priorities for groups or individual files; new actions <SetGroupPriority>
and <SetFilePriority> of RPC-command <editqueue>; remote command
<--list/-L> prints priorities and indicates files or groups being
downloaded; ncurses-frontend prints priorities and indicates files or
groups being download; new command <PRIORITY> to set priority of nzb-file
from nzbprocess-script; RPC-commands <listgroups> and <listfiles> return
priorities and indicate files or groups being downloaded;
- added renaming of groups; new subcommand <N> for command <--edit/-E>; new
action <SetName> for RPC-method <editqueue>;
- added new option <AccurateRate>, which enables syncronisation in speed
meter; that makes the indicated speed more accurate by eliminating
measurement errors possible due thread conflicts; thanks to anonymous
nzbget user for the patch;
- improved the parsing of filename from article subject;
- option <DirectWrite> now efficiently works on Windows with NTFS partitions;
- added URL-based-authentication as alternative to HTTP-header authentication
for XML- and JSON-RPC;
- fixed: nzb-files containing umlauts and other special characters could not
be parsed - replaced XML-Reader with SAX-Parser - only on POSIX (not on
Windows);
- fixed incorrect displaying of group sizes bigger than 4GB on many 64-bit
OSes;
- fixed a bug causing error on decoding of input data in JSON-RPC;
- fixed a compilation error on some windows versions;
- fixed: par-repair could fail when the filenames were not correctly parsed
from article subjects;
- fixed a compatibility issue with OpenBSD (and possibly other BSD based
systems); added the automatic configuring of required signal handling logic
to better support BSD without breaking the compatibility with certain Linux
systems;
- corrected the address of Free Software Foundation in copyright notice.
nzbget-0.7.0:
- added history: new option <KeepHistory>, new remote subcommand <H> for
commands <L> (list history entries) and <E> (delete history entries,

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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 if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -54,16 +54,19 @@
#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()
void Connection::Init(bool bTLS)
{
debug("Initializing global connection data");
@@ -84,7 +87,21 @@ void Connection::Init()
#endif
#ifndef DISABLE_TLS
TLSSocket::Init();
if (bTLS)
{
debug("Initializing TLS library");
char* szErrStr;
int iRes = tls_lib_init(&szErrStr);
bTLSLibInitialized = iRes == TLS_EOK;
if (!bTLSLibInitialized)
{
error("Could not initialize TLS library: %s", szErrStr ? szErrStr : "unknown error");
if (szErrStr)
{
free(szErrStr);
}
}
}
#endif
#ifndef HAVE_GETADDRINFO
@@ -103,7 +120,11 @@ void Connection::Final()
#endif
#ifndef DISABLE_TLS
TLSSocket::Final();
if (bTLSLibInitialized)
{
debug("Finalizing TLS library");
tls_lib_deinit();
}
#endif
#ifndef HAVE_GETADDRINFO
@@ -113,48 +134,38 @@ void Connection::Final()
#endif
}
Connection::Connection(const char* szHost, int iPort, bool bTLS)
Connection::Connection(NetAddress* pNetAddress)
{
debug("Creating Connection");
m_szHost = NULL;
m_iPort = iPort;
m_bTLS = bTLS;
m_szCipher = NULL;
m_pNetAddress = pNetAddress;
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
if (szHost)
{
m_szHost = strdup(szHost);
}
}
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_pNetAddress = NULL;
m_eStatus = csConnected;
m_iSocket = iSocket;
m_iBufAvail = 0;
m_iTimeout = 60;
m_bSuppressErrors = true;
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
m_bAutoClose = bAutoClose;
#ifndef DISABLE_TLS
m_pTLSSocket = NULL;
m_bTLSError = false;
m_pTLS = NULL;
#endif
}
@@ -162,65 +173,32 @@ Connection::~Connection()
{
debug("Destroying Connection");
Disconnect();
if (m_szHost)
if (m_eStatus == csConnected && m_bAutoClose)
{
free(m_szHost);
Disconnect();
}
if (m_szCipher)
{
free(m_szCipher);
}
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");
if (m_eStatus == csConnected)
{
return true;
}
bool bRes = DoConnect();
if (bRes)
{
m_eStatus = csConnected;
}
else
{
Connection::DoDisconnect();
}
return bRes;
}
@@ -230,9 +208,7 @@ bool Connection::Disconnect()
debug("Disconnecting");
if (m_eStatus == csDisconnected)
{
return true;
}
bool bRes = DoDisconnect();
@@ -276,27 +252,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 +278,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 +308,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)");
@@ -396,18 +357,17 @@ bool Connection::DoConnect()
addr_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
addr_hints.ai_socktype = SOCK_STREAM,
sprintf(iPortStr, "%d", m_iPort);
sprintf(iPortStr, "%d", m_pNetAddress->GetPort());
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
int res = getaddrinfo(m_pNetAddress->GetHost(), iPortStr, &addr_hints, &addr_list);
if (res != 0)
{
ReportError("Could not resolve hostname %s", m_szHost, true, 0);
ReportError("Could not resolve hostname %s", m_pNetAddress->GetHost(), true, 0);
return false;
}
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
{
bool bLastAddr = !addr->ai_next;
m_iSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (m_iSocket != INVALID_SOCKET)
{
@@ -418,33 +378,20 @@ bool Connection::DoConnect()
break;
}
// Connection failed
if (bLastAddr)
{
ReportError("Connection to %s failed", m_szHost, true, 0);
}
closesocket(m_iSocket);
m_iSocket = INVALID_SOCKET;
}
else if (bLastAddr)
{
ReportError("Socket creation failed for %s", m_szHost, true, 0);
}
}
freeaddrinfo(addr_list);
if (m_iSocket == INVALID_SOCKET)
{
return false;
}
#else
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
sSocketAddress.sin_port = htons(m_iPort);
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_szHost);
sSocketAddress.sin_port = htons(m_pNetAddress->GetPort());
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_pNetAddress->GetHost());
if (sSocketAddress.sin_addr.s_addr == (unsigned int)-1)
{
return false;
@@ -453,20 +400,25 @@ bool Connection::DoConnect()
m_iSocket = socket(PF_INET, SOCK_STREAM, 0);
if (m_iSocket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_szHost, true, 0);
ReportError("Socket creation failed for %s", m_pNetAddress->GetHost(), true, 0);
return false;
}
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_pNetAddress->GetHost(), true, 0);
return false;
}
#ifdef WIN32
int MSecVal = m_iTimeout * 1000;
int err = setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&MSecVal, sizeof(MSecVal));
@@ -478,16 +430,9 @@ 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))
{
return false;
}
#endif
return true;
}
@@ -497,11 +442,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;
@@ -585,15 +533,6 @@ char* Connection::DoReadLine(char* pBuffer, int iSize, int* pBytesRead)
return pBuffer;
}
void Connection::ReadBuffer(char** pBuffer, int *iBufLen)
{
*iBufLen = m_iBufAvail;
*pBuffer = m_szBufPtr;
m_iBufAvail = 0;
};
int Connection::DoBind()
{
debug("Do binding");
@@ -607,12 +546,12 @@ int Connection::DoBind()
addr_hints.ai_socktype = SOCK_STREAM,
addr_hints.ai_flags = AI_PASSIVE; // For wildcard IP address
sprintf(iPortStr, "%d", m_iPort);
sprintf(iPortStr, "%d", m_pNetAddress->GetPort());
int res = getaddrinfo(m_szHost, iPortStr, &addr_hints, &addr_list);
int res = getaddrinfo(m_pNetAddress->GetHost(), iPortStr, &addr_hints, &addr_list);
if (res != 0)
{
error("Could not resolve hostname %s", m_szHost);
error( "Could not resolve hostname %s", m_pNetAddress->GetHost() );
return -1;
}
@@ -643,24 +582,24 @@ int Connection::DoBind()
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
if (!m_szHost || strlen(m_szHost) == 0)
if (!m_pNetAddress->GetHost() || strlen(m_pNetAddress->GetHost()) == 0)
{
sSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_szHost);
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_pNetAddress->GetHost());
if (sSocketAddress.sin_addr.s_addr == (unsigned int)-1)
{
return -1;
}
}
sSocketAddress.sin_port = htons(m_iPort);
sSocketAddress.sin_port = htons(m_pNetAddress->GetPort());
m_iSocket = socket(PF_INET, SOCK_STREAM, 0);
if (m_iSocket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_szHost, true, 0);
ReportError("Socket creation failed for %s", m_pNetAddress->GetHost(), true, 0);
return -1;
}
@@ -678,13 +617,13 @@ int Connection::DoBind()
if (m_iSocket == INVALID_SOCKET)
{
ReportError("Binding socket failed for %s", m_szHost, true, 0);
ReportError("Binding socket failed for %s", m_pNetAddress->GetHost(), true, 0);
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);
ReportError("Listen on socket failed for %s", m_pNetAddress->GetHost(), true, 0);
return -1;
}
@@ -693,7 +632,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 +675,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 +695,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 +704,7 @@ void Connection::ReportError(const char* szMsgPrefix, const char* szMsgArg, bool
{
error("%s: ErrNo %i, %s", szErrPrefix, ErrCode, szErrMsg);
}
#endif
}
else
{
@@ -775,40 +720,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 +799,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 +868,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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -27,14 +27,12 @@
#ifndef CONNECTION_H
#define CONNECTION_H
#include "NetAddress.h"
#ifndef HAVE_GETADDRINFO
#ifndef HAVE_GETHOSTBYNAME_R
#include "Thread.h"
#endif
#endif
#ifndef DISABLE_TLS
#include "TLS.h"
#endif
class Connection
{
@@ -46,22 +44,20 @@ public:
csListening,
csCancelled
};
protected:
char* m_szHost;
int m_iPort;
NetAddress* m_pNetAddress;
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 +66,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,39 +77,36 @@ 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();
#endif
public:
Connection(const char* szHost, int iPort, bool bTLS);
Connection(NetAddress* pNetAddress);
Connection(SOCKET iSocket, bool bAutoClose);
virtual ~Connection();
static void Init();
static void Init(bool bTLS);
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);
NetAddress* GetServer() { return m_pNetAddress; }
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

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -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, 12);
// save nzb-infos
SaveNZBList(pDownloadQueue, outfile);
@@ -93,9 +93,6 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
// save post-queue
SavePostQueue(pDownloadQueue, outfile);
// save url-queue
SaveUrlQueue(pDownloadQueue, outfile);
// save history
SaveHistory(pDownloadQueue, outfile);
@@ -105,7 +102,6 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
fclose(outfile);
if (pDownloadQueue->GetFileQueue()->empty() &&
pDownloadQueue->GetUrlQueue()->empty() &&
pDownloadQueue->GetPostQueue()->empty() &&
pDownloadQueue->GetHistoryList()->empty())
{
@@ -136,7 +132,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 > 12)
{
error("Could not load diskstate due to file version mismatch");
fclose(infile);
@@ -152,7 +148,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())
{
@@ -160,16 +156,10 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
LoadOldPostQueue(pDownloadQueue);
}
if (iFormatVersion >= 15)
{
// load url-queue
if (!LoadUrlQueue(pDownloadQueue, infile, iFormatVersion)) goto error;
}
if (iFormatVersion >= 9)
{
// load history
if (!LoadHistory(pDownloadQueue, infile, iFormatVersion)) goto error;
if (!LoadHistory(pDownloadQueue, infile)) goto error;
// load parked file-infos
if (!LoadFileQueue(pDownloadQueue, pDownloadQueue->GetParkedFiles(), infile, iFormatVersion)) goto error;
@@ -201,11 +191,10 @@ void DiskState::SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile)
fprintf(outfile, "%s\n", pNZBInfo->GetFilename());
fprintf(outfile, "%s\n", pNZBInfo->GetDestDir());
fprintf(outfile, "%s\n", pNZBInfo->GetQueuedFilename());
fprintf(outfile, "%s\n", pNZBInfo->GetName());
fprintf(outfile, "%s\n", pNZBInfo->GetCategory());
fprintf(outfile, "%i\n", (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());
@@ -280,16 +269,6 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
pNZBInfo->SetQueuedFilename(buf);
}
if (iFormatVersion >= 13)
{
if (!fgets(buf, sizeof(buf), infile)) goto error;
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
if (strlen(buf) > 0)
{
pNZBInfo->SetName(buf);
}
}
if (iFormatVersion >= 4)
{
if (!fgets(buf, sizeof(buf), infile)) goto error;
@@ -298,52 +277,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 +388,7 @@ 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\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused(), (int)pFileInfo->GetTime());
}
}
}
@@ -452,26 +401,17 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
if (fscanf(infile, "%i\n", &size) != 1) goto error;
for (int i = 0; i < size; i++)
{
unsigned int id, iNZBIndex, paused;
unsigned int iTime = 0;
int iPriority = 0, iExtraPriority = 0;
if (iFormatVersion >= 17)
{
if (fscanf(infile, "%i,%i,%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime, &iPriority, &iExtraPriority) != 6) goto error;
}
else if (iFormatVersion >= 14)
{
if (fscanf(infile, "%i,%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime, &iPriority) != 5) goto error;
}
else if (iFormatVersion >= 12)
unsigned int id, iNZBIndex, paused, iTime;
if (iFormatVersion >= 12)
{
if (fscanf(infile, "%i,%i,%i,%i\n", &id, &iNZBIndex, &paused, &iTime) != 4) goto error;
}
else
{
if (fscanf(infile, "%i,%i,%i\n", &id, &iNZBIndex, &paused) != 3) goto error;
iTime = 0;
}
if (iNZBIndex > pDownloadQueue->GetNZBInfoList()->size()) goto error;
if (iNZBIndex < 0 || iNZBIndex > pDownloadQueue->GetNZBInfoList()->size()) goto error;
char fileName[1024];
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
@@ -483,8 +423,6 @@ bool DiskState::LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQue
pFileInfo->SetID(id);
pFileInfo->SetPaused(paused);
pFileInfo->SetTime(iTime);
pFileInfo->SetPriority(iPriority);
pFileInfo->SetExtraPriority(iExtraPriority != 0);
pFileInfo->SetNZBInfo(pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1));
pFileQueue->push_back(pFileInfo);
}
@@ -632,14 +570,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 +590,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 +743,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)
{
@@ -868,94 +792,6 @@ error:
return false;
}
void DiskState::SaveUrlQueue(DownloadQueue* pDownloadQueue, FILE* outfile)
{
debug("Saving url-queue to disk");
fprintf(outfile, "%i\n", pDownloadQueue->GetUrlQueue()->size());
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
{
UrlInfo* pUrlInfo = *it;
SaveUrlInfo(pUrlInfo, outfile);
}
}
bool DiskState::LoadUrlQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
{
debug("Loading url-queue from disk");
bool bSkipUrlQueue = !g_pOptions->GetReloadUrlQueue();
int size;
// load url-infos
if (fscanf(infile, "%i\n", &size) != 1) goto error;
for (int i = 0; i < size; i++)
{
UrlInfo* pUrlInfo = NULL;
if (!bSkipUrlQueue)
{
pUrlInfo = new UrlInfo();
}
if (!LoadUrlInfo(pUrlInfo, infile, iFormatVersion)) goto error;
if (!bSkipUrlQueue)
{
pDownloadQueue->GetUrlQueue()->push_back(pUrlInfo);
}
}
return true;
error:
error("Error reading diskstate for url-queue");
return false;
}
void DiskState::SaveUrlInfo(UrlInfo* pUrlInfo, FILE* outfile)
{
fprintf(outfile, "%i,%i\n", (int)pUrlInfo->GetStatus(), pUrlInfo->GetPriority());
fprintf(outfile, "%i,%i\n", (int)pUrlInfo->GetAddTop(), pUrlInfo->GetAddPaused());
fprintf(outfile, "%s\n", pUrlInfo->GetURL());
fprintf(outfile, "%s\n", pUrlInfo->GetNZBFilename());
fprintf(outfile, "%s\n", pUrlInfo->GetCategory());
}
bool DiskState::LoadUrlInfo(UrlInfo* pUrlInfo, FILE* infile, int iFormatVersion)
{
char buf[10240];
int iStatus, iPriority;
if (fscanf(infile, "%i,%i\n", &iStatus, &iPriority) != 2) goto error;
if (pUrlInfo) pUrlInfo->SetStatus((UrlInfo::EStatus)iStatus);
if (pUrlInfo) pUrlInfo->SetPriority(iPriority);
if (iFormatVersion >= 16)
{
int iAddTop, iAddPaused;
if (fscanf(infile, "%i,%i\n", &iAddTop, &iAddPaused) != 2) goto error;
if (pUrlInfo) pUrlInfo->SetAddTop(iAddTop);
if (pUrlInfo) pUrlInfo->SetAddPaused(iAddPaused);
}
if (!fgets(buf, sizeof(buf), infile)) goto error;
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
if (pUrlInfo) pUrlInfo->SetURL(buf);
if (!fgets(buf, sizeof(buf), infile)) goto error;
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
if (pUrlInfo) pUrlInfo->SetNZBFilename(buf);
if (!fgets(buf, sizeof(buf), infile)) goto error;
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
if (pUrlInfo) pUrlInfo->SetCategory(buf);
return true;
error:
return false;
}
void DiskState::SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile)
{
debug("Saving history to disk");
@@ -963,25 +799,14 @@ void DiskState::SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile)
fprintf(outfile, "%i\n", pDownloadQueue->GetHistoryList()->size());
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
fprintf(outfile, "%i\n", (int)pHistoryInfo->GetKind());
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
{
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pHistoryInfo->GetNZBInfo());
fprintf(outfile, "%i\n", iNZBIndex);
}
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
{
SaveUrlInfo(pHistoryInfo->GetUrlInfo(), outfile);
}
fprintf(outfile, "%i\n", (int)pHistoryInfo->GetTime());
NZBInfo* pNZBInfo = *it;
int iNZBIndex = FindNZBInfoIndex(pDownloadQueue, pNZBInfo);
fprintf(outfile, "%i\n", iNZBIndex);
fprintf(outfile, "%i\n", (int)pNZBInfo->GetHistoryTime());
}
}
bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile)
{
debug("Loading history from disk");
@@ -989,41 +814,23 @@ bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
if (fscanf(infile, "%i\n", &size) != 1) goto error;
for (int i = 0; i < size; i++)
{
HistoryInfo* pHistoryInfo = NULL;
HistoryInfo::EKind eKind = HistoryInfo::hkNZBInfo;
unsigned int iNZBIndex;
if (fscanf(infile, "%i\n", &iNZBIndex) != 1) goto error;
if (iFormatVersion >= 15)
{
int iKind = 0;
if (fscanf(infile, "%i\n", &iKind) != 1) goto error;
eKind = (HistoryInfo::EKind)iKind;
}
if (eKind == HistoryInfo::hkNZBInfo)
{
unsigned int iNZBIndex;
if (fscanf(infile, "%i\n", &iNZBIndex) != 1) goto error;
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1);
pHistoryInfo = new HistoryInfo(pNZBInfo);
}
else if (eKind == HistoryInfo::hkUrlInfo)
{
UrlInfo* pUrlInfo = new UrlInfo();
if (!LoadUrlInfo(pUrlInfo, infile, iFormatVersion)) goto error;
pHistoryInfo = new HistoryInfo(pUrlInfo);
}
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(iNZBIndex - 1);
int iTime;
if (fscanf(infile, "%i\n", &iTime) != 1) goto error;
pHistoryInfo->SetTime((time_t)iTime);
pNZBInfo->SetHistoryTime((time_t)iTime);
pDownloadQueue->GetHistoryList()->push_back(pHistoryInfo);
pNZBInfo->AddReference();
pDownloadQueue->GetHistoryList()->push_back(pNZBInfo);
}
return true;
error:
error("Error reading diskstate for history");
error("Error reading diskstate for post-processor queue");
return false;
}
@@ -1066,7 +873,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 <= 12)
{
// skip nzb-infos
int size = 0;
@@ -1080,31 +887,19 @@ bool DiskState::DiscardDownloadQueue()
{
if (!fgets(buf, sizeof(buf), infile)) break; // localfile
}
if (iFormatVersion >= 13)
{
if (!fgets(buf, sizeof(buf), infile)) break; // name
}
if (iFormatVersion >= 4)
{
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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -39,14 +39,10 @@ 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);
void SaveUrlInfo(UrlInfo* pUrlInfo, FILE* outfile);
bool LoadUrlInfo(UrlInfo* pUrlInfo, FILE* infile, int iFormatVersion);
void SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile);
bool LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
bool LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile);
int FindNZBInfoIndex(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
public:

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -36,7 +36,6 @@
#include <string.h>
#include <cctype>
#include <cstdio>
#include <map>
#include <sys/stat.h>
#include "nzbget.h"
@@ -50,8 +49,6 @@ extern Options* g_pOptions;
int FileInfo::m_iIDGen = 0;
int NZBInfo::m_iIDGen = 0;
int PostInfo::m_iIDGen = 0;
int UrlInfo::m_iIDGen = 0;
int HistoryInfo::m_iIDGen = 0;
NZBParameter::NZBParameter(const char* szName)
{
@@ -124,22 +121,18 @@ NZBInfo::NZBInfo()
m_szFilename = NULL;
m_szDestDir = NULL;
m_szCategory = strdup("");
m_szName = NULL;
m_iFileCount = 0;
m_iParkedFileCount = 0;
m_lSize = 0;
m_iRefCount = 0;
m_bPostProcess = false;
m_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_tHistoryTime = 0;
m_Owner = NULL;
m_Messages.clear();
m_iIDMessageGen = 0;
@@ -163,10 +156,6 @@ NZBInfo::~NZBInfo()
{
free(m_szCategory);
}
if (m_szName)
{
free(m_szName);
}
if (m_szQueuedFilename)
{
free(m_szQueuedFilename);
@@ -231,23 +220,6 @@ void NZBInfo::SetFilename(const char * szFilename)
free(m_szFilename);
}
m_szFilename = strdup(szFilename);
if (!m_szName)
{
char szNZBNicename[1024];
MakeNiceNZBName(m_szFilename, szNZBNicename, sizeof(szNZBNicename), true);
szNZBNicename[1024-1] = '\0';
SetName(szNZBNicename);
}
}
void NZBInfo::SetName(const char* szName)
{
if (m_szName)
{
free(m_szName);
}
m_szName = szName ? strdup(szName) : NULL;
}
void NZBInfo::SetCategory(const char* szCategory)
@@ -268,81 +240,96 @@ void NZBInfo::SetQueuedFilename(const char * szQueuedFilename)
m_szQueuedFilename = strdup(szQueuedFilename);
}
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize, bool bRemoveExt)
void NZBInfo::GetNiceNZBName(char* szBuffer, int iSize)
{
MakeNiceNZBName(m_szFilename, szBuffer, iSize);
}
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize)
{
char postname[1024];
const char* szBaseName = Util::BaseFileName(szNZBFilename);
strncpy(postname, szBaseName, 1024);
postname[1024-1] = '\0';
if (bRemoveExt)
// if .nzb file has a certain structure, try to strip out certain elements
if (sscanf(szBaseName, "msgid_%*d_%1023s", postname) == 1)
{
// wipe out ".nzb"
char* p = strrchr(postname, '.');
if (p && !strcasecmp(p, ".nzb")) *p = '\0';
// OK, using stripped name
}
else
{
// using complete filename
strncpy(postname, szBaseName, 1024);
postname[1024-1] = '\0';
}
// wipe out ".nzb"
if (char* p = strrchr(postname, '.')) *p = '\0';
Util::MakeValidFilename(postname, '_', false);
// if the resulting name is empty, use basename without cleaning up "msgid_"
if (strlen(postname) == 0)
{
// using complete filename
strncpy(postname, szBaseName, 1024);
postname[1024-1] = '\0';
// wipe out ".nzb"
if (char* p = strrchr(postname, '.')) *p = '\0';
Util::MakeValidFilename(postname, '_', false);
// if the resulting name is STILL empty, use "noname"
if (strlen(postname) == 0)
{
strncpy(postname, "noname", 1024);
}
}
strncpy(szBuffer, postname, iSize);
szBuffer[iSize-1] = '\0';
}
void NZBInfo::BuildDestDirName()
{
char 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());
char szNiceNZBName[1024];
GetNiceNZBName(szNiceNZBName, 1024);
if (g_pOptions->GetAppendCategoryDir() && bHasCategory)
{
snprintf(szBuffer, 1024, "%s%s%c%s", g_pOptions->GetDestDir(), szCategory, PATH_SEPARATOR, szNiceNZBName);
}
else
{
snprintf(szBuffer, 1024, "%s%s", g_pOptions->GetDestDir(), szNiceNZBName);
}
szBuffer[1024-1] = '\0';
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 +355,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 +447,6 @@ FileInfo::FileInfo()
m_Groups.clear();
m_szSubject = NULL;
m_szFilename = NULL;
m_szOutputFilename = NULL;
m_bFilenameConfirmed = false;
m_lSize = 0;
m_lRemainingSize = 0;
@@ -469,9 +456,6 @@ FileInfo::FileInfo()
m_iCompleted = 0;
m_bOutputInitialized = false;
m_pNZBInfo = NULL;
m_iPriority = 0;
m_bExtraPriority = false;
m_iActiveDownloads = 0;
m_iIDGen++;
m_iID = m_iIDGen;
}
@@ -488,10 +472,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 +544,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];
@@ -603,9 +574,6 @@ GroupInfo::GroupInfo()
m_iRemainingParCount = 0;
m_tMinTime = 0;
m_tMaxTime = 0;
m_iMinPriority = 0;
m_iMaxPriority = 0;
m_iActiveDownloads = 0;
}
GroupInfo::~GroupInfo()
@@ -625,11 +593,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 +603,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 +681,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())
@@ -730,12 +697,19 @@ void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
{
std::map<int, GroupInfo*> groupMap;
for (FileQueue::iterator it = GetFileQueue()->begin(); it != GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
GroupInfo *&pGroupInfo = groupMap[pFileInfo->GetNZBInfo()->GetID()];
GroupInfo* pGroupInfo = NULL;
for (GroupQueue::iterator itg = pGroupQueue->begin(); itg != pGroupQueue->end(); itg++)
{
GroupInfo* pGroupInfo1 = *itg;
if (pGroupInfo1->GetNZBInfo() == pFileInfo->GetNZBInfo())
{
pGroupInfo = pGroupInfo1;
break;
}
}
if (!pGroupInfo)
{
pGroupInfo = new GroupInfo();
@@ -745,8 +719,6 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
pGroupInfo->m_iLastID = pFileInfo->GetID();
pGroupInfo->m_tMinTime = pFileInfo->GetTime();
pGroupInfo->m_tMaxTime = pFileInfo->GetTime();
pGroupInfo->m_iMinPriority = pFileInfo->GetPriority();
pGroupInfo->m_iMaxPriority = pFileInfo->GetPriority();
pGroupQueue->push_back(pGroupInfo);
}
if (pFileInfo->GetID() < pGroupInfo->GetFirstID())
@@ -768,16 +740,6 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
pGroupInfo->m_tMaxTime = pFileInfo->GetTime();
}
}
if (pFileInfo->GetPriority() < pGroupInfo->GetMinPriority())
{
pGroupInfo->m_iMinPriority = pFileInfo->GetPriority();
}
if (pFileInfo->GetPriority() > pGroupInfo->GetMaxPriority())
{
pGroupInfo->m_iMaxPriority = pFileInfo->GetPriority();
}
pGroupInfo->m_iActiveDownloads += pFileInfo->GetActiveDownloads();
pGroupInfo->m_iRemainingFileCount++;
pGroupInfo->m_lRemainingSize += pFileInfo->GetRemainingSize();
if (pFileInfo->GetPaused())
@@ -796,151 +758,3 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
}
}
}
UrlInfo::UrlInfo()
{
//debug("Creating ArticleInfo");
m_szURL = NULL;
m_szNZBFilename = strdup("");
m_szCategory = strdup("");
m_iPriority = 0;
m_bAddTop = false;
m_bAddPaused = false;
m_eStatus = aiUndefined;
m_iIDGen++;
m_iID = m_iIDGen;
}
UrlInfo::~ UrlInfo()
{
if (m_szURL)
{
free(m_szURL);
}
if (m_szNZBFilename)
{
free(m_szNZBFilename);
}
if (m_szCategory)
{
free(m_szCategory);
}
}
void UrlInfo::SetURL(const char* szURL)
{
if (m_szURL)
{
free(m_szURL);
}
m_szURL = strdup(szURL);
}
void UrlInfo::SetID(int s)
{
m_iID = s;
if (m_iIDGen < m_iID)
{
m_iIDGen = m_iID;
}
}
void UrlInfo::SetNZBFilename(const char* szNZBFilename)
{
if (m_szNZBFilename)
{
free(m_szNZBFilename);
}
m_szNZBFilename = strdup(szNZBFilename);
}
void UrlInfo::SetCategory(const char* szCategory)
{
if (m_szCategory)
{
free(m_szCategory);
}
m_szCategory = strdup(szCategory);
}
void UrlInfo::GetName(char* szBuffer, int iSize)
{
MakeNiceName(m_szURL, m_szNZBFilename, szBuffer, iSize);
}
void UrlInfo::MakeNiceName(const char* szURL, const char* szNZBFilename, char* szBuffer, int iSize)
{
URL url(szURL);
if (strlen(szNZBFilename) > 0)
{
char szNZBNicename[1024];
NZBInfo::MakeNiceNZBName(szNZBFilename, szNZBNicename, sizeof(szNZBNicename), true);
snprintf(szBuffer, iSize, "%s @ %s", szNZBNicename, url.GetHost());
}
else
{
snprintf(szBuffer, iSize, "%s%s", url.GetHost(), url.GetResource());
}
szBuffer[iSize-1] = '\0';
}
HistoryInfo::HistoryInfo(NZBInfo* pNZBInfo)
{
m_eKind = hkNZBInfo;
m_pInfo = pNZBInfo;
pNZBInfo->AddReference();
m_tTime = 0;
m_iIDGen++;
m_iID = m_iIDGen;
}
HistoryInfo::HistoryInfo(UrlInfo* pUrlInfo)
{
m_eKind = hkUrlInfo;
m_pInfo = pUrlInfo;
m_tTime = 0;
m_iIDGen++;
m_iID = m_iIDGen;
}
HistoryInfo::~HistoryInfo()
{
if (m_eKind == hkNZBInfo && m_pInfo)
{
((NZBInfo*)m_pInfo)->Release();
}
else if (m_eKind == hkUrlInfo && m_pInfo)
{
delete (UrlInfo*)m_pInfo;
}
}
void HistoryInfo::SetID(int s)
{
m_iID = s;
if (m_iIDGen < m_iID)
{
m_iIDGen = m_iID;
}
}
void HistoryInfo::GetName(char* szBuffer, int iSize)
{
if (m_eKind == hkNZBInfo)
{
strncpy(szBuffer, GetNZBInfo()->GetName(), iSize);
szBuffer[iSize-1] = '\0';
}
else if (m_eKind == hkUrlInfo)
{
GetUrlInfo()->GetName(szBuffer, iSize);
}
else
{
strncpy(szBuffer, "<unknown>", iSize);
}
}

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -91,11 +91,7 @@ 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,17 +126,9 @@ 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; }
};
typedef std::deque<FileInfo*> FileQueue;
@@ -158,9 +146,6 @@ private:
int m_iRemainingParCount;
time_t m_tMinTime;
time_t m_tMaxTime;
int m_iMinPriority;
int m_iMaxPriority;
int m_iActiveDownloads;
friend class DownloadQueue;
@@ -177,9 +162,6 @@ public:
int GetRemainingParCount() { return m_iRemainingParCount; }
time_t GetMinTime() { return m_tMinTime; }
time_t GetMaxTime() { return m_tMaxTime; }
int GetMinPriority() { return m_iMinPriority; }
int GetMaxPriority() { return m_iMaxPriority; }
int GetActiveDownloads() { return m_iActiveDownloads; }
};
typedef std::deque<GroupInfo*> GroupQueue;
@@ -214,29 +196,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 +212,6 @@ public:
srSuccess
};
enum EMoveStatus
{
msNone,
msFailure,
msSuccess
};
typedef std::vector<char*> Files;
typedef std::deque<Message*> Messages;
@@ -261,7 +219,6 @@ private:
int m_iID;
int m_iRefCount;
char* m_szFilename;
char* m_szName;
char* m_szDestDir;
char* m_szCategory;
int m_iFileCount;
@@ -269,16 +226,13 @@ 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;
time_t m_tHistoryTime;
NZBInfoList* m_Owner;
NZBParameterList m_ppParameters;
Mutex m_mutexLog;
@@ -297,13 +251,12 @@ public:
int GetID() { return m_iID; }
const char* GetFilename() { return m_szFilename; }
void SetFilename(const char* szFilename);
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize, bool bRemoveExt);
void GetNiceNZBName(char* szBuffer, int iSize);
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize);
const char* GetDestDir() { return m_szDestDir; } // needs locking (for shared objects)
void SetDestDir(const char* szDestDir); // needs locking (for shared objects)
const char* GetCategory() { return m_szCategory; } // needs locking (for shared objects)
void SetCategory(const char* szCategory); // needs locking (for shared objects)
const char* GetName() { return m_szName; } // needs locking (for shared objects)
void SetName(const char* szName); // needs locking (for shared objects)
long long GetSize() { return m_lSize; }
void SetSize(long long lSize) { m_lSize = lSize; }
int GetFileCount() { return m_iFileCount; }
@@ -311,19 +264,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 +280,8 @@ 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; }
time_t GetHistoryTime() { return m_tHistoryTime; }
void SetHistoryTime(time_t tHistoryTime) { m_tHistoryTime = tHistoryTime; }
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 +309,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 +328,6 @@ public:
rpAll
};
enum EUnpackStatus
{
usNone,
usSkipped,
usFailure,
usSuccess
};
enum EScriptStatus
{
srNone,
@@ -419,19 +345,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 +389,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();
};
@@ -488,91 +408,7 @@ typedef std::deque<PostInfo*> PostQueue;
typedef std::vector<int> IDList;
typedef std::vector<char*> NameList;
class UrlInfo
{
public:
enum EStatus
{
aiUndefined,
aiRunning,
aiFinished,
aiFailed,
aiRetry
};
private:
int m_iID;
char* m_szURL;
char* m_szNZBFilename;
char* m_szCategory;
int m_iPriority;
bool m_bAddTop;
bool m_bAddPaused;
EStatus m_eStatus;
static int m_iIDGen;
public:
UrlInfo();
~UrlInfo();
int GetID() { return m_iID; }
void SetID(int s);
const char* GetURL() { return m_szURL; } // needs locking (for shared objects)
void SetURL(const char* szURL); // needs locking (for shared objects)
const char* GetNZBFilename() { return m_szNZBFilename; } // needs locking (for shared objects)
void SetNZBFilename(const char* szNZBFilename); // needs locking (for shared objects)
const char* GetCategory() { return m_szCategory; } // needs locking (for shared objects)
void SetCategory(const char* szCategory); // needs locking (for shared objects)
int GetPriority() { return m_iPriority; }
void SetPriority(int iPriority) { m_iPriority = iPriority; }
bool GetAddTop() { return m_bAddTop; }
void SetAddTop(bool bAddTop) { m_bAddTop = bAddTop; }
bool GetAddPaused() { return m_bAddPaused; }
void SetAddPaused(bool bAddPaused) { m_bAddPaused = bAddPaused; }
void GetName(char* szBuffer, int iSize); // needs locking (for shared objects)
static void MakeNiceName(const char* szURL, const char* szNZBFilename, char* szBuffer, int iSize);
EStatus GetStatus() { return m_eStatus; }
void SetStatus(EStatus Status) { m_eStatus = Status; }
};
typedef std::deque<UrlInfo*> UrlQueue;
class HistoryInfo
{
public:
enum EKind
{
hkUnknown,
hkNZBInfo,
hkUrlInfo
};
private:
int m_iID;
EKind m_eKind;
void* m_pInfo;
time_t m_tTime;
static int m_iIDGen;
public:
HistoryInfo(NZBInfo* pNZBInfo);
HistoryInfo(UrlInfo* pUrlInfo);
~HistoryInfo();
int GetID() { return m_iID; }
void SetID(int s);
EKind GetKind() { return m_eKind; }
NZBInfo* GetNZBInfo() { return (NZBInfo*)m_pInfo; }
UrlInfo* GetUrlInfo() { return (UrlInfo*)m_pInfo; }
void DiscardUrlInfo() { m_pInfo = NULL; }
time_t GetTime() { return m_tTime; }
void SetTime(time_t tTime) { m_tTime = tTime; }
void GetName(char* szBuffer, int iSize); // needs locking (for shared objects)
};
typedef std::deque<HistoryInfo*> HistoryList;
typedef std::deque<NZBInfo*> HistoryList;
class DownloadQueue
{
@@ -582,7 +418,6 @@ protected:
PostQueue m_PostQueue;
HistoryList m_HistoryList;
FileQueue m_ParkedFiles;
UrlQueue m_UrlQueue;
public:
NZBInfoList* GetNZBInfoList() { return &m_NZBInfoList; }
@@ -590,7 +425,6 @@ public:
PostQueue* GetPostQueue() { return &m_PostQueue; }
HistoryList* GetHistoryList() { return &m_HistoryList; }
FileQueue* GetParkedFiles() { return &m_ParkedFiles; }
UrlQueue* GetUrlQueue() { return &m_UrlQueue; }
void BuildGroups(GroupQueue* pGroupQueue);
};

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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;
@@ -87,7 +87,7 @@ bool Frontend::PrepareData()
}
if (!RequestMessages() || ((m_bSummary || m_bFileList) && !RequestFileList()))
{
printf("\nUnable to send request to nzbget-server at %s (port %i) \n", g_pOptions->GetControlIP(), g_pOptions->GetControlPort());
printf("\nUnable to send request to nzbget-server at %s (port %i) \n", g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
Stop();
return false;
}
@@ -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);
}
}
@@ -236,13 +235,14 @@ void Frontend::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest, int
pMessageBase->m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
pMessageBase->m_iType = htonl(iRequest);
pMessageBase->m_iStructSize = htonl(iSize);
strncpy(pMessageBase->m_szPassword, g_pOptions->GetControlPassword(), NZBREQUESTPASSWORDSIZE);
strncpy(pMessageBase->m_szPassword, g_pOptions->GetServerPassword(), NZBREQUESTPASSWORDSIZE);
pMessageBase->m_szPassword[NZBREQUESTPASSWORDSIZE - 1] = '\0';
}
bool Frontend::RequestMessages()
{
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
NetAddress netAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
Connection connection(&netAddress);
bool OK = connection.Connect();
if (!OK)
@@ -262,15 +262,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 +281,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;
@@ -313,7 +313,8 @@ bool Frontend::RequestMessages()
bool Frontend::RequestFileList()
{
Connection connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
NetAddress netAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
Connection connection(&netAddress);
bool OK = connection.Connect();
if (!OK)
@@ -326,15 +327,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 +346,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 +360,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 +392,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()
@@ -409,5 +410,5 @@ bool Frontend::RequestEditQueue(eRemoteEditAction iAction, int iOffset, int iID)
{
RemoteClient client;
client.SetVerbose(false);
return client.RequestServerEditQueue(iAction, iOffset, NULL, &iID, 1, NULL, eRemoteMatchModeID, false);
return client.RequestServerEditQueue(iAction, iOffset, NULL, &iID, 1, false);
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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);

27
Log.cpp
View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -59,7 +59,11 @@ Log::Log()
Log::~Log()
{
Clear();
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
{
delete *it;
}
m_Messages.clear();
if (m_szLogFilename)
{
free(m_szLogFilename);
@@ -311,17 +315,6 @@ Message::~ Message()
}
}
void Log::Clear()
{
m_mutexLog.Lock();
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
{
delete *it;
}
m_Messages.clear();
m_mutexLog.Unlock();
}
void Log::AppendMessage(Message::EKind eKind, const char * szText)
{
Message* pMessage = new Message(++m_iIDGen, eKind, time(NULL), szText);
@@ -358,10 +351,9 @@ void Log::ResetLog()
* During intializing stage (when options were not read yet) all messages
* are saved in screen log, even if they shouldn't (according to options).
* Method "InitOptions()" check all messages added to screen log during
* intializing stage and does three things:
* intializing stage and does two things:
* 1) save the messages to log-file (if they should according to options);
* 2) delete messages from screen log (if they should not be saved in screen log).
* 3) renumerate IDs
*/
void Log::InitOptions()
{
@@ -372,8 +364,6 @@ void Log::InitOptions()
m_szLogFilename = strdup(g_pOptions->GetLogFile());
}
m_iIDGen = 0;
for (unsigned int i = 0; i < m_Messages.size(); )
{
Message* pMessage = m_Messages.at(i);
@@ -409,7 +399,6 @@ void Log::InitOptions()
}
else
{
pMessage->m_iID = ++m_iIDGen;
i++;
}
}

11
Log.h
View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -64,11 +64,9 @@ private:
time_t m_tTime;
char* m_szText;
friend class Log;
public:
Message(unsigned int iID, EKind eKind, time_t tTime, const char* szText);
~Message();
Message(unsigned int iID, EKind eKind, time_t tTime, const char* szText);
~Message();
unsigned int GetID() { return m_iID; }
EKind GetKind() { return m_eKind; }
time_t GetTime() { return m_tTime; }
@@ -110,7 +108,6 @@ public:
~Log();
Messages* LockMessages();
void UnlockMessages();
void Clear();
void ResetLog();
void InitOptions();
};

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

@@ -1,123 +1,23 @@
#
# This file if part of nzbget
#
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
bin_PROGRAMS = nzbget
nzbget_SOURCES = \
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
NZBFile.h 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 \
NZBFile.h NetAddress.cpp NetAddress.h NewsServer.cpp NewsServer.h Observer.cpp \
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h \
PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
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
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h Util.cpp \
Util.h XmlRpc.cpp XmlRpc.h nzbget.cpp nzbget.h
EXTRA_DIST = \
Makefile.cvs nzbgetd nzbget-postprocess.sh \
$(patches_FILES) $(windows_FILES)
patches_FILES = \
EXTRA_DIST = nzbget.conf.example postprocess-example.sh postprocess-example.conf \
win32.h NTService.cpp NTService.h \
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch
windows_FILES = \
win32.h NTService.cpp NTService.h nzbget.sln nzbget.vcproj nzbget-shell.bat
doc_FILES = \
README ChangeLog COPYING
exampleconf_FILES = \
nzbget.conf nzbget-postprocess.conf
webui_FILES = \
webui/index.html webui/index.js webui/downloads.js webui/edit.js webui/fasttable.js \
webui/history.js webui/messages.js webui/status.js webui/style.css webui/upload.js \
webui/util.js webui/config.js \
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
webui/lib/jquery.js webui/lib/jquery.min.js \
webui/img/icons.png webui/img/icons-2x.png \
webui/img/transmit.gif webui/img/transmit-file.gif webui/img/favicon.ico \
webui/img/download-anim-green-2x.png webui/img/download-anim-orange-2x.png \
webui/img/transmit-reload-2x.gif
# Install
sbin_SCRIPTS = nzbgetd
bin_SCRIPTS = nzbget-postprocess.sh
dist_doc_DATA = $(doc_FILES)
exampleconfdir = $(datadir)/nzbget
dist_exampleconf_DATA = $(exampleconf_FILES)
webuiconfdir = $(datadir)/nzbget/webui
dist_webuiconf_DATA = $(exampleconf_FILES)
webuidir = $(datadir)/nzbget
nobase_dist_webui_DATA = $(webui_FILES)
# Note about "sed":
# We need to make some changes in installed files.
# On Linux "sed" has option "-i" for in-place-edit. Unfortunateley the BSD version of "sed"
# has incompatible syntax. To solve the problem we perform in-place-edit in three steps:
# 1) copy the original file to original.temp (delete existing original.temp, if any);
# 2) sed < original.temp > original
# 3) delete original.temp
# These steps ensure that the output file has the same permissions as the original file.
# Configure installed script
install-exec-hook:
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
# Prepare example configuration files
install-data-hook:
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:"nzbget-postprocess.sh":"nzbget-postprocess.sh" (installed into $(bindir)):' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:^WebDir=:WebDir=$(webuidir)/webui:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
rm "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
# Install configuration files into /etc
# (only if they do not exist there to prevent override by update)
install-conf:
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; then \
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
cp "$(DESTDIR)$(sysconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
sed 's:^PostProcess=:PostProcess=$(bindir)/nzbget-postprocess.sh:' < "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
rm "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
fi
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf" ; then \
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
cp "$(DESTDIR)$(exampleconfdir)/nzbget-postprocess.conf" "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf" ; \
fi
uninstall-conf:
rm -f "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf"
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf"
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch \
Makefile.cvs nzbget.kdevelop nzbget.sln nzbget.vcproj \
nzbgetd nzbget-shell.bat
# Determining subversion revision:
# 1) If directory ".svn" exists we take revision from it using program svnversion (part of subversion package)
@@ -156,15 +56,4 @@ svn_version.cpp: FORCE
fi
FORCE:
# Ignore "svn_version.cpp" in distcleancheck
distcleancheck_listfiles = \
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
sh '{}' ';'
clean-bak: rm *~
# Fix premissions
dist-hook:
chmod -x $(distdir)/*.cpp $(distdir)/*.h
find $(distdir)/webui -type f -print -exec chmod -x {} \;

View File

@@ -14,29 +14,6 @@
@SET_MAKE@
#
# This file if part of nzbget
#
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
@@ -59,11 +36,8 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
bin_PROGRAMS = nzbget$(EXEEXT)
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
$(dist_exampleconf_DATA) $(dist_webuiconf_DATA) \
$(nobase_dist_webui_DATA) $(srcdir)/Makefile.am \
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
config.guess config.sub depcomp install-sh missing
@@ -77,10 +51,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" \
"$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuiconfdir)" \
"$(DESTDIR)$(webuidir)"
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
@@ -88,22 +59,16 @@ am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
Decoder.$(OBJEXT) DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
Frontend.$(OBJEXT) Log.$(OBJEXT) LoggableFrontend.$(OBJEXT) \
NCursesFrontend.$(OBJEXT) NNTPConnection.$(OBJEXT) \
NZBFile.$(OBJEXT) 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) \
NZBFile.$(OBJEXT) NetAddress.$(OBJEXT) NewsServer.$(OBJEXT) \
Observer.$(OBJEXT) Options.$(OBJEXT) ParChecker.$(OBJEXT) \
PrePostProcessor.$(OBJEXT) QueueCoordinator.$(OBJEXT) \
QueueEditor.$(OBJEXT) RemoteClient.$(OBJEXT) \
RemoteServer.$(OBJEXT) Scanner.$(OBJEXT) Scheduler.$(OBJEXT) \
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)
Util.$(OBJEXT) XmlRpc.$(OBJEXT) nzbget.$(OBJEXT)
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
nzbget_LDADD = $(LDADD)
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
SCRIPTS = $(bin_SCRIPTS) $(sbin_SCRIPTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -118,18 +83,6 @@ CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(nzbget_SOURCES)
DIST_SOURCES = $(nzbget_SOURCES)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
dist_docDATA_INSTALL = $(INSTALL_DATA)
dist_exampleconfDATA_INSTALL = $(INSTALL_DATA)
dist_webuiconfDATA_INSTALL = $(INSTALL_DATA)
nobase_dist_webuiDATA_INSTALL = $(install_sh_DATA)
DATA = $(dist_doc_DATA) $(dist_exampleconf_DATA) \
$(dist_webuiconf_DATA) $(nobase_dist_webui_DATA)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -142,14 +95,18 @@ am__remove_distdir = \
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
ADDSRCS = @ADDSRCS@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
@@ -227,8 +184,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@
@@ -236,70 +191,26 @@ psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
nzbget_SOURCES = \
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
NZBFile.h 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 \
NZBFile.h NetAddress.cpp NetAddress.h NewsServer.cpp NewsServer.h Observer.cpp \
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h \
PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
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
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h Util.cpp \
Util.h XmlRpc.cpp XmlRpc.h nzbget.cpp nzbget.h
EXTRA_DIST = \
Makefile.cvs nzbgetd nzbget-postprocess.sh \
$(patches_FILES) $(windows_FILES)
patches_FILES = \
EXTRA_DIST = nzbget.conf.example postprocess-example.sh postprocess-example.conf \
win32.h NTService.cpp NTService.h \
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch
windows_FILES = \
win32.h NTService.cpp NTService.h nzbget.sln nzbget.vcproj nzbget-shell.bat
doc_FILES = \
README ChangeLog COPYING
exampleconf_FILES = \
nzbget.conf nzbget-postprocess.conf
webui_FILES = \
webui/index.html webui/index.js webui/downloads.js webui/edit.js webui/fasttable.js \
webui/history.js webui/messages.js webui/status.js webui/style.css webui/upload.js \
webui/util.js webui/config.js \
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
webui/lib/jquery.js webui/lib/jquery.min.js \
webui/img/icons.png webui/img/icons-2x.png \
webui/img/transmit.gif webui/img/transmit-file.gif webui/img/favicon.ico \
webui/img/download-anim-green-2x.png webui/img/download-anim-orange-2x.png \
webui/img/transmit-reload-2x.gif
# Install
sbin_SCRIPTS = nzbgetd
bin_SCRIPTS = nzbget-postprocess.sh
dist_doc_DATA = $(doc_FILES)
exampleconfdir = $(datadir)/nzbget
dist_exampleconf_DATA = $(exampleconf_FILES)
webuiconfdir = $(datadir)/nzbget/webui
dist_webuiconf_DATA = $(exampleconf_FILES)
webuidir = $(datadir)/nzbget
nobase_dist_webui_DATA = $(webui_FILES)
# Ignore "svn_version.cpp" in distcleancheck
distcleancheck_listfiles = \
find . -type f -exec sh -c 'test -f $(srcdir)/$$1 || echo $$1' \
sh '{}' ';'
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch \
Makefile.cvs nzbget.kdevelop nzbget.sln nzbget.vcproj \
nzbgetd nzbget-shell.bat
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -382,44 +293,6 @@ clean-binPROGRAMS:
nzbget$(EXEEXT): $(nzbget_OBJECTS) $(nzbget_DEPENDENCIES)
@rm -f nzbget$(EXEEXT)
$(CXXLINK) $(nzbget_LDFLAGS) $(nzbget_OBJECTS) $(nzbget_LDADD) $(LIBS)
install-binSCRIPTS: $(bin_SCRIPTS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
@list='$(bin_SCRIPTS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f $$d$$p; then \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \
else :; fi; \
done
uninstall-binSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(bin_SCRIPTS)'; for p in $$list; do \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
install-sbinSCRIPTS: $(sbin_SCRIPTS)
@$(NORMAL_INSTALL)
test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f $$d$$p; then \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " $(sbinSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
$(sbinSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(sbindir)/$$f"; \
else :; fi; \
done
uninstall-sbinSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(sbin_SCRIPTS)'; for p in $$list; do \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
rm -f "$(DESTDIR)$(sbindir)/$$f"; \
done
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -440,12 +313,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NCursesFrontend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NNTPConnection.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NZBFile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetAddress.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NewsServer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Observer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParChecker.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParRenamer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PrePostProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueEditor.Po@am__quote@
@@ -457,11 +329,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TLS.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Unpack.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UrlCoordinator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebDownloader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebServer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nzbget.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svn_version.Po@am__quote@
@@ -480,76 +348,6 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
uninstall-info-am:
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)"
@list='$(dist_doc_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \
$(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \
done
uninstall-dist_docDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_doc_DATA)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \
rm -f "$(DESTDIR)$(docdir)/$$f"; \
done
install-dist_exampleconfDATA: $(dist_exampleconf_DATA)
@$(NORMAL_INSTALL)
test -z "$(exampleconfdir)" || $(mkdir_p) "$(DESTDIR)$(exampleconfdir)"
@list='$(dist_exampleconf_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(dist_exampleconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(exampleconfdir)/$$f'"; \
$(dist_exampleconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(exampleconfdir)/$$f"; \
done
uninstall-dist_exampleconfDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_exampleconf_DATA)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(exampleconfdir)/$$f'"; \
rm -f "$(DESTDIR)$(exampleconfdir)/$$f"; \
done
install-dist_webuiconfDATA: $(dist_webuiconf_DATA)
@$(NORMAL_INSTALL)
test -z "$(webuiconfdir)" || $(mkdir_p) "$(DESTDIR)$(webuiconfdir)"
@list='$(dist_webuiconf_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(dist_webuiconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(webuiconfdir)/$$f'"; \
$(dist_webuiconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(webuiconfdir)/$$f"; \
done
uninstall-dist_webuiconfDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_webuiconf_DATA)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(webuiconfdir)/$$f'"; \
rm -f "$(DESTDIR)$(webuiconfdir)/$$f"; \
done
install-nobase_dist_webuiDATA: $(nobase_dist_webui_DATA)
@$(NORMAL_INSTALL)
test -z "$(webuidir)" || $(mkdir_p) "$(DESTDIR)$(webuidir)"
@$(am__vpath_adj_setup) \
list='$(nobase_dist_webui_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
$(am__vpath_adj) \
echo " $(nobase_dist_webuiDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(webuidir)/$$f'"; \
$(nobase_dist_webuiDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(webuidir)/$$f"; \
done
uninstall-nobase_dist_webuiDATA:
@$(NORMAL_UNINSTALL)
@$(am__vpath_adj_setup) \
list='$(nobase_dist_webui_DATA)'; for p in $$list; do \
$(am__vpath_adj) \
echo " rm -f '$(DESTDIR)$(webuidir)/$$f'"; \
rm -f "$(DESTDIR)$(webuidir)/$$f"; \
done
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -602,7 +400,6 @@ distclean-tags:
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkdir_p) $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
@@ -629,9 +426,6 @@ distdir: $(DISTFILES)
|| exit 1; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$(top_distdir)" distdir="$(distdir)" \
dist-hook
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
@@ -731,9 +525,9 @@ distcleancheck: distclean
exit 1; } >&2
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) config.h
all-am: Makefile $(PROGRAMS) config.h
installdirs:
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuiconfdir)" "$(DESTDIR)$(webuidir)"; do \
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: install-am
@@ -781,15 +575,9 @@ info: info-am
info-am:
install-data-am: install-dist_docDATA install-dist_exampleconfDATA \
install-dist_webuiconfDATA install-nobase_dist_webuiDATA
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-data-hook
install-data-am:
install-exec-am: install-binPROGRAMS install-binSCRIPTS \
install-sbinSCRIPTS
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
install-exec-am: install-binPROGRAMS
install-info: install-info-am
@@ -816,76 +604,23 @@ ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
uninstall-dist_docDATA uninstall-dist_exampleconfDATA \
uninstall-dist_webuiconfDATA uninstall-info-am \
uninstall-nobase_dist_webuiDATA uninstall-sbinSCRIPTS
uninstall-am: uninstall-binPROGRAMS uninstall-info-am
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
dist-gzip dist-hook dist-shar dist-tarZ dist-zip distcheck \
distclean distclean-compile distclean-generic distclean-hdr \
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
distclean-compile distclean-generic distclean-hdr \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
install-binPROGRAMS install-binSCRIPTS install-data \
install-data-am install-data-hook install-dist_docDATA \
install-dist_exampleconfDATA install-dist_webuiconfDATA \
install-exec install-exec-am install-exec-hook install-info \
install-info-am install-man install-nobase_dist_webuiDATA \
install-sbinSCRIPTS install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
ps ps-am tags uninstall uninstall-am uninstall-binPROGRAMS \
uninstall-binSCRIPTS uninstall-dist_docDATA \
uninstall-dist_exampleconfDATA uninstall-dist_webuiconfDATA \
uninstall-info-am uninstall-nobase_dist_webuiDATA \
uninstall-sbinSCRIPTS
install-binPROGRAMS install-data install-data-am install-exec \
install-exec-am install-info install-info-am install-man \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-binPROGRAMS \
uninstall-info-am
# Note about "sed":
# We need to make some changes in installed files.
# On Linux "sed" has option "-i" for in-place-edit. Unfortunateley the BSD version of "sed"
# has incompatible syntax. To solve the problem we perform in-place-edit in three steps:
# 1) copy the original file to original.temp (delete existing original.temp, if any);
# 2) sed < original.temp > original
# 3) delete original.temp
# These steps ensure that the output file has the same permissions as the original file.
# Configure installed script
install-exec-hook:
rm -f "$(DESTDIR)$(sbindir)/nzbgetd.temp"
cp "$(DESTDIR)$(sbindir)/nzbgetd" "$(DESTDIR)$(sbindir)/nzbgetd.temp"
sed 's?/usr/local/bin?$(bindir)?' < "$(DESTDIR)$(sbindir)/nzbgetd.temp" > "$(DESTDIR)$(sbindir)/nzbgetd"
rm "$(DESTDIR)$(sbindir)/nzbgetd.temp"
# Prepare example configuration files
install-data-hook:
rm -f "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:"nzbget-postprocess.sh":"nzbget-postprocess.sh" (installed into $(bindir)):' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:^WebDir=:WebDir=$(webuidir)/webui:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
rm "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
# Install configuration files into /etc
# (only if they do not exist there to prevent override by update)
install-conf:
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; then \
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
cp "$(DESTDIR)$(exampleconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
cp "$(DESTDIR)$(sysconfdir)/nzbget.conf" "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
sed 's:^PostProcess=:PostProcess=$(bindir)/nzbget-postprocess.sh:' < "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(sysconfdir)/nzbget.conf" ; \
rm "$(DESTDIR)$(sysconfdir)/nzbget.conf.temp" ; \
fi
if test ! -f "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf" ; then \
$(mkinstalldirs) "$(DESTDIR)$(sysconfdir)" ; \
cp "$(DESTDIR)$(exampleconfdir)/nzbget-postprocess.conf" "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf" ; \
fi
uninstall-conf:
rm -f "$(DESTDIR)$(sysconfdir)/nzbget-postprocess.conf"
rm -f "$(DESTDIR)$(sysconfdir)/nzbget.conf"
# Determining subversion revision:
# 1) If directory ".svn" exists we take revision from it using program svnversion (part of subversion package)
# File is recreated only if revision number was changed.
@@ -924,11 +659,6 @@ svn_version.cpp: FORCE
FORCE:
clean-bak: rm *~
# Fix premissions
dist-hook:
chmod -x $(distdir)/*.cpp $(distdir)/*.h
find $(distdir)/webui -type f -print -exec chmod -x {} \;
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

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-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -27,7 +27,7 @@
#ifndef MESSAGEBASE_H
#define MESSAGEBASE_H
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6212; // = "nzb-XX" (protocol version)
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6208; // = "nzb8" (protocol version)
static const int NZBREQUESTFILENAMESIZE = 512;
static const int NZBREQUESTPASSWORDSIZE = 32;
@@ -56,14 +56,11 @@ enum eRemoteRequest
eRemoteRequestEditQueue,
eRemoteRequestLog,
eRemoteRequestShutdown,
eRemoteRequestReload,
eRemoteRequestVersion,
eRemoteRequestPostQueue,
eRemoteRequestWriteLog,
eRemoteRequestScan,
eRemoteRequestHistory,
eRemoteRequestDownloadUrl,
eRemoteRequestUrlQueue
eRemoteRequestHistory
};
// Possible values for field "m_iAction" of struct "SNZBEditQueueRequest":
@@ -79,8 +76,6 @@ enum eRemoteEditAction
eRemoteEditActionFileDelete, // delete files
eRemoteEditActionFilePauseAllPars, // pause only (all) pars (does not affect other files)
eRemoteEditActionFilePauseExtraPars, // pause only (almost all) pars, except main par-file (does not affect other files)
eRemoteEditActionFileSetPriority, // set priority for files
eRemoteEditActionFileReorder, // (not supported)
eRemoteEditActionGroupMoveOffset, // move group to m_iOffset relative to the current position in download-queue
eRemoteEditActionGroupMoveTop, // move group to the top of download-queue
eRemoteEditActionGroupMoveBottom, // move group to the bottom of download-queue
@@ -89,11 +84,9 @@ enum eRemoteEditAction
eRemoteEditActionGroupDelete, // delete group
eRemoteEditActionGroupPauseAllPars, // pause only (all) pars (does not affect other files) in group
eRemoteEditActionGroupPauseExtraPars, // pause only (almost all) pars in group, except main par-file (does not affect other files)
eRemoteEditActionGroupSetPriority, // set priority for groups
eRemoteEditActionGroupSetCategory, // set or change category for a group
eRemoteEditActionGroupMerge, // merge group
eRemoteEditActionGroupSetParameter, // set post-process parameter for group
eRemoteEditActionGroupSetName, // set group name (rename group)
eRemoteEditActionPostMoveOffset = 51, // move post-job to m_iOffset relative to the current position in post-queue
eRemoteEditActionPostMoveTop, // move post-job to the top of post-queue
eRemoteEditActionPostMoveBottom, // move post-job to the bottom of post-queue
@@ -112,14 +105,6 @@ enum eRemotePauseUnpauseAction
eRemotePauseUnpauseActionScan // pause/unpause scan of incoming nzb-directory
};
// Possible values for field "m_iMatchMode" of struct "SNZBEditQueueRequest":
enum eRemoteMatchMode
{
eRemoteMatchModeID = 1, // ID
eRemoteMatchModeName, // Name
eRemoteMatchModeRegEx, // RegEx
};
// The basic SNZBRequestBase struct, used in all requests
struct SNZBRequestBase
{
@@ -141,10 +126,8 @@ struct SNZBDownloadRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
char m_szFilename[NZBREQUESTFILENAMESIZE]; // Name of nzb-file, may contain full path (local path on client) or only filename
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, be empty
int32_t m_bAddFirst; // 1 - add file to the top of download queue
int32_t m_bAddPaused; // 1 - pause added files
int32_t m_iPriority; // Priority for files (0 - default)
int32_t m_iTrailingDataLength; // Length of nzb-file in bytes
//char m_szContent[m_iTrailingDataLength]; // variable sized
};
@@ -164,9 +147,6 @@ struct SNZBListRequest
SNZBRequestBase m_MessageBase; // Must be the first in the struct
int32_t m_bFileList; // 1 - return file list
int32_t m_bServerState; // 1 - return server state
int32_t m_iMatchMode; // File/Group match mode, see enum eRemoteMatchMode (only values eRemoteMatchModeID (no filter) and eRemoteMatchModeRegEx are allowed)
int32_t m_bMatchGroup; // 0 - match files; 1 - match nzbs (when m_iMatchMode == eRemoteMatchModeRegEx)
char m_szPattern[NZBREQUESTFILENAMESIZE]; // RegEx Pattern (when m_iMatchMode == eRemoteMatchModeRegEx)
};
// A list response
@@ -189,7 +169,6 @@ struct SNZBListResponse
int32_t m_iDownloadTimeSec; // Server download time in seconds (up_time - standby_time)
int32_t m_iDownloadedBytesLo; // Amount of data downloaded since server start, Low 32-bits of 64-bit value
int32_t m_iDownloadedBytesHi; // Amount of data downloaded since server start, High 32-bits of 64-bit value
int32_t m_bRegExValid; // 0 - error in RegEx-pattern, 1 - RegEx-pattern is valid (only when Request has eRemoteMatchModeRegEx)
int32_t m_iNrTrailingNZBEntries; // Number of List-NZB-entries, following to this structure
int32_t m_iNrTrailingPPPEntries; // Number of List-PPP-entries, following to this structure
int32_t m_iNrTrailingFileEntries; // Number of List-File-entries, following to this structure
@@ -204,14 +183,11 @@ struct SNZBListResponseNZBEntry
{
int32_t m_iSizeLo; // Size of all files in bytes, Low 32-bits of 64-bit value
int32_t m_iSizeHi; // Size of all files in bytes, High 32-bits of 64-bit value
int32_t m_bMatch; // 1 - group matches the pattern (only when Request has eRemoteMatchModeRegEx)
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
int32_t m_iNameLen; // Length of Name-string (m_szName), following to this record
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
int32_t m_iCategoryLen; // Length of Category-string (m_szCategory), following to this record
int32_t m_iQueuedFilenameLen; // Length of queued file name (m_szQueuedFilename), following to this record
//char m_szFilename[m_iFilenameLen]; // variable sized
//char m_szName[m_iNameLen]; // variable sized
//char m_szDestDir[m_iDestDirLen]; // variable sized
//char m_szCategory[m_iCategoryLen]; // variable sized
//char m_szQueuedFilename[m_iQueuedFilenameLen]; // variable sized
@@ -238,9 +214,6 @@ struct SNZBListResponseFileEntry
int32_t m_iRemainingSizeHi; // Remaining size in bytes, High 32-bits of 64-bit value
int32_t m_bPaused; // 1 - file is paused
int32_t m_bFilenameConfirmed; // 1 - Filename confirmed (read from article body), 0 - Filename parsed from subject (can be changed after reading of article)
int32_t m_iPriority; // Download priority
int32_t m_iActiveDownloads; // Number of active downloads for this file
int32_t m_bMatch; // 1 - file matches the pattern (only when Request has eRemoteMatchModeRegEx)
int32_t m_iSubjectLen; // Length of Subject-string (m_szSubject), following to this record
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
//char m_szSubject[m_iSubjectLen]; // variable sized
@@ -308,7 +281,7 @@ struct SNZBSetDownloadRateResponse
//char m_szText[m_iTrailingDataLength]; // variable sized
};
// edit queue request
// An edit queue request
struct SNZBEditQueueRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
@@ -316,15 +289,11 @@ struct SNZBEditQueueRequest
int32_t m_iOffset; // Offset to move (for m_iAction = 0)
int32_t m_bSmartOrder; // For Move-Actions: 0 - execute action for each ID in order they are placed in array;
// 1 - smart execute to ensure that the relative order of all affected IDs are not changed.
int32_t m_iMatchMode; // File/Group match mode, see enum eRemoteMatchMode
int32_t m_iNrTrailingIDEntries; // Number of ID-entries, following to this structure
int32_t m_iNrTrailingNameEntries; // Number of Name-entries, following to this structure
int32_t m_iTrailingNameEntriesLen; // Length of all Name-entries, following to this structure
int32_t m_iTextLen; // Length of Text-string (m_szText), following to this record
int32_t m_iTrailingDataLength; // Length of Text-string and all ID-entries, following to this structure
//char m_szText[m_iTextLen]; // variable sized
//int32_t m_iIDs[m_iNrTrailingIDEntries]; // variable sized array of IDs. For File-Actions - ID of file, for Group-Actions - ID of any file belonging to group
//char* m_szNames[m_iNrTrailingNameEntries]; // variable sized array of strings. For File-Actions - name of file incl. nzb-name as path, for Group-Actions - name of group
int32_t m_iNrTrailingEntries; // Number of ID-entries, following to this structure
int32_t m_iTextLen; // Length of Text-string (m_szText), following to this record
int32_t m_iTrailingDataLength; // Length of Text-string and all ID-entries, following to this structure
//char m_szText[m_iTextLen]; // variable sized
//int32_t m_iIDs[m_iNrTrailingEntries]; // variable sized array of IDs. For File-Actions - ID of file, for Group-Actions - ID of any file belonging to group
};
// An edit queue response
@@ -366,21 +335,6 @@ struct SNZBShutdownResponse
//char m_szText[m_iTrailingDataLength]; // variable sized
};
// Reload server request
struct SNZBReloadRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
};
// Reload server response
struct SNZBReloadResponse
{
SNZBResponseBase m_MessageBase; // Must be the first in the struct
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
//char m_szText[m_iTrailingDataLength]; // variable sized
};
// Server version request
struct SNZBVersionRequest
{
@@ -455,7 +409,6 @@ struct SNZBWriteLogResponse
struct SNZBScanRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
int32_t m_bSyncMode; // 0 - asynchronous Scan (the command returns immediately), 1 - synchronous Scan (the command returns when the scan is completed)
};
// Scan nzb directory response
@@ -473,80 +426,34 @@ struct SNZBHistoryRequest
SNZBRequestBase m_MessageBase; // Must be the first in the struct
};
// history response
// A history response
struct SNZBHistoryResponse
{
SNZBResponseBase m_MessageBase; // Must be the first in the struct
int32_t m_iEntrySize; // Size of the SNZBHistoryResponseEntry-struct
int32_t m_iNrTrailingEntries; // Number of History-entries, following to this structure
int32_t m_iTrailingDataLength; // Length of all History-entries, following to this structure
// SNZBHistoryResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
// SNZBHistoryResponseEntry m_NZBEntries[m_iNrTrailingNZBEntries] // variable sized
};
// history entry
// A list response nzb entry
struct SNZBHistoryResponseEntry
{
int32_t m_iID; // History-ID
int32_t m_iKind; // Kind of Item: 1 - Collection (NZB), 2 - URL
int32_t m_iID; // NZBID
int32_t m_tTime; // When the item was added to history. time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
int32_t m_iNicenameLen; // Length of Nicename-string (m_szNicename), following to this record
// for Collection items (m_iKind = 1)
int32_t m_iSizeLo; // Size of all files in bytes, Low 32-bits of 64-bit value
int32_t m_iSizeHi; // Size of all files in bytes, High 32-bits of 64-bit value
int32_t m_iFileCount; // Initial number of files included in NZB-file
int32_t m_iParStatus; // See NZBInfo::EParStatus
int32_t m_iScriptStatus; // See NZBInfo::EScriptStatus
// for URL items (m_iKind = 2)
int32_t m_iUrlStatus; // See UrlInfo::EStatus
// trailing data
//char m_szNicename[m_iNicenameLen]; // variable sized
};
// download url request
struct SNZBDownloadUrlRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
char m_szURL[NZBREQUESTFILENAMESIZE]; // url to nzb-file
char m_szNZBFilename[NZBREQUESTFILENAMESIZE];// Name of nzb-file. Can be empty, then the filename is read from URL download response
char m_szCategory[NZBREQUESTFILENAMESIZE]; // Category, can be empty
int32_t m_bAddFirst; // 1 - add url to the top of download queue
int32_t m_bAddPaused; // 1 - pause added files
int32_t m_iPriority; // Priority for files (0 - default)
};
// download url response
struct SNZBDownloadUrlResponse
{
SNZBResponseBase m_MessageBase; // Must be the first in the struct
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
//char m_szText[m_iTrailingDataLength]; // variable sized
};
// UrlQueue request
struct SNZBUrlQueueRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
};
// UrlQueue response
struct SNZBUrlQueueResponse
{
SNZBResponseBase m_MessageBase; // Must be the first in the struct
int32_t m_iEntrySize; // Size of the SNZBUrlQueueResponseEntry-struct
int32_t m_iNrTrailingEntries; // Number of UrlQueue-entries, following to this structure
int32_t m_iTrailingDataLength; // Length of all UrlQueue-entries, following to this structure
// SNZBUrlQueueResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
};
// UrlQueue response entry
struct SNZBUrlQueueResponseEntry
{
int32_t m_iID; // ID of Url-entry
int32_t m_iURLLen; // Length of URL-string (m_szURL), following to this record
int32_t m_iNZBFilenameLen; // Length of NZBFilename-string (m_szNZBFilename), following to this record
//char m_szURL[m_iURLLen]; // variable sized
//char m_szNZBFilename[m_iNZBFilenameLen]; // variable sized
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
int32_t m_iCategoryLen; // Length of Category-string (m_szCategory), following to this record
int32_t m_iQueuedFilenameLen; // Length of queued file name (m_szQueuedFilename), following to this record
//char m_szFilename[m_iFilenameLen]; // variable sized
//char m_szDestDir[m_iDestDirLen]; // variable sized
//char m_szCategory[m_iCategoryLen]; // variable sized
//char m_szQueuedFilename[m_iQueuedFilenameLen]; // variable sized
};
#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-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -613,10 +613,10 @@ void NCursesFrontend::PrintStatus()
char timeString[100];
timeString[0] = '\0';
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 ?
@@ -819,19 +819,6 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
color = NCURSES_COLORPAIR_TEXT;
}
const char* szDownloading = "";
if (pFileInfo->GetActiveDownloads() > 0)
{
szDownloading = " *";
}
char szPriority[100];
szPriority[0] = '\0';
if (pFileInfo->GetPriority() != 0)
{
sprintf(szPriority, " [%+i]", pFileInfo->GetPriority());
}
char szCompleted[20];
szCompleted[0] = '\0';
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
@@ -842,7 +829,7 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
char szNZBNiceName[1024];
if (m_bShowNZBname)
{
strncpy(szNZBNiceName, pFileInfo->GetNZBInfo()->GetName(), 1023);
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
int len = strlen(szNZBNiceName);
szNZBNiceName[len] = PATH_SEPARATOR;
szNZBNiceName[len + 1] = '\0';
@@ -853,9 +840,8 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
}
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s%s%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(),
Brace2, szPriority, szDownloading, szNZBNiceName, pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(),
Brace2, szNZBNiceName, pFileInfo->GetFilename(), (float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
@@ -926,7 +912,6 @@ void NCursesFrontend::PrintGroupQueue()
{
int iLineNr = m_iQueueWinTop;
LockQueue();
GroupQueue* pGroupQueue = &m_groupQueue;
if (pGroupQueue->empty())
{
@@ -981,7 +966,6 @@ void NCursesFrontend::PrintGroupQueue()
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, m_iQueueWinTop, false);
}
UnlockQueue();
}
void NCursesFrontend::ResetColWidths()
@@ -993,23 +977,21 @@ void NCursesFrontend::ResetColWidths()
void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSelected, bool bCalcColWidth)
{
int color = NCURSES_COLORPAIR_TEXT;
char chBrace1 = '[';
char chBrace2 = ']';
int color = 0;
const char* Brace1 = "[";
const char* Brace2 = "]";
if (m_eInputMode == eEditQueue && bSelected)
{
color = NCURSES_COLORPAIR_TEXTHIGHL;
if (!m_bUseColor)
{
chBrace1 = '<';
chBrace2 = '>';
Brace1 = "<";
Brace2 = ">";
}
}
const char* szDownloading = "";
if (pGroupInfo->GetActiveDownloads() > 0)
else
{
szDownloading = " *";
color = NCURSES_COLORPAIR_TEXT;
}
long long lUnpausedRemainingSize = pGroupInfo->GetRemainingSize() - pGroupInfo->GetPausedSize();
@@ -1017,19 +999,8 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
char szPriority[100];
szPriority[0] = '\0';
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
{
if (pGroupInfo->GetMinPriority() == pGroupInfo->GetMaxPriority())
{
sprintf(szPriority, " [%+i]", pGroupInfo->GetMinPriority());
}
else
{
sprintf(szPriority, " [%+i..%+i]", pGroupInfo->GetMinPriority(), pGroupInfo->GetMaxPriority());
}
}
char szNZBNiceName[1024];
pGroupInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
char szBuffer[MAX_SCREEN_WIDTH];
@@ -1059,21 +1030,20 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
Util::FormatFileSize(szTotal, sizeof(szTotal), pGroupInfo->GetNZBInfo()->GetSize());
char szNameWithIds[1024];
snprintf(szNameWithIds, 1024, "%c%i-%i%c%s%s %s", chBrace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), chBrace2,
szPriority, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
snprintf(szNameWithIds, 1024, "%s%i-%i%s %s", Brace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), Brace2, szNZBNiceName);
szNameWithIds[iNameLen] = '\0';
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);
@@ -1105,8 +1075,7 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
}
else
{
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%c%i-%i%c%s %s", chBrace1, pGroupInfo->GetFirstID(),
pGroupInfo->GetLastID(), chBrace2, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i-%i%s %s", Brace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), Brace2, szNZBNiceName);
}
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
@@ -1448,7 +1417,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

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -44,13 +44,11 @@
static const int CONNECTION_LINEBUFFER_SIZE = 1024*10;
NNTPConnection::NNTPConnection(NewsServer* pNewsServer) : Connection(pNewsServer->GetHost(), pNewsServer->GetPort(), pNewsServer->GetTLS())
NNTPConnection::NNTPConnection(NewsServer* server) : Connection(server)
{
m_pNewsServer = pNewsServer;
m_szActiveGroup = NULL;
m_szLineBuf = (char*)malloc(CONNECTION_LINEBUFFER_SIZE);
m_bAuthError = false;
SetCipher(pNewsServer->GetCipher());
}
NNTPConnection::~NNTPConnection()
@@ -83,7 +81,7 @@ const char* NNTPConnection::Request(const char* req)
if (!strncmp(answer, "480", 3))
{
debug("%s requested authorization", GetHost());
debug("%s requested authorization", m_pNetAddress->GetHost());
//authentication required!
if (!Authenticate())
@@ -103,8 +101,8 @@ const char* NNTPConnection::Request(const char* req)
bool NNTPConnection::Authenticate()
{
if (!(m_pNewsServer)->GetUser() ||
!(m_pNewsServer)->GetPassword())
if (!((NewsServer*)m_pNetAddress)->GetUser() ||
!((NewsServer*)m_pNetAddress)->GetPassword())
{
return true;
}
@@ -120,7 +118,7 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
}
char tmp[1024];
snprintf(tmp, 1024, "AUTHINFO USER %s\r\n", m_pNewsServer->GetUser());
snprintf(tmp, 1024, "AUTHINFO USER %s\r\n", ((NewsServer*)m_pNetAddress)->GetUser());
tmp[1024-1] = '\0';
WriteLine(tmp);
@@ -128,13 +126,13 @@ bool NNTPConnection::AuthInfoUser(int iRecur)
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
if (!answer)
{
ReportError("Authorization for %s failed: Connection closed by remote host", GetHost(), false, 0);
ReportError("Authorization for %s failed: Connection closed by remote host.", m_pNetAddress->GetHost(), true, 0);
return false;
}
if (!strncmp(answer, "281", 3))
{
debug("Authorization for %s successful", GetHost());
debug("Authorization for %s successful", m_pNetAddress->GetHost());
return true;
}
else if (!strncmp(answer, "381", 3))
@@ -163,7 +161,7 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
}
char tmp[1024];
snprintf(tmp, 1024, "AUTHINFO PASS %s\r\n", m_pNewsServer->GetPassword());
snprintf(tmp, 1024, "AUTHINFO PASS %s\r\n", ((NewsServer*)m_pNetAddress)->GetPassword());
tmp[1024-1] = '\0';
WriteLine(tmp);
@@ -171,12 +169,12 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
char* answer = ReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
if (!answer)
{
ReportError("Authorization for %s failed: Connection closed by remote host", GetHost(), false, 0);
ReportError("Authorization for %s failed: Connection closed by remote host.", m_pNetAddress->GetHost(), true, 0);
return false;
}
else if (!strncmp(answer, "2", 1))
{
debug("Authorization for %s successful", GetHost());
debug("Authorization for %s successful", m_pNetAddress->GetHost());
return true;
}
else if (!strncmp(answer, "381", 3))
@@ -214,7 +212,7 @@ const char* NNTPConnection::JoinGroup(const char* grp)
if (answer && !strncmp(answer, "2", 1))
{
debug("Changed group to %s on %s", grp, GetHost());
debug("Changed group to %s on %s", grp, GetServer()->GetHost());
if (m_szActiveGroup)
{
@@ -224,7 +222,8 @@ const char* NNTPConnection::JoinGroup(const char* grp)
}
else
{
debug("Error changing group on %s to %s: %s.", GetHost(), grp, answer);
debug("Error changing group on %s to %s: %s.",
GetServer()->GetHost(), grp, answer);
}
return answer;
@@ -232,18 +231,28 @@ const char* NNTPConnection::JoinGroup(const char* grp)
bool NNTPConnection::DoConnect()
{
debug("Opening connection to %s", GetHost());
debug("Opening connection to %s", GetServer()->GetHost());
bool res = Connection::DoConnect();
if (!res)
{
return res;
}
#ifndef DISABLE_TLS
if (GetNewsServer()->GetTLS())
{
if (!StartTLS())
{
return false;
}
}
#endif
char* answer = DoReadLine(m_szLineBuf, CONNECTION_LINEBUFFER_SIZE, NULL);
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.", m_pNetAddress->GetHost(), true, 0);
return false;
}
@@ -253,7 +262,7 @@ bool NNTPConnection::DoConnect()
return false;
}
debug("Connection to %s established", GetHost());
debug("Connection to %s established", GetServer()->GetHost());
return true;
}
@@ -275,7 +284,7 @@ bool NNTPConnection::DoDisconnect()
void NNTPConnection::ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer)
{
char szErrStr[1024];
snprintf(szErrStr, 1024, szMsgPrefix, GetHost(), szAnswer);
snprintf(szErrStr, 1024, szMsgPrefix, m_pNetAddress->GetHost(), szAnswer);
szErrStr[1024-1] = '\0';
ReportError(szErrStr, NULL, false, 0);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -33,7 +33,6 @@
class NNTPConnection : public Connection
{
private:
NewsServer* m_pNewsServer;
char* m_szActiveGroup;
char* m_szLineBuf;
bool m_bAuthError;
@@ -44,9 +43,9 @@ private:
void ReportErrorAnswer(const char* szMsgPrefix, const char* szAnswer);
public:
NNTPConnection(NewsServer* pNewsServer);
NNTPConnection(NewsServer* server);
virtual ~NNTPConnection();
NewsServer* GetNewsServer() { return m_pNewsServer; }
NewsServer* GetNewsServer() { return(NewsServer*)m_pNetAddress; }
const char* Request(const char* req);
bool Authenticate();
bool AuthInfoUser(int iRecur = 0);
@@ -55,5 +54,6 @@ public:
bool GetAuthError() { return m_bAuthError; }
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

@@ -1,8 +1,8 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -36,13 +36,12 @@
#include <list>
#ifdef WIN32
#include <comutil.h>
#import <msxml.tlb> named_guids
#import "MSXML.dll" named_guids
using namespace MSXML;
#else
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/xmlerror.h>
#include <libxml/entities.h>
#endif
#include "nzbget.h"
@@ -56,6 +55,23 @@ using namespace MSXML;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
#ifndef WIN32
static void libxml_errorhandler(void *ebuf, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
char szErrMsg[1024];
vsnprintf(szErrMsg, sizeof(szErrMsg), fmt, argp);
szErrMsg[1024-1] = '\0';
va_end(argp);
// remove trailing CRLF
for (char* pend = szErrMsg + strlen(szErrMsg) - 1; pend >= szErrMsg && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
error("Error parsing nzb-file: %s", szErrMsg);
}
#endif
NZBFile::NZBFile(const char* szFileName, const char* szCategory)
{
debug("Creating NZBFile");
@@ -67,13 +83,6 @@ NZBFile::NZBFile(const char* szFileName, const char* szCategory)
m_pNZBInfo->SetCategory(szCategory);
m_pNZBInfo->BuildDestDirName();
#ifndef WIN32
m_pFileInfo = NULL;
m_pArticle = NULL;
m_szTagContent = NULL;
m_iTagContentLen = 0;
#endif
m_FileInfos.clear();
}
@@ -97,18 +106,6 @@ NZBFile::~NZBFile()
{
m_pNZBInfo->Release();
}
#ifndef WIN32
if (m_pFileInfo)
{
delete m_pFileInfo;
}
if (m_szTagContent)
{
free(m_szTagContent);
}
#endif
}
void NZBFile::LogDebugInfo()
@@ -161,10 +158,17 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
if (!pArticles->empty())
{
ParseSubject(pFileInfo);
m_FileInfos.push_back(pFileInfo);
pFileInfo->SetNZBInfo(m_pNZBInfo);
m_pNZBInfo->SetSize(m_pNZBInfo->GetSize() + pFileInfo->GetSize());
m_pNZBInfo->SetFileCount(m_pNZBInfo->GetFileCount() + 1);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveFile(pFileInfo);
pFileInfo->ClearArticles();
}
}
else
{
@@ -172,34 +176,8 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
}
}
void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
void NZBFile::ParseSubject(FileInfo* pFileInfo)
{
if (TryQuotes)
{
// try to use the filename in quatation marks
char* p = (char*)pFileInfo->GetSubject();
char* start = strchr(p, '\"');
if (start)
{
start++;
char* end = strchr(start + 1, '\"');
if (end)
{
int len = (int)(end - start);
char* point = strchr(start + 1, '.');
if (point && point < end)
{
char* filename = (char*)malloc(len + 1);
strncpy(filename, start, len);
filename[len] = '\0';
pFileInfo->SetFilename(filename);
free(filename);
return;
}
}
}
}
// tokenize subject, considering spaces as separators and quotation
// marks as non separatable token delimiters.
// then take the last token containing dot (".") as a filename
@@ -282,14 +260,19 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
debug("Could not extract Filename from Subject: %s. Using Subject as Filename", pFileInfo->GetSubject());
pFileInfo->SetFilename(pFileInfo->GetSubject());
}
pFileInfo->MakeValidFilename();
}
bool NZBFile::HasDuplicateFilenames()
/**
* Check if the parsing of subject was correct
*/
void NZBFile::CheckFilenames()
{
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo1 = *it;
int iDupe = 1;
int iDupe = 0;
for (FileInfos::iterator it2 = it + 1; it2 != m_FileInfos.end(); it2++)
{
FileInfo* pFileInfo2 = *it2;
@@ -308,52 +291,21 @@ bool NZBFile::HasDuplicateFilenames()
// an often case by posting-errors to repost bad files
if (iDupe > 2 || (iDupe == 2 && m_FileInfos.size() == 2))
{
return true;
for (FileInfos::iterator it2 = it; it2 != m_FileInfos.end(); it2++)
{
FileInfo* pFileInfo2 = *it2;
pFileInfo2->SetFilename(pFileInfo2->GetSubject());
pFileInfo2->MakeValidFilename();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->LoadArticles(pFileInfo2);
g_pDiskState->SaveFile(pFileInfo2);
pFileInfo2->ClearArticles();
}
}
}
}
return false;
}
/**
* Generate filenames from subjects and check if the parsing of subject was correct
*/
void NZBFile::ProcessFilenames()
{
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
ParseSubject(pFileInfo, true);
}
if (HasDuplicateFilenames())
{
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
ParseSubject(pFileInfo, false);
}
}
if (HasDuplicateFilenames())
{
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetFilename(pFileInfo->GetSubject());
}
}
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->MakeValidFilename();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveFile(pFileInfo);
pFileInfo->ClearArticles();
}
}
}
#ifdef WIN32
@@ -400,7 +352,7 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const c
NZBFile* pFile = new NZBFile(szFileName, szCategory);
if (pFile->ParseNZB(doc))
{
pFile->ProcessFilenames();
pFile->CheckFilenames();
}
else
{
@@ -503,235 +455,158 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize, bool bFromBuffer)
{
NZBFile* pFile = new NZBFile(szFileName, szCategory);
xmlSAXHandler SAX_handler = {0};
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
SAX_handler.characters = reinterpret_cast<charactersSAXFunc>(SAX_characters);
SAX_handler.error = reinterpret_cast<errorSAXFunc>(SAX_error);
SAX_handler.getEntity = reinterpret_cast<getEntitySAXFunc>(SAX_getEntity);
int ret = 0;
pFile->m_bIgnoreNextError = false;
xmlSetGenericErrorFunc(NULL, libxml_errorhandler);
xmlTextReaderPtr doc;
if (bFromBuffer)
{
ret = xmlSAXUserParseMemory(&SAX_handler, pFile, szBuffer, iSize);
doc = xmlReaderForMemory(szBuffer, iSize-1, "", NULL, 0);
}
else
{
ret = xmlSAXUserParseFile(&SAX_handler, pFile, szFileName);
doc = xmlReaderForFile(szFileName, NULL, 0);
}
if (ret == 0)
if (!doc)
{
error("Could not create XML-Reader");
return NULL;
}
NZBFile* pFile = new NZBFile(szFileName, szCategory);
if (pFile->ParseNZB(doc))
{
pFile->ProcessFilenames();
pFile->CheckFilenames();
}
else
{
error("Failed to parse nzb-file");
delete pFile;
pFile = NULL;
}
return pFile;
xmlFreeTextReader(doc);
return pFile;
}
void NZBFile::Parse_StartElement(const char *name, const char **atts)
bool NZBFile::ParseNZB(void* nzb)
{
if (m_szTagContent)
{
free(m_szTagContent);
m_szTagContent = NULL;
m_iTagContentLen = 0;
}
if (!strcmp("file", name))
{
m_pFileInfo = new FileInfo();
m_pFileInfo->SetFilename(m_szFileName);
FileInfo* pFileInfo = NULL;
xmlTextReaderPtr node = (xmlTextReaderPtr)nzb;
// walk through whole doc and search for segments-tags
int ret = xmlTextReaderRead(node);
while (ret == 1)
{
if (node)
{
xmlChar *name, *value;
for (int i = 0; atts[i]; i += 2)
{
const char* attrname = atts[i];
const char* attrvalue = atts[i + 1];
if (!strcmp("subject", attrname))
{
m_pFileInfo->SetSubject(attrvalue);
}
if (!strcmp("date", attrname))
{
m_pFileInfo->SetTime(atoi(attrvalue));
}
}
}
else if (!strcmp("segment", name))
{
if (!m_pFileInfo)
{
// error: bad nzb-file
return;
}
long long lsize = -1;
int partNumber = -1;
name = xmlTextReaderName(node);
if (name == NULL)
{
name = xmlStrdup(BAD_CAST "--");
}
value = xmlTextReaderValue(node);
for (int i = 0; atts[i]; i += 2)
{
const char* attrname = atts[i];
const char* attrvalue = atts[i + 1];
if (!strcmp("bytes", attrname))
{
lsize = atol(attrvalue);
}
if (!strcmp("number", attrname))
{
partNumber = atol(attrvalue);
}
}
if (lsize > 0)
{
m_pFileInfo->SetSize(m_pFileInfo->GetSize() + lsize);
}
if (xmlTextReaderNodeType(node) == 1)
{
if (!strcmp("file", (char*)name))
{
pFileInfo = new FileInfo();
pFileInfo->SetFilename(m_szFileName);
if (partNumber > 0)
{
// new segment, add it!
m_pArticle = new ArticleInfo();
m_pArticle->SetPartNumber(partNumber);
m_pArticle->SetSize(lsize);
AddArticle(m_pFileInfo, m_pArticle);
}
}
}
while (xmlTextReaderMoveToNextAttribute(node))
{
xmlFree(name);
name = xmlTextReaderName(node);
if (!strcmp("subject",(char*)name))
{
xmlFree(value);
value = xmlTextReaderValue(node);
pFileInfo->SetSubject((char*)value);
}
if (!strcmp("date",(char*)name))
{
xmlFree(value);
value = xmlTextReaderValue(node);
pFileInfo->SetTime(atoi((char*)value));
}
}
}
else if (!strcmp("segment",(char*)name))
{
long long lsize = -1;
int partNumber = -1;
void NZBFile::Parse_EndElement(const char *name)
{
if (!strcmp("file", name))
{
// Close the file element, add the new file to file-list
AddFileInfo(m_pFileInfo);
m_pFileInfo = NULL;
m_pArticle = NULL;
}
else if (!strcmp("group", name))
{
if (!m_pFileInfo)
{
// error: bad nzb-file
return;
}
m_pFileInfo->GetGroups()->push_back(m_szTagContent);
m_szTagContent = NULL;
m_iTagContentLen = 0;
}
else if (!strcmp("segment", name))
{
if (!m_pFileInfo || !m_pArticle)
{
// error: bad nzb-file
return;
}
while (xmlTextReaderMoveToNextAttribute(node))
{
xmlFree(name);
name = xmlTextReaderName(node);
xmlFree(value);
value = xmlTextReaderValue(node);
if (!strcmp("bytes",(char*)name))
{
lsize = atol((char*)value);
}
if (!strcmp("number",(char*)name))
{
partNumber = atol((char*)value);
}
}
if (lsize > 0)
{
pFileInfo->SetSize(pFileInfo->GetSize() + lsize);
}
/* Get the #text part */
ret = xmlTextReaderRead(node);
// Get the #text part
char ID[2048];
snprintf(ID, 2048, "<%s>", m_szTagContent);
m_pArticle->SetMessageID(ID);
m_pArticle = NULL;
}
}
if (partNumber > 0)
{
// new segment, add it!
xmlFree(value);
value = xmlTextReaderValue(node);
char tmp[2048];
snprintf(tmp, 2048, "<%s>", (char*)value);
ArticleInfo* pArticle = new ArticleInfo();
pArticle->SetPartNumber(partNumber);
pArticle->SetMessageID(tmp);
pArticle->SetSize(lsize);
AddArticle(pFileInfo, pArticle);
}
}
else if (!strcmp("group",(char*)name))
{
ret = xmlTextReaderRead(node);
xmlFree(value);
value = xmlTextReaderValue(node);
if (!pFileInfo)
{
// error: bad nzb-file
break;
}
pFileInfo->GetGroups()->push_back(strdup((char*)value));
}
}
void NZBFile::Parse_Content(const char *buf, int len)
{
m_szTagContent = (char*)realloc(m_szTagContent, m_iTagContentLen + len + 1);
strncpy(m_szTagContent + m_iTagContentLen, buf, len);
m_iTagContentLen += len;
m_szTagContent[m_iTagContentLen] = '\0';
}
if (xmlTextReaderNodeType(node) == 15)
{
/* Close the file element, add the new file to file-list */
if (!strcmp("file",(char*)name))
{
AddFileInfo(pFileInfo);
}
}
void NZBFile::SAX_StartElement(NZBFile* pFile, const char *name, const char **atts)
{
pFile->Parse_StartElement(name, atts);
}
void NZBFile::SAX_EndElement(NZBFile* pFile, const char *name)
{
pFile->Parse_EndElement(name);
}
void NZBFile::SAX_characters(NZBFile* pFile, const char * xmlstr, int len)
{
char* str = (char*)xmlstr;
// trim starting blanks
int off = 0;
for (int i = 0; i < len; i++)
{
char ch = str[i];
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
{
off++;
}
else
{
break;
}
}
int newlen = len - off;
// trim ending blanks
for (int i = len - 1; i >= off; i--)
{
char ch = str[i];
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
{
newlen--;
}
else
{
break;
}
}
if (newlen > 0)
{
// interpret tag content
pFile->Parse_Content(str + off, newlen);
}
}
void* NZBFile::SAX_getEntity(NZBFile* pFile, const char * name)
{
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
if (!e)
{
warn("entity not found");
pFile->m_bIgnoreNextError = true;
}
return e;
}
void NZBFile::SAX_error(NZBFile* pFile, const char *msg, ...)
{
if (pFile->m_bIgnoreNextError)
{
pFile->m_bIgnoreNextError = false;
return;
}
va_list argp;
va_start(argp, msg);
char szErrMsg[1024];
vsnprintf(szErrMsg, sizeof(szErrMsg), msg, argp);
szErrMsg[1024-1] = '\0';
va_end(argp);
// remove trailing CRLF
for (char* pend = szErrMsg + strlen(szErrMsg) - 1; pend >= szErrMsg && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
error("Error parsing nzb-file: %s", szErrMsg);
xmlFree(name);
xmlFree(value);
}
ret = xmlTextReaderRead(node);
}
if (ret != 0)
{
error("Failed to parse nzb-file");
return false;
}
return true;
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -44,27 +44,13 @@ private:
NZBFile(const char* szFileName, const char* szCategory);
void AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
void AddFileInfo(FileInfo* pFileInfo);
void ParseSubject(FileInfo* pFileInfo, bool TryQuotes);
void ProcessFilenames();
bool HasDuplicateFilenames();
void ParseSubject(FileInfo* pFileInfo);
void CheckFilenames();
#ifdef WIN32
bool ParseNZB(IUnknown* nzb);
static void EncodeURL(const char* szFilename, char* szURL);
#else
FileInfo* m_pFileInfo;
ArticleInfo* m_pArticle;
char* m_szTagContent;
int m_iTagContentLen;
bool m_bIgnoreNextError;
static void SAX_StartElement(NZBFile* pFile, const char *name, const char **atts);
static void SAX_EndElement(NZBFile* pFile, const char *name);
static void SAX_characters(NZBFile* pFile, const char * xmlstr, int len);
static void* SAX_getEntity(NZBFile* pFile, const char * name);
static void SAX_error(NZBFile* pFile, const char *msg, ...);
void Parse_StartElement(const char *name, const char **atts);
void Parse_EndElement(const char *name);
void Parse_Content(const char *buf, int len);
bool ParseNZB(void* nzb);
#endif
static NZBFile* Create(const char* szFileName, const char* szCategory, const char* szBuffer, int iSize, bool bFromBuffer);

54
NetAddress.cpp Normal file
View File

@@ -0,0 +1,54 @@
/*
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "nzbget.h"
#include "NetAddress.h"
NetAddress::NetAddress(const char* szHost, int iPort)
{
m_szHost = NULL;
m_iPort = iPort;
if (szHost)
m_szHost = strdup(szHost);
}
NetAddress::~NetAddress()
{
if (m_szHost)
free(m_szHost);
m_szHost = NULL;
}

44
NetAddress.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef NETADDRESS_H
#define NETADDRESS_H
class NetAddress
{
private:
char* m_szHost;
int m_iPort;
public:
NetAddress(const char* szHost, int iPort);
virtual ~NetAddress();
const char* GetHost() { return m_szHost; }
int GetPort() { return m_iPort; }
};
#endif

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -37,32 +37,29 @@
#include "nzbget.h"
#include "NewsServer.h"
#include "Log.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) : NetAddress(szHost, iPort)
{
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 (szUser)
{
m_szUser = strdup(szUser);
}
if (szPass)
{
m_szPassword = strdup(szPass);
}
}
NewsServer::~NewsServer()
{
if (m_szHost)
{
free(m_szHost);
}
if (m_szUser)
{
free(m_szUser);
@@ -71,8 +68,4 @@ NewsServer::~NewsServer()
{
free(m_szPassword);
}
if (m_szCipher)
{
free(m_szCipher);
}
}

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2008 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -27,37 +27,27 @@
#ifndef NEWSSERVER_H
#define NEWSSERVER_H
class NewsServer
#include "NetAddress.h"
class NewsServer : public NetAddress
{
private:
int m_iID;
int m_iGroup;
char* m_szHost;
int m_iPort;
char* m_szUser;
char* m_szPassword;
int m_iMaxConnections;
int m_iLevel;
bool m_bJoinGroup;
bool m_bTLS;
char* m_szCipher;
public:
NewsServer(int iID, const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup);
~NewsServer();
int GetID() { return m_iID; }
int GetGroup() { return m_iGroup; }
const char* GetHost() { return m_szHost; }
int GetPort() { return m_iPort; }
NewsServer(const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS, int iMaxConnections, int iLevel);
virtual ~NewsServer();
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 if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

View File

File diff suppressed because it is too large Load Diff

170
Options.h
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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -28,7 +28,6 @@
#define OPTIONS_H
#include <vector>
#include <time.h>
#include "Thread.h"
class Options
@@ -46,12 +45,10 @@ public:
opClientRequestEditQueue,
opClientRequestLog,
opClientRequestShutdown,
opClientRequestReload,
opClientRequestVersion,
opClientRequestPostQueue,
opClientRequestWriteLog,
opClientRequestScanSync,
opClientRequestScanAsync,
opClientRequestScan,
opClientRequestDownloadPause,
opClientRequestDownloadUnpause,
opClientRequestDownload2Pause,
@@ -60,9 +57,7 @@ public:
opClientRequestPostUnpause,
opClientRequestScanPause,
opClientRequestScanUnpause,
opClientRequestHistory,
opClientRequestDownloadUrl,
opClientRequestUrlQueue
opClientRequestHistory
};
enum EMessageTarget
{
@@ -83,12 +78,6 @@ public:
lpOne,
lpAll
};
enum EParScan
{
psLimited,
psFull,
psAuto
};
enum EScriptLogKind
{
slNone,
@@ -99,92 +88,37 @@ public:
slDebug
};
enum EMatchMode
{
mmID = 1,
mmName,
mmRegEx
};
enum EDomain
{
dmServer = 1,
dmPostProcess
};
class OptEntry
{
private:
char* m_szName;
char* m_szValue;
char* m_szDefValue;
int m_iLineNo;
void SetName(const char* szName);
void SetValue(const char* szValue);
void SetLineNo(int iLineNo) { m_iLineNo = iLineNo; }
friend class Options;
public:
OptEntry();
OptEntry(const char* szName, const char* szValue);
~OptEntry();
const char* GetName() { return m_szName; }
const char* GetValue() { return m_szValue; }
const char* GetDefValue() { return m_szDefValue; }
int GetLineNo() { return m_iLineNo; }
};
typedef std::vector<OptEntry*> OptEntriesBase;
class OptEntries: public OptEntriesBase
{
public:
~OptEntries();
OptEntry* FindOption(const char* szName);
};
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);
};
typedef std::vector<OptEntry*> OptEntries;
private:
OptEntries m_OptEntries;
bool m_bConfigInitialized;
Mutex m_mutexOptEntries;
Categories m_Categories;
// Options
bool m_bConfigErrors;
int m_iConfigLine;
char* m_szConfigFilename;
char* m_szDestDir;
char* m_szInterDir;
char* m_szTempDir;
char* m_szQueueDir;
char* m_szNzbDir;
char* m_szWebDir;
EMessageTarget m_eInfoTarget;
EMessageTarget m_eWarningTarget;
EMessageTarget m_eErrorTarget;
@@ -203,31 +137,22 @@ private:
int m_iRetryInterval;
bool m_bSaveQueue;
bool m_bDupeCheck;
char* m_szControlIP;
char* m_szControlPassword;
int m_iControlPort;
bool m_bSecureControl;
int m_iSecurePort;
char* m_szSecureCert;
char* m_szSecureKey;
char* m_szServerIP;
char* m_szServerPassword;
int m_szServerPort;
char* m_szLockFile;
char* m_szDaemonUserName;
EOutputMode m_eOutputMode;
bool m_bReloadQueue;
bool m_bReloadUrlQueue;
bool m_bReloadPostQueue;
int m_iUrlConnections;
int m_iLogBufferSize;
bool m_bCreateLog;
char* m_szLogFile;
ELoadPars m_eLoadPars;
bool m_bParCheck;
bool m_bParRepair;
EParScan m_eParScan;
char* m_szPostProcess;
char* m_szPostConfigFilename;
char* m_szNZBProcess;
char* m_szNZBAddedProcess;
bool m_bStrictParName;
bool m_bNoConfig;
int m_iUMask;
@@ -236,6 +161,7 @@ private:
bool m_bCursesTime;
bool m_bCursesGroup;
bool m_bCrcCheck;
bool m_bRetryOnCrcError;
int m_iThreadLimit;
bool m_bDirectWrite;
int m_iWriteBufferSize;
@@ -254,12 +180,6 @@ private:
bool m_bMergeNzb;
int m_iParTimeLimit;
int m_iKeepHistory;
bool m_bAccurateRate;
bool m_bUnpack;
bool m_bUnpackCleanupDisk;
char* m_szUnrarCmd;
char* m_szSevenZipCmd;
bool m_bUnpackPauseQueue;
// Parsed command-line parameters
bool m_bServerMode;
@@ -269,18 +189,13 @@ private:
int m_iEditQueueOffset;
int* m_pEditQueueIDList;
int m_iEditQueueIDCount;
NameList m_EditQueueNameList;
EMatchMode m_EMatchMode;
char* m_szEditQueueText;
char* m_szArgFilename;
char* m_szAddCategory;
int m_iAddPriority;
bool m_bAddPaused;
char* m_szAddNZBFilename;
char* m_szCategory;
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,58 +205,42 @@ 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();
void InitCommandLine(int argc, char* argv[]);
void InitOptions();
void InitPostConfig();
void InitFileArg(int argc, char* argv[]);
void InitServers();
void InitCategories();
void InitScheduler();
void CheckOptions();
void PrintUsage(char* com);
void Dump();
int ParseEnumValue(const char* OptName, int argc, const char* argn[], const int argv[]);
int ParseIntValue(const char* OptName, int iBase);
float ParseFloatValue(const char* OptName);
int ParseOptionValue(const char* OptName, int argc, const char* argn[], const int argv[]);
OptEntry* FindOption(const char* optname);
const char* GetOption(const char* optname);
void SetOption(const char* optname, const char* value);
bool SetOptionString(const char* option);
bool ValidateOptionName(const char* optname);
void LoadConfigFile();
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate);
void LoadConfig(const char* configfile);
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty);
void ParseFileIDList(int argc, char* argv[], int optind);
void ParseFileNameList(int argc, char* argv[], int optind);
bool ParseTime(const char** pTime, int* pHours, int* pMinutes);
bool ParseWeekDays(const char* szWeekDays, int* pWeekDaysBits);
void ConfigError(const char* msg, ...);
void ConfigWarn(const char* msg, ...);
void LocateOptionSrcPos(const char *szOptionName);
void ConvertOldOptionName(char *szOption, int iBufLen);
public:
Options(int argc, char* argv[]);
~Options();
bool LoadConfig(EDomain eDomain, OptEntries* pOptEntries);
bool SaveConfig(EDomain eDomain, OptEntries* pOptEntries);
// Options
OptEntries* LockOptEntries();
void UnlockOptEntries();
const char* GetConfigFilename() { return m_szConfigFilename; }
const char* GetDestDir() { return m_szDestDir; }
const char* GetInterDir() { return m_szInterDir; }
const char* GetTempDir() { return m_szTempDir; }
const char* GetQueueDir() { return m_szQueueDir; }
const char* GetNzbDir() { return m_szNzbDir; }
const char* GetWebDir() { return m_szWebDir; }
bool GetCreateBrokenLog() const { return m_bCreateBrokenLog; }
bool GetResetLog() const { return m_bResetLog; }
EMessageTarget GetInfoTarget() const { return m_eInfoTarget; }
@@ -360,31 +259,22 @@ public:
int GetRetryInterval() { return m_iRetryInterval; }
bool GetSaveQueue() { return m_bSaveQueue; }
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; }
const char* GetServerIP() { return m_szServerIP; }
const char* GetServerPassword() { return m_szServerPassword; }
int GetServerPort() { return m_szServerPort; }
const char* GetLockFile() { return m_szLockFile; }
const char* GetDaemonUserName() { return m_szDaemonUserName; }
EOutputMode GetOutputMode() { return m_eOutputMode; }
bool GetReloadQueue() { return m_bReloadQueue; }
bool GetReloadUrlQueue() { return m_bReloadUrlQueue; }
bool GetReloadPostQueue() { return m_bReloadPostQueue; }
int GetUrlConnections() { return m_iUrlConnections; }
int GetLogBufferSize() { return m_iLogBufferSize; }
bool GetCreateLog() { return m_bCreateLog; }
const char* GetLogFile() { return m_szLogFile; }
ELoadPars GetLoadPars() { return m_eLoadPars; }
bool GetParCheck() { return m_bParCheck; }
bool GetParRepair() { return m_bParRepair; }
EParScan GetParScan() { return m_eParScan; }
const char* GetPostProcess() { return m_szPostProcess; }
const char* GetPostConfigFilename() { return m_szPostConfigFilename; }
const char* GetNZBProcess() { return m_szNZBProcess; }
const char* GetNZBAddedProcess() { return m_szNZBAddedProcess; }
bool GetStrictParName() { return m_bStrictParName; }
int GetUMask() { return m_iUMask; }
int GetUpdateInterval() {return m_iUpdateInterval; }
@@ -392,6 +282,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; }
@@ -410,14 +301,6 @@ public:
bool GetMergeNzb() { return m_bMergeNzb; }
int GetParTimeLimit() { return m_iParTimeLimit; }
int GetKeepHistory() { return m_iKeepHistory; }
bool GetAccurateRate() { return m_bAccurateRate; }
bool GetUnpack() { return m_bUnpack; }
bool GetUnpackCleanupDisk() { return m_bUnpackCleanupDisk; }
const char* GetUnrarCmd() { return m_szUnrarCmd; }
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); }
// Parsed command-line parameters
bool GetServerMode() { return m_bServerMode; }
@@ -428,17 +311,12 @@ public:
int GetEditQueueOffset() { return m_iEditQueueOffset; }
int* GetEditQueueIDList() { return m_pEditQueueIDList; }
int GetEditQueueIDCount() { return m_iEditQueueIDCount; }
NameList* GetEditQueueNameList() { return &m_EditQueueNameList; }
EMatchMode GetMatchMode() { return m_EMatchMode; }
const char* GetEditQueueText() { return m_szEditQueueText; }
const char* GetArgFilename() { return m_szArgFilename; }
const char* GetAddCategory() { return m_szAddCategory; }
bool GetAddPaused() { return m_bAddPaused; }
const char* GetCategory() { return m_szCategory; }
const char* GetLastArg() { return m_szLastArg; }
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 +330,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

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -41,7 +41,6 @@
#include <par2cmdline.h>
#include <par2repairer.h>
#else
#include <unistd.h>
#include <libpar2/par2cmdline.h>
#include <libpar2/par2repairer.h>
#endif
@@ -67,90 +66,10 @@ const char* Par2CmdLineErrStr[] = { "OK",
class Repairer : public Par2Repairer
{
private:
CommandLine commandLine;
public:
Result PreProcess(const char *szParFilename);
Result Process(bool dorepair);
friend class ParChecker;
};
Result Repairer::PreProcess(const char *szParFilename)
{
#ifdef HAVE_PAR2_BUGFIXES_V2
// Ensure linking against the patched version of libpar2
BugfixesPatchVersion2();
#endif
if (g_pOptions->GetParScan() == Options::psFull)
{
char szWildcardParam[1024];
strncpy(szWildcardParam, szParFilename, 1024);
szWildcardParam[1024-1] = '\0';
char* szBasename = Util::BaseFileName(szWildcardParam);
if (szBasename != szWildcardParam && strlen(szBasename) > 0)
{
szBasename[0] = '*';
szBasename[1] = '\0';
}
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename, szWildcardParam };
if (!commandLine.Parse(6, (char**)argv))
{
return eInvalidCommandLineArguments;
}
}
else
{
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename };
if (!commandLine.Parse(5, (char**)argv))
{
return eInvalidCommandLineArguments;
}
}
return Par2Repairer::PreProcess(commandLine);
}
Result Repairer::Process(bool dorepair)
{
return Par2Repairer::Process(commandLine, dorepair);
}
class MissingFilesComparator
{
private:
const char* m_szBaseParFilename;
public:
MissingFilesComparator(const char* szBaseParFilename) : m_szBaseParFilename(szBaseParFilename) {}
bool operator()(CommandLine::ExtraFile* pFirst, CommandLine::ExtraFile* pSecond) const;
};
/*
* Files with the same name as in par-file (and a differnt extension) are
* placed at the top of the list to be scanned first.
*/
bool MissingFilesComparator::operator()(CommandLine::ExtraFile* pFile1, CommandLine::ExtraFile* pFile2) const
{
char name1[1024];
strncpy(name1, Util::BaseFileName(pFile1->FileName().c_str()), 1024);
name1[1024-1] = '\0';
if (char* ext = strrchr(name1, '.')) *ext = '\0'; // trim extension
char name2[1024];
strncpy(name2, Util::BaseFileName(pFile2->FileName().c_str()), 1024);
name2[1024-1] = '\0';
if (char* ext = strrchr(name2, '.')) *ext = '\0'; // trim extension
return strcmp(name1, m_szBaseParFilename) == 0 && strcmp(name1, name2) != 0;
}
ParChecker::ParChecker()
{
debug("Creating ParChecker");
@@ -166,6 +85,7 @@ ParChecker::ParChecker()
m_bVerifyingExtraFiles = false;
m_bCancelled = false;
m_eStage = ptLoadingPars;
m_QueuedParFiles.clear();
}
ParChecker::~ParChecker()
@@ -186,22 +106,11 @@ ParChecker::~ParChecker()
}
free(m_szProgressLabel);
Cleanup();
}
void ParChecker::Cleanup()
{
for (FileList::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
for (QueuedParFiles::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
{
free(*it);
}
m_QueuedParFiles.clear();
for (FileList::iterator it = m_ProcessedFiles.begin(); it != m_ProcessedFiles.end() ;it++)
{
free(*it);
}
m_ProcessedFiles.clear();
}
void ParChecker::SetParFilename(const char * szParFilename)
@@ -230,7 +139,6 @@ void ParChecker::SetStatus(EStatus eStatus)
void ParChecker::Run()
{
Cleanup();
m_bRepairNotNeeded = false;
m_eStage = ptLoadingPars;
m_iProcessedFiles = 0;
@@ -242,7 +150,15 @@ void ParChecker::Run()
SetStatus(psWorking);
debug("par: %s", m_szParFilename);
CommandLine commandLine;
const char* argv[] = { "par2", "r", "-v", "-v", m_szParFilename };
if (!commandLine.Parse(5, (char**)argv))
{
error("Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
SetStatus(psFailed);
return;
}
Result res;
Repairer* pRepairer = new Repairer();
@@ -258,24 +174,15 @@ void ParChecker::Run()
m_iStageProgress = 0;
UpdateProgress();
res = pRepairer->PreProcess(m_szParFilename);
res = pRepairer->PreProcess(commandLine);
debug("ParChecker: PreProcess-result=%i", res);
if (res != eSuccess || IsStopped())
{
if (res == eInvalidCommandLineArguments)
{
error("Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
m_szErrMsg = strdup("Command line could not be parsed");
}
else
{
error("Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
m_szErrMsg = strdup("par2-file could not be processed");
}
error("Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
m_szErrMsg = strdup("par2-file could not be processed");
SetStatus(psFailed);
delete pRepairer;
Cleanup();
return;
}
@@ -288,19 +195,13 @@ void ParChecker::Run()
m_szErrMsg = NULL;
m_eStage = ptVerifyingSources;
res = pRepairer->Process(false);
res = pRepairer->Process(commandLine, false);
debug("ParChecker: Process-result=%i", res);
if (!IsStopped() && pRepairer->missingfilecount > 0 && g_pOptions->GetParScan() == Options::psAuto && AddMissingFiles())
{
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
if (!IsStopped() && res == eRepairNotPossible && CheckSplittedFragments())
{
pRepairer->UpdateVerificationResults();
res = pRepairer->Process(false);
res = pRepairer->Process(commandLine, false);
debug("ParChecker: Process-result=%i", res);
}
@@ -365,7 +266,7 @@ void ParChecker::Run()
if (bMoreFilesLoaded)
{
pRepairer->UpdateVerificationResults();
res = pRepairer->Process(false);
res = pRepairer->Process(commandLine, false);
debug("ParChecker: Process-result=%i", res);
}
}
@@ -374,7 +275,6 @@ void ParChecker::Run()
{
SetStatus(psFailed);
delete pRepairer;
Cleanup();
return;
}
@@ -398,7 +298,7 @@ void ParChecker::Run()
m_iFilesToRepair = pRepairer->damagedfilecount + pRepairer->missingfilecount;
UpdateProgress();
res = pRepairer->Process(true);
res = pRepairer->Process(commandLine, true);
debug("ParChecker: Process-result=%i", res);
if (res == eSuccess)
{
@@ -433,18 +333,17 @@ void ParChecker::Run()
}
delete pRepairer;
Cleanup();
}
bool ParChecker::LoadMorePars()
{
m_mutexQueuedParFiles.Lock();
FileList moreFiles;
QueuedParFiles moreFiles;
moreFiles.assign(m_QueuedParFiles.begin(), m_QueuedParFiles.end());
m_QueuedParFiles.clear();
m_mutexQueuedParFiles.Unlock();
for (FileList::iterator it = moreFiles.begin(); it != moreFiles.end() ;it++)
for (QueuedParFiles::iterator it = moreFiles.begin(); it != moreFiles.end() ;it++)
{
char* szParFilename = *it;
bool loadedOK = ((Repairer*)m_pRepairer)->LoadPacketsFromFile(szParFilename);
@@ -481,7 +380,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 +407,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())
@@ -538,7 +437,7 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
if (!extrafiles.empty())
{
m_iExtraFiles += extrafiles.size();
m_iExtraFiles = extrafiles.size();
m_bVerifyingExtraFiles = true;
bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
m_bVerifyingExtraFiles = false;
@@ -547,93 +446,6 @@ bool ParChecker::AddSplittedFragments(const char* szFilename)
return bFragmentsAdded;
}
bool ParChecker::AddMissingFiles()
{
info("Performing extra par-scan for %s", m_szInfoName);
char szDirectory[1024];
strncpy(szDirectory, m_szParFilename, 1024);
szDirectory[1024-1] = '\0';
char* szBasename = Util::BaseFileName(szDirectory);
if (szBasename == szDirectory)
{
return false;
}
szBasename[-1] = '\0';
std::list<CommandLine::ExtraFile*> extrafiles;
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt"))
{
bool bAlreadyScanned = false;
for (FileList::iterator it = m_ProcessedFiles.begin(); it != m_ProcessedFiles.end(); it++)
{
const char* szProcessedFilename = *it;
if (!strcasecmp(Util::BaseFileName(szProcessedFilename), filename))
{
bAlreadyScanned = true;
break;
}
}
if (!bAlreadyScanned)
{
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
fullfilename[1024-1] = '\0';
extrafiles.push_back(new CommandLine::ExtraFile(fullfilename, Util::FileSize(fullfilename)));
}
}
}
// Sort the list
char* szBaseParFilename = strdup(Util::BaseFileName(m_szParFilename));
if (char* ext = strrchr(szBaseParFilename, '.')) *ext = '\0'; // trim extension
extrafiles.sort(MissingFilesComparator(szBaseParFilename));
free(szBaseParFilename);
// Scan files
bool bFilesAdded = false;
if (!extrafiles.empty())
{
m_iExtraFiles += extrafiles.size();
m_bVerifyingExtraFiles = true;
std::list<CommandLine::ExtraFile> extrafiles1;
// adding files one by one until all missing files are found
while (!IsStopped() && !m_bCancelled && extrafiles.size() > 0 && ((Repairer*)m_pRepairer)->missingfilecount > 0)
{
CommandLine::ExtraFile* pExtraFile = extrafiles.front();
extrafiles.pop_front();
extrafiles1.clear();
extrafiles1.push_back(*pExtraFile);
bFilesAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles1) || bFilesAdded;
((Repairer*)m_pRepairer)->UpdateVerificationResults();
delete pExtraFile;
}
m_bVerifyingExtraFiles = false;
// free any remaining objects
for (std::list<CommandLine::ExtraFile*>::iterator it = extrafiles.begin(); it != extrafiles.end() ;it++)
{
delete *it;
}
}
return bFilesAdded;
}
void ParChecker::signal_filename(std::string str)
{
const char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
@@ -645,11 +457,6 @@ void ParChecker::signal_filename(std::string str)
info("%s %s", szStageMessage[m_eStage], str.c_str());
if (m_eStage == ptLoadingPars || m_eStage == ptVerifyingSources)
{
m_ProcessedFiles.push_back(strdup(str.c_str()));
}
snprintf(m_szProgressLabel, 1024, "%s %s", szStageMessage[m_eStage], str.c_str());
m_szProgressLabel[1024-1] = '\0';
m_iFileProgress = 0;
@@ -713,7 +520,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;
@@ -743,7 +550,7 @@ void ParChecker::Cancel()
((Repairer*)m_pRepairer)->cancelled = true;
m_bCancelled = true;
#else
error("Could not cancel par-repair. The program was compiled using version of libpar2 which doesn't support cancelling of par-repair. Please apply libpar2-patches supplied with NZBGet and recompile libpar2 and NZBGet (see README for details).");
error("Could not cancel par-repair. The used version of libpar2 does not support the cancelling of par-repair. Libpar2 needs to be patched for that feature to work.");
#endif
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -52,7 +52,7 @@ public:
ptVerifyingRepaired,
};
typedef std::deque<char*> FileList;
typedef std::deque<char*> QueuedParFiles;
private:
char* m_szInfoName;
@@ -62,10 +62,9 @@ private:
void* m_pRepairer; // declared as void* to prevent the including of libpar2-headers into this header-file
char* m_szErrMsg;
bool m_bRepairNotNeeded;
FileList m_QueuedParFiles;
QueuedParFiles m_QueuedParFiles;
Mutex m_mutexQueuedParFiles;
bool m_bQueuedParFilesChanged;
FileList m_ProcessedFiles;
int m_iProcessedFiles;
int m_iFilesToRepair;
int m_iExtraFiles;
@@ -75,11 +74,9 @@ private:
int m_iStageProgress;
bool m_bCancelled;
void Cleanup();
bool LoadMorePars();
bool CheckSplittedFragments();
bool AddSplittedFragments(const char* szFilename);
bool AddMissingFiles();
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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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);
bool bIgnoreFirstInPostQueue, 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();
@@ -114,7 +152,7 @@ public:
virtual void Stop();
void QueueCoordinatorUpdate(Subject* Caller, void* Aspect);
bool HasMoreJobs() { return m_bHasMoreJobs; }
void ScanNZBDir(bool bSyncMode);
void ScanNZBDir();
bool QueueEditList(IDList* pIDList, EEditAction eAction, int iOffset);
};

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-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -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
@@ -168,12 +168,9 @@ void QueueCoordinator::Run()
int iSleepInterval = bStandBy ? 100 : 5;
usleep(iSleepInterval * 1000);
if (!bStandBy)
{
AddSpeedReading(0);
}
AddSpeedReading(0);
iResetCounter += iSleepInterval;
iResetCounter+= iSleepInterval;
if (iResetCounter >= 1000)
{
// this code should not be called too often, once per second is OK
@@ -297,99 +294,75 @@ 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;
}
/*
* NOTE: we should use mutex by access to m_iSpeedBytes and m_iSpeedBytesIndex,
* but this would results in a big performance loss (the function
* "AddSpeedReading" is called extremly often), so we better agree with calculation
* errors possible because of simultaneuos access from several threads.
* The used algorithm is able to recover after few seconds.
* In any case the calculation errors can not result in fatal system
* errors (segmentation faults).
*/
void QueueCoordinator::AddSpeedReading(int iBytes)
{
time_t tCurTime = time(NULL);
int iNowSlot = (int)tCurTime / SPEEDMETER_SLOTSIZE;
int iNowSlot = (int)time(NULL) / SPEEDMETER_SLOTSIZE;
if (g_pOptions->GetAccurateRate())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Lock();
#else
m_mutexSpeed.Lock();
#endif
}
if (iNowSlot > m_iSpeedTime[m_iSpeedBytesIndex])
{
//record bytes in next slot
m_iSpeedBytesIndex++;
if (m_iSpeedBytesIndex >= SPEEDMETER_SLOTS)
{
m_iSpeedBytesIndex = 0;
}
//Adjust counters with outging information.
m_iSpeedTotalBytes -= m_iSpeedBytes[m_iSpeedBytesIndex];
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];
//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())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Unlock();
#else
m_mutexSpeed.Unlock();
#endif
}
}
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()
@@ -452,90 +425,31 @@ void QueueCoordinator::Stop()
debug("ArticleDownloads are notified");
}
/*
* Returns next article for download.
*/
bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArticleInfo)
{
// find an unpaused file with the highest priority, then take the next article from the file.
// if the file doesn't have any articles left for download, we store that fact and search again,
// ignoring all files which were previously marked as not having any articles.
// special case: if the file has ExtraPriority-flag set, it has the highest priority and the
// Paused-flag is ignored.
//debug("QueueCoordinator::GetNextArticle()");
bool bOK = false;
// pCheckedFiles stores
bool* pCheckedFiles = NULL;
while (!bOK)
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
{
//debug("QueueCoordinator::GetNextArticle() - in loop");
pFileInfo = NULL;
int iNum = 0;
int iFileNum = 0;
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
pFileInfo = *it;
if (!pFileInfo->GetPaused() && !pFileInfo->GetDeleted())
{
FileInfo* pFileInfo1 = *it;
if ((!pCheckedFiles || !pCheckedFiles[iNum]) &&
!pFileInfo1->GetPaused() && !pFileInfo1->GetDeleted() &&
(!pFileInfo ||
(pFileInfo1->GetExtraPriority() == pFileInfo->GetExtraPriority() &&
pFileInfo1->GetPriority() > pFileInfo->GetPriority()) ||
(pFileInfo1->GetExtraPriority() > pFileInfo->GetExtraPriority())))
if (pFileInfo->GetArticles()->empty() && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
pFileInfo = pFileInfo1;
iFileNum = iNum;
g_pDiskState->LoadArticles(pFileInfo);
}
iNum++;
}
if (!pFileInfo)
{
// there are no more files for download
break;
}
if (pFileInfo->GetArticles()->empty() && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->LoadArticles(pFileInfo);
}
// check if the file has any articles left for download
for (FileInfo::Articles::iterator at = pFileInfo->GetArticles()->begin(); at != pFileInfo->GetArticles()->end(); at++)
{
pArticleInfo = *at;
if (pArticleInfo->GetStatus() == 0)
for (FileInfo::Articles::iterator at = pFileInfo->GetArticles()->begin(); at != pFileInfo->GetArticles()->end(); at++)
{
bOK = true;
break;
pArticleInfo = *at;
if (pArticleInfo->GetStatus() == 0)
{
return true;
}
}
}
if (!bOK)
{
// the file doesn't have any articles left for download, we mark the file as such
if (!pCheckedFiles)
{
int iArrSize = sizeof(bool) * m_DownloadQueue.GetFileQueue()->size();
pCheckedFiles = (bool*)malloc(iArrSize);
memset(pCheckedFiles, false, iArrSize);
}
pCheckedFiles[iFileNum] = true;
}
}
if (pCheckedFiles)
{
free(pCheckedFiles);
}
return bOK;
return false;
}
void QueueCoordinator::StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pArticleInfo, NNTPConnection* pConnection)
@@ -551,7 +465,6 @@ void QueueCoordinator::StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pA
BuildArticleFilename(pArticleDownloader, pFileInfo, pArticleInfo);
pArticleInfo->SetStatus(ArticleInfo::aiRunning);
pFileInfo->SetActiveDownloads(pFileInfo->GetActiveDownloads() + 1);
m_ActiveDownloads.push_back(pArticleDownloader);
pArticleDownloader->Start();
@@ -570,28 +483,17 @@ void QueueCoordinator::BuildArticleFilename(ArticleDownloader* pArticleDownloade
tmpname[1024-1] = '\0';
pArticleDownloader->SetTempFilename(tmpname);
snprintf(name, 1024, "%s%c%s [%i/%i]", pFileInfo->GetNZBInfo()->GetName(), (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
char szNZBNiceName[1024];
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
snprintf(name, 1024, "%s%c%s [%i/%i]", szNZBNiceName, (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
name[1024-1] = '\0';
pArticleDownloader->SetInfoName(name);
if (g_pOptions->GetDirectWrite())
{
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);
}
}
@@ -705,8 +607,6 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
}
}
pFileInfo->SetActiveDownloads(pFileInfo->GetActiveDownloads() - 1);
if (deleteFileObj)
{
bool fileDeleted = pFileInfo->GetDeleted();
@@ -767,9 +667,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);
}
}
@@ -801,25 +704,9 @@ bool QueueCoordinator::IsDupe(FileInfo* pFileInfo)
void QueueCoordinator::LogDebugInfo()
{
debug("--------------------------------------------");
debug("Dumping debug debug to log");
debug("Dumping debug info to log");
debug("--------------------------------------------");
debug(" SpeedMeter");
debug(" ----------");
float fSpeed = (float)(CalcCurrentDownloadSpeed() / 1024.0);
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
debug(" Speed: %f", fSpeed);
debug(" SpeedStartTime: %i", m_iSpeedStartTime);
debug(" SpeedTotalBytes: %i", m_iSpeedTotalBytes);
debug(" SpeedBytesIndex: %i", m_iSpeedBytesIndex);
debug(" AllBytes: %i", m_iAllBytes);
debug(" Time: %i", (int)time(NULL));
debug(" TimeDiff: %i", iTimeDiff);
for (int i=0; i < SPEEDMETER_SLOTS; i++)
{
debug(" Bytes[%i]: %i, Time[%i]: %i", i, m_iSpeedBytes[i], i, m_iSpeedTime[i]);
}
debug(" QueueCoordinator");
debug(" ----------------");
@@ -839,7 +726,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 +738,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();
@@ -873,7 +753,6 @@ void QueueCoordinator::ResetHangingDownloads()
error("Could not terminate hanging download %s", Util::BaseFileName(pArticleInfo->GetResultFilename()));
}
m_ActiveDownloads.erase(it);
pArticleDownloader->GetFileInfo()->SetActiveDownloads(pArticleDownloader->GetFileInfo()->GetActiveDownloads() - 1);
// it's not safe to destroy pArticleDownloader, because the state of object is unknown
delete pArticleDownloader;
it = m_ActiveDownloads.begin();
@@ -955,7 +834,9 @@ bool QueueCoordinator::SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* s
{
if (pNZBInfo->GetPostProcess())
{
error("Could not change category for %s. File in post-process-stage", pNZBInfo->GetName());
char szNZBNiceName[1024];
pNZBInfo->GetNiceNZBName(szNZBNiceName, 1024);
error("Could not change category for %s. File in post-process-stage", szNZBNiceName);
return false;
}
@@ -972,36 +853,6 @@ bool QueueCoordinator::SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* s
return bOK;
}
bool QueueCoordinator::SetQueueEntryNZBName(NZBInfo* pNZBInfo, const char* szName)
{
if (pNZBInfo->GetPostProcess())
{
error("Could not rename %s. File in post-process-stage", pNZBInfo->GetName());
return false;
}
if (strlen(szName) == 0)
{
error("Could not rename %s. The new name cannot be empty", pNZBInfo->GetName());
return false;
}
char szOldDestDir[1024];
strncpy(szOldDestDir, pNZBInfo->GetDestDir(), 1024);
szOldDestDir[1024-1] = '\0';
char szNZBNicename[1024];
NZBInfo::MakeNiceNZBName(szName, szNZBNicename, sizeof(szNZBNicename), false);
pNZBInfo->SetName(szNZBNicename);
pNZBInfo->BuildDestDirName();
bool bDirUnchanged = !strcmp(pNZBInfo->GetDestDir(), szOldDestDir);
bool bOK = bDirUnchanged || ArticleDownloader::MoveCompletedFiles(pNZBInfo, szOldDestDir);
return bOK;
}
/*
* NOTE: DownloadQueue must be locked prior to call of this function
*/
@@ -1009,7 +860,11 @@ bool QueueCoordinator::MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZB
{
if (pDestNZBInfo->GetPostProcess() || pSrcNZBInfo->GetPostProcess())
{
error("Could not merge %s and %s. File in post-process-stage", pDestNZBInfo->GetName(), pSrcNZBInfo->GetName());
char szDestNZBNiceName[1024];
pDestNZBInfo->GetNiceNZBName(szDestNZBNiceName, 1024);
char szSrcNZBNiceName[1024];
pSrcNZBInfo->GetNiceNZBName(szSrcNZBNiceName, 1024);
error("Could not merge %s and %s. File in post-process-stage", szDestNZBNiceName, szSrcNZBNiceName);
return false;
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -71,12 +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
Mutex m_mutexSpeed;
#endif
int m_iSpeedBytesIndex;
long long m_iAllBytes;
@@ -107,7 +101,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);
@@ -119,7 +113,6 @@ public:
bool GetStandBy() { return m_bStandBy; }
bool DeleteQueueEntry(FileInfo* pFileInfo);
bool SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* szCategory);
bool SetQueueEntryNZBName(NZBInfo* pNZBInfo, const char* szName);
bool MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZBInfo);
void DiscardDiskFile(FileInfo* pFileInfo);
QueueEditor* GetQueueEditor() { return &m_QueueEditor; }

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -36,7 +36,6 @@
#include <cctype>
#include <cstdio>
#include <sys/stat.h>
#include <set>
#ifndef WIN32
#include <unistd.h>
#include <sys/time.h>
@@ -111,7 +110,7 @@ void QueueEditor::PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause)
}
/*
* Removes entry
* Removes entry with index iEntry
* returns true if successful, false if operation is not possible
*/
void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
@@ -121,7 +120,7 @@ void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
}
/*
* Moves entry in the queue
* Moves entry identified with iID in the queue
* returns true if successful, false if operation is not possible
*/
void QueueEditor::MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, int iOffset)
@@ -149,23 +148,12 @@ void QueueEditor::MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
}
}
/*
* Set priority for entry
* returns true if successful, false if operation is not possible
*/
void QueueEditor::SetPriorityEntry(FileInfo* pFileInfo, const char* szPriority)
{
debug("Setting priority %s for file %s", szPriority, pFileInfo->GetFilename());
int iPriority = atoi(szPriority);
pFileInfo->SetPriority(iPriority);
}
bool QueueEditor::EditEntry(int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
{
IDList cIDList;
cIDList.clear();
cIDList.push_back(ID);
return EditList(&cIDList, NULL, mmID, bSmartOrder, eAction, iOffset, szText);
return EditList(&cIDList, bSmartOrder, eAction, iOffset, szText);
}
bool QueueEditor::LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
@@ -176,20 +164,11 @@ bool QueueEditor::LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bS
return InternEditList(pDownloadQueue, &cIDList, bSmartOrder, eAction, iOffset, szText);
}
bool QueueEditor::EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, bool bSmartOrder,
EEditAction eAction, int iOffset, const char* szText)
bool QueueEditor::EditList(IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText)
{
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
bool bOK = true;
if (pNameList)
{
pIDList = new IDList();
bOK = BuildIDListFromNameList(pDownloadQueue, pIDList, pNameList, eMatchMode, eAction);
}
bOK = bOK && (InternEditList(pDownloadQueue, pIDList, bSmartOrder, eAction, iOffset, szText) || eMatchMode == mmRegEx);
bool bOK = InternEditList(pDownloadQueue, pIDList, bSmartOrder, eAction, iOffset, szText);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
@@ -198,11 +177,6 @@ bool QueueEditor::EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMat
g_pQueueCoordinator->UnlockQueue();
if (pNameList)
{
delete pIDList;
}
return bOK;
}
@@ -229,10 +203,6 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
{
MergeGroups(pDownloadQueue, &cItemList);
}
else if (eAction == eaFileReorder)
{
ReorderFiles(pDownloadQueue, &cItemList);
}
else
{
for (ItemList::iterator it = cItemList.begin(); it != cItemList.end(); it++)
@@ -258,18 +228,10 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
DeleteEntry(pItem->m_pFileInfo);
break;
case eaFileSetPriority:
SetPriorityEntry(pItem->m_pFileInfo, szText);
break;
case eaGroupSetCategory:
SetNZBCategory(pItem->m_pFileInfo->GetNZBInfo(), szText);
break;
case eaGroupSetName:
SetNZBName(pItem->m_pFileInfo->GetNZBInfo(), szText);
break;
case eaGroupSetParameter:
SetNZBParameter(pItem->m_pFileInfo->GetNZBInfo(), szText);
break;
@@ -282,14 +244,12 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
case eaGroupMoveOffset:
case eaGroupPauseAllPars:
case eaGroupPauseExtraPars:
case eaGroupSetPriority:
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset, szText);
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset);
break;
case eaFilePauseAllPars:
case eaFilePauseExtraPars:
case eaGroupMerge:
case eaFileReorder:
// remove compiler warning "enumeration not handled in switch"
break;
}
@@ -405,79 +365,7 @@ void QueueEditor::PrepareList(DownloadQueue* pDownloadQueue, ItemList* pItemList
}
}
bool QueueEditor::BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction)
{
#ifndef HAVE_REGEX_H
if (eMatchMode == mmRegEx)
{
return false;
}
#endif
std::set<int> uniqueIDs;
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
{
const char* szName = *it;
RegEx *pRegEx = NULL;
if (eMatchMode == mmRegEx)
{
pRegEx = new RegEx(szName);
if (!pRegEx->IsValid())
{
delete pRegEx;
return false;
}
}
bool bFound = false;
for (FileQueue::iterator it2 = pDownloadQueue->GetFileQueue()->begin(); it2 != pDownloadQueue->GetFileQueue()->end(); it2++)
{
FileInfo* pFileInfo = *it2;
if (eAction < eaGroupMoveOffset)
{
// file action
char szFilename[MAX_PATH];
snprintf(szFilename, sizeof(szFilename) - 1, "%s/%s", pFileInfo->GetNZBInfo()->GetName(), Util::BaseFileName(pFileInfo->GetFilename()));
if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) &&
(uniqueIDs.find(pFileInfo->GetID()) == uniqueIDs.end()))
{
uniqueIDs.insert(pFileInfo->GetID());
pIDList->push_back(pFileInfo->GetID());
bFound = true;
}
}
else
{
// group action
const char *szFilename = pFileInfo->GetNZBInfo()->GetName();
if (((!pRegEx && !strcmp(szFilename, szName)) || (pRegEx && pRegEx->Match(szFilename))) &&
(uniqueIDs.find(pFileInfo->GetNZBInfo()->GetID()) == uniqueIDs.end()))
{
uniqueIDs.insert(pFileInfo->GetNZBInfo()->GetID());
pIDList->push_back(pFileInfo->GetID());
bFound = true;
}
}
}
if (pRegEx)
{
delete pRegEx;
}
if (!bFound && (eMatchMode == mmName))
{
return false;
}
}
return true;
}
bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset, const char* szText)
bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset)
{
IDList cIDList;
cIDList.clear();
@@ -543,13 +431,10 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
pFileInfo->GetNZBInfo()->SetCleanupDisk(CanCleanupDisk(pDownloadQueue, pFileInfo->GetNZBInfo()));
}
EEditAction GroupToFileMap[] = { (EEditAction)0, eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom,
eaFilePause, eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority, eaFileReorder,
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete,
eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority,
(EEditAction)0, (EEditAction)0, (EEditAction)0 };
EEditAction GroupToFileMap[] = { (EEditAction)0, eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars,
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars, (EEditAction)0, (EEditAction)0, (EEditAction)0 };
return InternEditList(pDownloadQueue, &cIDList, true, GroupToFileMap[eAction], iOffset, szText);
return InternEditList(pDownloadQueue, &cIDList, true, GroupToFileMap[eAction], iOffset, NULL);
}
void QueueEditor::BuildGroupList(DownloadQueue* pDownloadQueue, FileList* pGroupList)
@@ -648,11 +533,11 @@ void QueueEditor::AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pID
for (FileList::iterator it = cAffectedGroupList.begin(); it != cAffectedGroupList.end(); it++)
{
FileInfo* pFileInfo = *it;
AlignGroup(pDownloadQueue, pFileInfo->GetNZBInfo());
AlignGroup(pDownloadQueue, pFileInfo);
}
}
void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFileInfo)
{
FileInfo* pLastFileInfo = NULL;
unsigned int iLastNum = 0;
@@ -660,7 +545,7 @@ void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
while (iNum < pDownloadQueue->GetFileQueue()->size())
{
FileInfo* pFileInfo = pDownloadQueue->GetFileQueue()->at(iNum);
if (pFileInfo->GetNZBInfo() == pNZBInfo)
if (pFirstFileInfo->GetNZBInfo() == pFileInfo->GetNZBInfo())
{
if (pLastFileInfo && iNum - iLastNum > 1)
{
@@ -802,13 +687,6 @@ void QueueEditor::SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory)
g_pQueueCoordinator->SetQueueEntryNZBCategory(pNZBInfo, szCategory);
}
void QueueEditor::SetNZBName(NZBInfo* pNZBInfo, const char* szName)
{
debug("QueueEditor: renaming '%s' to '%s'", Util::BaseFileName(pNZBInfo->GetFilename()), szName);
g_pQueueCoordinator->SetQueueEntryNZBName(pNZBInfo, szName);
}
/**
* Check if deletion of already downloaded files is possible (when nzb id deleted from queue).
* The deletion is most always possible, except the case if all remaining files in queue
@@ -854,55 +732,18 @@ void QueueEditor::MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList
delete pItem;
}
// align group
AlignGroup(pDownloadQueue, pDestItem->m_pFileInfo->GetNZBInfo());
delete pDestItem;
}
void QueueEditor::ReorderFiles(DownloadQueue* pDownloadQueue, ItemList* pItemList)
{
if (pItemList->size() == 0)
// align group ("AlignGroup" needs the first file item as parameter)
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
return;
}
EditItem* pFirstItem = pItemList->front();
NZBInfo* pNZBInfo = pFirstItem->m_pFileInfo->GetNZBInfo();
unsigned int iInsertPos = 0;
// find first file of the group
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (pFileInfo->GetNZBInfo() == pNZBInfo)
FileInfo* pFileInfo = *it;
if (pFileInfo->GetNZBInfo() == pDestItem->m_pFileInfo->GetNZBInfo())
{
AlignGroup(pDownloadQueue, pFileInfo);
break;
}
iInsertPos++;
}
// now can reorder
for (ItemList::iterator it = pItemList->begin(); it != pItemList->end(); it++)
{
EditItem* pItem = *it;
FileInfo* pFileInfo = pItem->m_pFileInfo;
// move file item
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo1 = *it;
if (pFileInfo1 == pFileInfo)
{
pDownloadQueue->GetFileQueue()->erase(it);
pDownloadQueue->GetFileQueue()->insert(pDownloadQueue->GetFileQueue()->begin() + iInsertPos, pFileInfo);
iInsertPos++;
break;
}
}
delete pItem;
}
delete pDestItem;
}
void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
@@ -920,7 +761,7 @@ void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
}
else
{
error("Could not set nzb parameter for %s: invalid argument: %s", pNZBInfo->GetName(), szParamString);
error("Could not set nzb parameter for %s: invalid argument: %s", Util::BaseFileName(pNZBInfo->GetFilename()), szParamString);
}
free(szStr);

View File

@@ -1,7 +1,7 @@
/*
* This file if part of nzbget
*
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -43,8 +43,6 @@ public:
eaFileDelete,
eaFilePauseAllPars,
eaFilePauseExtraPars,
eaFileSetPriority,
eaFileReorder,
eaGroupMoveOffset, // move to m_iOffset relative to the current position in queue
eaGroupMoveTop,
eaGroupMoveBottom,
@@ -53,18 +51,9 @@ public:
eaGroupDelete,
eaGroupPauseAllPars,
eaGroupPauseExtraPars,
eaGroupSetPriority,
eaGroupSetCategory,
eaGroupMerge,
eaGroupSetParameter,
eaGroupSetName
};
enum EMatchMode
{
mmID = 1,
mmName,
mmRegEx
eaGroupSetParameter
};
private:
@@ -85,32 +74,28 @@ private:
int FindFileInfoEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo);
bool InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
void PrepareList(DownloadQueue* pDownloadQueue, ItemList* pItemList, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset);
bool BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction);
bool EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset, const char* szText);
bool EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, EEditAction eAction, int iOffset);
void BuildGroupList(DownloadQueue* pDownloadQueue, FileList* pGroupList);
void AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, int iOffset);
bool ItemExists(FileList* pFileList, FileInfo* pFileInfo);
void AlignGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFileInfo);
void PauseParsInGroups(ItemList* pItemList, bool bExtraParsOnly);
void PausePars(FileList* pFileList, bool bExtraParsOnly);
void SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory);
void SetNZBName(NZBInfo* pNZBInfo, const char* szName);
bool CanCleanupDisk(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList);
void ReorderFiles(DownloadQueue* pDownloadQueue, ItemList* pItemList);
void SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString);
void PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause);
void DeleteEntry(FileInfo* pFileInfo);
void MoveEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, int iOffset);
void SetPriorityEntry(FileInfo* pFileInfo, const char* szPriority);
public:
QueueEditor();
~QueueEditor();
bool EditEntry(int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
bool EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
bool EditList(IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
bool LockedEditEntry(DownloadQueue* pDownloadQueue, int ID, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);
bool LockedEditList(DownloadQueue* pDownloadQueue, IDList* pIDList, bool bSmartOrder, EEditAction eAction, int iOffset, const char* szText);

166
README
View File

@@ -2,10 +2,6 @@
NZBGet ReadMe
=====================================
This is a short documentation. For more information please
visit NZBGet home page at
http://nzbget.sourceforge.net
Contents
--------
1. About NZBGet
@@ -33,9 +29,6 @@ In server/client mode NZBGet runs as server in background.
Then you use client to send requests to server. The sample requests
are: download nzb-file, list files in queue, etc.
There is also a built-in web-interface. The server has RPC-support
and can be controlled from third party applications too.
Standalone-tool, server and client are all contained in only one
executable file "nzbget". The mode in which the program works
depends on command-line parameters passed to the program.
@@ -48,12 +41,13 @@ NZBGet is written in C++ and was initialy developed on Linux.
It was ported to Windows later and tested for compatibility with
several POSIX-OS'es.
It should run at least on:
- Linux Debian 5.0 on x86;
- Linux with uClibc on MIPSEL and ARM;
- OpenBSD 5.0 on x86;
- Mac OS X 10.7 Lion on x64;
- Windows XP SP3 on x86 and Windows 7 on x64.
The current version (0.7.0) should run at least on:
- Linux Debian 4.0 on x86;
- Linux with uClibc and BusyBox on MIPSEL and ARM;
- FreeBSD 7.0 on x86;
- OpenSolaris 2008.11 on x86;
- Mac OS X;
- Windows XP SP2 on x86.
Clients and servers running on different OS'es may communicate with
each other. For example, you can use NZBGet as client on Windows to
@@ -95,9 +89,6 @@ And the following libraries are optional:
or
- OpenSSL (http://www.openssl.org)
- for gzip support in web-server and web-client (enabled by default):
- zlib (http://www.zlib.net)
All these libraries are included in modern Linux distributions and
should be available as installable packages. Please note that you also
need the developer packages for these libraries too, they package names
@@ -108,41 +99,24 @@ download the libraries at the given URLs and compile them (see hints below).
4. Installation on POSIX
=====================================
Installation from the source distribution archive (nzbget-VERSION.tar.gz):
Well, the usual stuff:
- untar the nzbget-source via
tar -zxf nzbget-VERSION.tar.gz
- change into nzbget-directory via
cd nzbget-VERSION
- configure it via
./configure
(maybe you have to tell configure, where to find some libraries.
./configure --help is your friend!
also see "Configure-options" later)
- in a case you don't have root access or want to install the program
in your home directory use the configure parameter --prefix, e. g.:
./configure --prefix ~/usr
./configure --help is your friend!)
also see "Configure-options" later.)
- compile it via
make
- to install system wide become root via:
- become root via
su
- install it via:
- install it via
make install
- install configuration files into <prefix>/etc via:
make install-conf
(you can skip this step if you intend to store configuration
files in a non-standard location)
Configure-options
-----------------
You may run configure with additional arguments:
@@ -158,9 +132,6 @@ You may run configure with additional arguments:
--disable-tls - to make without TLS/SSL support. Use this option if
you can not neither GnuTLS nor OpenSSL.
--disable-gzip - to make without gzip support. Use this option
if you can not use zlib.
--enable-debug - to build in debug-mode, if you want to see and log
debug-messages.
@@ -274,27 +245,17 @@ in MS Visual C++ 2005 you should be able to compile NZBGet.
6. Configuration
=====================================
NZBGet needs a configuration file.
NZBGet needs a configuration-file to work properly.
An example configuration file is provided in "nzbget.conf", which
is installed into "<prefix>/share/nzbget" (where <prefix> depends on
system configuration and configure options - typically "/usr/local",
"/usr" or "/opt"). The installer adjusts the file according to your
system paths. If you have performed the installation step
"make install-conf" this file is already copied to "<prefix>/etc" and
NZBGet finds it automatically. If you install the program manually
from a binary archive you have to copy the file from "<prefix>/share/nzbget"
to one of the locations listed below.
Open the file in a text editor and modify it accodring to your needs.
You need to set at least the option "MAINDIR" and one news server in
configuration file. The file has comments on how to use each option.
You need to set at least the option "MAINDIR" and one newsserver in
configuration file. Have a look at the example in nzbget.conf.example,
it has comments on how to use each option.
The program looks for configuration file in following standard
locations (in this order):
On POSIX systems:
~/.nzbget
/etc/nzbget.conf
/usr/etc/nzbget.conf
@@ -422,89 +383,47 @@ Running client & server on seperate machines:
Since nzbget communicates via TCP/IP it's possible to have a server running on
one computer and adding downloads via a client on another computer.
Do this by setting the "ControlIP" option in the nzbget.conf file to point to the
Do this by setting the "serverip" option in the nzbget.conf file to point to the
IP of the server (default is localhost which means client and server runs on
same computer)
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
-----------------------
After the download of nzb-file is completed nzbget can call post-processing
script, defined in configuration file. See example configuration file for
the description of parameters passed to the script (option "PostProcess").
After the download of nzb-file is completed nzbget can call post-process-script,
defined in configuration file. See example configuration file for the
description of parameters passed to the script.
An example script for unraring of downloaded files is provided in file
"nzbget-postprocess.sh" installed into "<prefix>/bin". The script requires
configuration file "nzbget-postprocess.conf". If you have installed the
program with "make install" this file is copied to "<prefix>/etc",
where the post-processing script finds it automatically. If you install
the program manually from a binary archive you have to copy the file
from "<prefix>/share/nzbget" to the directory where you have put the
nzbget configuration file ("nzbget.conf").
Set the option "PostProcess" in "nzbget.conf" to point to the post-
processing script.
Additional usage instructions are included in "nzbget-postprocess.sh",
please open the file in a text editor to read them.
NOTE: The post-processing script "nzbget-postprocess.sh" is for
POSIX systems and will not work on Windows.
Web-interface
-------------
NZBGet has a built-in web-server providing the access to the program
functions via web-interface.
To activate web-interface set the option "WebDir" to the path with
web-interface files. If you install using "make install-conf" as
described above the option is set automatically. If you install using
binary files you should check if the option is set correctly.
To access web-interface from your web-browser use the server address
and port defined in NZBGet configuration file in options "ControlIP" and
"ControlPort". For example:
http://localhost:6789/
For login credentials type username "nzbget" (predefined and not changeable)
and the password from the option "ControlPassword" (default is tegbzn6789).
In a case your browser forget credentials, to prevent typing them each
time, there is a workaround - use URL in the form:
http://localhost:6789/nzbget:password/
Please note, that in this case the password is saved in a bookmark or in
browser history in plain text and is easy to find by persons having
access to your computer.
postprocess-example.sh. The usage instructions are included in the file,
please open the file in any text editor to read them.
NOTE: That example script is for POSIX systems (not for Windows).
=====================================
8. Authors
=====================================
NZBGet is developed and maintained by Andrey Prygunkov
NZBGet was initialiy written by Sven Henkel (sidddy@users.sourceforge.net).
Up to version 0.2.3 it was developed and maintained by Bo Cordes Petersen
(placebodk@users.sourceforge.net).
Beginning at version 0.3.0 the program is being developed by Andrei Prygounkov
(hugbug@users.sourceforge.net).
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.
Module TLS (TLS.c, TLS.h) is based on work by Martin Lambers (marlam@marlam.de).
=====================================
9. Copyright
@@ -524,19 +443,16 @@ 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
=====================================
If you encounter any problem, feel free to use the forum
If you encounter any problem, feel free to use forums on
nzbget.sourceforge.net/forum
sourceforge.net/projects/nzbget
or contact me at

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -46,7 +46,6 @@
#include "nzbget.h"
#include "RemoteClient.h"
#include "DownloadInfo.h"
#include "Options.h"
#include "Log.h"
#include "Util.h"
@@ -56,6 +55,7 @@ extern Options* g_pOptions;
RemoteClient::RemoteClient()
{
m_pConnection = NULL;
m_pNetAddress = NULL;
m_bVerbose = true;
/*
@@ -80,6 +80,11 @@ RemoteClient::~RemoteClient()
{
delete m_pConnection;
}
if (m_pNetAddress)
{
delete m_pNetAddress;
}
}
void RemoteClient::printf(const char * msg,...)
@@ -104,19 +109,13 @@ void RemoteClient::perror(const char * msg)
bool RemoteClient::InitConnection()
{
// Create a connection to the server
const char *szControlIP = g_pOptions->GetControlIP();
if (!strcmp(szControlIP, "0.0.0.0"))
{
szControlIP = "127.0.0.1";
}
m_pConnection = new Connection(szControlIP, g_pOptions->GetControlPort(), false);
m_pNetAddress = new NetAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
m_pConnection = new Connection(m_pNetAddress);
bool OK = m_pConnection->Connect();
if (!OK)
{
printf("Unable to send request to nzbserver at %s (port %i)\n", szControlIP, g_pOptions->GetControlPort());
printf("Unable to send request to nzbserver at %s (port %i)\n", g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
}
return OK;
}
@@ -126,7 +125,7 @@ void RemoteClient::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest,
pMessageBase->m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
pMessageBase->m_iType = htonl(iRequest);
pMessageBase->m_iStructSize = htonl(iSize);
strncpy(pMessageBase->m_szPassword, g_pOptions->GetControlPassword(), NZBREQUESTPASSWORDSIZE - 1);
strncpy(pMessageBase->m_szPassword, g_pOptions->GetServerPassword(), NZBREQUESTPASSWORDSIZE - 1);
pMessageBase->m_szPassword[NZBREQUESTPASSWORDSIZE - 1] = '\0';
}
@@ -138,22 +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");
free(buf);
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;
}
@@ -165,7 +177,7 @@ bool RemoteClient::ReceiveBoolResponse()
/*
* Sends a message to the running nzbget process.
*/
bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst)
{
// Read the file into the buffer
char* szBuffer = NULL;
@@ -182,8 +194,6 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
SNZBDownloadRequest DownloadRequest;
InitMessageBase(&DownloadRequest.m_MessageBase, eRemoteRequestDownload, sizeof(DownloadRequest));
DownloadRequest.m_bAddFirst = htonl(bAddFirst);
DownloadRequest.m_bAddPaused = htonl(bAddPaused);
DownloadRequest.m_iPriority = htonl(iPriority);
DownloadRequest.m_iTrailingDataLength = htonl(iLength);
strncpy(DownloadRequest.m_szFilename, szFilename, NZBREQUESTFILENAMESIZE - 1);
@@ -195,7 +205,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;
@@ -229,29 +239,23 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
SNZBListResponseNZBEntry* pListAnswer = (SNZBListResponseNZBEntry*) pBufPtr;
const char* szFileName = pBufPtr + sizeof(SNZBListResponseNZBEntry);
const char* szName = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen);
const char* szDestDir = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iNameLen);
const char* szCategory = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen);
const char* m_szQueuedFilename = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen);
const char* szDestDir = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen);
const char* szCategory = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) + ntohl(pListAnswer->m_iDestDirLen);
const char* m_szQueuedFilename = pBufPtr + sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) + ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen);
MatchedNZBInfo* pNZBInfo = new MatchedNZBInfo();
NZBInfo* pNZBInfo = new NZBInfo();
pNZBInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo)));
pNZBInfo->SetFilename(szFileName);
pNZBInfo->SetName(szName);
pNZBInfo->SetDestDir(szDestDir);
pNZBInfo->SetCategory(szCategory);
pNZBInfo->SetQueuedFilename(m_szQueuedFilename);
pNZBInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
pNZBInfo->AddReference();
pDownloadQueue->GetNZBInfoList()->Add(pNZBInfo);
pBufPtr += sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) +
ntohl(pListAnswer->m_iCategoryLen) + ntohl(pListAnswer->m_iQueuedFilenameLen);
ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen) +
ntohl(pListAnswer->m_iQueuedFilenameLen);
}
//read ppp entries
@@ -277,7 +281,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
const char* szSubject = pBufPtr + sizeof(SNZBListResponseFileEntry);
const char* szFileName = pBufPtr + sizeof(SNZBListResponseFileEntry) + ntohl(pListAnswer->m_iSubjectLen);
MatchedFileInfo* pFileInfo = new MatchedFileInfo();
FileInfo* pFileInfo = new FileInfo();
pFileInfo->SetID(ntohl(pListAnswer->m_iID));
pFileInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo)));
pFileInfo->SetRemainingSize(Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
@@ -285,9 +289,6 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
pFileInfo->SetSubject(szSubject);
pFileInfo->SetFilename(szFileName);
pFileInfo->SetFilenameConfirmed(ntohl(pListAnswer->m_bFilenameConfirmed));
pFileInfo->SetActiveDownloads(ntohl(pListAnswer->m_iActiveDownloads));
pFileInfo->SetPriority(ntohl(pListAnswer->m_iPriority));
pFileInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
@@ -303,7 +304,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
pDownloadQueue->GetNZBInfoList()->ReleaseAll();
}
bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPattern)
bool RemoteClient::RequestServerList(bool bFiles, bool bGroups)
{
if (!InitConnection()) return false;
@@ -311,15 +312,8 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
InitMessageBase(&ListRequest.m_MessageBase, eRemoteRequestList, sizeof(ListRequest));
ListRequest.m_bFileList = htonl(true);
ListRequest.m_bServerState = htonl(true);
ListRequest.m_iMatchMode = htonl(szPattern ? eRemoteMatchModeRegEx : eRemoteMatchModeID);
ListRequest.m_bMatchGroup = htonl(bGroups);
if (szPattern)
{
strncpy(ListRequest.m_szPattern, szPattern, NZBREQUESTFILENAMESIZE - 1);
ListRequest.m_szPattern[NZBREQUESTFILENAMESIZE-1] = '\0';
}
if (!m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)))
if (m_pConnection->Send((char*)(&ListRequest), sizeof(ListRequest)) < 0)
{
perror("m_pConnection->Send");
return false;
@@ -329,12 +323,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 +343,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;
@@ -351,13 +352,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
m_pConnection->Disconnect();
if (szPattern && !ListResponse.m_bRegExValid)
{
printf("Error in regular expression\n");
free(pBuf);
return false;
}
if (bFiles)
{
if (ntohl(ListResponse.m_iTrailingDataLength) == 0)
@@ -374,33 +368,17 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
long long lRemaining = 0;
long long lPaused = 0;
int iMatches = 0;
for (FileQueue::iterator it = cRemoteQueue.GetFileQueue()->begin(); it != cRemoteQueue.GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
char szPriority[100];
szPriority[0] = '\0';
if (pFileInfo->GetPriority() != 0)
{
sprintf(szPriority, "[%+i] ", pFileInfo->GetPriority());
}
char szCompleted[100];
szCompleted[0] = '\0';
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
{
sprintf(szCompleted, ", %i%s", (int)(100 - Util::Int64ToFloat(pFileInfo->GetRemainingSize()) * 100.0 / Util::Int64ToFloat(pFileInfo->GetSize())), "%");
}
char szThreads[100];
szThreads[0] = '\0';
if (pFileInfo->GetActiveDownloads() > 0)
{
sprintf(szThreads, ", %i thread%s", pFileInfo->GetActiveDownloads(), (pFileInfo->GetActiveDownloads() > 1 ? "s" : ""));
}
char szStatus[100];
if (pFileInfo->GetPaused())
{
@@ -412,30 +390,18 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
szStatus[0] = '\0';
lRemaining += pFileInfo->GetRemainingSize();
}
if (!szPattern || ((MatchedFileInfo*)pFileInfo)->m_bMatch)
{
printf("[%i] %s%s/%s (%.2f MB%s%s)%s\n", pFileInfo->GetID(), szPriority, pFileInfo->GetNZBInfo()->GetName(),
pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
szCompleted, szThreads, szStatus);
iMatches++;
}
char szNZBNiceName[1024];
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
printf("[%i] %s%c%s (%.2f MB%s)%s\n", pFileInfo->GetID(), szNZBNiceName, (int)PATH_SEPARATOR, pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0), szCompleted, szStatus);
delete pFileInfo;
}
if (iMatches == 0)
{
printf("No matches founds\n");
}
printf("-----------------------------------\n");
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
if (szPattern)
{
printf("Matches: %i\n", iMatches);
}
if (lPaused > 0)
{
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0),
@@ -467,7 +433,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
long long lRemaining = 0;
long long lPaused = 0;
int iMatches = 0;
for (GroupQueue::iterator it = cGroupQueue.begin(); it != cGroupQueue.end(); it++)
{
@@ -479,20 +444,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
char szPriority[100];
szPriority[0] = '\0';
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
{
if (pGroupInfo->GetMinPriority() == pGroupInfo->GetMaxPriority())
{
sprintf(szPriority, "[%+i] ", pGroupInfo->GetMinPriority());
}
else
{
sprintf(szPriority, "[%+i..%+i] ", pGroupInfo->GetMinPriority(), pGroupInfo->GetMaxPriority());
}
}
char szPaused[20];
szPaused[0] = '\0';
if (pGroupInfo->GetPausedSize() > 0)
@@ -503,6 +454,9 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
lPaused += pGroupInfo->GetPausedSize();
}
char szNZBNiceName[1024];
pGroupInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
char szCategory[1024];
szCategory[0] = '\0';
if (pGroupInfo->GetNZBInfo()->GetCategory() && strlen(pGroupInfo->GetNZBInfo()->GetCategory()) > 0)
@@ -510,13 +464,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
sprintf(szCategory, " (%s)", pGroupInfo->GetNZBInfo()->GetCategory());
}
char szThreads[100];
szThreads[0] = '\0';
if (pGroupInfo->GetActiveDownloads() > 0)
{
sprintf(szThreads, ", %i thread%s", pGroupInfo->GetActiveDownloads(), (pGroupInfo->GetActiveDownloads() > 1 ? "s" : ""));
}
char szParameters[1024];
szParameters[0] = '\0';
for (NZBParameterList::iterator it = pGroupInfo->GetNZBInfo()->GetParameters()->begin(); it != pGroupInfo->GetNZBInfo()->GetParameters()->end(); it++)
@@ -539,14 +486,9 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
strncat(szParameters, ")", 1024);
}
if (!szPattern || ((MatchedNZBInfo*)pGroupInfo->GetNZBInfo())->m_bMatch)
{
printf("[%i-%i] %s%s (%i file%s, %s%s%s)%s%s\n", pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), szPriority,
pGroupInfo->GetNZBInfo()->GetName(), pGroupInfo->GetRemainingFileCount(),
pGroupInfo->GetRemainingFileCount() > 1 ? "s" : "", szRemaining,
szPaused, szThreads, szCategory, szParameters);
iMatches++;
}
printf("[%i-%i] %s (%i file%s, %s%s)%s%s\n", pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), szNZBNiceName,
pGroupInfo->GetRemainingFileCount(), pGroupInfo->GetRemainingFileCount() > 1 ? "s" : "", szRemaining,
szPaused, szCategory, szParameters);
delete pGroupInfo;
}
@@ -556,17 +498,8 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
delete *it;
}
if (iMatches == 0)
{
printf("No matches founds\n");
}
printf("-----------------------------------\n");
printf("Groups: %i\n", cGroupQueue.size());
if (szPattern)
{
printf("Matches: %i\n", iMatches);
}
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
if (lPaused > 0)
{
@@ -680,7 +613,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 +623,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 +643,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 +706,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 +719,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 +747,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();
@@ -820,10 +760,9 @@ bool RemoteClient::RequestServerDumpDebug()
return OK;
}
bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder)
bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText, int* pIDList, int iIDCount, bool bSmartOrder)
{
if ((iIDCount <= 0 || pIDList == NULL) && (pNameList == NULL || pNameList->size() == 0))
if (iIDCount <= 0 || pIDList == NULL)
{
printf("File(s) not specified\n");
return false;
@@ -831,38 +770,18 @@ bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset
if (!InitConnection()) return false;
int iIDLength = sizeof(int32_t) * iIDCount;
int iNameCount = 0;
int iNameLength = 0;
if (pNameList && pNameList->size() > 0)
{
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
{
const char *szName = *it;
iNameLength += strlen(szName) + 1;
iNameCount++;
}
// align size to 4-bytes, needed by ARM-processor (and may be others)
iNameLength += iNameLength % 4 > 0 ? 4 - iNameLength % 4 : 0;
}
int iTextLen = szText ? strlen(szText) + 1 : 0;
// align size to 4-bytes, needed by ARM-processor (and may be others)
iTextLen += iTextLen % 4 > 0 ? 4 - iTextLen % 4 : 0;
int iLength = iTextLen + iIDLength + iNameLength;
int iLength = sizeof(int32_t) * iIDCount + iTextLen;
SNZBEditQueueRequest EditQueueRequest;
InitMessageBase(&EditQueueRequest.m_MessageBase, eRemoteRequestEditQueue, sizeof(EditQueueRequest));
EditQueueRequest.m_iAction = htonl(iAction);
EditQueueRequest.m_iMatchMode = htonl(iMatchMode);
EditQueueRequest.m_iOffset = htonl((int)iOffset);
EditQueueRequest.m_bSmartOrder = htonl(bSmartOrder);
EditQueueRequest.m_iTextLen = htonl(iTextLen);
EditQueueRequest.m_iNrTrailingIDEntries = htonl(iIDCount);
EditQueueRequest.m_iNrTrailingNameEntries = htonl(iNameCount);
EditQueueRequest.m_iTrailingNameEntriesLen = htonl(iNameLength);
EditQueueRequest.m_iNrTrailingEntries = htonl(iIDCount);
EditQueueRequest.m_iTrailingDataLength = htonl(iLength);
char* pTrailingData = (char*)malloc(iLength);
@@ -878,21 +797,9 @@ bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset
{
pIDs[i] = htonl(pIDList[i]);
}
if (iNameCount > 0)
{
char *pNames = pTrailingData + iTextLen + iIDLength;
for (NameList::iterator it = pNameList->begin(); it != pNameList->end(); it++)
{
const char *szName = *it;
int iLen = strlen(szName);
strncpy(pNames, szName, iLen + 1);
pNames += iLen + 1;
}
}
bool OK = false;
if (!m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)))
if (m_pConnection->Send((char*)(&EditQueueRequest), sizeof(EditQueueRequest)) < 0)
{
perror("m_pConnection->Send");
}
@@ -916,28 +823,7 @@ bool RemoteClient::RequestServerShutdown()
SNZBShutdownRequest ShutdownRequest;
InitMessageBase(&ShutdownRequest.m_MessageBase, eRemoteRequestShutdown, sizeof(ShutdownRequest));
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest));
if (OK)
{
OK = ReceiveBoolResponse();
}
else
{
perror("m_pConnection->Send");
}
m_pConnection->Disconnect();
return OK;
}
bool RemoteClient::RequestServerReload()
{
if (!InitConnection()) return false;
SNZBReloadRequest ReloadRequest;
InitMessageBase(&ReloadRequest.m_MessageBase, eRemoteRequestReload, sizeof(ReloadRequest));
bool OK = m_pConnection->Send((char*)(&ReloadRequest), sizeof(ReloadRequest));
bool OK = m_pConnection->Send((char*)(&ShutdownRequest), sizeof(ShutdownRequest)) >= 0;
if (OK)
{
OK = ReceiveBoolResponse();
@@ -958,7 +844,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 +865,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 +875,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 +895,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 +920,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 +956,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;
@@ -1074,16 +968,14 @@ bool RemoteClient::RequestWriteLog(int iKind, const char* szText)
return OK;
}
bool RemoteClient::RequestScan(bool bSyncMode)
bool RemoteClient::RequestScan()
{
if (!InitConnection()) return false;
SNZBScanRequest ScanRequest;
InitMessageBase(&ScanRequest.m_MessageBase, eRemoteRequestScan, sizeof(ScanRequest));
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 +996,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 +1006,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 +1026,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;
@@ -1150,33 +1049,27 @@ bool RemoteClient::RequestHistory()
{
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) pBufPtr;
HistoryInfo::EKind eKind = (HistoryInfo::EKind)ntohl(pListAnswer->m_iKind);
const char* szNicename = pBufPtr + sizeof(SNZBHistoryResponseEntry);
const char* szFileName = pBufPtr + sizeof(SNZBHistoryResponseEntry);
if (eKind == HistoryInfo::hkNZBInfo)
{
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
char szSize[20];
Util::FormatFileSize(szSize, sizeof(szSize), lSize);
char szNZBNiceName[1024];
NZBInfo::MakeNiceNZBName(szFileName, szNZBNiceName, 1024);
const char* szParStatusText[] = { "", ", Par failed", ", Par possible", ", Par successful" };
const char* szScriptStatusText[] = { "", ", Script status unknown", ", Script failed", ", Script successful" };
char szSize[20];
Util::FormatFileSize(szSize, sizeof(szSize), lSize);
printf("[%i] %s (%i files, %s%s%s)\n", ntohl(pListAnswer->m_iID), szNicename,
ntohl(pListAnswer->m_iFileCount), szSize,
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
}
else if (eKind == HistoryInfo::hkUrlInfo)
{
const char* szUrlStatusText[] = { "", "", "Url download successful", "Url download failed", "" };
const char* szParStatusText[] = { "", ", Par failed", ", Par possible", ", Par successful" };
const char* szScriptStatusText[] = { "", ", Script status unknown", ", Script failed", ", Script successful" };
printf("[%i] %s (%s)\n", ntohl(pListAnswer->m_iID), szNicename,
szUrlStatusText[ntohl(pListAnswer->m_iUrlStatus)]);
}
printf("[%i] %s (%i files, %s%s%s)\n", ntohl(pListAnswer->m_iID), szNZBNiceName,
ntohl(pListAnswer->m_iFileCount), szSize,
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
pBufPtr += sizeof(SNZBHistoryResponseEntry) + ntohl(pListAnswer->m_iNicenameLen);
pBufPtr += sizeof(SNZBHistoryResponseEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen) +
ntohl(pListAnswer->m_iQueuedFilenameLen);
}
printf("-----------------------------------\n");
@@ -1187,117 +1080,3 @@ bool RemoteClient::RequestHistory()
return true;
}
bool RemoteClient::RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority)
{
if (!InitConnection()) return false;
SNZBDownloadUrlRequest DownloadUrlRequest;
InitMessageBase(&DownloadUrlRequest.m_MessageBase, eRemoteRequestDownloadUrl, sizeof(DownloadUrlRequest));
DownloadUrlRequest.m_bAddFirst = htonl(bAddFirst);
DownloadUrlRequest.m_bAddPaused = htonl(bAddPaused);
DownloadUrlRequest.m_iPriority = htonl(iPriority);
strncpy(DownloadUrlRequest.m_szURL, szURL, NZBREQUESTFILENAMESIZE - 1);
DownloadUrlRequest.m_szURL[NZBREQUESTFILENAMESIZE-1] = '\0';
DownloadUrlRequest.m_szCategory[0] = '\0';
if (szCategory)
{
strncpy(DownloadUrlRequest.m_szCategory, szCategory, NZBREQUESTFILENAMESIZE - 1);
}
DownloadUrlRequest.m_szCategory[NZBREQUESTFILENAMESIZE-1] = '\0';
DownloadUrlRequest.m_szNZBFilename[0] = '\0';
if (szNZBFilename)
{
strncpy(DownloadUrlRequest.m_szNZBFilename, szNZBFilename, NZBREQUESTFILENAMESIZE - 1);
}
DownloadUrlRequest.m_szNZBFilename[NZBREQUESTFILENAMESIZE-1] = '\0';
bool OK = m_pConnection->Send((char*)(&DownloadUrlRequest), sizeof(DownloadUrlRequest));
if (OK)
{
OK = ReceiveBoolResponse();
}
else
{
perror("m_pConnection->Send");
}
m_pConnection->Disconnect();
return OK;
}
bool RemoteClient::RequestUrlQueue()
{
if (!InitConnection()) return false;
SNZBUrlQueueRequest UrlQueueRequest;
InitMessageBase(&UrlQueueRequest.m_MessageBase, eRemoteRequestUrlQueue, sizeof(UrlQueueRequest));
if (!m_pConnection->Send((char*)(&UrlQueueRequest), sizeof(UrlQueueRequest)))
{
perror("m_pConnection->Send");
return false;
}
printf("Request sent\n");
// Now listen for the returned list
SNZBUrlQueueResponse UrlQueueResponse;
bool bRead = m_pConnection->Recv((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
if (!bRead ||
(int)ntohl(UrlQueueResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
ntohl(UrlQueueResponse.m_MessageBase.m_iStructSize) != sizeof(UrlQueueResponse))
{
printf("No response or invalid response (timeout, not nzbget-server or wrong nzbget-server version)\n");
return false;
}
char* pBuf = NULL;
if (ntohl(UrlQueueResponse.m_iTrailingDataLength) > 0)
{
pBuf = (char*)malloc(ntohl(UrlQueueResponse.m_iTrailingDataLength));
if (!m_pConnection->Recv(pBuf, ntohl(UrlQueueResponse.m_iTrailingDataLength)))
{
free(pBuf);
return false;
}
}
m_pConnection->Disconnect();
if (ntohl(UrlQueueResponse.m_iTrailingDataLength) == 0)
{
printf("Server has no urls queued for download\n");
}
else
{
printf("Url-Queue\n");
printf("-----------------------------------\n");
char* pBufPtr = (char*)pBuf;
for (unsigned int i = 0; i < ntohl(UrlQueueResponse.m_iNrTrailingEntries); i++)
{
SNZBUrlQueueResponseEntry* pUrlQueueAnswer = (SNZBUrlQueueResponseEntry*) pBufPtr;
const char* szURL = pBufPtr + sizeof(SNZBUrlQueueResponseEntry);
const char* szTitle = pBufPtr + sizeof(SNZBUrlQueueResponseEntry) + ntohl(pUrlQueueAnswer->m_iURLLen);
char szNiceName[1024];
UrlInfo::MakeNiceName(szURL, szTitle, szNiceName, 1024);
printf("[%i] %s\n", ntohl(pUrlQueueAnswer->m_iID), szNiceName);
pBufPtr += sizeof(SNZBUrlQueueResponseEntry) + ntohl(pUrlQueueAnswer->m_iURLLen) +
ntohl(pUrlQueueAnswer->m_iNZBFilenameLen);
}
free(pBuf);
printf("-----------------------------------\n");
}
return true;
}

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-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -35,19 +35,8 @@
class RemoteClient
{
private:
class MatchedNZBInfo: public NZBInfo
{
public:
bool m_bMatch;
};
class MatchedFileInfo: public FileInfo
{
public:
bool m_bMatch;
};
Connection* m_pConnection;
NetAddress* m_pNetAddress;
bool m_bVerbose;
bool InitConnection();
@@ -60,23 +49,19 @@ public:
RemoteClient();
~RemoteClient();
void SetVerbose(bool bVerbose) { m_bVerbose = bVerbose; };
bool RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
bool RequestServerList(bool bFiles, bool bGroups, const char* szPattern);
bool RequestServerDownload(const char* szFilename, const char* szCategory, bool bAddFirst);
bool RequestServerList(bool bFiles, bool bGroups);
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);
bool RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText, int* pIDList, int iIDCount, bool bSmartOrder);
bool RequestServerLog(int iLines);
bool RequestServerShutdown();
bool RequestServerReload();
bool RequestServerVersion();
bool RequestPostQueue();
bool RequestWriteLog(int iKind, const char* szText);
bool RequestScan(bool bSyncMode);
bool RequestScan();
bool RequestHistory();
bool RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
bool RequestUrlQueue();
void BuildFileList(SNZBListResponse* pListResponse, const char* pTrailingData, DownloadQueue* pDownloadQueue);
};

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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -44,21 +44,20 @@
#include "nzbget.h"
#include "RemoteServer.h"
#include "BinRpc.h"
#include "WebServer.h"
#include "XmlRpc.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_pNetAddress = new NetAddress(g_pOptions->GetServerIP(), g_pOptions->GetServerPort());
m_pConnection = NULL;
}
@@ -70,50 +69,32 @@ RemoteServer::~RemoteServer()
{
delete m_pConnection;
}
delete m_pNetAddress;
}
void RemoteServer::Run()
{
debug("Entering RemoteServer-loop");
#ifndef DISABLE_TLS
if (m_bTLS)
{
if (strlen(g_pOptions->GetSecureCert()) == 0 || !Util::FileExists(g_pOptions->GetSecureCert()))
{
error("Could not initialize TLS, secure certificate is not configured or the cert-file was not found. Check option <SecureCert>");
return;
}
if (strlen(g_pOptions->GetSecureKey()) == 0 || !Util::FileExists(g_pOptions->GetSecureKey()))
{
error("Could not initialize TLS, secure key is not configured or the key-file was not found. Check option <SecureKey>");
return;
}
}
#endif
while (!IsStopped())
{
bool bBind = true;
if (!m_pConnection)
{
m_pConnection = new Connection(g_pOptions->GetControlIP(),
m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(),
m_bTLS);
m_pConnection = new Connection(m_pNetAddress);
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 +109,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 +136,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,47 +169,62 @@ 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) ||
!strncmp((char*)&iSignature, "GET ", 4) ||
!strncmp((char*)&iSignature, "OPTI", 4))
else if (!strncmp((char*)&iSignature, "POST", 4) || !strncmp((char*)&iSignature, "GET ", 4))
{
// HTTP request received
// XML-RPC or JSON-RPC 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;
XmlRpcProcessor::EHttpMethod eHttpMethod = XmlRpcProcessor::hmGet;
char* szUrl = szBuffer;
if (!strncmp((char*)&iSignature, "POST", 4))
{
eHttpMethod = WebProcessor::hmPost;
eHttpMethod = XmlRpcProcessor::hmPost;
szUrl++;
}
if (!strncmp((char*)&iSignature, "OPTI", 4) && strlen(szUrl) > 4)
{
eHttpMethod = WebProcessor::hmOptions;
szUrl += 4;
}
if (char* p = strchr(szUrl, ' '))
{
*p = '\0';
}
debug("url: %s", szUrl);
XmlRpcProcessor::ERpcProtocol eProtocol = XmlRpcProcessor::rpUndefined;
if (!strcmp(szUrl, "/xmlrpc") || !strncmp(szUrl, "/xmlrpc/", 8))
{
eProtocol = XmlRpcProcessor::rpXmlRpc;
}
else if (!strcmp(szUrl, "/jsonrpc") || !strncmp(szUrl, "/jsonrpc/", 9))
{
eProtocol = XmlRpcProcessor::rpJsonRpc;
}
else if (!strcmp(szUrl, "/jsonprpc") || !strncmp(szUrl, "/jsonprpc/", 10))
{
eProtocol = XmlRpcProcessor::rpJsonPRpc;
}
WebProcessor processor;
processor.SetConnection(m_pConnection);
processor.SetUrl(szUrl);
processor.SetHttpMethod(eHttpMethod);
processor.Execute();
bOK = true;
if (eProtocol != XmlRpcProcessor::rpUndefined)
{
XmlRpcProcessor processor;
processor.SetConnection(&con);
processor.SetClientIP(ip);
processor.SetProtocol(eProtocol);
processor.SetHttpMethod(eHttpMethod);
processor.SetUrl(szUrl);
processor.Execute();
bOK = true;
}
}
}
if (!bOK)
{
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->GetServerPort(), 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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -28,16 +28,17 @@
#define REMOTESERVER_H
#include "Thread.h"
#include "NetAddress.h"
#include "Connection.h"
class RemoteServer : public Thread
{
private:
bool m_bTLS;
NetAddress* m_pNetAddress;
Connection* m_pConnection;
public:
RemoteServer(bool bTLS);
RemoteServer();
~RemoteServer();
virtual void Run();
virtual void Stop();
@@ -46,14 +47,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-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -36,8 +36,6 @@
#include <fstream>
#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <errno.h>
@@ -72,7 +70,6 @@ Scanner::Scanner()
debug("Creating Scanner");
m_bRequestedNZBDirScan = false;
m_bScanning = false;
m_iNZBDirInterval = g_pOptions->GetNzbDirInterval() * 1000;
m_iPass = 0;
m_iStepMSec = 0;
@@ -101,14 +98,7 @@ void Scanner::Check()
// check nzbdir every g_pOptions->GetNzbDirInterval() seconds or if requested
bool bCheckStat = !m_bRequestedNZBDirScan;
m_bRequestedNZBDirScan = false;
m_bScanning = true;
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
if (!bCheckStat && m_bNZBScript)
{
// if immediate scan requesten, we need second scan to process files extracted by NzbProcess-script
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
}
m_bScanning = false;
m_iNZBDirInterval = 0;
// if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval
@@ -280,14 +270,12 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
char* szNZBCategory = strdup(szCategory);
NZBParameterList* pParameterList = new NZBParameterList;
int iPriority = 0;
bool bExists = true;
if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed"))
{
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory,
&szNZBCategory, &iPriority, pParameterList);
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory, &szNZBCategory, pParameterList);
bExists = Util::FileExists(szFullFilename);
if (bExists && strcasecmp(szExtension, ".nzb"))
{
@@ -306,7 +294,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024);
if (bRenameOK)
{
AddFileToQueue(szRenamedName, szNZBCategory, iPriority, pParameterList);
AddFileToQueue(szRenamedName, szNZBCategory, pParameterList);
}
else
{
@@ -315,7 +303,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
}
else if (bExists && !strcasecmp(szExtension, ".nzb"))
{
AddFileToQueue(szFullFilename, szNZBCategory, iPriority, pParameterList);
AddFileToQueue(szFullFilename, szNZBCategory, pParameterList);
}
for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++)
@@ -328,7 +316,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
free(szNZBCategory);
}
void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, int iPriority, NZBParameterList* pParameterList)
void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList)
{
const char* szBasename = Util::BaseFileName(szFilename);
@@ -357,12 +345,6 @@ void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, int
pNZBFile->GetNZBInfo()->SetParameter(pParameter->GetName(), pParameter->GetValue());
}
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetPriority(iPriority);
}
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, false);
info("Collection %s added to queue", szBasename);
}
@@ -373,15 +355,9 @@ void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, int
}
}
void Scanner::ScanNZBDir(bool bSyncMode)
void Scanner::ScanNZBDir()
{
// ideally we should use mutex to access "m_bRequestedNZBDirScan",
// but it's not critical here.
m_bScanning = true;
m_bRequestedNZBDirScan = true;
while (bSyncMode && (m_bScanning || m_bRequestedNZBDirScan))
{
usleep(100 * 1000);
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -58,10 +58,9 @@ private:
int m_iPass;
int m_iStepMSec;
FileList m_FileList;
bool m_bScanning;
void CheckIncomingNZBs(const char* szDirectory, const char* szCategory, bool bCheckStat);
void AddFileToQueue(const char* szFilename, const char* szCategory, int iPriority, NZBParameterList* pParameterList);
void AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList);
void ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename, const char* szFullFilename, const char* szCategory);
bool CanProcessFile(const char* szFullFilename, bool bCheckStat);
void DropOldFiles();
@@ -70,7 +69,7 @@ public:
Scanner();
~Scanner();
void SetStepInterval(int iStepMSec) { m_iStepMSec = iStepMSec; }
void ScanNZBDir(bool bSyncMode);
void ScanNZBDir();
void Check();
};

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$

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-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -43,18 +43,14 @@
#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 char* (*szEnvironmentVariables)[];
extern DownloadQueueHolder* g_pDownloadQueueHolder;
static const int POSTPROCESS_PARCHECK_CURRENT = 91;
@@ -124,9 +120,9 @@ EnvironmentStrings::~EnvironmentStrings()
void EnvironmentStrings::InitFromCurrentProcess()
{
for (int i = 0; (*g_szEnvironmentVariables)[i]; i++)
for (int i = 0; (*szEnvironmentVariables)[i]; i++)
{
char* szVar = (*g_szEnvironmentVariables)[i];
char* szVar = (*szEnvironmentVariables)[i];
Append(strdup(szVar));
}
}
@@ -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,53 +593,32 @@ 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();
}
void PostScriptController::Run()
{
// the locking is needed for accessing the members of NZBInfo
// the locking is needed for accessing the memebers of NZBInfo
g_pDownloadQueueHolder->LockQueue();
char szNZBName[1024];
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 +644,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);
@@ -734,35 +663,35 @@ void PostScriptController::Run()
szArgs[8] = NULL;
SetArgs(szArgs, false);
SetEnvVar("NZBPP_NZBNAME", szNZBName);
SetEnvVar("NZBPP_DIRECTORY", szDestDir);
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 +703,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 +722,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 +750,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();
@@ -869,7 +806,7 @@ void PostScriptController::Stop()
}
void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBFilename,
const char* szDirectory, char** pCategory, int* iPriority, NZBParameterList* pParameterList)
const char* szDirectory, char** pCategory, NZBParameterList* pParameterList)
{
info("Executing nzb-process-script for %s", Util::BaseFileName(szNZBFilename));
@@ -877,7 +814,6 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
pScriptController->SetScript(szScript);
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameterList = pParameterList;
pScriptController->m_iPriority = iPriority;
char szInfoName[1024];
snprintf(szInfoName, 1024, "nzb-process-script for %s", Util::BaseFileName(szNZBFilename));
@@ -912,7 +848,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))
{
@@ -937,10 +873,6 @@ void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, co
}
free(szParam);
}
else if (!strncmp(szText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szText + 6 + 9);
}
else
{
error("Invalid command \"%s\" received from %s", szText, GetInfoName());
@@ -948,72 +880,10 @@ void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, co
}
else
{
ScriptController::AddMessage(eKind, bDefaultKind, szText);
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
}
}
void NZBAddedScriptController::StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript)
{
NZBAddedScriptController* pScriptController = new NZBAddedScriptController();
pScriptController->SetScript(szScript);
pScriptController->m_szNZBName = strdup(pNZBInfo->GetName());
pScriptController->SetEnvVar("NZBNA_NAME", pNZBInfo->GetName());
pScriptController->SetEnvVar("NZBNA_FILENAME", pNZBInfo->GetFilename());
pScriptController->SetEnvVar("NZBNA_CATEGORY", pNZBInfo->GetCategory());
int iLastID = 0;
int iMaxPriority = 0;
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (pFileInfo->GetNZBInfo() == pNZBInfo && ( pFileInfo->GetPriority() > iMaxPriority || iLastID == 0))
{
iMaxPriority = pFileInfo->GetPriority();
}
if (pFileInfo->GetNZBInfo() == pNZBInfo && pFileInfo->GetID() > iLastID)
{
iLastID = pFileInfo->GetID();
}
}
char buf[100];
snprintf(buf, 100, "%i", iLastID);
pScriptController->SetEnvVar("NZBNA_LASTID", buf);
snprintf(buf, 100, "%i", iMaxPriority);
pScriptController->SetEnvVar("NZBNA_PRIORITY", buf);
pScriptController->PrepareEnvParameters(pNZBInfo);
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
}
void NZBAddedScriptController::Run()
{
char szInfoName[1024];
snprintf(szInfoName, 1024, "nzb-added process-script for %s", m_szNZBName);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
info("Executing %s", szInfoName);
SetDefaultKindPrefix("NZB-Added Process: ");
SetDefaultLogKind(g_pOptions->GetProcessLogKind());
const char* szArgs[2];
szArgs[0] = GetScript();
szArgs[1] = NULL;
SetArgs(szArgs, false);
Execute();
free(m_szNZBName);
}
void SchedulerScriptController::StartScript(const char* szCommandLine)
{
char** argv = NULL;

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-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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,39 +101,29 @@ 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
{
private:
char** m_pCategory;
int* m_iPriority;
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);
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory, char** pCategory, NZBParameterList* pParameterList);
};
class NZBAddedScriptController : public Thread, public ScriptController
{
private:
char* m_szNZBName;
public:
virtual void Run();
static void StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript);
};
class SchedulerScriptController : public Thread, public ScriptController
class SchedulerScriptController : public Thread, ScriptController
{
public:
virtual void Run();

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -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");
}
}
@@ -237,7 +187,7 @@ void ServerPool::CloseUnusedConnections()
int tdiff = (int)(curtime - pConnection->GetFreeTime());
if (tdiff > CONNECTION_HOLD_SECODNS)
{
debug("Closing unused connection to %s", pConnection->GetHost());
debug("Closing unused connection to %s", pConnection->GetNewsServer()->GetHost());
pConnection->Disconnect();
}
}
@@ -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

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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();

1822
TLS.cpp
View File

File diff suppressed because it is too large Load Diff

206
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 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +21,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -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

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -98,48 +98,6 @@ void Mutex::Unlock()
}
#ifdef HAVE_SPINLOCK
SpinLock::SpinLock()
{
#ifdef WIN32
m_pSpinLockObj = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *)m_pSpinLockObj, 0x00FFFFFF);
#else
m_pSpinLockObj = (pthread_spinlock_t *)malloc(sizeof(pthread_spinlock_t));
pthread_spin_init((pthread_spinlock_t *)m_pSpinLockObj, PTHREAD_PROCESS_PRIVATE);
#endif
}
SpinLock::~SpinLock()
{
#ifdef WIN32
DeleteCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_destroy((pthread_spinlock_t *)m_pSpinLockObj);
#endif
free((void*)m_pSpinLockObj);
}
void SpinLock::Lock()
{
#ifdef WIN32
EnterCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_lock((pthread_spinlock_t *)m_pSpinLockObj);
#endif
}
void SpinLock::Unlock()
{
#ifdef WIN32
LeaveCriticalSection((CRITICAL_SECTION *)m_pSpinLockObj);
#else
pthread_spin_unlock((pthread_spinlock_t *)m_pSpinLockObj);
#endif
}
#endif
void Thread::Init()
{
debug("Initializing global thread data");

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -39,23 +39,6 @@ public:
void Unlock();
};
#ifdef HAVE_SPINLOCK
class SpinLock
{
private:
#ifdef WIN32
void* m_pSpinLockObj;
#else
volatile void* m_pSpinLockObj;
#endif
public:
SpinLock();
~SpinLock();
void Lock();
void Unlock();
};
#endif
class Thread
{

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

@@ -1,455 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
#include "nzbget.h"
#include "UrlCoordinator.h"
#include "Options.h"
#include "WebDownloader.h"
#include "DiskState.h"
#include "Log.h"
#include "Util.h"
#include "NZBFile.h"
#include "QueueCoordinator.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
extern QueueCoordinator* g_pQueueCoordinator;
UrlDownloader::UrlDownloader() : WebDownloader()
{
m_szCategory = NULL;
}
UrlDownloader::~UrlDownloader()
{
if (m_szCategory)
{
free(m_szCategory);
}
}
void UrlDownloader::ProcessHeader(const char* szLine)
{
WebDownloader::ProcessHeader(szLine);
if (!strncmp(szLine, "X-DNZB-Category: ", 17))
{
if (m_szCategory)
{
free(m_szCategory);
}
const char *szCat = szLine + 17;
int iCatLen = strlen(szCat);
// trim trailing CR/LF/spaces
while (iCatLen > 0 && (szCat[iCatLen-1] == '\n' || szCat[iCatLen-1] == '\r' || szCat[iCatLen-1] == ' ')) iCatLen--;
m_szCategory = (char*)malloc(iCatLen + 1);
strncpy(m_szCategory, szCat, iCatLen);
m_szCategory[iCatLen] = '\0';
debug("Category: %s", m_szCategory);
}
}
UrlCoordinator::UrlCoordinator()
{
debug("Creating UrlCoordinator");
m_bHasMoreJobs = true;
}
UrlCoordinator::~UrlCoordinator()
{
debug("Destroying UrlCoordinator");
// Cleanup
debug("Deleting UrlDownloaders");
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
delete *it;
}
m_ActiveDownloads.clear();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
{
delete *it;
}
pDownloadQueue->GetUrlQueue()->clear();
g_pQueueCoordinator->UnlockQueue();
debug("UrlCoordinator destroyed");
}
void UrlCoordinator::Run()
{
debug("Entering UrlCoordinator-loop");
int iResetCounter = 0;
while (!IsStopped())
{
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
{
// start download for next URL
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
if ((int)m_ActiveDownloads.size() < g_pOptions->GetUrlConnections())
{
UrlInfo* pUrlInfo;
bool bHasMoreUrls = GetNextUrl(pDownloadQueue, pUrlInfo);
bool bUrlDownloadsRunning = !m_ActiveDownloads.empty();
m_bHasMoreJobs = bHasMoreUrls || bUrlDownloadsRunning;
if (bHasMoreUrls && !IsStopped() && Thread::GetThreadCount() < g_pOptions->GetThreadLimit())
{
StartUrlDownload(pUrlInfo);
}
}
g_pQueueCoordinator->UnlockQueue();
}
int iSleepInterval = 100;
usleep(iSleepInterval * 1000);
iResetCounter += iSleepInterval;
if (iResetCounter >= 1000)
{
// this code should not be called too often, once per second is OK
ResetHangingDownloads();
iResetCounter = 0;
}
}
// waiting for downloads
debug("UrlCoordinator: waiting for Downloads to complete");
bool completed = false;
while (!completed)
{
g_pQueueCoordinator->LockQueue();
completed = m_ActiveDownloads.size() == 0;
g_pQueueCoordinator->UnlockQueue();
usleep(100 * 1000);
ResetHangingDownloads();
}
debug("UrlCoordinator: Downloads are completed");
debug("Exiting UrlCoordinator-loop");
}
void UrlCoordinator::Stop()
{
Thread::Stop();
debug("Stopping UrlDownloads");
g_pQueueCoordinator->LockQueue();
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
(*it)->Stop();
}
g_pQueueCoordinator->UnlockQueue();
debug("UrlDownloads are notified");
}
void UrlCoordinator::ResetHangingDownloads()
{
const int TimeOut = g_pOptions->GetTerminateTimeout();
if (TimeOut == 0)
{
return;
}
g_pQueueCoordinator->LockQueue();
time_t tm = ::time(NULL);
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
{
UrlDownloader* pUrlDownloader = *it;
if (tm - pUrlDownloader->GetLastUpdateTime() > TimeOut &&
pUrlDownloader->GetStatus() == UrlDownloader::adRunning)
{
UrlInfo* pUrlInfo = pUrlDownloader->GetUrlInfo();
debug("Terminating hanging download %s", pUrlDownloader->GetInfoName());
if (pUrlDownloader->Terminate())
{
error("Terminated hanging download %s", pUrlDownloader->GetInfoName());
pUrlInfo->SetStatus(UrlInfo::aiUndefined);
}
else
{
error("Could not terminate hanging download %s", pUrlDownloader->GetInfoName());
}
m_ActiveDownloads.erase(it);
// it's not safe to destroy pUrlDownloader, because the state of object is unknown
delete pUrlDownloader;
it = m_ActiveDownloads.begin();
continue;
}
it++;
}
g_pQueueCoordinator->UnlockQueue();
}
void UrlCoordinator::LogDebugInfo()
{
debug(" UrlCoordinator");
debug(" ----------------");
g_pQueueCoordinator->LockQueue();
debug(" Active Downloads: %i", m_ActiveDownloads.size());
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
UrlDownloader* pUrlDownloader = *it;
pUrlDownloader->LogDebugInfo();
}
g_pQueueCoordinator->UnlockQueue();
}
void UrlCoordinator::AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst)
{
debug("Adding NZB-URL to queue");
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
pDownloadQueue->GetUrlQueue()->push_back(pUrlInfo);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
g_pQueueCoordinator->UnlockQueue();
}
/*
* Returns next URL for download.
*/
bool UrlCoordinator::GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo)
{
bool bOK = false;
for (UrlQueue::iterator at = pDownloadQueue->GetUrlQueue()->begin(); at != pDownloadQueue->GetUrlQueue()->end(); at++)
{
pUrlInfo = *at;
if (pUrlInfo->GetStatus() == 0)
{
bOK = true;
break;
}
}
return bOK;
}
void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
{
debug("Starting new UrlDownloader");
UrlDownloader* pUrlDownloader = new UrlDownloader();
pUrlDownloader->SetAutoDestroy(true);
pUrlDownloader->Attach(this);
pUrlDownloader->SetUrlInfo(pUrlInfo);
pUrlDownloader->SetURL(pUrlInfo->GetURL());
char tmp[1024];
pUrlInfo->GetName(tmp, 1024);
pUrlDownloader->SetInfoName(tmp);
snprintf(tmp, 1024, "%surl-%i.tmp", g_pOptions->GetTempDir(), pUrlInfo->GetID());
tmp[1024-1] = '\0';
pUrlDownloader->SetOutputFilename(tmp);
pUrlInfo->SetStatus(UrlInfo::aiRunning);
m_ActiveDownloads.push_back(pUrlDownloader);
pUrlDownloader->Start();
}
void UrlCoordinator::Update(Subject* Caller, void* Aspect)
{
debug("Notification from UrlDownloader received");
UrlDownloader* pUrlDownloader = (UrlDownloader*) Caller;
if ((pUrlDownloader->GetStatus() == WebDownloader::adFinished) ||
(pUrlDownloader->GetStatus() == WebDownloader::adFailed) ||
(pUrlDownloader->GetStatus() == WebDownloader::adRetry))
{
UrlCompleted(pUrlDownloader);
}
}
void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
{
debug("URL downloaded");
UrlInfo* pUrlInfo = pUrlDownloader->GetUrlInfo();
if (pUrlDownloader->GetStatus() == WebDownloader::adFinished)
{
pUrlInfo->SetStatus(UrlInfo::aiFinished);
}
else if (pUrlDownloader->GetStatus() == WebDownloader::adFailed)
{
pUrlInfo->SetStatus(UrlInfo::aiFailed);
}
else if (pUrlDownloader->GetStatus() == WebDownloader::adRetry)
{
pUrlInfo->SetStatus(UrlInfo::aiUndefined);
}
char filename[1024];
if (pUrlDownloader->GetOriginalFilename())
{
strncpy(filename, pUrlDownloader->GetOriginalFilename(), 1024);
filename[1024-1] = '\0';
}
else
{
strncpy(filename, Util::BaseFileName(pUrlInfo->GetURL()), 1024);
filename[1024-1] = '\0';
// TODO: decode URL escaping
}
Util::MakeValidFilename(filename, '_', false);
debug("Filename: [%s]", filename);
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
// delete Download from Queue
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
UrlDownloader* pa = *it;
if (pa == pUrlDownloader)
{
m_ActiveDownloads.erase(it);
break;
}
}
bool bDeleteObj = false;
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished || pUrlInfo->GetStatus() == UrlInfo::aiFailed)
{
// delete UrlInfo from Queue
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
{
UrlInfo* pa = *it;
if (pa == pUrlInfo)
{
pDownloadQueue->GetUrlQueue()->erase(it);
break;
}
}
bDeleteObj = true;
if (g_pOptions->GetKeepHistory() > 0 && pUrlInfo->GetStatus() == UrlInfo::aiFailed)
{
HistoryInfo* pHistoryInfo = new HistoryInfo(pUrlInfo);
pHistoryInfo->SetTime(time(NULL));
pDownloadQueue->GetHistoryList()->push_front(pHistoryInfo);
bDeleteObj = false;
}
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
}
g_pQueueCoordinator->UnlockQueue();
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished)
{
// add nzb-file to download queue
AddToNZBQueue(pUrlInfo, pUrlDownloader->GetOutputFilename(), filename, pUrlDownloader->GetCategory());
}
if (bDeleteObj)
{
delete pUrlInfo;
}
}
void UrlCoordinator::AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory)
{
info("Queue downloaded collection %s", szOriginalFilename);
NZBFile* pNZBFile = NZBFile::CreateFromFile(szTempFilename, pUrlInfo->GetCategory());
if (pNZBFile)
{
pNZBFile->GetNZBInfo()->SetName(NULL);
pNZBFile->GetNZBInfo()->SetFilename(pUrlInfo->GetNZBFilename() && strlen(pUrlInfo->GetNZBFilename()) > 0 ? pUrlInfo->GetNZBFilename() : szOriginalFilename);
if (strlen(pUrlInfo->GetCategory()) > 0)
{
pNZBFile->GetNZBInfo()->SetCategory(pUrlInfo->GetCategory());
}
else if (szOriginalCategory)
{
pNZBFile->GetNZBInfo()->SetCategory(szOriginalCategory);
}
pNZBFile->GetNZBInfo()->BuildDestDirName();
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetPriority(pUrlInfo->GetPriority());
pFileInfo->SetPaused(pUrlInfo->GetAddPaused());
}
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, pUrlInfo->GetAddTop());
delete pNZBFile;
info("Collection %s added to queue", szOriginalFilename);
}
else
{
error("Could not add downloaded collection %s to queue", szOriginalFilename);
}
}

View File

@@ -1,86 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef URLCOORDINATOR_H
#define URLCOORDINATOR_H
#include <deque>
#include <list>
#include <time.h>
#include "Thread.h"
#include "WebDownloader.h"
#include "DownloadInfo.h"
#include "Observer.h"
class UrlDownloader;
class UrlCoordinator : public Thread, public Observer, public Subject
{
public:
typedef std::list<UrlDownloader*> ActiveDownloads;
private:
ActiveDownloads m_ActiveDownloads;
bool m_bHasMoreJobs;
bool GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo);
void StartUrlDownload(UrlInfo* pUrlInfo);
void UrlCompleted(UrlDownloader* pUrlDownloader);
void ResetHangingDownloads();
void AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory);
public:
UrlCoordinator();
virtual ~UrlCoordinator();
virtual void Run();
virtual void Stop();
void Update(Subject* Caller, void* Aspect);
// Editing the queue
void AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst);
bool HasMoreJobs() { return m_bHasMoreJobs; }
void LogDebugInfo();
};
class UrlDownloader : public WebDownloader
{
private:
UrlInfo* m_pUrlInfo;
char* m_szCategory;
protected:
virtual void ProcessHeader(const char* szLine);
public:
UrlDownloader();
~UrlDownloader();
void SetUrlInfo(UrlInfo* pUrlInfo) { m_pUrlInfo = pUrlInfo; }
UrlInfo* GetUrlInfo() { return m_pUrlInfo; }
const char* GetCategory() { return m_szCategory; }
};
#endif

1268
Util.cpp
View File

File diff suppressed because it is too large Load Diff

131
Util.h
View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -64,26 +64,21 @@ public:
static char* BaseFileName(const char* filename);
static void NormalizePathSeparators(char* szPath);
static bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength);
static bool CreateSparseFile(const char* szFilename, int iSize);
static bool TruncateFile(const char* szFilename, int iSize);
static bool SetFileSize(const char* szFilename, int iSize);
static void MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSlashes);
static bool MoveFile(const char* szSrcFilename, const char* szDstFilename);
static bool FileExists(const char* szFilename);
static bool DirectoryExists(const char* szDirFilename);
static bool CreateDirectory(const char* szDirFilename);
static bool 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);
static long long FileSize(const char* szFilename);
static long long FreeDiskSize(const char* szPath);
static bool DirEmpty(const char* szDirFilename);
static bool RenameBak(const char* szFilename, const char* szBakPart, bool bRemoveOldExtension, char* szNewNameBuf, int iNewNameBufSize);
#ifndef WIN32
static bool ExpandHomePath(const char* szFilename, char* szBuffer, int iBufSize);
#endif
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
#endif
static void FormatFileSize(char* szBuffer, int iBufLen, long long lFileSize);
/*
@@ -110,27 +105,6 @@ public:
*/
static float Int64ToFloat(long long Int64);
static void TrimRight(char* szStr);
/*
* Returns program version and revision number as string formatted like "0.7.0-r295".
* If revision number is not available only version is returned ("0.7.0").
*/
static const char* VersionRevision() { return VersionRevisionBuf; };
/*
* Initialize buffer for program version and revision number.
* This function must be called during program initialization before any
* call to "VersionRevision()".
*/
static void InitVersionRevision();
static char VersionRevisionBuf[40];
};
class WebUtil
{
public:
static unsigned int DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer);
/*
@@ -181,98 +155,19 @@ public:
static const char* JsonNextValue(const char* szJsonText, int* pValueLength);
/*
* Unquote http quoted string.
* The string is decoded on the place overwriting the content of raw-data.
* Returns program version and revision number as string formatted like "0.7.0-r295".
* If revision number is not available only version is returned ("0.7.0").
*/
static void HttpUnquote(char* raw);
};
class URL
{
private:
char* m_szAddress;
char* m_szProtocol;
char* m_szUser;
char* m_szPassword;
char* m_szHost;
char* m_szResource;
int m_iPort;
bool m_bTLS;
bool m_bValid;
void ParseURL();
public:
URL(const char* szAddress);
~URL();
bool IsValid() { return m_bValid; }
const char* GetAddress() { return m_szAddress; }
const char* GetProtocol() { return m_szProtocol; }
const char* GetUser() { return m_szUser; }
const char* GetPassword() { return m_szPassword; }
const char* GetHost() { return m_szHost; }
const char* GetResource() { return m_szResource; }
int GetPort() { return m_iPort; }
bool GetTLS() { return m_bTLS; }
};
class RegEx
{
private:
void* m_pContext;
bool m_bValid;
public:
RegEx(const char *szPattern);
~RegEx();
bool IsValid() { return m_bValid; }
bool Match(const char *szStr);
};
#ifndef DISABLE_GZIP
class ZLib
{
public:
/*
* calculates the size required for output buffer
*/
static unsigned int GZipLen(int iInputBufferLength);
static const char* VersionRevision() { return VersionRevisionBuf; };
/*
* returns the size of bytes written to szOutputBuffer or 0 if the buffer is too small or an error occured.
* Initialize buffer for program version and revision number.
* This function must be called during program initialization before any
* call to "VersionRevision()".
*/
static unsigned int GZip(const void* szInputBuffer, int iInputBufferLength, void* szOutputBuffer, int iOutputBufferLength);
static void InitVersionRevision();
static char VersionRevisionBuf[40];
};
class GUnzipStream
{
public:
enum EStatus
{
zlError,
zlFinished,
zlOK
};
private:
void* m_pZStream;
void* m_pOutputBuffer;
int m_iBufferSize;
public:
GUnzipStream(int BufferSize);
~GUnzipStream();
/*
* set next memory block for uncompression
*/
void Write(const void *pInputBuffer, int iInputBufferLength);
/*
* get next uncompressed memory block.
* iOutputBufferLength - the size of uncompressed block. if it is "0" the next compressed block must be provided via "Write".
*/
EStatus Read(const void **pOutputBuffer, int *iOutputBufferLength);
};
#endif
#endif

View File

@@ -1,679 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#include <sys/time.h>
#endif
#include <sys/stat.h>
#include <errno.h>
#include "nzbget.h"
#include "WebDownloader.h"
#include "Log.h"
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
WebDownloader::WebDownloader()
{
debug("Creating WebDownloader");
m_szURL = NULL;
m_szOutputFilename = NULL;
m_pConnection = NULL;
m_szInfoName = NULL;
m_bConfirmedLength = false;
m_eStatus = adUndefined;
m_szOriginalFilename = NULL;
SetLastUpdateTimeNow();
}
WebDownloader::~WebDownloader()
{
debug("Destroying WebDownloader");
if (m_szURL)
{
free(m_szURL);
}
if (m_szInfoName)
{
free(m_szInfoName);
}
if (m_szOutputFilename)
{
free(m_szOutputFilename);
}
if (m_szOriginalFilename)
{
free(m_szOriginalFilename);
}
}
void WebDownloader::SetOutputFilename(const char* v)
{
m_szOutputFilename = strdup(v);
}
void WebDownloader::SetInfoName(const char* v)
{
m_szInfoName = strdup(v);
}
void WebDownloader::SetURL(const char * szURL)
{
m_szURL = strdup(szURL);
}
void WebDownloader::SetStatus(EStatus eStatus)
{
m_eStatus = eStatus;
Notify(NULL);
}
void WebDownloader::Run()
{
debug("Entering WebDownloader-loop");
SetStatus(adRunning);
int iRemainedDownloadRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
int iRemainedConnectRetries = iRemainedDownloadRetries > 10 ? iRemainedDownloadRetries : 10;
EStatus Status = adFailed;
while (!IsStopped() && iRemainedDownloadRetries > 0 && iRemainedConnectRetries > 0)
{
SetLastUpdateTimeNow();
Status = Download();
if ((((Status == adFailed) && (iRemainedDownloadRetries > 1)) ||
((Status == adConnectError) && (iRemainedConnectRetries > 1)))
&& !IsStopped() && !(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
{
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
int msec = 0;
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
{
usleep(100 * 1000);
msec += 100;
}
}
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
{
Status = adRetry;
break;
}
if (Status == adFinished || Status == adFatalError || Status == adNotFound)
{
break;
}
if (Status != adConnectError)
{
iRemainedDownloadRetries--;
}
else
{
iRemainedConnectRetries--;
}
}
if (Status != adFinished && Status != adRetry)
{
Status = adFailed;
}
if (Status == adFailed)
{
if (IsStopped())
{
detail("Download %s cancelled", m_szInfoName);
}
else
{
error("Download %s failed", m_szInfoName);
}
}
if (Status == adFinished)
{
detail("Download %s completed", m_szInfoName);
}
SetStatus(Status);
debug("Exiting WebDownloader-loop");
}
WebDownloader::EStatus WebDownloader::Download()
{
EStatus Status = adRunning;
URL url(m_szURL);
Status = CreateConnection(&url);
if (Status != adRunning)
{
return Status;
}
m_pConnection->SetSuppressErrors(false);
// connection
bool bConnected = m_pConnection->Connect();
if (!bConnected || IsStopped())
{
FreeConnection();
return adConnectError;
}
// Okay, we got a Connection. Now start downloading.
detail("Downloading %s", m_szInfoName);
SendHeaders(&url);
Status = DownloadHeaders();
if (Status == adRunning)
{
Status = DownloadBody();
}
if (IsStopped())
{
Status = adFailed;
}
FreeConnection();
if (Status != adFinished)
{
// Download failed, delete broken output file
remove(m_szOutputFilename);
}
return Status;
}
WebDownloader::EStatus WebDownloader::CreateConnection(URL *pUrl)
{
if (!pUrl->IsValid())
{
error("URL is not valid: %s", pUrl->GetAddress());
return adFatalError;
}
int iPort = pUrl->GetPort();
if (iPort == 0 && !strcasecmp(pUrl->GetProtocol(), "http"))
{
iPort = 80;
}
if (iPort == 0 && !strcasecmp(pUrl->GetProtocol(), "https"))
{
iPort = 443;
}
if (strcasecmp(pUrl->GetProtocol(), "http") && strcasecmp(pUrl->GetProtocol(), "https"))
{
error("Unsupported protocol in URL: %s", pUrl->GetAddress());
return adFatalError;
}
#ifdef DISABLE_TLS
if (!strcasecmp(pUrl->GetProtocol(), "https"))
{
error("Program was compiled without TLS/SSL-support. Cannot download using https protocol. URL: %s", pUrl->GetAddress());
return adFatalError;
}
#endif
bool bTLS = !strcasecmp(pUrl->GetProtocol(), "https");
m_pConnection = new Connection(pUrl->GetHost(), iPort, bTLS);
return adRunning;
}
void WebDownloader::SendHeaders(URL *pUrl)
{
char tmp[1024];
// retrieve file
snprintf(tmp, 1024, "GET %s HTTP/1.0\r\n", pUrl->GetResource());
tmp[1024-1] = '\0';
m_pConnection->WriteLine(tmp);
snprintf(tmp, 1024, "User-Agent: nzbget/%s\r\n", Util::VersionRevision());
tmp[1024-1] = '\0';
m_pConnection->WriteLine(tmp);
snprintf(tmp, 1024, "Host: %s\r\n", pUrl->GetHost());
tmp[1024-1] = '\0';
m_pConnection->WriteLine(tmp);
m_pConnection->WriteLine("Accept: */*\r\n");
#ifndef DISABLE_GZIP
m_pConnection->WriteLine("Accept-Encoding: gzip\r\n");
#endif
m_pConnection->WriteLine("Connection: close\r\n");
m_pConnection->WriteLine("\r\n");
}
WebDownloader::EStatus WebDownloader::DownloadHeaders()
{
EStatus Status = adRunning;
m_bConfirmedLength = false;
const int LineBufSize = 1024*10;
char* szLineBuf = (char*)malloc(LineBufSize);
m_iContentLen = -1;
bool bFirstLine = true;
m_bGZip = false;
// Headers
while (!IsStopped())
{
SetLastUpdateTimeNow();
int iLen = 0;
char* line = m_pConnection->ReadLine(szLineBuf, LineBufSize, &iLen);
if (bFirstLine)
{
Status = CheckResponse(szLineBuf);
if (Status != adRunning)
{
break;
}
bFirstLine = false;
}
// Have we encountered a timeout?
if (!line)
{
if (!IsStopped())
{
warn("URL %s failed: Unexpected end of file", m_szInfoName);
}
Status = adFailed;
break;
}
debug("Header: %s", line);
// detect body of response
if (*line == '\r' || *line == '\n')
{
if (m_iContentLen == -1 && !m_bGZip)
{
warn("URL %s: Content-Length is not submitted by server, cannot verify whether the file is complete", m_szInfoName);
}
break;
}
ProcessHeader(line);
}
free(szLineBuf);
return Status;
}
WebDownloader::EStatus WebDownloader::DownloadBody()
{
EStatus Status = adRunning;
m_pOutFile = NULL;
bool bEnd = false;
const int LineBufSize = 1024*10;
char* szLineBuf = (char*)malloc(LineBufSize);
int iWrittenLen = 0;
#ifndef DISABLE_GZIP
m_pGUnzipStream = NULL;
if (m_bGZip)
{
m_pGUnzipStream = new GUnzipStream(1024*10);
}
#endif
// Body
while (!IsStopped())
{
SetLastUpdateTimeNow();
char* szBuffer;
int iLen;
m_pConnection->ReadBuffer(&szBuffer, &iLen);
if (iLen == 0)
{
iLen = m_pConnection->TryRecv(szLineBuf, LineBufSize);
szBuffer = szLineBuf;
}
// Have we encountered a timeout?
if (iLen <= 0)
{
if (m_iContentLen == -1)
{
bEnd = true;
break;
}
if (!IsStopped())
{
warn("URL %s failed: Unexpected end of file", m_szInfoName);
}
Status = adFailed;
break;
}
// write to output file
if (!Write(szBuffer, iLen))
{
Status = adFatalError;
break;
}
iWrittenLen += iLen;
//detect end of file
if (iWrittenLen == m_iContentLen || (m_iContentLen == -1 && m_bGZip && m_bConfirmedLength))
{
bEnd = true;
break;
}
}
free(szLineBuf);
#ifndef DISABLE_GZIP
if (m_pGUnzipStream)
{
delete m_pGUnzipStream;
}
#endif
if (m_pOutFile)
{
fclose(m_pOutFile);
}
if (!bEnd && Status == adRunning && !IsStopped())
{
warn("URL %s failed: file incomplete", m_szInfoName);
Status = adFailed;
}
if (bEnd)
{
Status = adFinished;
}
return Status;
}
WebDownloader::EStatus WebDownloader::CheckResponse(const char* szResponse)
{
if (!szResponse)
{
if (!IsStopped())
{
warn("URL %s: Connection closed by remote host", m_szInfoName);
}
return adConnectError;
}
const char* szHTTPResponse = strchr(szResponse, ' ');
if (strncmp(szResponse, "HTTP", 4) || !szHTTPResponse)
{
warn("URL %s failed: %s", m_szInfoName, szResponse);
return adFailed;
}
szHTTPResponse++;
if (!strncmp(szHTTPResponse, "400", 3) || !strncmp(szHTTPResponse, "499", 3))
{
warn("URL %s failed: %s", m_szInfoName, szHTTPResponse);
return adConnectError;
}
else if (!strncmp(szHTTPResponse, "404", 3))
{
warn("URL %s failed: %s", m_szInfoName, szHTTPResponse);
return adNotFound;
}
else if (!strncmp(szHTTPResponse, "200", 3))
{
// OK
return adRunning;
}
else
{
// unknown error, no special handling
warn("URL %s failed: %s", m_szInfoName, szResponse);
return adFailed;
}
}
void WebDownloader::ProcessHeader(const char* szLine)
{
if (!strncmp(szLine, "Content-Length: ", 16))
{
m_iContentLen = atoi(szLine + 16);
m_bConfirmedLength = true;
}
if (!strncmp(szLine, "Content-Encoding: gzip", 22))
{
m_bGZip = true;
}
if (!strncmp(szLine, "Content-Disposition: ", 21))
{
ParseFilename(szLine);
}
}
void WebDownloader::ParseFilename(const char* szContentDisposition)
{
// Examples:
// Content-Disposition: attachment; filename="fname.ext"
// Content-Disposition: attachement;filename=fname.ext
// Content-Disposition: attachement;filename=fname.ext;
const char *p = strstr(szContentDisposition, "filename");
if (!p)
{
return;
}
p = strchr(p, '=');
if (!p)
{
return;
}
p++;
while (*p == ' ') p++;
char fname[1024];
strncpy(fname, p, 1024);
fname[1024-1] = '\0';
char *pe = fname + strlen(fname) - 1;
while ((*pe == ' ' || *pe == '\n' || *pe == '\r' || *pe == ';') && pe > fname) {
*pe = '\0';
pe--;
}
WebUtil::HttpUnquote(fname);
if (m_szOriginalFilename)
{
free(m_szOriginalFilename);
}
m_szOriginalFilename = strdup(Util::BaseFileName(fname));
debug("OriginalFilename: %s", m_szOriginalFilename);
}
bool WebDownloader::Write(void* pBuffer, int iLen)
{
if (!m_pOutFile && !PrepareFile())
{
return false;
}
#ifndef DISABLE_GZIP
if (m_bGZip)
{
m_pGUnzipStream->Write(pBuffer, iLen);
const void *pOutBuf;
int iOutLen = 1;
while (iOutLen > 0)
{
GUnzipStream::EStatus eGZStatus = m_pGUnzipStream->Read(&pOutBuf, &iOutLen);
if (eGZStatus == GUnzipStream::zlError)
{
error("URL %s: GUnzip failed", m_szInfoName);
return false;
}
if (iOutLen > 0 && fwrite(pOutBuf, 1, iOutLen, m_pOutFile) <= 0)
{
return false;
}
if (eGZStatus == GUnzipStream::zlFinished)
{
m_bConfirmedLength = true;
return true;
}
}
return true;
}
else
#endif
return fwrite(pBuffer, 1, iLen, m_pOutFile) > 0;
}
bool WebDownloader::PrepareFile()
{
// prepare file for writing
const char* szFilename = m_szOutputFilename;
m_pOutFile = fopen(szFilename, "wb");
if (!m_pOutFile)
{
error("Could not %s file %s", "create", szFilename);
return false;
}
if (g_pOptions->GetWriteBufferSize() > 0)
{
setvbuf(m_pOutFile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
}
return true;
}
void WebDownloader::LogDebugInfo()
{
char szTime[50];
#ifdef HAVE_CTIME_R_3
ctime_r(&m_tLastUpdateTime, szTime, 50);
#else
ctime_r(&m_tLastUpdateTime, szTime);
#endif
debug(" Web-Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(m_szOutputFilename));
}
void WebDownloader::Stop()
{
debug("Trying to stop WebDownloader");
Thread::Stop();
m_mutexConnection.Lock();
if (m_pConnection)
{
m_pConnection->SetSuppressErrors(true);
m_pConnection->Cancel();
}
m_mutexConnection.Unlock();
debug("WebDownloader stopped successfully");
}
bool WebDownloader::Terminate()
{
Connection* pConnection = m_pConnection;
bool terminated = Kill();
if (terminated && pConnection)
{
debug("Terminating connection");
pConnection->SetSuppressErrors(true);
pConnection->Cancel();
pConnection->Disconnect();
delete pConnection;
}
return terminated;
}
void WebDownloader::FreeConnection()
{
if (m_pConnection)
{
debug("Releasing connection");
m_mutexConnection.Lock();
if (m_pConnection->GetStatus() == Connection::csCancelled)
{
m_pConnection->Disconnect();
}
delete m_pConnection;
m_pConnection = NULL;
m_mutexConnection.Unlock();
}
}

View File

@@ -1,103 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef WEBDOWNLOADER_H
#define WEBDOWNLOADER_H
#include <time.h>
#include "Observer.h"
#include "Thread.h"
#include "Connection.h"
#include "Util.h"
class WebDownloader : public Thread, public Subject
{
public:
enum EStatus
{
adUndefined,
adRunning,
adFinished,
adFailed,
adRetry,
adNotFound,
adConnectError,
adFatalError
};
private:
char* m_szURL;
char* m_szOutputFilename;
Connection* m_pConnection;
Mutex m_mutexConnection;
EStatus m_eStatus;
time_t m_tLastUpdateTime;
char* m_szInfoName;
FILE* m_pOutFile;
int m_iContentLen;
bool m_bConfirmedLength;
char* m_szOriginalFilename;
bool m_bGZip;
#ifndef DISABLE_GZIP
GUnzipStream* m_pGUnzipStream;
#endif
void SetStatus(EStatus eStatus);
bool Write(void* pBuffer, int iLen);
bool PrepareFile();
void FreeConnection();
EStatus CheckResponse(const char* szResponse);
EStatus Download();
EStatus CreateConnection(URL *pUrl);
void ParseFilename(const char* szContentDisposition);
void SendHeaders(URL *pUrl);
EStatus DownloadHeaders();
EStatus DownloadBody();
protected:
virtual void ProcessHeader(const char* szLine);
public:
WebDownloader();
~WebDownloader();
EStatus GetStatus() { return m_eStatus; }
virtual void Run();
virtual void Stop();
bool Terminate();
void SetInfoName(const char* v);
const char* GetInfoName() { return m_szInfoName; }
void SetURL(const char* szURL);
const char* GetOutputFilename() { return m_szOutputFilename; }
void SetOutputFilename(const char* v);
time_t GetLastUpdateTime() { return m_tLastUpdateTime; }
void SetLastUpdateTimeNow() { m_tLastUpdateTime = ::time(NULL); }
bool GetConfirmedLength() { return m_bConfirmedLength; }
const char* GetOriginalFilename() { return m_szOriginalFilename; }
void LogDebugInfo();
};
#endif

View File

@@ -1,481 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#ifndef WIN32
#include <unistd.h>
#endif
#include "nzbget.h"
#include "WebServer.h"
#include "XmlRpc.h"
#include "Log.h"
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
static const char* ERR_HTTP_BAD_REQUEST = "400 Bad Request";
static const char* ERR_HTTP_NOT_FOUND = "404 Not Found";
static const char* ERR_HTTP_SERVICE_UNAVAILABLE = "503 Service Unavailable";
static const int MAX_UNCOMPRESSED_SIZE = 500;
//*****************************************************************
// WebProcessor
WebProcessor::WebProcessor()
{
m_pConnection = NULL;
m_szRequest = NULL;
m_szUrl = NULL;
m_szOrigin = NULL;
}
WebProcessor::~WebProcessor()
{
if (m_szRequest)
{
free(m_szRequest);
}
if (m_szUrl)
{
free(m_szUrl);
}
if (m_szOrigin)
{
free(m_szOrigin);
}
}
void WebProcessor::SetUrl(const char* szUrl)
{
m_szUrl = strdup(szUrl);
}
void WebProcessor::Execute()
{
m_bGZip =false;
char szAuthInfo[1024];
szAuthInfo[0] = '\0';
// reading http header
char szBuffer[1024];
int iContentLen = 0;
while (char* p = m_pConnection->ReadLine(szBuffer, sizeof(szBuffer), NULL))
{
if (char* pe = strrchr(p, '\r')) *pe = '\0';
debug("header=%s", p);
if (!strncasecmp(p, "Content-Length: ", 16))
{
iContentLen = atoi(p + 16);
}
if (!strncasecmp(p, "Authorization: Basic ", 21))
{
char* szAuthInfo64 = p + 21;
if (strlen(szAuthInfo64) > sizeof(szAuthInfo))
{
error("invalid-request: auth-info too big");
return;
}
szAuthInfo[WebUtil::DecodeBase64(szAuthInfo64, 0, szAuthInfo)] = '\0';
}
if (!strncasecmp(p, "Accept-Encoding: ", 17))
{
m_bGZip = strstr(p, "gzip");
}
if (!strncasecmp(p, "Origin: ", 8))
{
m_szOrigin = strdup(p + 8);
}
if (*p == '\0')
{
break;
}
}
debug("URL=%s", m_szUrl);
debug("Authorization=%s", szAuthInfo);
if (m_eHttpMethod == hmPost && iContentLen <= 0)
{
error("invalid-request: content length is 0");
return;
}
if (m_eHttpMethod == hmOptions)
{
SendOptionsResponse();
return;
}
// remove subfolder "nzbget" from the path (if exists)
// http://localhost:6789/nzbget/username:password/jsonrpc -> http://localhost:6789/username:password/jsonrpc
if (!strncmp(m_szUrl, "/nzbget/", 8))
{
char* sz_OldUrl = m_szUrl;
m_szUrl = strdup(m_szUrl + 7);
free(sz_OldUrl);
}
// http://localhost:6789/nzbget -> http://localhost:6789
if (!strcmp(m_szUrl, "/nzbget"))
{
char szRedirectURL[1024];
snprintf(szRedirectURL, 1024, "%s/", m_szUrl);
szRedirectURL[1024-1] = '\0';
SendRedirectResponse(szRedirectURL);
return;
}
// authorization via URL in format:
// http://localhost:6789/username:password/jsonrpc
char* pauth1 = strchr(m_szUrl + 1, ':');
char* pauth2 = strchr(m_szUrl + 1, '/');
if (pauth1 && pauth1 < pauth2)
{
char* pstart = m_szUrl + 1;
int iLen = 0;
char* pend = strchr(pstart + 1, '/');
if (pend)
{
iLen = (int)(pend - pstart < (int)sizeof(szAuthInfo) - 1 ? pend - pstart : (int)sizeof(szAuthInfo) - 1);
}
else
{
iLen = strlen(pstart);
}
strncpy(szAuthInfo, pstart, iLen);
szAuthInfo[iLen] = '\0';
char* sz_OldUrl = m_szUrl;
m_szUrl = strdup(pend);
free(sz_OldUrl);
}
debug("Final URL=%s", m_szUrl);
if (strlen(szAuthInfo) == 0)
{
SendAuthResponse();
return;
}
// Authorization
char* pw = strchr(szAuthInfo, ':');
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());
SendAuthResponse();
return;
}
if (m_eHttpMethod == hmPost)
{
// reading http body (request content)
m_szRequest = (char*)malloc(iContentLen + 1);
m_szRequest[iContentLen] = '\0';
if (!m_pConnection->Recv(m_szRequest, iContentLen))
{
free(m_szRequest);
error("invalid-request: could not read data");
return;
}
debug("Request=%s", m_szRequest);
}
debug("request received from %s", m_pConnection->GetRemoteAddr());
Dispatch();
}
void WebProcessor::Dispatch()
{
if (*m_szUrl != '/')
{
SendErrorResponse(ERR_HTTP_BAD_REQUEST);
return;
}
if (XmlRpcProcessor::IsRpcRequest(m_szUrl))
{
XmlRpcProcessor processor;
processor.SetRequest(m_szRequest);
processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost);
processor.SetUrl(m_szUrl);
processor.Execute();
SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType());
return;
}
if (!g_pOptions->GetWebDir() || strlen(g_pOptions->GetWebDir()) == 0)
{
SendErrorResponse(ERR_HTTP_SERVICE_UNAVAILABLE);
return;
}
if (m_eHttpMethod != hmGet)
{
SendErrorResponse(ERR_HTTP_BAD_REQUEST);
return;
}
// for security reasons we allow only characters "0..9 A..Z a..z . - _ /" in the URLs
// we also don't allow ".." in the URLs
for (char *p = m_szUrl; *p; p++)
{
if (!((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
*p == '.' || *p == '-' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.'))
{
SendErrorResponse(ERR_HTTP_NOT_FOUND);
return;
}
}
const char *szDefRes = "";
if (m_szUrl[strlen(m_szUrl)-1] == '/')
{
// default file in directory (if not specified) is "index.html"
szDefRes = "index.html";
}
char disk_filename[1024];
snprintf(disk_filename, sizeof(disk_filename), "%s%s%s", g_pOptions->GetWebDir(), m_szUrl + 1, szDefRes);
disk_filename[sizeof(disk_filename)-1] = '\0';
SendFileResponse(disk_filename);
}
void WebProcessor::SendAuthResponse()
{
const char* AUTH_RESPONSE_HEADER =
"HTTP/1.0 401 Unauthorized\r\n"
"WWW-Authenticate: Basic realm=\"NZBGet\"\r\n"
"Connection: close\r\n"
"Content-Type: text/plain\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, AUTH_RESPONSE_HEADER, Util::VersionRevision());
// Send the response answer
debug("ResponseHeader=%s", szResponseHeader);
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
}
void WebProcessor::SendOptionsResponse()
{
const char* OPTIONS_RESPONSE_HEADER =
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
//"Content-Type: plain/text\r\n"
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
"Access-Control-Allow-Origin: %s\r\n"
"Access-Control-Allow-Credentials: true\r\n"
"Access-Control-Max-Age: 86400\r\n"
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, OPTIONS_RESPONSE_HEADER,
m_szOrigin ? m_szOrigin : "",
Util::VersionRevision());
// Send the response answer
debug("ResponseHeader=%s", szResponseHeader);
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
}
void WebProcessor::SendErrorResponse(const char* szErrCode)
{
const char* RESPONSE_HEADER =
"HTTP/1.0 %s\r\n"
"Connection: close\r\n"
"Content-Length: %i\r\n"
"Content-Type: text/html\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
warn("Web-Server: %s, Resource: %s", szErrCode, m_szUrl);
char szResponseBody[1024];
snprintf(szResponseBody, 1024, "<html><head><title>%s</title></head><body>Error: %s</body></html>", szErrCode, szErrCode);
int iPageContentLen = strlen(szResponseBody);
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, RESPONSE_HEADER, szErrCode, iPageContentLen, Util::VersionRevision());
// Send the response answer
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
m_pConnection->Send(szResponseBody, iPageContentLen);
}
void WebProcessor::SendRedirectResponse(const char* szURL)
{
const char* REDIRECT_RESPONSE_HEADER =
"HTTP/1.0 301 Moved Permanently\r\n"
"Location: %s\r\n"
"Connection: close\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, REDIRECT_RESPONSE_HEADER, szURL, Util::VersionRevision());
// Send the response answer
debug("ResponseHeader=%s", szResponseHeader);
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
}
void WebProcessor::SendBodyResponse(const char* szBody, int iBodyLen, const char* szContentType)
{
const char* RESPONSE_HEADER =
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
"Access-Control-Allow-Origin: %s\r\n"
"Access-Control-Allow-Credentials: true\r\n"
"Access-Control-Max-Age: 86400\r\n"
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
"Content-Length: %i\r\n"
"%s" // Content-Type: xxx
"%s" // Content-Encoding: gzip
"Server: nzbget-%s\r\n"
"\r\n";
#ifndef DISABLE_GZIP
char *szGBuf = NULL;
bool bGZip = m_bGZip && iBodyLen > MAX_UNCOMPRESSED_SIZE;
if (bGZip)
{
unsigned int iOutLen = ZLib::GZipLen(iBodyLen);
szGBuf = (char*)malloc(iOutLen);
int iGZippedLen = ZLib::GZip(szBody, iBodyLen, szGBuf, iOutLen);
if (iGZippedLen > 0 && iGZippedLen < iBodyLen)
{
szBody = szGBuf;
iBodyLen = iGZippedLen;
}
else
{
free(szGBuf);
szGBuf = NULL;
bGZip = false;
}
}
#else
bool bGZip = false;
#endif
char szContentTypeHeader[1024];
if (szContentType)
{
snprintf(szContentTypeHeader, 1024, "Content-Type: %s\r\n", szContentType);
}
else
{
szContentTypeHeader[0] = '\0';
}
char szResponseHeader[1024];
snprintf(szResponseHeader, 1024, RESPONSE_HEADER,
m_szOrigin ? m_szOrigin : "",
iBodyLen, szContentTypeHeader,
bGZip ? "Content-Encoding: gzip\r\n" : "",
Util::VersionRevision());
// Send the request answer
m_pConnection->Send(szResponseHeader, strlen(szResponseHeader));
m_pConnection->Send(szBody, iBodyLen);
#ifndef DISABLE_GZIP
if (szGBuf)
{
free(szGBuf);
}
#endif
}
void WebProcessor::SendFileResponse(const char* szFilename)
{
debug("serving file: %s", szFilename);
char *szBody;
int iBodyLen;
if (!Util::LoadFileIntoBuffer(szFilename, &szBody, &iBodyLen))
{
SendErrorResponse(ERR_HTTP_NOT_FOUND);
return;
}
// "LoadFileIntoBuffer" adds a trailing NULL, which we don't need here
iBodyLen--;
SendBodyResponse(szBody, iBodyLen, DetectContentType(szFilename));
free(szBody);
}
const char* WebProcessor::DetectContentType(const char* szFilename)
{
if (const char *szExt = strrchr(szFilename, '.'))
{
if (!strcasecmp(szExt, ".css"))
{
return "text/css";
}
else if (!strcasecmp(szExt, ".html"))
{
return "text/html";
}
else if (!strcasecmp(szExt, ".js"))
{
return "application/javascript";
}
else if (!strcasecmp(szExt, ".png"))
{
return "image/png";
}
else if (!strcasecmp(szExt, ".jpeg"))
{
return "image/jpeg";
}
else if (!strcasecmp(szExt, ".gif"))
{
return "image/gif";
}
}
return NULL;
}

View File

@@ -1,67 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include "Connection.h"
class WebProcessor
{
public:
enum EHttpMethod
{
hmPost,
hmGet,
hmOptions
};
private:
Connection* m_pConnection;
char* m_szRequest;
char* m_szUrl;
EHttpMethod m_eHttpMethod;
bool m_bGZip;
char* m_szOrigin;
void Dispatch();
void SendAuthResponse();
void SendOptionsResponse();
void SendErrorResponse(const char* szErrCode);
void SendFileResponse(const char* szFilename);
void SendBodyResponse(const char* szBody, int iBodyLen, const char* szContentType);
void SendRedirectResponse(const char* szURL);
const char* DetectContentType(const char* szFilename);
public:
WebProcessor();
~WebProcessor();
void Execute();
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
void SetUrl(const char* szUrl);
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
};
#endif

1048
XmlRpc.cpp
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-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -61,28 +61,28 @@ public:
};
private:
Connection* m_pConnection;
const char* m_szClientIP;
char* m_szRequest;
const char* m_szContentType;
ERpcProtocol m_eProtocol;
EHttpMethod m_eHttpMethod;
char* m_szUrl;
StringBuilder m_cResponse;
void Dispatch();
void SendAuthResponse();
void SendResponse(const char* szResponse, const char* szCallbackFunc, bool bFault);
XmlCommand* CreateCommand(const char* szMethodName);
void MutliCall();
void BuildResponse(const char* szResponse, const char* szCallbackFunc, bool bFault);
public:
XmlRpcProcessor();
~XmlRpcProcessor();
void Execute();
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
void SetProtocol(ERpcProtocol eProtocol) { m_eProtocol = eProtocol; }
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
void SetUrl(const char* szUrl);
void SetRequest(char* szRequest) { m_szRequest = szRequest; }
const char* GetResponse() { return m_cResponse.GetBuffer(); }
const char* GetContentType() { return m_szContentType; }
static bool IsRpcRequest(const char* szUrl);
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
};
class XmlCommand
@@ -96,7 +96,7 @@ protected:
XmlRpcProcessor::ERpcProtocol m_eProtocol;
XmlRpcProcessor::EHttpMethod m_eHttpMethod;
void BuildErrorResponse(int iErrCode, const char* szErrText, ...);
void BuildErrorResponse(int iErrCode, const char* szErrText);
void BuildBoolResponse(bool bOK);
void AppendResponse(const char* szPart);
bool IsJson();
@@ -106,7 +106,6 @@ protected:
bool NextParamAsStr(char** szValueBuf);
const char* BoolToStr(bool bValue);
char* EncodeStr(const char* szStr);
void DecodeStr(char* szStr);
public:
XmlCommand();
@@ -152,24 +151,12 @@ public:
virtual void Execute();
};
class ScheduleResumeXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class ShutdownXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class ReloadXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class VersionXmlCommand: public XmlCommand
{
public:
@@ -236,12 +223,6 @@ public:
virtual void Execute();
};
class ClearLogXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class ScanXmlCommand: public XmlCommand
{
public:
@@ -254,35 +235,4 @@ public:
virtual void Execute();
};
class DownloadUrlXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class UrlQueueXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class ConfigXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class LoadConfigXmlCommand: public XmlCommand
{
public:
virtual void Execute();
};
class SaveConfigXmlCommand: public XmlCommand
{
public:
virtual void Execute();
void Save(const char *szFilename);
};
#endif

View File

@@ -6,9 +6,6 @@
/* Define to 1 to not use curses */
#undef DISABLE_CURSES
/* Define to 1 to disable gzip-support */
#undef DISABLE_GZIP
/* Define to 1 to disable smart par-verification and restoration */
#undef DISABLE_PARCHECK
@@ -67,18 +64,9 @@
/* Define to 1 to use OpenSSL library for TLS/SSL-support. */
#undef HAVE_OPENSSL
/* Define to 1 if libpar2 has recent bugfixes-patch (version 2) */
#undef HAVE_PAR2_BUGFIXES_V2
/* Define to 1 if libpar2 supports cancelling (needs a special patch) */
#undef HAVE_PAR2_CANCEL
/* Define to 1 if you have the <regex.h> header file. */
#undef HAVE_REGEX_H
/* Define to 1 if spinlocks are supported */
#undef HAVE_SPINLOCK
/* Define to 1 if stat64 is supported */
#undef HAVE_STAT64
@@ -127,9 +115,6 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 to install an empty signal handler for SIGCHLD */
#undef SIGCHLD_HANDLER
/* Determine what socket length (socklen_t) data type is */
#undef SOCKLEN_T

4914
configure vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,18 +2,34 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(nzbget, 10.1, hugbug@users.sourceforge.net)
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(nzbget, 10.1)
AC_INIT(nzbget, 0.7.0, hugbug@users.sourceforge.net)
AM_INIT_AUTOMAKE(nzbget, 0.7.0)
AC_CONFIG_SRCDIR([nzbget.cpp])
AC_CONFIG_HEADERS([config.h])
dnl
dnl Architecture check.
dnl
AC_CANONICAL_HOST
dnl
dnl Set default library path, if not specified in environment variable "LIBPREF".
dnl
if test "$LIBPREF" = ""; then
LIBPREF="/usr"
case "$host" in
*-linux*)
LIBPREF="/usr"
;;
*-freebsd*)
LIBPREF="/usr/local"
;;
*-solaris*)
LIBPREF="/usr"
;;
esac
fi
@@ -36,7 +52,6 @@ dnl
dnl Checks for header files.
dnl
AC_CHECK_HEADERS(sys/prctl.h)
AC_CHECK_HEADERS(regex.h)
dnl
@@ -143,14 +158,6 @@ if test "$FOUND" = "no"; then
fi
dnl
dnl cCheck if spinlocks are available
dnl
AC_CHECK_FUNC(pthread_spin_init,
[AC_DEFINE([HAVE_SPINLOCK], 1, [Define to 1 if spinlocks are supported])]
AC_SEARCH_LIBS([pthread_spin_init], [pthread]),)
dnl
dnl Determine what socket length (socklen_t) data type is
dnl
@@ -187,6 +194,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 +204,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 +230,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 +290,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
@@ -335,32 +345,6 @@ if test "$ENABLEPARCHECK" = "yes"; then
AC_MSG_RESULT([[yes]])
AC_DEFINE([HAVE_PAR2_CANCEL], 1, [Define to 1 if libpar2 supports cancelling (needs a special patch)]),
AC_MSG_RESULT([[no]]))
dnl
dnl check if libpar2 has recent bugfixes-patch
dnl
AC_MSG_CHECKING(whether libpar2 has recent bugfixes-patch (version 2))
AC_TRY_COMPILE(
[#include <libpar2/par2cmdline.h>]
[#include <libpar2/par2repairer.h>]
[ class Repairer : public Par2Repairer { void test() { BugfixesPatchVersion2(); } }; ],
[],
AC_MSG_RESULT([[yes]])
PAR2PATCHV2=yes
AC_DEFINE([HAVE_PAR2_BUGFIXES_V2], 1, [Define to 1 if libpar2 has recent bugfixes-patch (version 2)]),
AC_MSG_RESULT([[no]])
PAR2PATCHV2=no)
if test "$PAR2PATCHV2" = "no" ; then
AC_ARG_ENABLE(libpar2-bugfixes-check,
[AS_HELP_STRING([--disable-libpar2-bugfixes-check], [do not check if libpar2 has recent bugfixes-patch applied])],
[ PAR2PATCHCHECK=$enableval ],
[ PAR2PATCHCHECK=yes] )
if test "$PAR2PATCHCHECK" = "yes"; then
AC_ERROR([Your version of libpar2 doesn't include the recent bugfixes-patch (version 2, updated Dec 3, 2012). Please patch libpar2 with the patches supplied with NZBGet (see README for details). If you cannot patch libpar2, you can use configure parameter --disable-libpar2-bugfixes-check to suppress the check. Please note however that in this case the program may crash during par-check/repair. The patch is highly recommended!])
fi
fi
else
AC_DEFINE([DISABLE_PARCHECK],1,[Define to 1 to disable smart par-verification and restoration])
fi
@@ -390,11 +374,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 +404,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 +424,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])
@@ -470,61 +449,6 @@ else
fi
dnl
dnl checks for zlib includes and libraries.
dnl
AC_MSG_CHECKING(whether to use gzip)
AC_ARG_ENABLE(gzip,
[AS_HELP_STRING([--disable-gzip], [disable gzip-compression/decompression (removes dependency from zlib-library)])],
[USEZLIB=$enableval],
[USEZLIB=yes] )
AC_MSG_RESULT($USEZLIB)
if test "$USEZLIB" = "yes"; then
INCVAL="${LIBPREF}/include"
LIBVAL="${LIBPREF}/lib"
AC_ARG_WITH(zlib_includes,
[AS_HELP_STRING([--with-zlib-includes=DIR], [zlib include directory])],
[INCVAL="$withval"])
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
AC_ARG_WITH(zlib_libraries,
[AS_HELP_STRING([--with-zlib-libraries=DIR], [zlib library directory])],
[LIBVAL="$withval"])
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
AC_CHECK_HEADER(zlib.h,,
AC_MSG_ERROR("zlib header files not found"))
AC_SEARCH_LIBS([deflateBound], [z], ,
AC_MSG_ERROR("zlib library not found"))
else
AC_DEFINE([DISABLE_GZIP],1,[Define to 1 to disable gzip-support])
fi
dnl
dnl Some Linux systems require an empty signal handler for SIGCHLD
dnl in order for exit codes to be correctly delivered to parent process.
dnl Some BSD systems however may not function properly if the handler is installed.
dnl The default behavior is to check the target and disable the handler on BSD but keep it enabled on other systems.
dnl
AC_MSG_CHECKING(whether to use an empty SIGCHLD handler)
AC_ARG_ENABLE(sigchld-handler,
[AS_HELP_STRING([--disable-sigchld-handler], [do not use sigchld-handler (the disabling is recommended for BSD)])],
[SIGCHLDHANDLER=$enableval],
[SIGCHLDHANDLER=auto])
if test "$SIGCHLDHANDLER" = "auto"; then
SIGCHLDHANDLER=yes
case "$target" in
*bsd*)
SIGCHLDHANDLER=no
;;
esac
fi
AC_MSG_RESULT($SIGCHLDHANDLER)
if test "$SIGCHLDHANDLER" = "yes"; then
AC_DEFINE([SIGCHLD_HANDLER], 1, [Define to 1 to install an empty signal handler for SIGCHLD])
fi
dnl
dnl Debugging. Default: no
dnl
@@ -621,5 +545,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,9 +1,7 @@
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
--- ../libpar2-0.2-original/par2repairer.cpp 2006-01-20 18:25:20.000000000 +0100
+++ ../libpar2-0.2/par2repairer.cpp 2012-11-30 14:23:31.000000000 +0100
@@ -76,10 +76,11 @@
++sf;
}
+++ ../libpar2-0.2/par2repairer.cpp 2008-02-06 12:02:53.226050300 +0100
@@ -78,6 +78,7 @@
delete mainpacket;
delete creatorpacket;
@@ -11,11 +9,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
Result Par2Repairer::PreProcess(const CommandLine &commandline)
{
@@ -1259,11 +1260,11 @@
string path;
string name;
@@ -1261,7 +1262,7 @@
DiskFile::SplitFilename(filename, path, name);
cout << "Target: \"" << name << "\" - missing." << endl;
@@ -24,37 +18,12 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
}
++sf;
}
@@ -1802,11 +1803,11 @@
<< "\" - no data found."
<< endl;
@@ -1804,7 +1805,7 @@
}
}
}
- sig_done.emit(name,count,sourcefile->GetVerificationPacket()->BlockCount());
+ sig_done.emit(name,count, count>0 && sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
+ sig_done.emit(name,count, sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
sig_progress.emit(1000.0);
return true;
}
// Find out how much data we have found
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.h ../libpar2-0.2/par2repairer.h
--- ../libpar2-0.2-original/par2repairer.h 2006-01-20 00:38:27.000000000 +0100
+++ ../libpar2-0.2/par2repairer.h 2012-11-30 14:24:46.000000000 +0100
@@ -34,10 +34,15 @@
sigc::signal<void, std::string> sig_filename;
sigc::signal<void, double> sig_progress;
sigc::signal<void, ParHeaders*> sig_headers;
sigc::signal<void, std::string, int, int> sig_done;
+ // This method allows to determine whether libpar2 includes the patches
+ // ("libpar2-0.2-bugfixes.patch") submitted to libpar2 project.
+ // Use the method in configure scripts for detection.
+ void BugfixesPatchVersion2() { }
+
protected:
// Steps in verifying and repairing files:
// Load packets from the specified file
bool LoadPacketsFromFile(string filename);

View File

@@ -1,9 +1,7 @@
diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
--- ../libpar2-0.2-original/par2repairer.cpp 2012-12-03 10:47:04.000000000 +0100
+++ ../libpar2-0.2/par2repairer.cpp 2012-12-03 10:48:13.000000000 +0100
@@ -50,10 +50,12 @@
outputbuffer = 0;
diff -aud ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repairer.cpp
--- ../libpar2-0.2-original/par2repairer.cpp 2008-10-26 19:54:33.000000000 +0100
+++ ../libpar2-0.2/par2repairer.cpp 2008-10-29 10:24:48.000000000 +0100
@@ -52,6 +52,8 @@
noiselevel = CommandLine::nlNormal;
headers = new ParHeaders;
alreadyloaded = false;
@@ -12,11 +10,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
Par2Repairer::~Par2Repairer(void)
{
delete [] (u8*)inputbuffer;
@@ -404,10 +406,14 @@
{
cout << "Loading: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
@@ -406,6 +408,10 @@
progress = offset;
sig_progress.emit(newfraction);
@@ -27,11 +21,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
}
// Attempt to read the next packet header
PACKET_HEADER header;
@@ -582,10 +588,15 @@
if (noiselevel > CommandLine::nlQuiet)
cout << "No new packets found" << endl;
@@ -584,6 +590,11 @@
delete diskfile;
}
@@ -43,11 +33,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
return true;
}
// Finish loading a recovery packet
bool Par2Repairer::LoadRecoveryPacket(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
@@ -831,26 +842,42 @@
// Load packets from each file that was found
@@ -833,9 +844,17 @@
for (list<string>::const_iterator s=files->begin(); s!=files->end(); ++s)
{
LoadPacketsFromFile(*s);
@@ -65,10 +51,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
{
string wildcard = name.empty() ? "*.PAR2" : name + ".*.PAR2";
list<string> *files = DiskFile::FindFiles(path, wildcard);
// Load packets from each file that was found
@@ -846,9 +865,17 @@
for (list<string>::const_iterator s=files->begin(); s!=files->end(); ++s)
{
LoadPacketsFromFile(*s);
@@ -86,11 +69,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
return true;
}
@@ -864,13 +891,22 @@
// If the filename contains ".par2" anywhere
if (string::npos != filename.find(".par2") ||
@@ -866,9 +893,18 @@
string::npos != filename.find(".PAR2"))
{
LoadPacketsFromFile(filename);
@@ -109,11 +88,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
return true;
}
// Check that the packets are consistent and discard any that are not
bool Par2Repairer::CheckPacketConsistency(void)
@@ -1208,10 +1244,15 @@
// Start verifying the files
@@ -1210,6 +1246,11 @@
sf = sortedfiles.begin();
while (sf != sortedfiles.end())
{
@@ -125,11 +100,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
// Do we have a source file
Par2RepairerSourceFile *sourcefile = *sf;
// What filename does the file use
string filename = sourcefile->TargetFileName();
@@ -1560,10 +1601,14 @@
if (oldfraction != newfraction)
{
@@ -1562,6 +1603,10 @@
cout << "Scanning: \"" << shortname << "\": " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
sig_progress.emit(newfraction);
@@ -140,11 +111,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
}
}
// If we fail to find a match, it might be because it was a duplicate of a block
// that we have already found.
@@ -1649,10 +1694,15 @@
return false;
}
@@ -1651,6 +1696,11 @@
}
}
@@ -156,11 +123,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
// Get the Full and 16k hash values of the file
filechecksummer.GetFileHashes(hashfull, hash16k);
// Did we make any matches at all
if (count > 0)
@@ -2289,14 +2339,23 @@
if (oldfraction != newfraction)
{
@@ -2291,10 +2341,19 @@
cout << "Repairing: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
sig_progress.emit(newfraction);
@@ -180,11 +143,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
++inputblock;
++inputindex;
}
}
else
@@ -2346,13 +2405,22 @@
if (oldfraction != newfraction)
{
@@ -2348,9 +2407,18 @@
cout << "Processing: " << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
sig_progress.emit(newfraction);
@@ -203,11 +162,7 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
++copyblock;
++inputblock;
}
}
@@ -2360,10 +2428,15 @@
if (lastopenfile != NULL)
{
@@ -2362,6 +2430,11 @@
lastopenfile->Close();
}
@@ -219,14 +174,10 @@ diff -aud -U 5 ../libpar2-0.2-original/par2repairer.cpp ../libpar2-0.2/par2repai
if (noiselevel > CommandLine::nlQuiet)
cout << "Writing recovered data\r";
// For each output block that has been recomputed
vector<DataBlock*>::iterator outputblock = outputblocks.begin();
diff -aud -U 5 ../libpar2-0.2-with-bugfixes-patch/par2repairer.h ../libpar2-0.2/par2repairer.h
--- ../libpar2-0.2-original/par2repairer.h 2012-12-03 10:47:04.000000000 +0100
+++ ../libpar2-0.2/par2repairer.h 2012-12-03 10:48:13.000000000 +0100
@@ -186,8 +186,9 @@
u64 progress; // How much data has been processed.
diff -aud ../libpar2-0.2-original/par2repairer.h ../libpar2-0.2/par2repairer.h
--- ../libpar2-0.2-original/par2repairer.h 2006-01-20 00:38:27.000000000 +0100
+++ ../libpar2-0.2/par2repairer.h 2008-10-26 19:01:08.000000000 +0100
@@ -183,6 +183,7 @@
u64 totaldata; // Total amount of data to be processed.
u64 totalsize; // Total data size

View File

@@ -1,50 +0,0 @@
#
# This file if part of nzbget
#
# Template configuration file for post-processing script "nzbget-postprocess.sh".
# Please refer to "nzbget-postprocess.sh" for usage instructions.
#
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
##############################################################################
### OPTIONS ###
# Rename img-files to iso (yes, no).
RenameIMG=yes
# Joint TS-files (yes, no).
JoinTS=yes
##############################################################################
### 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
# nzb-file with id=2:
# nzbget -E G O PostProcess=no 2
# Perform postprocessing (yes, no).
#
# Set to "no" to skip postprocessing for this nzb-file.
PostProcess=yes
# Destination directory.
DestDir=

View File

@@ -1,231 +0,0 @@
#!/bin/sh
#
# This file if part of nzbget
#
# Example postprocessing script for NZBGet
#
# Copyright (C) 2008 Peter Roubos <peterroubos@hotmail.com>
# Copyright (C) 2008 Otmar Werner
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
####################### Usage instructions #######################
# o Script will cleanup, join ts-files and rename img-files to iso.
#
# o To use this script with nzbget set the option "PostProcess" in
# nzbget configuration file to point to this script file. E.g.:
# PostProcess=/home/user/nzbget/nzbget-postprocess.sh
#
# o The script needs a configuration file. An example configuration file
# is provided in file "nzbget-postprocess.conf". Put the configuration file
# into the directory where nzbget's configuration file (nzbget.conf) is located.
# Then edit the configuration file in any text editor to adjust the settings.
#
# o You can also edit the script's configuration via web-interface.
#
# o There are few options, which can be ajdusted for each nzb-file individually.
#
####################### 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_PARSTATUS - result of par-check:
# 0 = not checked: par-check is disabled or nzb-file does
# not contain any par-files;
# 1 = checked and failed to repair;
# 2 = checked and successfully repaired;
# 3 = checked and can be repaired but repair is disabled.
# 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.
# Name of script's configuration file
SCRIPT_CONFIG_FILE="nzbget-postprocess.conf"
# Exit codes
POSTPROCESS_PARCHECK_CURRENT=91
POSTPROCESS_PARCHECK_ALL=92
POSTPROCESS_SUCCESS=93
POSTPROCESS_ERROR=94
POSTPROCESS_NONE=95
# Check if the script is called from nzbget 10.0 or later
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)."
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
# 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"
exit $POSTPROCESS_NONE
fi
echo "[INFO] Post-Process: Post-processing script successfully started"
cd "$NZBPP_DIRECTORY"
# Determine the location of configuration file (it must be stored in
# the directory with nzbget.conf).
ConfigDir="${NZBOP_CONFIGFILE%/*}"
ScriptConfigFile="$ConfigDir/$SCRIPT_CONFIG_FILE"
if [ ! -f "$ScriptConfigFile" ]; then
echo "[ERROR] Post-Process: Configuration file $ScriptConfigFile not found, exiting"
exit $POSTPROCESS_ERROR
fi
# Readg configuration file
while read line; do eval "$line"; done < $ScriptConfigFile
# Check nzbget.conf options
BadConfig=0
if [ "$NZBOP_ALLOWREPROCESS" = "yes" ]; then
echo "[ERROR] Post-Process: Please disable option \"AllowReProcess\" in nzbget configuration file"
BadConfig=1
fi
if [ "$NZBOP_UNPACK" != "yes" ]; then
echo "[ERROR] Post-Process: Please enable option \"Unpack\" in nzbget configuration file"
BadConfig=1
fi
if [ "$BadConfig" -eq 1 ]; then
echo "[ERROR] Post-Process: Exiting due to incompatible nzbget configuration"
exit $POSTPROCESS_ERROR
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
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
# Check if destination directory exists (important for reprocessing of history items)
if [ ! -d "$NZBPP_DIRECTORY" ]; then
echo "[ERROR] Post-Process: Nothing to post-process: destination directory $NZBPP_DIRECTORY doesn't exist"
exit $POSTPROCESS_ERROR
fi
# All checks done, now processing the files
# If download contains only nzb-files move them into nzb-directory
# for further download
# Check if command "wc" exists
wc -l . >/dev/null 2>&1
if [ "$?" -ne 127 ]; then
AllFilesCount=`ls -1 2>/dev/null | wc -l`
NZBFilesCount=`ls -1 *.nzb 2>/dev/null | wc -l`
if [ "$AllFilesCount" -eq "$NZBFilesCount" ]; then
echo "[INFO] Moving downloaded nzb-files into incoming nzb-directory for further download"
mv *.nzb $NZBOP_NZBDIR
fi
fi
# Clean up
echo "[INFO] Post-Process: Cleaning up"
chmod -R a+rw .
rm *.nzb >/dev/null 2>&1
rm *.sfv >/dev/null 2>&1
rm *.1 >/dev/null 2>&1
rm _brokenlog.txt >/dev/null 2>&1
rm *.[pP][aA][rR]2 >/dev/null 2>&1
if [ "$JoinTS" = "yes" ]; then
# Join any split .ts files if they are named xxxx.0000.ts xxxx.0001.ts
# They will be joined together to a file called xxxx.0001.ts
if (ls *.ts >/dev/null 2>&1); then
echo "[INFO] Post-Process: Joining ts-files"
tsname=`find . -name "*0001.ts" |awk -F/ '{print $NF}'`
cat *0???.ts > ./$tsname
# Remove all the split .ts files
echo "[INFO] Post-Process: Deleting source ts-files"
rm *0???.ts >/dev/null 2>&1
fi
fi
if [ "$RenameIMG" = "yes" ]; then
# Rename img file to iso
# It will be renamed to .img.iso so you can see that it has been renamed
if (ls *.img >/dev/null 2>&1); then
echo "[INFO] Post-Process: Renaming img-files to iso"
imgname=`find . -name "*.img" |awk -F/ '{print $NF}'`
mv $imgname $imgname.iso
fi
fi
# Check if destination directory was set in postprocessing parameters
# (for current nzb-file) via web-interface or via command line with
# "nzbget -E G O DestDir=/new/path <ID>"
if [ "$NZBPR_DestDir" != "" ]; then
mkdir $NZBPR_DestDir
mv * $NZBPR_DestDir >/dev/null 2>&1
cd ..
rmdir $NZBPP_DIRECTORY
fi
# All OK, requesting cleaning up of download queue
exit $POSTPROCESS_SUCCESS

View File

@@ -4,7 +4,7 @@ rem
rem Batch file to start nzbget shell
rem
rem Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
rem Copyright (C) 2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
rem Copyright (C) 2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
rem
rem This program is free software; you can redistribute it and/or modify
rem it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ rem GNU General Public License for more details.
rem
rem You should have received a copy of the GNU General Public License
rem along with this program; if not, write to the Free Software
rem Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
rem Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
rem
rem ####################### Usage instructions #######################

View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <config.h>
#endif
#ifdef WIN32
@@ -66,7 +66,6 @@
#include "ColoredFrontend.h"
#include "NCursesFrontend.h"
#include "QueueCoordinator.h"
#include "UrlCoordinator.h"
#include "RemoteServer.h"
#include "RemoteClient.h"
#include "MessageBase.h"
@@ -80,9 +79,7 @@
#endif
// Prototypes
void RunMain();
void Run(bool bReload);
void Reload();
void Run();
void Cleanup();
void ProcessClientRequest();
#ifndef WIN32
@@ -104,19 +101,14 @@ Thread* g_pFrontend = NULL;
Options* g_pOptions = NULL;
ServerPool* g_pServerPool = NULL;
QueueCoordinator* g_pQueueCoordinator = NULL;
UrlCoordinator* g_pUrlCoordinator = NULL;
RemoteServer* g_pRemoteServer = NULL;
RemoteServer* g_pRemoteSecureServer = NULL;
DownloadSpeedMeter* g_pDownloadSpeedMeter = NULL;
DownloadQueueHolder* g_pDownloadQueueHolder = NULL;
Log* g_pLog = NULL;
PrePostProcessor* g_pPrePostProcessor = NULL;
DiskState* g_pDiskState = NULL;
Scheduler* g_pScheduler = NULL;
int g_iArgumentCount;
char* (*g_szEnvironmentVariables)[] = NULL;
char* (*g_szArguments)[] = NULL;
bool g_bReloading = true;
char* (*szEnvironmentVariables)[] = NULL;
/*
* Main loop
@@ -145,67 +137,17 @@ int main(int argc, char *argv[], char *argp[])
DisableCout();
#endif
g_iArgumentCount = argc;
g_szArguments = (char*(*)[])argv;
g_szEnvironmentVariables = (char*(*)[])argp;
#ifdef WIN32
for (int i=0; i < argc; i++)
{
if (!strcmp(argv[i], "-D"))
{
StartService(RunMain);
return 0;
}
}
#endif
RunMain();
#ifdef WIN32
#ifdef _DEBUG
_CrtDumpMemoryLeaks();
#endif
#endif
return 0;
}
void RunMain()
{
// we need to save and later restore current directory each time
// the program is reloaded (RPC-Method "reload") in order for
// config to properly load in a case relative paths are used
// in command line
char szCurDir[MAX_PATH + 1];
Util::GetCurrentDirectory(szCurDir, sizeof(szCurDir));
bool bReload = false;
while (g_bReloading)
{
g_bReloading = false;
Util::SetCurrentDirectory(szCurDir);
Run(bReload);
bReload = true;
}
}
void Run(bool bReload)
{
g_pLog = new Log();
debug("nzbget %s", Util::VersionRevision());
if (!bReload)
{
Thread::Init();
}
g_pServerPool = new ServerPool();
g_pScheduler = new Scheduler();
Thread::Init();
debug("Reading options");
g_pOptions = new Options(g_iArgumentCount, *g_szArguments);
g_pOptions = new Options(argc, argv);
szEnvironmentVariables = (char*(*)[])argp;
#ifndef WIN32
if (g_pOptions->GetUMask() < 01000)
@@ -223,7 +165,7 @@ void Run(bool bReload)
g_pLog->InitOptions();
if (g_pOptions->GetDaemonMode() && !bReload)
if (g_pOptions->GetDaemonMode())
{
#ifdef WIN32
info("nzbget %s service-mode", Util::VersionRevision());
@@ -232,7 +174,7 @@ void Run(bool bReload)
info("nzbget %s daemon-mode", Util::VersionRevision());
#endif
}
else if (g_pOptions->GetServerMode() && !bReload)
else if (g_pOptions->GetServerMode())
{
info("nzbget %s server-mode", Util::VersionRevision());
}
@@ -241,11 +183,6 @@ void Run(bool bReload)
info("nzbget %s remote-mode", Util::VersionRevision());
}
if (!bReload)
{
Connection::Init();
}
if (!g_pOptions->GetRemoteClientMode())
{
g_pServerPool->InitConnections();
@@ -254,7 +191,13 @@ void Run(bool bReload)
#endif
}
#ifndef WIN32
#ifdef WIN32
if (g_pOptions->GetDaemonMode())
{
StartService(Run);
return 0;
}
#else
#ifdef HAVE_SYS_PRCTL_H
if (g_pOptions->GetDumpCore())
{
@@ -263,6 +206,19 @@ void Run(bool bReload)
#endif
#endif
Run();
#ifdef WIN32
#ifdef _DEBUG
_CrtDumpMemoryLeaks();
#endif
#endif
return 0;
}
void Run()
{
#ifndef WIN32
InstallSignalHandlers();
#ifdef DEBUG
@@ -272,6 +228,9 @@ void Run(bool bReload)
}
#endif
#endif
Connection::Init(g_pOptions->GetTLS() && !g_pOptions->GetRemoteClientMode() &&
(g_pOptions->GetClientOperation() == Options::opClientNoOperation));
// client request
if (g_pOptions->GetClientOperation() != Options::opClientNoOperation)
@@ -287,21 +246,13 @@ void Run(bool bReload)
g_pQueueCoordinator = new QueueCoordinator();
g_pDownloadSpeedMeter = g_pQueueCoordinator;
g_pDownloadQueueHolder = g_pQueueCoordinator;
g_pUrlCoordinator = new UrlCoordinator();
}
// Setup the network-server
if (g_pOptions->GetServerMode())
{
g_pRemoteServer = new RemoteServer(false);
g_pRemoteServer = new RemoteServer();
g_pRemoteServer->Start();
if (g_pOptions->GetSecureControl())
{
g_pRemoteSecureServer = new RemoteServer(true);
g_pRemoteSecureServer->Start();
}
}
// Creating PrePostProcessor
@@ -341,7 +292,7 @@ void Run(bool bReload)
// Standalone-mode
if (!g_pOptions->GetServerMode())
{
NZBFile* pNZBFile = NZBFile::CreateFromFile(g_pOptions->GetArgFilename(), g_pOptions->GetAddCategory() ? g_pOptions->GetAddCategory() : "");
NZBFile* pNZBFile = NZBFile::CreateFromFile(g_pOptions->GetArgFilename(), g_pOptions->GetCategory() ? g_pOptions->GetCategory() : "");
if (!pNZBFile)
{
abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A");
@@ -357,28 +308,18 @@ void Run(bool bReload)
}
g_pQueueCoordinator->Start();
g_pUrlCoordinator->Start();
g_pPrePostProcessor->Start();
// enter main program-loop
while (g_pQueueCoordinator->IsRunning() ||
g_pUrlCoordinator->IsRunning() ||
g_pPrePostProcessor->IsRunning())
while (g_pQueueCoordinator->IsRunning() || g_pPrePostProcessor->IsRunning())
{
if (!g_pOptions->GetServerMode() &&
!g_pQueueCoordinator->HasMoreJobs() &&
!g_pUrlCoordinator->HasMoreJobs() &&
!g_pPrePostProcessor->HasMoreJobs())
if (!g_pOptions->GetServerMode() && !g_pQueueCoordinator->HasMoreJobs() && !g_pPrePostProcessor->HasMoreJobs())
{
// Standalone-mode: download completed
if (!g_pQueueCoordinator->IsStopped())
{
g_pQueueCoordinator->Stop();
}
if (!g_pUrlCoordinator->IsStopped())
{
g_pUrlCoordinator->Stop();
}
if (!g_pPrePostProcessor->IsStopped())
{
g_pPrePostProcessor->Stop();
@@ -389,7 +330,6 @@ void Run(bool bReload)
// main program-loop is terminated
debug("QueueCoordinator stopped");
debug("UrlCoordinator stopped");
debug("PrePostProcessor stopped");
}
@@ -411,25 +351,7 @@ 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)
{
@@ -455,15 +377,15 @@ void ProcessClientRequest()
switch (g_pOptions->GetClientOperation())
{
case Options::opClientRequestListFiles:
Client->RequestServerList(true, false, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
Client->RequestServerList(true, false);
break;
case Options::opClientRequestListGroups:
Client->RequestServerList(false, true, g_pOptions->GetMatchMode() == Options::mmRegEx ? g_pOptions->GetEditQueueText() : NULL);
Client->RequestServerList(false, true);
break;
case Options::opClientRequestListStatus:
Client->RequestServerList(false, false, NULL);
Client->RequestServerList(false, false);
break;
case Options::opClientRequestDownloadPause:
@@ -492,8 +414,7 @@ void ProcessClientRequest()
case Options::opClientRequestEditQueue:
Client->RequestServerEditQueue((eRemoteEditAction)g_pOptions->GetEditQueueAction(), g_pOptions->GetEditQueueOffset(),
g_pOptions->GetEditQueueText(), g_pOptions->GetEditQueueIDList(), g_pOptions->GetEditQueueIDCount(),
g_pOptions->GetEditQueueNameList(), (eRemoteMatchMode)g_pOptions->GetMatchMode(), true);
g_pOptions->GetEditQueueText(), g_pOptions->GetEditQueueIDList(), g_pOptions->GetEditQueueIDCount(), true);
break;
case Options::opClientRequestLog:
@@ -504,12 +425,8 @@ void ProcessClientRequest()
Client->RequestServerShutdown();
break;
case Options::opClientRequestReload:
Client->RequestServerReload();
break;
case Options::opClientRequestDownload:
Client->RequestServerDownload(g_pOptions->GetArgFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
Client->RequestServerDownload(g_pOptions->GetArgFilename(), g_pOptions->GetCategory(), g_pOptions->GetAddTop());
break;
case Options::opClientRequestVersion:
@@ -524,12 +441,8 @@ void ProcessClientRequest()
Client->RequestWriteLog(g_pOptions->GetWriteLogKind(), g_pOptions->GetLastArg());
break;
case Options::opClientRequestScanAsync:
Client->RequestScan(false);
break;
case Options::opClientRequestScanSync:
Client->RequestScan(true);
case Options::opClientRequestScan:
Client->RequestScan();
break;
case Options::opClientRequestPostPause:
@@ -552,14 +465,6 @@ void ProcessClientRequest()
Client->RequestHistory();
break;
case Options::opClientRequestDownloadUrl:
Client->RequestServerDownloadUrl(g_pOptions->GetLastArg(), g_pOptions->GetAddNZBFilename(), g_pOptions->GetAddCategory(), g_pOptions->GetAddTop(), g_pOptions->GetAddPaused(), g_pOptions->GetAddPriority());
break;
case Options::opClientRequestUrlQueue:
Client->RequestUrlQueue();
break;
case Options::opClientNoOperation:
break;
}
@@ -569,10 +474,7 @@ void ProcessClientRequest()
void ExitProc()
{
if (!g_bReloading)
{
info("Stopping, please wait...");
}
info("Stopping, please wait...");
if (g_pOptions->GetRemoteClientMode())
{
if (g_pFrontend)
@@ -587,19 +489,11 @@ void ExitProc()
{
debug("Stopping QueueCoordinator");
g_pQueueCoordinator->Stop();
g_pUrlCoordinator->Stop();
g_pPrePostProcessor->Stop();
}
}
}
void Reload()
{
g_bReloading = true;
info("Reloading...");
ExitProc();
}
#ifndef WIN32
#ifdef DEBUG
typedef void(*sighandler)(int);
@@ -628,10 +522,22 @@ void SignalProc(int iSignal)
break;
#ifdef DEBUG
case SIGPIPE:
// ignoring
break;
case SIGSEGV:
signal(SIGSEGV, SIG_DFL); // Reset the signal handler
PrintBacktrace();
break;
default:
// printf("Signal %i received\n", iSignal);
if (SignalProcList[iSignal - 1])
{
SignalProcList[iSignal - 1](iSignal);
}
break;
#endif
}
}
@@ -640,14 +546,15 @@ void InstallSignalHandlers()
{
signal(SIGINT, SignalProc);
signal(SIGTERM, SignalProc);
signal(SIGCHLD, SignalProc);
signal(SIGPIPE, SIG_IGN);
#ifdef DEBUG
signal(SIGSEGV, SignalProc);
#endif
#ifdef SIGCHLD_HANDLER
// it could be necessary on some systems to activate a handler for SIGCHLD
// however it make troubles on other systems and is deactivated by default
signal(SIGCHLD, SignalProc);
SignalProcList.clear();
for (int i = 1; i <= 32; i++)
{
SignalProcList.push_back((sighandler)signal(i, SignalProc));
}
signal(SIGWINCH, SIG_DFL);
#endif
}
@@ -712,13 +619,13 @@ void Cleanup()
{
debug("Cleaning up global objects");
debug("Deleting UrlCoordinator");
if (g_pUrlCoordinator)
debug("Deleting QueueCoordinator");
if (g_pQueueCoordinator)
{
delete g_pUrlCoordinator;
g_pUrlCoordinator = NULL;
delete g_pQueueCoordinator;
g_pQueueCoordinator = NULL;
}
debug("UrlCoordinator deleted");
debug("QueueCoordinator deleted");
debug("Deleting RemoteServer");
if (g_pRemoteServer)
@@ -728,14 +635,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)
{
@@ -752,14 +651,6 @@ void Cleanup()
}
debug("Frontend deleted");
debug("Deleting QueueCoordinator");
if (g_pQueueCoordinator)
{
delete g_pQueueCoordinator;
g_pQueueCoordinator = NULL;
}
debug("QueueCoordinator deleted");
debug("Deleting DiskState");
if (g_pDiskState)
{
@@ -771,7 +662,7 @@ void Cleanup()
debug("Deleting Options");
if (g_pOptions)
{
if (g_pOptions->GetDaemonMode() && !g_bReloading)
if (g_pOptions->GetDaemonMode())
{
info("Deleting lock file");
remove(g_pOptions->GetLockFile());
@@ -797,11 +688,9 @@ void Cleanup()
}
debug("Scheduler deleted");
if (!g_bReloading)
{
Connection::Final();
Thread::Final();
}
Connection::Final();
Thread::Final();
debug("Global objects cleaned up");

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Revision$
* $Date$
@@ -50,15 +50,11 @@
#define usleep(usec) Sleep((usec) / 1000)
#define gettimeofday(tm, ignore) _ftime(tm)
#define socklen_t int
#define SHUT_WR 0x01
#define SHUT_RDWR 0x02
#define PATH_SEPARATOR '\\'
#define ALT_PATH_SEPARATOR '/'
#define LINE_ENDING "\r\n"
#define pid_t int
#ifndef FSCTL_SET_SPARSE
#define FSCTL_SET_SPARSE 590020
#endif
#pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning)
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data

View File

@@ -38,7 +38,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -58,7 +58,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0d.lib par2d.lib libgnutls-26.lib libgcrypt-11.lib regex.lib zlib.lib $(NOINHERIT)"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0d.lib par2d.lib libgnutls-26.lib libgcrypt-11.lib $(NOINHERIT)"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
@@ -112,7 +112,7 @@
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
ExceptionHandling="1"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
@@ -131,7 +131,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib libgnutls-26.lib libgcrypt-11.lib regex.lib zlib.lib $(NOINHERIT)"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib libgnutls-26.lib libgcrypt-11.lib $(NOINHERIT)"
LinkIncremental="0"
GenerateDebugInformation="true"
SubSystem="1"
@@ -187,7 +187,7 @@
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;DISABLE_TLS"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;DISABLE_TLS"
ExceptionHandling="1"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
@@ -206,7 +206,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib regex.lib zlib.lib $(NOINHERIT)"
AdditionalDependencies="WS2_32.lib ole32.lib OleAut32.Lib comsuppwd.lib Advapi32.lib sigc-2.0.lib par2.lib $(NOINHERIT)"
LinkIncremental="0"
GenerateDebugInformation="true"
SubSystem="1"
@@ -335,6 +335,14 @@
RelativePath=".\NCursesFrontend.h"
>
</File>
<File
RelativePath=".\NetAddress.cpp"
>
</File>
<File
RelativePath=".\NetAddress.h"
>
</File>
<File
RelativePath=".\NewsServer.cpp"
>
@@ -391,14 +399,6 @@
RelativePath=".\Options.h"
>
</File>
<File
RelativePath=".\ParCoordinator.cpp"
>
</File>
<File
RelativePath=".\ParCoordinator.h"
>
</File>
<File
RelativePath=".\ParChecker.cpp"
>
@@ -407,14 +407,6 @@
RelativePath=".\ParChecker.h"
>
</File>
<File
RelativePath=".\ParRenamer.cpp"
>
</File>
<File
RelativePath=".\ParRenamer.h"
>
</File>
<File
RelativePath=".\PrePostProcessor.cpp"
>
@@ -503,22 +495,6 @@
RelativePath=".\TLS.h"
>
</File>
<File
RelativePath=".\Unpack.cpp"
>
</File>
<File
RelativePath=".\Unpack.h"
>
</File>
<File
RelativePath=".\UrlCoordinator.cpp"
>
</File>
<File
RelativePath=".\UrlCoordinator.h"
>
</File>
<File
RelativePath=".\Util.cpp"
>
@@ -527,22 +503,6 @@
RelativePath=".\Util.h"
>
</File>
<File
RelativePath=".\WebDownloader.cpp"
>
</File>
<File
RelativePath=".\WebDownloader.h"
>
</File>
<File
RelativePath=".\WebServer.cpp"
>
</File>
<File
RelativePath=".\WebServer.h"
>
</File>
<File
RelativePath=".\win32.h"
>

58
nzbgetd
View File

@@ -3,7 +3,7 @@
# Script used to start and stop the nzbget usenet service
#
# Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
# Copyright (C) 2009-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,47 +17,48 @@
#
# 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.
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# --- CONFIGURATION -----------------------------------------------
# Location of the nzbget executable
NZBGET_BINARY="/usr/local/bin/nzbget"
export NZBGET_BINARY="/usr/local/bin/nzbget"
# Additional options, e. g. config file location:
# NZBGET_OPTS="-c /mnt/hdd/tools/nzbget/conf/nzbget.conf"
NZBGET_OPTS=""
# -----------------------------------------------------------------
# start/stop section
execCommand() {
"$NZBGET_BINARY" $@
sleep 1 # allows prompt to return
}
start() {
execCommand "--daemon"
}
stop() {
execCommand "--quit"
}
status() {
execCommand "--log 5"
}
if [ -z "$1" ] ; then
case `echo "$0" | sed 's:^.*/\(.*\):\1:g'` in
S??*) rc="start" ;;
K??*) rc="stop" ;;
*) rc="usage" ;;
esac
else
rc="$1"
fi
case "$rc" in
case "$1" in
start)
"$NZBGET_BINARY" $NZBGET_OPTS -D
start
;;
stop)
"$NZBGET_BINARY" $NZBGET_OPTS -Q
stop
;;
restart)
"$NZBGET_BINARY" $NZBGET_OPTS -Q
stop
sleep 10 # since stop is backgrounded
"$NZBGET_BINARY" $NZBGET_OPTS -D
;;
status)
"$NZBGET_BINARY" $NZBGET_OPTS -L S
start
;;
pstatus)
retval=$(pgrep -l -f nzbget > /dev/null ; echo $?)
retval=$(pgrep -l -f "$NZBGET_BINARY --daemon" > /dev/null ; echo $?)
if [ "$retval" = "0" ] ; then
echo " ------- nzbget *is* running -------"
ps -Ho user,pid,cmd:32,pcpu -C nzbget
@@ -67,8 +68,11 @@ case "$rc" in
exit 0
fi
;;
istatus)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status|pstatus|usage}"
echo "Usage $0 {start|stop|restart|pstatus|istatus}"
exit 1
esac

45
postprocess-example.conf Normal file
View File

@@ -0,0 +1,45 @@
# Template configuration file for postprocessing script "postprocess-example.sh".
# Please refer to "postprocess-example.sh" for usage instructions.
##############################################################################
### PATHS ###
# Set the full path to unrar if it is not in your PATH.
UnrarCmd=unrar
##############################################################################
### OPTIONS ###
# Delete rar-files after unpacking (yes, no).
DeleteRarFiles=yes
# Rename img-files to iso (yes, no).
RenameIMG=yes
# Joint TS-files (yes, no).
JoinTS=no
##############################################################################
### POSTPROCESSING-PARAMETERS ###
# This section defines parameters, which can be set for each nzb-file
# individually using either web-interface or command line.
# Example command line for setting parameter "password" to value "123" for
# nzb-file with id=2:
# nzbget -E G O Password=123 2
# Perform postprocessing (yes, no).
#
# Set to "no" to skip postprocessing for this nzb-file.
PostProcess=yes
# Password for encrypted posts.
#
# If the post requires a password for unpacking.
Password=
# Destination directory.
#
# NOTE: NZBGet must have write-access-rights for that directory.
DestDir=

326
postprocess-example.sh Executable file
View File

@@ -0,0 +1,326 @@
#!/bin/sh
#
# Example postprocessing script for NZBGet
#
# Copyright (C) 2008 Peter Roubos <peterroubos@hotmail.com>
# Copyright (C) 2008 Otmar Werner
# Copyright (C) 2008-2009 Andrei Prygounkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
####################### Usage instructions #######################
# o Script will unrar downloaded rar files, join ts-files and rename img-files
# to iso.
#
# o To use this script with nzbget set the option "PostProcess" in
# nzbget configuration file to point to this script file. E.g.:
# PostProcess=/home/user/nzbget/nzbget-postprocess.sh
#
# o The script needs a configuration file. An example configuration file
# is provided in file "postprocess-example.conf". Put the configuration file
# into the directory where nzbget's configuration file (nzbget.conf) or where
# this script itself is located. Then edit the configuration file in any
# text editor to adjust the settings.
#
# o You can also edit the script's configuration via web-interface (requires
# NZBGetWeb 1.4 or later). Set the options "PostProcessConfigFile" and
# "PostProcessConfigTemplate" to point to "postprocess-example.conf"
# (including full path). The both options are under the section
# "CONFIGURATION OF POSTPROCESSING-SCRIPT" in NZBGetWeb.
#
# o There are few options, which can be ajdusted for each nzb-file
# individually. To view/edit them in web-interface click on a spanner icon
# near the name of nzb-file.
#
# o The script supports the feature called "delayed par-check".
# That means it can try to unpack downloaded files without par-checking
# them fisrt. Only if unpack fails, the script schedules par-check,
# then unpacks again.
# To use delayed par-check set following options in nzbget configuration file:
# ParCheck=no
# ParRepair=yes
# LoadPars=one (or) LoadPars=all
#
# o If you want to par-check/repair all files before trying to unpack them,
# set option "ParCheck=yes".
#
####################### End of Usage instructions #######################
# NZBGet passes following arguments to postprocess-programm as environment
# variables:
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
# NZBPP_NZBFILENAME - name of processed nzb-file;
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
# found);
# NZBPP_PARSTATUS - result of par-check:
# 0 = not checked: par-check disabled or nzb-file does
# not contain any par-files;
# 1 = checked and failed to repair;
# 2 = checked and successfully repaired;
# 3 = checked and can be repaired but repair is disabled;
# NZBPP_NZBCOMPLETED - state of nzb-job:
# 0 = there are more collections in this nzb-file queued;
# 1 = this was the last collection in nzb-file;
# NZBPP_PARFAILED - indication of failed par-jobs for current nzb-file:
# 0 = no failed par-jobs;
# 1 = current par-job or any of the previous par-jobs for
# the same nzb-files failed;
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string).
# Name of script's configuration file
SCRIPT_CONFIG_FILE="postprocess-example.conf"
# Exit codes
POSTPROCESS_PARCHECK_CURRENT=91
POSTPROCESS_PARCHECK_ALL=92
POSTPROCESS_SUCCESS=93
POSTPROCESS_ERROR=94
POSTPROCESS_NONE=95
# Check if the script is called from nzbget
if [ "$NZBPP_DIRECTORY" = "" -o "$NZBOP_CONFIGFILE" = "" ]; then
echo "*** NZBGet post-process script ***"
echo "This script is supposed to be called from nzbget (0.7.0 or later)."
exit $POSTPROCESS_ERROR
fi
# Check if postprocessing was disabled in postprocessing parameters
# (for current nzb-file) via web-interface or via command line with
# "nzbget -E G O PostProcess=no <ID>"
if [ "$NZBPR_PostProcess" = "no" ]; then
echo "[WARNING] Post-Process: Postprocessing disabled for this nzb-file, exiting"
exit $POSTPROCESS_NONE
fi
echo "[INFO] Post-Process: Post-process script successfully started"
# Determine the location of configuration file (it must be stored in
# the directory with nzbget.conf or in this script's directory).
ConfigDir="${NZBOP_CONFIGFILE%/*}"
ScriptConfigFile="$ConfigDir/$SCRIPT_CONFIG_FILE"
if [ ! -f "$ScriptConfigFile" ]; then
ConfigDir="${0%/*}"
ScriptConfigFile="$ConfigDir/$SCRIPT_CONFIG_FILE"
fi
if [ ! -f "$ScriptConfigFile" ]; then
echo "[ERROR] Post-Process: Configuration file $ScriptConfigFile not found, exiting"
exit $POSTPROCESS_ERROR
fi
# Readg configuration file
while read line; do eval "$line"; done < $ScriptConfigFile
# Check nzbget.conf options
BadConfig=0
if [ "$NZBOP_ALLOWREPROCESS" = "yes" ]; then
echo "[ERROR] Post-Process: Please disable option \"AllowReProcess\" in nzbget configuration file"
BadConfig=1
fi
if [ "$NZBOP_LOADPARS" = "none" ]; then
echo "[ERROR] Post-Process: Please set option \"LoadPars\" to \"One\" or \"All\" in nzbget configuration file"
BadConfig=1
fi
if [ "$NZBOP_PARREPAIR" = "no" ]; then
echo "[ERROR] Post-Process: Please set option \"ParRepair\" to \"Yes\" in nzbget configuration file"
BadConfig=1
fi
if [ "$BadConfig" -eq 1 ]; then
echo "[ERROR] Post-Process: Existing because of not compatible nzbget configuration"
exit $POSTPROCESS_ERROR
fi
# Check if all collections in nzb-file were downloaded
if [ ! "$NZBPP_NZBCOMPLETED" -eq 1 ]; then
echo "[INFO] Post-Process: Not the last collection in nzb-file, exiting"
exit $POSTPROCESS_SUCCESS
fi
# Check par status
if [ "$NZBPP_PARSTATUS" -eq 1 -o "$NZBPP_PARSTATUS" -eq 3 -o "$NZBPP_PARFAILED" -eq 1 ]; then
if [ "$NZBPP_PARSTATUS" -eq 3 ]; then
echo "[WARNING] Post-Process: Par-check successful, but Par-repair disabled, exiting"
else
echo "[WARNING] Post-Process: Par-check failed, exiting"
fi
exit $POSTPROCESS_ERROR
fi
# Check if destination directory exists (important for reprocessing of history items)
if [ ! -d "$NZBPP_DIRECTORY" ]; then
echo "[ERROR] Post-Process: Nothing to post-process: destination directory $NZBPP_DIRECTORY doesn't exist"
exit $POSTPROCESS_ERROR
fi
cd "$NZBPP_DIRECTORY"
# If not just repaired and file "_brokenlog.txt" exists, the collection is damaged
# exiting with returning code $POSTPROCESS_PARCHECK_ALL to request par-repair
if [ ! "$NZBPP_PARSTATUS" -eq 2 ]; then
if [ -f "_brokenlog.txt" ]; then
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
echo "[INFO] Post-Process: Brokenlog found, requesting par-repair"
exit $POSTPROCESS_PARCHECK_ALL
fi
fi
fi
# All checks done, now processing the files
# Flag indicates that something was unrared
Unrared=0
# Unrar the files (if any) to the temporary directory, if there are no rar files this will do nothing
if (ls *.rar >/dev/null 2>&1); then
# Check if unrar exists
$UnrarCmd >/dev/null 2>&1
if [ "$?" -eq 127 ]; then
echo "[ERROR] Post-Process: Unrar not found. Set the path to unrar in script's configuration"
exit $POSTPROCESS_ERROR
fi
# Make a temporary directory to store the unrarred files
ExtractedDirExists=0
if [ -d extracted ]; then
ExtractedDirExists=1
else
mkdir extracted
fi
echo "[INFO] Post-Process: Unraring"
rarpasswordparam=""
if [ "$NZBPR_Password" != "" ]; then
rarpasswordparam="-p$NZBPR_Password"
fi
$UnrarCmd x -y -p- "$rarpasswordparam" -o+ "*.rar" ./extracted/
if [ "$?" -eq 3 ]; then
echo "[ERROR] Post-Process: Unrar failed"
if [ "$ExtractedDirExists" -eq 0 ]; then
rm -R extracted
fi
# for delayed par-check/-repair at least one par-file must be already downloaded
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
echo "[INFO] Post-Process: Requesting par-repair"
exit $POSTPROCESS_PARCHECK_ALL
fi
exit $POSTPROCESS_ERROR
fi
Unrared=1
# Remove the rar files
if [ "$DeleteRarFiles" = "yes" ]; then
echo "[INFO] Post-Process: Deleting rar-files"
rm *.r[0-9][0-9] >/dev/null 2>&1
rm *.rar >/dev/null 2>&1
rm *.s[0-9][0-9] >/dev/null 2>&1
fi
# Go to the temp directory and try to unrar again.
# If there are any rars inside the extracted rars then these will no also be unrarred
cd extracted
if (ls *.rar >/dev/null 2>&1); then
echo "[INFO] Post-Process: Unraring (second pass)"
$UnrarCmd x -y -p- -o+ "*.rar"
if [ "$?" -eq 3 ]; then
echo "[INFO] Post-Process: Unrar (second pass) failed"
exit $POSTPROCESS_ERROR
fi
# Delete the Rar files
if [ "$DeleteRarFiles" = "yes" ]; then
echo "[INFO] Post-Process: Deleting rar-files (second pass)"
rm *.r[0-9][0-9] >/dev/null 2>&1
rm *.rar >/dev/null 2>&1
rm *.s[0-9][0-9] >/dev/null 2>&1
fi
fi
# Move everything back to the Download folder
mv * ..
cd ..
rmdir extracted
fi
# If download contains only nzb-files move them into nzb-directory
# for further download
# Check if command "wc" exists
wc -l . >/dev/null 2>&1
if [ "$?" -ne 127 ]; then
AllFilesCount=`ls -1 2>/dev/null | wc -l`
NZBFilesCount=`ls -1 *.nzb 2>/dev/null | wc -l`
if [ "$AllFilesCount" -eq "$NZBFilesCount" ]; then
echo "[INFO] Moving downloaded nzb-files into incoming nzb-directory for further download"
mv *.nzb $NZBOP_NZBDIR
fi
fi
# Clean up
echo "[INFO] Post-Process: Cleaning up"
chmod -R a+rw .
rm *.nzb >/dev/null 2>&1
rm *.sfv >/dev/null 2>&1
rm *.1 >/dev/null 2>&1
rm _brokenlog.txt >/dev/null 2>&1
if [ "$Unrared" -eq 1 ]; then
# Delete par2-file only if there were files for unpacking.
rm *.[pP][aA][rR]2 >/dev/null 2>&1
fi
if [ "$JoinTS" = "yes" ]; then
# Join any split .ts files if they are named xxxx.0000.ts xxxx.0001.ts
# They will be joined together to a file called xxxx.0001.ts
if (ls *.ts >/dev/null 2>&1); then
echo "[INFO] Post-Process: Joining ts-files"
tsname=`find . -name "*0001.ts" |awk -F/ '{print $NF}'`
cat *0???.ts > ./$tsname
fi
# Remove all the split .ts files
echo "[INFO] Post-Process: Deleting source ts-files"
rm *0???.ts >/dev/null 2>&1
fi
if [ "$RenameIMG" = "yes" ]; then
# Rename img file to iso
# It will be renamed to .img.iso so you can see that it has been renamed
if (ls *.img >/dev/null 2>&1); then
echo "[INFO] Post-Process: Renaming img-files to iso"
imgname=`find . -name "*.img" |awk -F/ '{print $NF}'`
mv $imgname $imgname.iso
fi
fi
# Check if destination directory was set in postprocessing parameters
# (for current nzb-file) via web-interface or via command line with
# "nzbget -E G O DestDir=/new/path <ID>"
if [ "$NZBPR_DestDir" != "" ]; then
mkdir $NZBPR_DestDir
mv * $NZBPR_DestDir >/dev/null 2>&1
cd ..
rmdir $NZBPP_DIRECTORY
fi
# All OK, requesting cleaning up of download queue
exit $POSTPROCESS_SUCCESS

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,700 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
/*
* In this module:
* 1) Download tab;
* 2) Functions for html generation for downloads, also used from other modules (edit and add dialogs).
*/
/*** DOWNLOADS TAB ***********************************************************/
var Downloads = (new function($)
{
'use strict';
// Controls
var $DownloadsTable;
var $DownloadsTabBadge;
var $DownloadsTabBadgeEmpty;
var $DownloadQueueEmpty;
var $DownloadsRecordsPerPage;
// State
var notification = null;
var updateTabInfo;
var groups;
var urls;
this.init = function(options)
{
updateTabInfo = options.updateTabInfo;
$DownloadsTable = $('#DownloadsTable');
$DownloadsTabBadge = $('#DownloadsTabBadge');
$DownloadsTabBadgeEmpty = $('#DownloadsTabBadgeEmpty');
$DownloadQueueEmpty = $('#DownloadQueueEmpty');
$DownloadsRecordsPerPage = $('#DownloadsRecordsPerPage');
var recordsPerPage = UISettings.read('$DownloadsRecordsPerPage', 10);
$DownloadsRecordsPerPage.val(recordsPerPage);
$DownloadsTable.fasttable(
{
filterInput: $('#DownloadsTable_filter'),
filterClearButton: $("#DownloadsTable_clearfilter"),
pagerContainer: $('#DownloadsTable_pager'),
infoContainer: $('#DownloadsTable_info'),
headerCheck: $('#DownloadsTable > thead > tr:first-child'),
filterCaseSensitive: false,
infoEmpty: '&nbsp;', // this is to disable default message "No records"
pageSize: recordsPerPage,
maxPages: UISettings.miniTheme ? 1 : 5,
pageDots: !UISettings.miniTheme,
fillFieldsCallback: fillFieldsCallback,
renderCellCallback: renderCellCallback,
updateInfoCallback: updateInfo
});
$DownloadsTable.on('click', 'a', itemClick);
$DownloadsTable.on('click', 'tbody div.check',
function(event) { $DownloadsTable.fasttable('itemCheckClick', this.parentNode.parentNode, event); });
$DownloadsTable.on('click', 'thead div.check',
function() { $DownloadsTable.fasttable('titleCheckClick') });
$DownloadsTable.on('mousedown', Util.disableShiftMouseDown);
}
this.applyTheme = function()
{
$DownloadsTable.fasttable('setPageSize', UISettings.read('$DownloadsRecordsPerPage', 10),
UISettings.miniTheme ? 1 : 5, !UISettings.miniTheme);
}
this.update = function()
{
RPC.call('listgroups', [], groups_loaded);
}
function groups_loaded(_groups)
{
groups = _groups;
RPC.call('postqueue', [100], posts_loaded);
}
function posts_loaded(posts)
{
mergequeues(posts);
prepare();
RPC.call('urlqueue', [], urls_loaded);
}
function urls_loaded(_urls)
{
urls = _urls;
RPC.next();
}
function mergequeues(posts)
{
var lastPPItemIndex = -1;
for (var i=0, il=posts.length; i < il; i++)
{
var post = posts[i];
var found = false;
for (var j=0, jl=groups.length; j < jl; j++)
{
var group = groups[j];
if (group.NZBID === post.NZBID)
{
found = true;
if (!group.post)
{
group.post = post;
}
lastPPItemIndex = j;
break;
}
}
if (!found)
{
// create a virtual group-item
var group = {post: post};
group.NZBID = post.NZBID;
group.NZBName = post.NZBName;
group.MaxPriority = 0;
group.Category = '';
group.LastID = 0;
group.MinPostTime = 0;
group.FileSizeMB = 0;
group.FileSizeLo = 0;
group.RemainingSizeMB = 0;
group.RemainingSizeLo = 0;
group.PausedSizeMB = 0;
group.PausedSizeLo = 0;
group.FileCount = 0;
group.RemainingFileCount = 0;
group.RemainingParCount = 0;
// insert it after the last pp-item
if (lastPPItemIndex > -1)
{
groups.splice(lastPPItemIndex + 1, 0, group);
}
else
{
groups.unshift(group);
}
}
}
}
function prepare()
{
for (var j=0, jl=groups.length; j < jl; j++)
{
detectStatus(groups[j]);
}
}
this.redraw = function()
{
redraw_table();
Util.show($DownloadsTabBadge, groups.length > 0);
Util.show($DownloadsTabBadgeEmpty, groups.length === 0 && UISettings.miniTheme);
Util.show($DownloadQueueEmpty, groups.length === 0);
}
/*** TABLE *************************************************************************/
function redraw_table()
{
var data = [];
for (var i=0; i < groups.length; i++)
{
var group = groups[i];
var nametext = group.NZBName;
var priority = DownloadsUI.buildPriorityText(group.MaxPriority);
var estimated = DownloadsUI.buildEstimated(group);
var age = Util.formatAge(group.MinPostTime + UISettings.timeZoneCorrection*60*60);
var size = Util.formatSizeMB(group.FileSizeMB, group.FileSizeLo);
var remaining = Util.formatSizeMB(group.RemainingSizeMB-group.PausedSizeMB, group.RemainingSizeLo-group.PausedSizeLo);
var item =
{
id: group.NZBID,
group: group,
data: { age: age, estimated: estimated, size: size, remaining: remaining },
search: group.status + ' ' + nametext + ' ' + priority + ' ' + group.Category + ' ' + age + ' ' + size + ' ' + remaining + ' ' + estimated
};
data.push(item);
}
$DownloadsTable.fasttable('update', data);
}
function fillFieldsCallback(item)
{
var group = item.group;
var status = DownloadsUI.buildStatus(group);
var priority = DownloadsUI.buildPriority(group.MaxPriority);
var progresslabel = DownloadsUI.buildProgressLabel(group);
var progress = DownloadsUI.buildProgress(group, item.data.size, item.data.remaining, item.data.estimated);
var name = '<a href="#" nzbid="' + group.NZBID + '">' + Util.textToHtml(Util.formatNZBName(group.NZBName)) + '</a>';
var category = Util.textToHtml(group.Category);
if (!UISettings.miniTheme)
{
var info = name + ' ' + priority + progresslabel;
item.fields = ['<div class="check img-check"></div>', status, info, category, item.data.age, progress, item.data.estimated];
}
else
{
var info = '<div class="check img-check"></div><span class="row-title">' + name + '</span>' +
' ' + (group.status === 'queued' ? '' : status) + ' ' + priority;
if (category)
{
info += ' <span class="label label-status">' + category + '</span>';
}
if (progresslabel)
{
progress = '<div class="downloads-progresslabel">' + progresslabel + '</div>' + progress;
}
item.fields = [info, progress];
}
}
function renderCellCallback(cell, index, item)
{
if (4 <= index && index <= 7)
{
cell.className = 'text-right';
}
}
function detectStatus(group)
{
group.paused = (group.PausedSizeLo != 0) && (group.RemainingSizeLo == group.PausedSizeLo);
group.postprocess = group.post !== undefined;
if (group.postprocess)
{
switch (group.post.Stage)
{
case 'QUEUED': group.status = 'pp-queued'; break;
case 'LOADING_PARS': group.status = 'checking'; break;
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 'FINISHED': group.status = 'finished'; break;
default: group.status = 'error: ' + group.post.Stage; break;
}
}
else if (group.ActiveDownloads > 0)
{
group.status = 'downloading';
}
else if (group.paused)
{
group.status = 'paused';
}
else
{
group.status = 'queued';
}
}
this.recordsPerPageChange = function()
{
var val = $DownloadsRecordsPerPage.val();
UISettings.write('$DownloadsRecordsPerPage', val);
$DownloadsTable.fasttable('setPageSize', val);
}
function updateInfo(stat)
{
updateTabInfo($DownloadsTabBadge, stat);
}
/*** EDIT ******************************************************/
function itemClick()
{
var nzbid = $(this).attr('nzbid');
$(this).blur();
DownloadsEditDialog.showModal(nzbid, groups);
}
function editCompleted()
{
Refresher.update();
if (notification)
{
Notification.show(notification);
notification = null;
}
}
/*** CHECKMARKS ******************************************************/
function checkBuildEditIDList(UseLastID)
{
var checkedRows = $DownloadsTable.fasttable('checkedRows');
var hasIDs = false;
var checkedEditIDs = [];
for (var i = 0; i < groups.length; i++)
{
var group = groups[i];
if (checkedRows.indexOf(group.NZBID) > -1)
{
if (group.postprocess)
{
Notification.show('#Notif_Downloads_CheckPostProcess');
return null;
}
checkedEditIDs.push(UseLastID ? group.LastID : group.NZBID);
}
}
if (checkedEditIDs.length === 0)
{
Notification.show('#Notif_Downloads_Select');
return null;
}
return checkedEditIDs;
}
/*** TOOLBAR: SELECTED ITEMS ******************************************************/
this.editClick = function()
{
var checkedEditIDs = checkBuildEditIDList(false);
if (!checkedEditIDs)
{
return;
}
if (checkedEditIDs.length == 1)
{
DownloadsEditDialog.showModal(checkedEditIDs[0], groups);
}
else
{
DownloadsMultiDialog.showModal(checkedEditIDs, groups);
}
}
this.mergeClick = function()
{
var checkedEditIDs = checkBuildEditIDList(false);
if (!checkedEditIDs)
{
return;
}
if (checkedEditIDs.length < 2)
{
Notification.show('#Notif_Downloads_SelectMulti');
return;
}
DownloadsMergeDialog.showModal(checkedEditIDs, groups);
}
this.pauseClick = function()
{
var checkedEditIDs = checkBuildEditIDList(true);
if (!checkedEditIDs)
{
return;
}
notification = '#Notif_Downloads_Paused';
RPC.call('editqueue', ['GroupPause', 0, '', checkedEditIDs], editCompleted);
}
this.resumeClick = function()
{
var checkedEditIDs = checkBuildEditIDList(true);
if (!checkedEditIDs)
{
return;
}
notification = '#Notif_Downloads_Resumed';
RPC.call('editqueue', ['GroupResume', 0, '', checkedEditIDs], function()
{
RPC.call('editqueue', ['GroupPauseExtraPars', 0, '', checkedEditIDs], editCompleted);
});
}
this.deleteClick = function()
{
var checkedRows = $DownloadsTable.fasttable('checkedRows');
var downloadIDs = [];
var postprocessIDs = [];
for (var i = 0; i < groups.length; i++)
{
var group = groups[i];
if (checkedRows.indexOf(group.NZBID) > -1)
{
if (group.postprocess)
{
postprocessIDs.push(group.post.ID);
}
if (group.LastID > 0)
{
downloadIDs.push(group.LastID);
}
}
}
if (downloadIDs.length === 0 && postprocessIDs.length === 0)
{
Notification.show('#Notif_Downloads_Select');
return;
}
notification = '#Notif_Downloads_Deleted';
var deletePosts = function()
{
if (postprocessIDs.length > 0)
{
RPC.call('editqueue', ['PostDelete', 0, '', postprocessIDs], editCompleted);
}
else
{
editCompleted();
}
};
var deleteGroups = function()
{
if (downloadIDs.length > 0)
{
RPC.call('editqueue', ['GroupDelete', 0, '', downloadIDs], deletePosts);
}
else
{
deletePosts();
}
};
ConfirmDialog.showModal('DownloadsDeleteConfirmDialog', deleteGroups);
}
this.moveClick = function(action)
{
var checkedEditIDs = checkBuildEditIDList(true);
if (!checkedEditIDs)
{
return;
}
var EditAction = '';
var EditOffset = 0;
switch (action)
{
case 'top':
EditAction = 'GroupMoveTop';
checkedEditIDs.reverse();
break;
case 'bottom':
EditAction = 'GroupMoveBottom';
break;
case 'up':
EditAction = 'GroupMoveOffset';
EditOffset = -1;
break;
case 'down':
EditAction = 'GroupMoveOffset';
EditOffset = 1;
checkedEditIDs.reverse();
break;
}
notification = '';
RPC.call('editqueue', [EditAction, EditOffset, '', checkedEditIDs], editCompleted);
}
}(jQuery));
/*** FUNCTIONS FOR HTML GENERATION (also used from other modules) *****************************/
var DownloadsUI = (new function($)
{
'use strict';
this.fillPriorityCombo = function(combo)
{
combo.empty();
combo.append('<option value="-100">very low</option>');
combo.append('<option value="-50">low</option>');
combo.append('<option value="0">normal</option>');
combo.append('<option value="50">high</option>');
combo.append('<option value="100">very high</option>');
}
this.fillCategoryCombo = function(combo)
{
combo.empty();
combo.append('<option></option>');
for (var i=0; i < Options.categories.length; i++)
{
combo.append($('<option></option>').text(Options.categories[i]));
}
}
this.buildStatus = function(group)
{
if (group.postprocess && group.status !== 'pp-queued')
{
if (Status.status.PostPaused)
{
return '<span class="label label-status label-warning">' + group.status + '</span>';
}
else
{
return '<span class="label label-status label-success">' + group.status + '</span>';
}
}
switch (group.status)
{
case 'pp-queued': return '<span class="label label-status">pp-queued</span>';
case 'downloading': return '<span class="label label-status label-success">downloading</span>';
case 'paused': return '<span class="label label-status label-warning">paused</span>';
case 'queued': return '<span class="label label-status">queued</span>';
default: return '<span class="label label-status label-important">internal error(' + group.status + ')</span>';
}
}
this.buildProgress = function(group, totalsize, remaining, estimated)
{
if (group.status === 'downloading' || (group.postprocess && !Status.status.PostPaused))
{
var kind = 'progress-success';
}
else if (group.status === 'paused' || (group.postprocess && Status.status.PostPaused))
{
var kind = 'progress-warning';
}
else
{
var kind = 'progress-none';
}
var totalMB = group.FileSizeMB-group.PausedSizeMB;
var remainingMB = group.RemainingSizeMB-group.PausedSizeMB;
var percent = Math.round((totalMB - remainingMB) / totalMB * 100);
var progress = '';
if (group.postprocess)
{
totalsize = '';
remaining = '';
percent = Math.round(group.post.StageProgress / 10);
}
if (!UISettings.miniTheme)
{
progress =
'<div class="progress-block">'+
'<div class="progress progress-striped ' + kind + '">'+
'<div class="bar" style="width:' + percent + '%;"></div>'+
'</div>'+
'<div class="bar-text-left">' + totalsize + '</div>'+
'<div class="bar-text-right">' + remaining + '</div>'+
'</div>';
}
else
{
progress =
'<div class="progress-block">'+
'<div class="progress progress-striped ' + kind + '">'+
'<div class="bar" style="width:' + percent + '%;"></div>'+
'</div>'+
'<div class="bar-text-left">' + (totalsize !== '' ? 'total ' : '') + totalsize + '</div>'+
'<div class="bar-text-center">' + (estimated !== '' ? '[' + estimated + ']': '') + '</div>'+
'<div class="bar-text-right">' + remaining + (remaining !== '' ? ' left' : '') + '</div>'+
'</div>';
}
return progress;
}
this.buildEstimated = function(group)
{
if (group.postprocess)
{
if (group.post.StageProgress > 0)
{
return Util.formatTimeLeft(group.post.StageTimeSec / group.post.StageProgress * (1000 - group.post.StageProgress));
}
}
else if (!group.paused && Status.status.DownloadRate > 0)
{
return Util.formatTimeLeft((group.RemainingSizeMB-group.PausedSizeMB)*1024/(Status.status.DownloadRate/1024));
}
return '';
}
this.buildProgressLabel = function(group)
{
var text = '';
if (group.postprocess && !Status.status.PostPaused)
{
switch (group.post.Stage)
{
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;
}
}
return text !== '' ? ' <span class="label label-success">' + text + '</span>' : '';
}
this.buildPriorityText = function(priority)
{
switch (priority)
{
case 0: return '';
case 100: return 'very high priority';
case 50: return 'high priority';
case -50: return 'low priority';
case -100: return 'very low priority';
default: return 'priority: ' + priority;
}
}
this.buildPriority = function(priority)
{
switch (priority)
{
case 0: return '';
case 100: return ' <span class="label label-priority label-important">very high priority</span>';
case 50: return ' <span class="label label-priority label-important">high priority</span>';
case -50: return ' <span class="label label-priority label-info">low priority</span>';
case -100: return ' <span class="label label-priority label-info">very low priority</span>';
}
if (priority > 0)
{
return ' <span class="label label-priority label-important">priority: ' + priority + '</span>';
}
else if (priority < 0)
{
return ' <span class="label label-priority label-info">priority: ' + priority + '</span>';
}
}
}(jQuery));

View File

File diff suppressed because it is too large Load Diff

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