Compare commits

..

1 Commits
v13.0 ... v12.0

Author SHA1 Message Date
Andrey Prygunkov
fada56ab2e version 12.0 (2 Jan. 2014) 2014-01-21 20:47:15 +00:00
142 changed files with 12361 additions and 26600 deletions

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,26 +50,26 @@
#include "Log.h"
#include "Options.h"
#include "ServerPool.h"
#include "StatMeter.h"
#include "Util.h"
extern DownloadSpeedMeter* g_pDownloadSpeedMeter;
extern DownloadQueueHolder* g_pDownloadQueueHolder;
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern StatMeter* g_pStatMeter;
ArticleDownloader::ArticleDownloader()
{
debug("Creating ArticleDownloader");
m_szResultFilename = NULL;
m_szTempFilename = NULL;
m_szArticleFilename = NULL;
m_szInfoName = NULL;
m_szOutputFilename = NULL;
m_pConnection = NULL;
m_eStatus = adUndefined;
m_bDuplicate = false;
m_eFormat = Decoder::efUnknown;
m_szResultFilename = NULL;
m_szTempFilename = NULL;
m_szArticleFilename = NULL;
m_szInfoName = NULL;
m_szOutputFilename = NULL;
m_pConnection = NULL;
m_eStatus = adUndefined;
m_bDuplicate = false;
m_eFormat = Decoder::efUnknown;
SetLastUpdateTimeNow();
}
@@ -128,7 +128,22 @@ void ArticleDownloader::Run()
BuildOutputFilename();
m_szResultFilename = m_pArticleInfo->GetResultFilename();
if (g_pOptions->GetContinuePartial())
{
if (Util::FileExists(m_szResultFilename))
{
// file exists from previous program's start
detail("Article %s already downloaded, skipping", m_szInfoName);
FreeConnection(true);
SetStatus(adFinished);
Notify(NULL);
return;
}
}
EStatus Status = adFailed;
int iRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
int iRemainedRetries = iRetries;
Servers failedServers;
@@ -137,7 +152,6 @@ void ArticleDownloader::Run()
NewsServer* pLastServer = NULL;
int iLevel = 0;
int iServerConfigGeneration = g_pServerPool->GetGeneration();
bool bForce = m_pFileInfo->GetNZBInfo()->GetForcePriority();
while (!IsStopped())
{
@@ -152,8 +166,7 @@ void ArticleDownloader::Run()
SetLastUpdateTimeNow();
SetStatus(adRunning);
if (IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
iServerConfigGeneration != g_pServerPool->GetGeneration())
{
Status = adRetry;
@@ -175,7 +188,7 @@ void ArticleDownloader::Run()
if (Status == adFinished || Status == adFailed || Status == adNotFound || Status == adCrcError)
{
m_ServerStats.StatOp(pNewsServer->GetID(), Status == adFinished ? 1 : 0, Status == adFinished ? 0 : 1, ServerStatList::soSet);
m_ServerStats.SetStat(pNewsServer->GetID(), Status == adFinished ? 1 : 0, Status == adFinished ? 0 : 1, false);
}
}
@@ -199,11 +212,6 @@ void ArticleDownloader::Run()
}
}
if (m_pConnection)
{
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
if (Status == adFinished || Status == adFatalError)
{
break;
@@ -222,16 +230,14 @@ void ArticleDownloader::Run()
}
if (pWantServer &&
!(IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
iServerConfigGeneration != g_pServerPool->GetGeneration()))
!(IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
iServerConfigGeneration != g_pServerPool->GetGeneration()))
{
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
SetStatus(adWaiting);
int msec = 0;
while (!(IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
iServerConfigGeneration != g_pServerPool->GetGeneration()) &&
while (!(IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
iServerConfigGeneration != g_pServerPool->GetGeneration()) &&
msec < g_pOptions->GetRetryInterval() * 1000)
{
usleep(100 * 1000);
@@ -241,8 +247,7 @@ void ArticleDownloader::Run()
SetStatus(adRunning);
}
if (IsStopped() || (g_pOptions->GetPauseDownload() && !bForce) ||
(g_pOptions->GetTempPauseDownload() && !m_pFileInfo->GetExtraPriority()) ||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
iServerConfigGeneration != g_pServerPool->GetGeneration())
{
Status = adRetry;
@@ -397,16 +402,11 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
while (!IsStopped())
{
time_t tOldTime = m_tLastUpdateTime;
SetLastUpdateTimeNow();
if (tOldTime != m_tLastUpdateTime)
{
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
// Throttle the bandwidth
while (!IsStopped() && (g_pOptions->GetDownloadRate() > 0.0f) &&
(g_pStatMeter->CalcCurrentDownloadSpeed() > g_pOptions->GetDownloadRate()))
(g_pDownloadSpeedMeter->CalcCurrentDownloadSpeed() > g_pOptions->GetDownloadRate()))
{
SetLastUpdateTimeNow();
usleep(10 * 1000);
@@ -414,12 +414,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
int iLen = 0;
char* line = m_pConnection->ReadLine(szLineBuf, LineBufSize, &iLen);
g_pStatMeter->AddSpeedReading(iLen);
if (g_pOptions->GetAccurateRate())
{
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
g_pDownloadSpeedMeter->AddSpeedReading(iLen);
// Have we encountered a timeout?
if (!line)
@@ -485,13 +480,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
if (m_pOutFile)
{
if (fclose(m_pOutFile) != 0)
{
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
char szErrBuf[256];
error("Could not close file %s: %s", (bDirectWrite ? m_szOutputFilename : m_szTempFilename),
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
fclose(m_pOutFile);
}
if (!bEnd && Status == adRunning && !IsStopped())
@@ -671,7 +660,7 @@ bool ArticleDownloader::PrepareFile(char* szLine)
{
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
const char* szFilename = bDirectWrite ? m_szOutputFilename : m_szTempFilename;
m_pOutFile = fopen(szFilename, bDirectWrite ? FOPEN_RBP : FOPEN_WB);
m_pOutFile = fopen(szFilename, bDirectWrite ? "rb+" : "wb");
if (!m_pOutFile)
{
char szSysErrStr[256];
@@ -794,8 +783,7 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
{
if (!Util::MoveFile(m_szTempFilename, m_szResultFilename))
{
char szErrBuf[256];
error("Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not rename file %s to %s! Errcode: %i", m_szTempFilename, m_szResultFilename, errno);
}
}
@@ -809,6 +797,19 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
if (bOK)
{
detail("Successfully downloaded %s", m_szInfoName);
if (bDirectWrite && g_pOptions->GetContinuePartial())
{
// create empty flag-file to indicate that the artcile was downloaded
FILE* flagfile = fopen(m_szResultFilename, "wb");
if (!flagfile)
{
error("Could not create file %s", m_szResultFilename);
// this error can be ignored
}
fclose(flagfile);
}
return adFinished;
}
else
@@ -850,8 +851,7 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
}
else
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not move file %s to %s! Errcode: %i", m_szTempFilename, m_szResultFilename, errno);
}
return adFinished;
}
@@ -866,7 +866,7 @@ void ArticleDownloader::LogDebugInfo()
ctime_r(&m_tLastUpdateTime, szTime);
#endif
info(" Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(GetTempFilename()));
debug(" Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(GetTempFilename()));
}
void ArticleDownloader::Stop()
@@ -893,7 +893,6 @@ bool ArticleDownloader::Terminate()
pConnection->SetSuppressErrors(true);
pConnection->Cancel();
pConnection->Disconnect();
g_pStatMeter->AddServerData(pConnection->FetchTotalBytesRead(), pConnection->GetNewsServer()->GetID());
g_pServerPool->FreeConnection(pConnection, true);
}
return terminated;
@@ -909,7 +908,6 @@ void ArticleDownloader::FreeConnection(bool bKeepConnected)
{
m_pConnection->Disconnect();
}
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
g_pServerPool->FreeConnection(m_pConnection, true);
m_pConnection = NULL;
m_mutexConnection.Unlock();
@@ -928,10 +926,10 @@ void ArticleDownloader::CompleteFileParts()
char szNZBName[1024];
char szNZBDestDir[1024];
// the locking is needed for accessing the memebers of NZBInfo
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
strncpy(szNZBName, m_pFileInfo->GetNZBInfo()->GetName(), 1024);
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
szNZBName[1024-1] = '\0';
szNZBDestDir[1024-1] = '\0';
@@ -972,7 +970,7 @@ void ArticleDownloader::CompleteFileParts()
if (g_pOptions->GetDecode() && !bDirectWrite)
{
remove(tmpdestfile);
outfile = fopen(tmpdestfile, FOPEN_WBP);
outfile = fopen(tmpdestfile, "wb+");
if (!outfile)
{
error("Could not create file %s!", tmpdestfile);
@@ -1022,7 +1020,7 @@ void ArticleDownloader::CompleteFileParts()
FILE* infile;
const char* fn = pa->GetResultFilename();
infile = fopen(fn, FOPEN_RB);
infile = fopen(fn, "rb");
if (infile)
{
int cnt = BUFFER_SIZE;
@@ -1051,8 +1049,7 @@ void ArticleDownloader::CompleteFileParts()
dstFileName[1024-1] = '\0';
if (!Util::MoveFile(fn, dstFileName))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", fn, dstFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not move file %s to %s! Errcode: %i", fn, dstFileName, errno);
}
}
}
@@ -1064,8 +1061,7 @@ void ArticleDownloader::CompleteFileParts()
fclose(outfile);
if (!Util::MoveFile(tmpdestfile, ofn))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", tmpdestfile, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not move file %s to %s! Errcode: %i", tmpdestfile, ofn, errno);
}
}
@@ -1073,8 +1069,7 @@ void ArticleDownloader::CompleteFileParts()
{
if (!Util::MoveFile(m_szOutputFilename, ofn))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", m_szOutputFilename, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
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)
@@ -1096,7 +1091,7 @@ void ArticleDownloader::CompleteFileParts()
}
}
if (!bDirectWrite)
if (!bDirectWrite || g_pOptions->GetContinuePartial())
{
for (FileInfo::Articles::iterator it = m_pFileInfo->GetArticles()->begin(); it != m_pFileInfo->GetArticles()->end(); it++)
{
@@ -1120,7 +1115,7 @@ void ArticleDownloader::CompleteFileParts()
char szBrokenLogName[1024];
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", szNZBDestDir, (int)PATH_SEPARATOR);
szBrokenLogName[1024-1] = '\0';
FILE* file = fopen(szBrokenLogName, FOPEN_AB);
FILE* file = fopen(szBrokenLogName, "ab");
fprintf(file, "%s (%i/%i)%s", m_pFileInfo->GetFilename(),
m_pFileInfo->GetTotalArticles() - iBrokenCount - m_pFileInfo->GetMissedArticles(),
m_pFileInfo->GetTotalArticles(), LINE_ENDING);
@@ -1129,14 +1124,14 @@ void ArticleDownloader::CompleteFileParts()
}
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
m_pFileInfo->GetNZBInfo()->GetCompletedFiles()->push_back(strdup(ofn));
if (strcmp(m_pFileInfo->GetNZBInfo()->GetDestDir(), szNZBDestDir))
{
// destination directory was changed during completion, need to move the file
MoveCompletedFiles(m_pFileInfo->GetNZBInfo(), szNZBDestDir);
}
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
SetStatus(adJoined);
}
@@ -1178,8 +1173,7 @@ bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldD
}
else
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", szFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not move file %s to %s! Errcode: %i", szFileName, szNewFileName, errno);
}
}
}
@@ -1201,11 +1195,11 @@ bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldD
{
// copy content to existing new file, then delete old file
FILE* outfile;
outfile = fopen(szBrokenLogName, FOPEN_AB);
outfile = fopen(szBrokenLogName, "ab");
if (outfile)
{
FILE* infile;
infile = fopen(szOldBrokenLogName, FOPEN_RB);
infile = fopen(szOldBrokenLogName, "rb");
if (infile)
{
static const int BUFFER_SIZE = 1024 * 50;
@@ -1236,8 +1230,7 @@ bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldD
// move to new destination
if (!Util::MoveFile(szOldBrokenLogName, szBrokenLogName))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
error("Could not move file %s to %s! Errcode: %i", szOldBrokenLogName, szBrokenLogName, errno);
}
}
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -89,7 +89,7 @@ private:
public:
ArticleDownloader();
virtual ~ArticleDownloader();
~ArticleDownloader();
void SetFileInfo(FileInfo* pFileInfo) { m_pFileInfo = pFileInfo; }
FileInfo* GetFileInfo() { return m_pFileInfo; }
void SetArticleInfo(ArticleInfo* pArticleInfo) { m_pArticleInfo = pArticleInfo; }
@@ -111,4 +111,12 @@ public:
void LogDebugInfo();
};
class DownloadSpeedMeter
{
public:
virtual ~DownloadSpeedMeter() {};
virtual int CalcCurrentDownloadSpeed() = 0;
virtual void AddSpeedReading(int iBytes) = 0;
};
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,22 +46,26 @@
#include "BinRpc.h"
#include "Log.h"
#include "Options.h"
#include "QueueCoordinator.h"
#include "UrlCoordinator.h"
#include "QueueEditor.h"
#include "PrePostProcessor.h"
#include "Util.h"
#include "DownloadInfo.h"
#include "Scanner.h"
#include "StatMeter.h"
extern Options* g_pOptions;
extern QueueCoordinator* g_pQueueCoordinator;
extern UrlCoordinator* g_pUrlCoordinator;
extern PrePostProcessor* g_pPrePostProcessor;
extern Scanner* g_pScanner;
extern StatMeter* g_pStatMeter;
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" };
"Pause/Unpause postprocessor", "History", "Download URL", "URL-queue" };
const unsigned int g_iMessageRequestSizes[] =
{ 0,
@@ -79,7 +83,8 @@ const unsigned int g_iMessageRequestSizes[] =
sizeof(SNZBWriteLogRequest),
sizeof(SNZBScanRequest),
sizeof(SNZBHistoryRequest),
sizeof(SNZBDownloadUrlRequest)
sizeof(SNZBDownloadUrlRequest),
sizeof(SNZBUrlQueueRequest)
};
//*****************************************************************
@@ -186,6 +191,10 @@ void BinRpcProcessor::Dispatch()
command = new DownloadUrlBinCommand();
break;
case eRemoteRequestUrlQueue:
command = new UrlQueueBinCommand();
break;
default:
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
break;
@@ -250,6 +259,10 @@ void PauseUnpauseBinCommand::Execute()
g_pOptions->SetPauseDownload(ntohl(PauseUnpauseRequest.m_bPause));
break;
case eRemotePauseUnpauseActionDownload2:
g_pOptions->SetPauseDownload2(ntohl(PauseUnpauseRequest.m_bPause));
break;
case eRemotePauseUnpauseActionPostProcess:
g_pOptions->SetPausePostProcess(ntohl(PauseUnpauseRequest.m_bPause));
break;
@@ -282,7 +295,8 @@ void DumpDebugBinCommand::Execute()
return;
}
g_pLog->LogDebugInfo();
g_pQueueCoordinator->LogDebugInfo();
g_pUrlCoordinator->LogDebugInfo();
SendBoolResponse(true, "Debug-Command completed successfully");
}
@@ -344,7 +358,7 @@ void DownloadBinCommand::Execute()
bool bAddTop = ntohl(DownloadRequest.m_bAddFirst);
bool bOK = g_pScanner->AddExternalFile(DownloadRequest.m_szFilename, DownloadRequest.m_szCategory,
iPriority, NULL, 0, dmScore, NULL, bAddTop, bAddPaused, NULL, NULL, pRecvBuffer, iBufLen, NULL) != Scanner::asFailed;
iPriority, NULL, 0, dmScore, NULL, bAddTop, bAddPaused, NULL, pRecvBuffer, iBufLen) != Scanner::asFailed;
char tmp[1024];
snprintf(tmp, 1024, bOK ? "Collection %s added to queue" : "Download Request failed for %s",
@@ -388,13 +402,13 @@ void ListBinCommand::Execute()
}
// Make a data structure and copy all the elements of the list into it
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
// calculate required buffer size for nzbs
int iNrNZBEntries = pDownloadQueue->GetQueue()->size();
int iNrNZBEntries = pDownloadQueue->GetNZBInfoList()->size();
int iNrPPPEntries = 0;
bufsize += iNrNZBEntries * sizeof(SNZBListResponseNZBEntry);
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
bufsize += strlen(pNZBInfo->GetFilename()) + 1;
@@ -419,47 +433,29 @@ void ListBinCommand::Execute()
}
// calculate required buffer size for files
int iNrFileEntries = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
int iNrFileEntries = pDownloadQueue->GetFileQueue()->size();
bufsize += iNrFileEntries * sizeof(SNZBListResponseFileEntry);
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
{
FileInfo* pFileInfo = *it2;
iNrFileEntries++;
bufsize += sizeof(SNZBListResponseFileEntry);
bufsize += strlen(pFileInfo->GetSubject()) + 1;
bufsize += strlen(pFileInfo->GetFilename()) + 1;
// align struct to 4-bytes, needed by ARM-processor (and may be others)
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
}
FileInfo* pFileInfo = *it;
bufsize += strlen(pFileInfo->GetSubject()) + 1;
bufsize += strlen(pFileInfo->GetFilename()) + 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;
// write nzb entries
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++)
{
unsigned long iSizeHi, iSizeLo;
NZBInfo* pNZBInfo = *it;
SNZBListResponseNZBEntry* pListAnswer = (SNZBListResponseNZBEntry*) bufptr;
unsigned long iSizeHi, iSizeLo, iRemainingSizeHi, iRemainingSizeLo, iPausedSizeHi, iPausedSizeLo;
Util::SplitInt64(pNZBInfo->GetSize(), &iSizeHi, &iSizeLo);
Util::SplitInt64(pNZBInfo->GetRemainingSize(), &iRemainingSizeHi, &iRemainingSizeLo);
Util::SplitInt64(pNZBInfo->GetPausedSize(), &iPausedSizeHi, &iPausedSizeLo);
pListAnswer->m_iID = htonl(pNZBInfo->GetID());
pListAnswer->m_iKind = htonl(pNZBInfo->GetKind());
pListAnswer->m_iSizeLo = htonl(iSizeLo);
pListAnswer->m_iSizeHi = htonl(iSizeHi);
pListAnswer->m_iRemainingSizeLo = htonl(iRemainingSizeLo);
pListAnswer->m_iRemainingSizeHi = htonl(iRemainingSizeHi);
pListAnswer->m_iPausedSizeLo = htonl(iPausedSizeLo);
pListAnswer->m_iPausedSizeHi = htonl(iPausedSizeHi);
pListAnswer->m_iPausedCount = htonl(pNZBInfo->GetPausedFileCount());
pListAnswer->m_iPriority = htonl(pNZBInfo->GetPriority());
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);
@@ -488,7 +484,7 @@ void ListBinCommand::Execute()
// write ppp entries
int iNZBIndex = 1;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++, iNZBIndex++)
for (NZBInfoList::iterator it = pDownloadQueue->GetNZBInfoList()->begin(); it != pDownloadQueue->GetNZBInfoList()->end(); it++, iNZBIndex++)
{
NZBInfo* pNZBInfo = *it;
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
@@ -514,62 +510,58 @@ void ListBinCommand::Execute()
}
// write file entries
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
unsigned long iSizeHi, iSizeLo;
FileInfo* pFileInfo = *it;
SNZBListResponseFileEntry* pListAnswer = (SNZBListResponseFileEntry*) bufptr;
pListAnswer->m_iID = htonl(pFileInfo->GetID());
int iNZBIndex = 0;
for (unsigned int i = 0; i < pDownloadQueue->GetNZBInfoList()->size(); i++)
{
FileInfo* pFileInfo = *it2;
unsigned long iSizeHi, iSizeLo;
SNZBListResponseFileEntry* pListAnswer = (SNZBListResponseFileEntry*) bufptr;
pListAnswer->m_iID = htonl(pFileInfo->GetID());
int iNZBIndex = 0;
for (unsigned int i = 0; i < pDownloadQueue->GetQueue()->size(); i++)
iNZBIndex++;
if (pDownloadQueue->GetNZBInfoList()->at(i) == pFileInfo->GetNZBInfo())
{
iNZBIndex++;
if (pDownloadQueue->GetQueue()->at(i) == pFileInfo->GetNZBInfo())
{
break;
}
break;
}
pListAnswer->m_iNZBIndex = htonl(iNZBIndex);
}
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));
}
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);
Util::SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo);
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_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
bufptr += sizeof(SNZBListResponseFileEntry);
strcpy(bufptr, pFileInfo->GetSubject());
bufptr += ntohl(pListAnswer->m_iSubjectLen);
strcpy(bufptr, pFileInfo->GetFilename());
bufptr += ntohl(pListAnswer->m_iFilenameLen);
// align struct to 4-bytes, needed by ARM-processor (and may be others)
if ((size_t)bufptr % 4 > 0)
{
pListAnswer->m_iFilenameLen = htonl(ntohl(pListAnswer->m_iFilenameLen) + 4 - (size_t)bufptr % 4);
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
bufptr += 4 - (size_t)bufptr % 4;
}
Util::SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
Util::SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo);
pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo);
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);
strcpy(bufptr, pFileInfo->GetSubject());
bufptr += ntohl(pListAnswer->m_iSubjectLen);
strcpy(bufptr, pFileInfo->GetFilename());
bufptr += ntohl(pListAnswer->m_iFilenameLen);
// align struct to 4-bytes, needed by ARM-processor (and may be others)
if ((size_t)bufptr % 4 > 0)
{
pListAnswer->m_iFilenameLen = htonl(ntohl(pListAnswer->m_iFilenameLen) + 4 - (size_t)bufptr % 4);
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
bufptr += 4 - (size_t)bufptr % 4;
}
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
delete pRegEx;
@@ -581,33 +573,25 @@ void ListBinCommand::Execute()
if (htonl(ListRequest.m_bServerState))
{
DownloadQueue *pDownloadQueue = DownloadQueue::Lock();
int iPostJobCount = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
iPostJobCount += pNZBInfo->GetPostInfo() ? 1 : 0;
}
long long lRemainingSize;
pDownloadQueue->CalcRemainingSize(&lRemainingSize, NULL);
DownloadQueue::Unlock();
unsigned long iSizeHi, iSizeLo;
ListResponse.m_iDownloadRate = htonl(g_pStatMeter->CalcCurrentDownloadSpeed());
Util::SplitInt64(lRemainingSize, &iSizeHi, &iSizeLo);
ListResponse.m_iDownloadRate = htonl(g_pQueueCoordinator->CalcCurrentDownloadSpeed());
Util::SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
ListResponse.m_iDownloadLimit = htonl(g_pOptions->GetDownloadRate());
ListResponse.m_bDownloadPaused = htonl(g_pOptions->GetPauseDownload());
ListResponse.m_bDownload2Paused = htonl(g_pOptions->GetPauseDownload2());
ListResponse.m_bPostPaused = htonl(g_pOptions->GetPausePostProcess());
ListResponse.m_bScanPaused = htonl(g_pOptions->GetPauseScan());
ListResponse.m_iThreadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself
ListResponse.m_iPostJobCount = htonl(iPostJobCount);
PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue();
ListResponse.m_iPostJobCount = htonl(pPostQueue->size());
g_pQueueCoordinator->UnlockQueue();
int iUpTimeSec, iDnTimeSec;
long long iAllBytes;
bool bStandBy;
g_pStatMeter->CalcTotalStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy);
g_pQueueCoordinator->CalcStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy);
ListResponse.m_iUpTimeSec = htonl(iUpTimeSec);
ListResponse.m_iDownloadTimeSec = htonl(iDnTimeSec);
ListResponse.m_bDownloadStandBy = htonl(bStandBy);
@@ -731,6 +715,7 @@ void EditQueueBinCommand::Execute()
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)
@@ -780,12 +765,19 @@ void EditQueueBinCommand::Execute()
}
}
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
bool bOK = pDownloadQueue->EditList(
iNrIDEntries > 0 ? &cIDList : NULL,
iNrNameEntries > 0 ? &cNameList : NULL,
(DownloadQueue::EMatchMode)iMatchMode, (DownloadQueue::EEditAction)iAction, iOffset, szText);
DownloadQueue::Unlock();
bool bOK = false;
if (iAction < eRemoteEditActionPostMoveOffset)
{
bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(
iNrIDEntries > 0 ? &cIDList : NULL,
iNrNameEntries > 0 ? &cNameList : NULL,
(QueueEditor::EMatchMode)iMatchMode, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset, szText);
}
else
{
bOK = g_pPrePostProcessor->QueueEditList(&cIDList, (PrePostProcessor::EEditAction)iAction, iOffset, szText);
}
free(pBuf);
@@ -824,23 +816,17 @@ void PostQueueBinCommand::Execute()
int bufsize = 0;
// Make a data structure and copy all the elements of the list into it
NZBList* pNZBList = DownloadQueue::Lock()->GetQueue();
PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue();
int NrEntries = pPostQueue->size();
// calculate required buffer size
int NrEntries = 0;
for (NZBList::iterator it = pNZBList->begin(); it != pNZBList->end(); it++)
bufsize = NrEntries * sizeof(SNZBPostQueueResponseEntry);
for (PostQueue::iterator it = pPostQueue->begin(); it != pPostQueue->end(); it++)
{
NZBInfo* pNZBInfo = *it;
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
if (!pPostInfo)
{
continue;
}
NrEntries++;
bufsize += sizeof(SNZBPostQueueResponseEntry);
PostInfo* pPostInfo = *it;
bufsize += strlen(pPostInfo->GetNZBInfo()->GetFilename()) + 1;
bufsize += strlen(pPostInfo->GetNZBInfo()->GetName()) + 1;
bufsize += strlen(pPostInfo->GetInfoName()) + 1;
bufsize += strlen(pPostInfo->GetNZBInfo()->GetDestDir()) + 1;
bufsize += strlen(pPostInfo->GetProgressLabel()) + 1;
// align struct to 4-bytes, needed by ARM-processor (and may be others)
@@ -851,30 +837,24 @@ void PostQueueBinCommand::Execute()
buf = (char*) malloc(bufsize);
char* bufptr = buf;
for (NZBList::iterator it = pNZBList->begin(); it != pNZBList->end(); it++)
for (PostQueue::iterator it = pPostQueue->begin(); it != pPostQueue->end(); it++)
{
NZBInfo* pNZBInfo = *it;
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
if (!pPostInfo)
{
continue;
}
PostInfo* pPostInfo = *it;
SNZBPostQueueResponseEntry* pPostQueueAnswer = (SNZBPostQueueResponseEntry*) bufptr;
pPostQueueAnswer->m_iID = htonl(pNZBInfo->GetID());
pPostQueueAnswer->m_iID = htonl(pPostInfo->GetID());
pPostQueueAnswer->m_iStage = htonl(pPostInfo->GetStage());
pPostQueueAnswer->m_iStageProgress = htonl(pPostInfo->GetStageProgress());
pPostQueueAnswer->m_iFileProgress = htonl(pPostInfo->GetFileProgress());
pPostQueueAnswer->m_iTotalTimeSec = htonl((int)(pPostInfo->GetStartTime() ? tCurTime - pPostInfo->GetStartTime() : 0));
pPostQueueAnswer->m_iStageTimeSec = htonl((int)(pPostInfo->GetStageTime() ? tCurTime - pPostInfo->GetStageTime() : 0));
pPostQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pPostInfo->GetNZBInfo()->GetFilename()) + 1);
pPostQueueAnswer->m_iInfoNameLen = htonl(strlen(pPostInfo->GetNZBInfo()->GetName()) + 1);
pPostQueueAnswer->m_iInfoNameLen = htonl(strlen(pPostInfo->GetInfoName()) + 1);
pPostQueueAnswer->m_iDestDirLen = htonl(strlen(pPostInfo->GetNZBInfo()->GetDestDir()) + 1);
pPostQueueAnswer->m_iProgressLabelLen = htonl(strlen(pPostInfo->GetProgressLabel()) + 1);
bufptr += sizeof(SNZBPostQueueResponseEntry);
strcpy(bufptr, pPostInfo->GetNZBInfo()->GetFilename());
bufptr += ntohl(pPostQueueAnswer->m_iNZBFilenameLen);
strcpy(bufptr, pPostInfo->GetNZBInfo()->GetName());
strcpy(bufptr, pPostInfo->GetInfoName());
bufptr += ntohl(pPostQueueAnswer->m_iInfoNameLen);
strcpy(bufptr, pPostInfo->GetNZBInfo()->GetDestDir());
bufptr += ntohl(pPostQueueAnswer->m_iDestDirLen);
@@ -889,7 +869,7 @@ void PostQueueBinCommand::Execute()
}
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
PostQueueResponse.m_iNrTrailingEntries = htonl(NrEntries);
PostQueueResponse.m_iTrailingDataLength = htonl(bufsize);
@@ -981,12 +961,12 @@ void HistoryBinCommand::Execute()
int bufsize = 0;
// Make a data structure and copy all the elements of the list into it
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
// calculate required buffer size for nzbs
int iNrEntries = pDownloadQueue->GetHistory()->size();
int iNrEntries = pDownloadQueue->GetHistoryList()->size();
bufsize += iNrEntries * sizeof(SNZBHistoryResponseEntry);
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
char szNicename[1024];
@@ -1000,7 +980,7 @@ void HistoryBinCommand::Execute()
char* bufptr = buf;
// write nzb entries
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
SNZBHistoryResponseEntry* pListAnswer = (SNZBHistoryResponseEntry*) bufptr;
@@ -1012,7 +992,7 @@ void HistoryBinCommand::Execute()
pHistoryInfo->GetName(szNicename, sizeof(szNicename));
pListAnswer->m_iNicenameLen = htonl(strlen(szNicename) + 1);
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
{
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
unsigned long iSizeHi, iSizeLo;
@@ -1023,10 +1003,10 @@ void HistoryBinCommand::Execute()
pListAnswer->m_iParStatus = htonl(pNZBInfo->GetParStatus());
pListAnswer->m_iScriptStatus = htonl(pNZBInfo->GetScriptStatuses()->CalcTotalStatus());
}
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
else if (pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
{
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
pListAnswer->m_iUrlStatus = htonl(pNZBInfo->GetUrlStatus());
UrlInfo* pUrlInfo = pHistoryInfo->GetUrlInfo();
pListAnswer->m_iUrlStatus = htonl(pUrlInfo->GetStatus());
}
bufptr += sizeof(SNZBHistoryResponseEntry);
@@ -1041,7 +1021,7 @@ void HistoryBinCommand::Execute()
}
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
HistoryResponse.m_iNrTrailingEntries = htonl(iNrEntries);
HistoryResponse.m_iTrailingDataLength = htonl(bufsize);
@@ -1076,18 +1056,15 @@ void DownloadUrlBinCommand::Execute()
return;
}
NZBInfo* pNZBInfo = new NZBInfo();
pNZBInfo->SetKind(NZBInfo::nkUrl);
pNZBInfo->SetURL(DownloadUrlRequest.m_szURL);
pNZBInfo->SetFilename(DownloadUrlRequest.m_szNZBFilename);
pNZBInfo->SetCategory(DownloadUrlRequest.m_szCategory);
pNZBInfo->SetPriority(ntohl(DownloadUrlRequest.m_iPriority));
pNZBInfo->SetAddUrlPaused(ntohl(DownloadUrlRequest.m_bAddPaused));
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));
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
pDownloadQueue->GetQueue()->Add(pNZBInfo, ntohl(DownloadUrlRequest.m_bAddFirst));
pDownloadQueue->Save();
DownloadQueue::Unlock();
g_pUrlCoordinator->AddUrlToQueue(pUrlInfo, ntohl(DownloadUrlRequest.m_bAddFirst));
info("Request: Queue url %s", DownloadUrlRequest.m_szURL);
@@ -1096,3 +1073,77 @@ void DownloadUrlBinCommand::Execute()
tmp[1024-1] = '\0';
SendBoolResponse(true, tmp);
}
void UrlQueueBinCommand::Execute()
{
SNZBUrlQueueRequest UrlQueueRequest;
if (!ReceiveRequest(&UrlQueueRequest, sizeof(UrlQueueRequest)))
{
return;
}
SNZBUrlQueueResponse UrlQueueResponse;
memset(&UrlQueueResponse, 0, sizeof(UrlQueueResponse));
UrlQueueResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
UrlQueueResponse.m_MessageBase.m_iStructSize = htonl(sizeof(UrlQueueResponse));
UrlQueueResponse.m_iEntrySize = htonl(sizeof(SNZBUrlQueueResponseEntry));
char* buf = NULL;
int bufsize = 0;
// Make a data structure and copy all the elements of the list into it
UrlQueue* pUrlQueue = g_pQueueCoordinator->LockQueue()->GetUrlQueue();
int NrEntries = pUrlQueue->size();
// calculate required buffer size
bufsize = NrEntries * sizeof(SNZBUrlQueueResponseEntry);
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
{
UrlInfo* pUrlInfo = *it;
bufsize += strlen(pUrlInfo->GetURL()) + 1;
bufsize += strlen(pUrlInfo->GetNZBFilename()) + 1;
// align struct to 4-bytes, needed by ARM-processor (and may be others)
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
}
buf = (char*) malloc(bufsize);
char* bufptr = buf;
for (UrlQueue::iterator it = pUrlQueue->begin(); it != pUrlQueue->end(); it++)
{
UrlInfo* pUrlInfo = *it;
SNZBUrlQueueResponseEntry* pUrlQueueAnswer = (SNZBUrlQueueResponseEntry*) bufptr;
pUrlQueueAnswer->m_iID = htonl(pUrlInfo->GetID());
pUrlQueueAnswer->m_iURLLen = htonl(strlen(pUrlInfo->GetURL()) + 1);
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pUrlInfo->GetNZBFilename()) + 1);
bufptr += sizeof(SNZBUrlQueueResponseEntry);
strcpy(bufptr, pUrlInfo->GetURL());
bufptr += ntohl(pUrlQueueAnswer->m_iURLLen);
strcpy(bufptr, pUrlInfo->GetNZBFilename());
bufptr += ntohl(pUrlQueueAnswer->m_iNZBFilenameLen);
// align struct to 4-bytes, needed by ARM-processor (and may be others)
if ((size_t)bufptr % 4 > 0)
{
pUrlQueueAnswer->m_iNZBFilenameLen = htonl(ntohl(pUrlQueueAnswer->m_iNZBFilenameLen) + 4 - (size_t)bufptr % 4);
memset(bufptr, 0, 4 - (size_t)bufptr % 4); //suppress valgrind warning "uninitialized data"
bufptr += 4 - (size_t)bufptr % 4;
}
}
g_pQueueCoordinator->UnlockQueue();
UrlQueueResponse.m_iNrTrailingEntries = htonl(NrEntries);
UrlQueueResponse.m_iTrailingDataLength = htonl(bufsize);
// Send the request answer
m_pConnection->Send((char*) &UrlQueueResponse, sizeof(UrlQueueResponse));
// Send the data
if (bufsize > 0)
{
m_pConnection->Send(buf, bufsize);
}
free(buf);
}

View File

2903
ChangeLog
View File

File diff suppressed because it is too large Load Diff

View File

@@ -76,7 +76,7 @@ void ColoredFrontend::PrintStatus()
timeString[0] = '\0';
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
if (iCurrentDownloadSpeed > 0 && !m_bPauseDownload)
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
{
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
int h = (int)(remain_sec / 3600);
@@ -115,7 +115,7 @@ void ColoredFrontend::PrintStatus()
snprintf(tmp, 1024, " %d threads, %.*f KB/s, %.2f MB remaining%s%s%s%s%s\n",
m_iThreadCount, (iCurrentDownloadSpeed >= 10*1024 ? 0 : 1), (float)iCurrentDownloadSpeed / 1024.0,
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
m_bPauseDownload || m_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
szDownloadLimit, szControlSeq);
tmp[1024-1] = '\0';
printf("%s", tmp);

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -117,20 +117,19 @@ Connection::Connection(const char* szHost, int iPort, bool bTLS)
{
debug("Creating Connection");
m_szHost = NULL;
m_iPort = iPort;
m_bTLS = bTLS;
m_szCipher = NULL;
m_eStatus = csDisconnected;
m_iSocket = INVALID_SOCKET;
m_iBufAvail = 0;
m_iTimeout = 60;
m_bSuppressErrors = true;
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
m_iTotalBytesRead = 0;
m_szHost = NULL;
m_iPort = iPort;
m_bTLS = bTLS;
m_szCipher = NULL;
m_eStatus = csDisconnected;
m_iSocket = INVALID_SOCKET;
m_iBufAvail = 0;
m_iTimeout = 60;
m_bSuppressErrors = true;
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
#ifndef DISABLE_TLS
m_pTLSSocket = NULL;
m_bTLSError = false;
m_pTLSSocket = NULL;
m_bTLSError = false;
#endif
if (szHost)
@@ -439,9 +438,7 @@ char* Connection::ReadLine(char* pBuffer, int iSize, int* pBytesRead)
{
*pBytesRead = iBytesRead;
}
m_iTotalBytesRead += iBytesRead;
if (pBufPtr == pBuffer)
{
return NULL;
@@ -861,10 +858,3 @@ const char* Connection::GetRemoteAddr()
return m_szRemoteAddr;
}
int Connection::FetchTotalBytesRead()
{
int iTotal = m_iTotalBytesRead;
m_iTotalBytesRead = 0;
return iTotal;
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -60,7 +60,6 @@ protected:
int m_iTimeout;
bool m_bSuppressErrors;
char m_szRemoteAddr[20];
int m_iTotalBytesRead;
#ifndef DISABLE_TLS
TLSSocket* m_pTLSSocket;
bool m_bTLSError;
@@ -113,7 +112,6 @@ public:
#ifndef DISABLE_TLS
bool StartTLS(bool bIsClient, const char* szCertFile, const char* szKeyFile);
#endif
int FetchTotalBytesRead();
};
#endif

View File

View File

View File

File diff suppressed because it is too large Load Diff

80
DiskState.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* 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 DISKSTATE_H
#define DISKSTATE_H
#include "DownloadInfo.h"
#include "FeedInfo.h"
#include "NewsServer.h"
class DiskState
{
private:
int fscanf(FILE* infile, const char* Format, ...);
int ParseFormatVersion(const char* szFormatSignature);
bool SaveFileInfo(FileInfo* pFileInfo, const char* szFilename);
bool LoadFileInfo(FileInfo* pFileInfo, const char* szFilename, bool bFileSummary, bool bArticles);
void SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile);
bool LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
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 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 SaveDupInfo(DupInfo* pDupInfo, FILE* outfile);
bool LoadDupInfo(DupInfo* pDupInfo, FILE* infile, int iFormatVersion);
void SaveHistory(DownloadQueue* pDownloadQueue, FILE* outfile);
bool LoadHistory(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
int FindNZBInfoIndex(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
bool SaveFeedStatus(Feeds* pFeeds, FILE* outfile);
bool LoadFeedStatus(Feeds* pFeeds, FILE* infile, int iFormatVersion);
bool SaveFeedHistory(FeedHistory* pFeedHistory, FILE* outfile);
bool LoadFeedHistory(FeedHistory* pFeedHistory, FILE* infile, int iFormatVersion);
void CalcCriticalHealth(DownloadQueue* pDownloadQueue);
bool SaveServerStats(Servers* pServers, FILE* outfile);
bool LoadServerStats(Servers* pServers, FILE* infile, int iFormatVersion);
void ConvertDupeKey(char* buf, int bufsize);
public:
bool DownloadQueueExists();
bool SaveDownloadQueue(DownloadQueue* pDownloadQueue);
bool LoadDownloadQueue(DownloadQueue* pDownloadQueue);
bool SaveFile(FileInfo* pFileInfo);
bool LoadArticles(FileInfo* pFileInfo);
void DiscardDownloadQueue();
bool DiscardFile(FileInfo* pFileInfo);
bool SaveFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
bool LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
bool SaveStats(Servers* pServers);
bool LoadStats(Servers* pServers);
void CleanupTempDir(DownloadQueue* pDownloadQueue);
};
#endif

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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,48 +31,11 @@
#include <deque>
#include <time.h>
#include "Observer.h"
#include "Log.h"
#include "Thread.h"
class NZBInfo;
class DownloadQueue;
class PostInfo;
class ServerStat
{
private:
int m_iServerID;
int m_iSuccessArticles;
int m_iFailedArticles;
public:
ServerStat(int iServerID);
int GetServerID() { return m_iServerID; }
int GetSuccessArticles() { return m_iSuccessArticles; }
void SetSuccessArticles(int iSuccessArticles) { m_iSuccessArticles = iSuccessArticles; }
int GetFailedArticles() { return m_iFailedArticles; }
void SetFailedArticles(int iFailedArticles) { m_iFailedArticles = iFailedArticles; }
};
typedef std::vector<ServerStat*> ServerStatListBase;
class ServerStatList : public ServerStatListBase
{
public:
enum EStatOperation
{
soSet,
soAdd,
soSubtract
};
public:
~ServerStatList();
void StatOp(int iServerID, int iSuccessArticles, int iFailedArticles, EStatOperation eStatOperation);
void ListOp(ServerStatList* pServerStats, EStatOperation eStatOperation);
void Clear();
};
class ArticleInfo
{
@@ -118,7 +81,6 @@ private:
NZBInfo* m_pNZBInfo;
Articles m_Articles;
Groups m_Groups;
ServerStatList m_ServerStats;
char* m_szSubject;
char* m_szFilename;
long long m_lSize;
@@ -135,10 +97,11 @@ private:
bool m_bDeleted;
bool m_bFilenameConfirmed;
bool m_bParFile;
int m_iCompletedArticles;
int m_iCompleted;
bool m_bOutputInitialized;
char* m_szOutputFilename;
Mutex* m_pMutexOutputFile;
int m_iPriority;
bool m_bExtraPriority;
int m_iActiveDownloads;
bool m_bAutoDeleted;
@@ -153,7 +116,7 @@ public:
void SetID(int iID);
static void ResetGenID(bool bMax);
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
void SetNZBInfo(NZBInfo* pNZBInfo) { m_pNZBInfo = pNZBInfo; }
void SetNZBInfo(NZBInfo* pNZBInfo);
Articles* GetArticles() { return &m_Articles; }
Groups* GetGroups() { return &m_Groups; }
const char* GetSubject() { return m_szSubject; }
@@ -184,11 +147,11 @@ public:
time_t GetTime() { return m_tTime; }
void SetTime(time_t tTime) { m_tTime = tTime; }
bool GetPaused() { return m_bPaused; }
void SetPaused(bool bPaused);
void SetPaused(bool Paused) { m_bPaused = Paused; }
bool GetDeleted() { return m_bDeleted; }
void SetDeleted(bool Deleted) { m_bDeleted = Deleted; }
int GetCompletedArticles() { return m_iCompletedArticles; }
void SetCompletedArticles(int iCompletedArticles) { m_iCompletedArticles = iCompletedArticles; }
int GetCompleted() { return m_iCompleted; }
void SetCompleted(int iCompleted) { m_iCompleted = iCompleted; }
bool GetParFile() { return m_bParFile; }
void SetParFile(bool bParFile) { m_bParFile = bParFile; }
void ClearArticles();
@@ -198,26 +161,62 @@ public:
void SetOutputFilename(const char* szOutputFilename);
bool GetOutputInitialized() { return m_bOutputInitialized; }
void SetOutputInitialized(bool bOutputInitialized) { m_bOutputInitialized = bOutputInitialized; }
int GetPriority() { return m_iPriority; }
void SetPriority(int iPriority) { m_iPriority = iPriority; }
bool GetExtraPriority() { return m_bExtraPriority; }
void SetExtraPriority(bool bExtraPriority) { m_bExtraPriority = bExtraPriority; };
int GetActiveDownloads() { return m_iActiveDownloads; }
void SetActiveDownloads(int iActiveDownloads);
bool GetAutoDeleted() { return m_bAutoDeleted; }
void SetAutoDeleted(bool bAutoDeleted) { m_bAutoDeleted = bAutoDeleted; }
ServerStatList* GetServerStats() { return &m_ServerStats; }
};
typedef std::deque<FileInfo*> FileListBase;
typedef std::deque<FileInfo*> FileQueue;
class FileList : public FileListBase
class GroupInfo
{
private:
bool m_bOwnObjects;
NZBInfo* m_pNZBInfo;
int m_iFirstID;
int m_iLastID;
int m_iRemainingFileCount;
int m_iPausedFileCount;
long long m_lRemainingSize;
long long m_lPausedSize;
int m_iRemainingParCount;
time_t m_tMinTime;
time_t m_tMaxTime;
int m_iMinPriority;
int m_iMaxPriority;
int m_iActiveDownloads;
friend class DownloadQueue;
public:
FileList(bool bOwnObjects = false) { m_bOwnObjects = bOwnObjects; }
~FileList();
GroupInfo();
~GroupInfo();
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
int GetFirstID() { return m_iFirstID; }
int GetLastID() { return m_iLastID; }
long long GetRemainingSize() { return m_lRemainingSize; }
long long GetPausedSize() { return m_lPausedSize; }
int GetRemainingFileCount() { return m_iRemainingFileCount; }
int GetPausedFileCount() { return m_iPausedFileCount; }
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*> GroupQueueBase;
class GroupQueue : public GroupQueueBase
{
public:
~GroupQueue();
void Clear();
void Remove(FileInfo* pFileInfo);
};
@@ -284,6 +283,33 @@ public:
ScriptStatus::EStatus CalcTotalStatus();
};
class ServerStat
{
private:
int m_iServerID;
int m_iSuccessArticles;
int m_iFailedArticles;
public:
ServerStat(int iServerID);
int GetServerID() { return m_iServerID; }
int GetSuccessArticles() { return m_iSuccessArticles; }
void SetSuccessArticles(int iSuccessArticles) { m_iSuccessArticles = iSuccessArticles; }
int GetFailedArticles() { return m_iFailedArticles; }
void SetFailedArticles(int iFailedArticles) { m_iFailedArticles = iFailedArticles; }
};
typedef std::vector<ServerStat*> ServerStatListBase;
class ServerStatList : public ServerStatListBase
{
public:
~ServerStatList();
void SetStat(int iServerID, int iSuccessArticles, int iFailedArticles, bool bAdd);
void Add(ServerStatList* pServerStats);
void Clear();
};
enum EDupeMode
{
dmScore,
@@ -291,6 +317,8 @@ enum EDupeMode
dmForce
};
class NZBInfoList;
class NZBInfo
{
public:
@@ -351,34 +379,12 @@ public:
ksGood
};
enum EUrlStatus
{
lsNone,
lsRunning,
lsFinished,
lsFailed,
lsRetry,
lsScanSkipped,
lsScanFailed
};
enum EKind
{
nkNzb,
nkUrl
};
typedef std::vector<char*> Files;
typedef std::deque<Message*> Messages;
static const int FORCE_PRIORITY = 900;
friend class DupInfo;
private:
int m_iID;
EKind m_eKind;
char* m_szURL;
int m_iRefCount;
char* m_szFilename;
char* m_szName;
char* m_szDestDir;
@@ -387,11 +393,6 @@ private:
int m_iFileCount;
int m_iParkedFileCount;
long long m_lSize;
long long m_lRemainingSize;
int m_iPausedFileCount;
long long m_lPausedSize;
int m_iRemainingParCount;
int m_iActiveDownloads;
long long m_lSuccessSize;
long long m_lFailedSize;
long long m_lCurrentSuccessSize;
@@ -404,12 +405,8 @@ private:
int m_iTotalArticles;
int m_iSuccessArticles;
int m_iFailedArticles;
int m_iCurrentSuccessArticles;
int m_iCurrentFailedArticles;
time_t m_tMinTime;
time_t m_tMaxTime;
int m_iPriority;
Files m_completedFiles;
bool m_bPostProcess;
ERenameStatus m_eRenameStatus;
EParStatus m_eParStatus;
EUnpackStatus m_eUnpackStatus;
@@ -417,8 +414,6 @@ private:
EMoveStatus m_eMoveStatus;
EDeleteStatus m_eDeleteStatus;
EMarkStatus m_eMarkStatus;
EUrlStatus m_eUrlStatus;
bool m_bAddUrlPaused;
bool m_bDeletePaused;
bool m_bManyDupeFiles;
char* m_szQueuedFilename;
@@ -434,34 +429,30 @@ private:
EDupeMode m_eDupeMode;
unsigned int m_iFullContentHash;
unsigned int m_iFilteredContentHash;
FileList m_FileList;
NZBInfoList* m_Owner;
NZBParameterList m_ppParameters;
ScriptStatusList m_scriptStatuses;
ServerStatList m_ServerStats;
ServerStatList m_CurrentServerStats;
Mutex m_mutexLog;
Messages m_Messages;
int m_iIDMessageGen;
PostInfo* m_pPostInfo;
static int m_iIDGen;
static int m_iIDMax;
friend class NZBInfoList;
public:
NZBInfo();
NZBInfo(bool bPersistent = true);
~NZBInfo();
void Retain();
void Release();
int GetID() { return m_iID; }
void SetID(int iID);
static void ResetGenID(bool bMax);
static int GenerateID();
EKind GetKind() { return m_eKind; }
void SetKind(EKind eKind) { m_eKind = eKind; }
const char* GetURL() { return m_szURL; } // needs locking (for shared objects)
void SetURL(const char* szURL); // needs locking (for shared objects)
const char* GetFilename() { return m_szFilename; }
void SetFilename(const char* szFilename);
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize, bool bRemoveExt);
static void MakeNiceUrlName(const char* szURL, 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* GetFinalDir() { return m_szFinalDir; } // needs locking (for shared objects)
@@ -476,16 +467,6 @@ public:
void SetParkedFileCount(int iParkedFileCount) { m_iParkedFileCount = iParkedFileCount; }
long long GetSize() { return m_lSize; }
void SetSize(long long lSize) { m_lSize = lSize; }
long long GetRemainingSize() { return m_lRemainingSize; }
void SetRemainingSize(long long lRemainingSize) { m_lRemainingSize = lRemainingSize; }
long long GetPausedSize() { return m_lPausedSize; }
void SetPausedSize(long long lPausedSize) { m_lPausedSize = lPausedSize; }
int GetPausedFileCount() { return m_iPausedFileCount; }
void SetPausedFileCount(int iPausedFileCount) { m_iPausedFileCount = iPausedFileCount; }
int GetRemainingParCount() { return m_iRemainingParCount; }
void SetRemainingParCount(int iRemainingParCount) { m_iRemainingParCount = iRemainingParCount; }
int GetActiveDownloads() { return m_iActiveDownloads; }
void SetActiveDownloads(int iActiveDownloads) { m_iActiveDownloads = iActiveDownloads; }
long long GetSuccessSize() { return m_lSuccessSize; }
void SetSuccessSize(long long lSuccessSize) { m_lSuccessSize = lSuccessSize; }
long long GetFailedSize() { return m_lFailedSize; }
@@ -510,21 +491,12 @@ public:
void SetSuccessArticles(int iSuccessArticles) { m_iSuccessArticles = iSuccessArticles; }
int GetFailedArticles() { return m_iFailedArticles; }
void SetFailedArticles(int iFailedArticles) { m_iFailedArticles = iFailedArticles; }
int GetCurrentSuccessArticles() { return m_iCurrentSuccessArticles; }
void SetCurrentSuccessArticles(int iCurrentSuccessArticles) { m_iCurrentSuccessArticles = iCurrentSuccessArticles; }
int GetCurrentFailedArticles() { return m_iCurrentFailedArticles; }
void SetCurrentFailedArticles(int iCurrentFailedArticles) { m_iCurrentFailedArticles = iCurrentFailedArticles; }
int GetPriority() { return m_iPriority; }
void SetPriority(int iPriority) { m_iPriority = iPriority; }
bool GetForcePriority() { return m_iPriority >= FORCE_PRIORITY; }
time_t GetMinTime() { return m_tMinTime; }
void SetMinTime(time_t tMinTime) { m_tMinTime = tMinTime; }
time_t GetMaxTime() { return m_tMaxTime; }
void SetMaxTime(time_t tMaxTime) { m_tMaxTime = tMaxTime; }
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; }
@@ -539,8 +511,6 @@ public:
void SetDeleteStatus(EDeleteStatus eDeleteStatus) { m_eDeleteStatus = eDeleteStatus; }
EMarkStatus GetMarkStatus() { return m_eMarkStatus; }
void SetMarkStatus(EMarkStatus eMarkStatus) { m_eMarkStatus = eMarkStatus; }
EUrlStatus GetUrlStatus() { return m_eUrlStatus; }
void SetUrlStatus(EUrlStatus eUrlStatus) { m_eUrlStatus = eUrlStatus; }
const char* GetQueuedFilename() { return m_szQueuedFilename; }
void SetQueuedFilename(const char* szQueuedFilename);
bool GetDeleting() { return m_bDeleting; }
@@ -559,15 +529,11 @@ public:
void SetCleanupDisk(bool bCleanupDisk) { m_bCleanupDisk = bCleanupDisk; }
bool GetUnpackCleanedUpDisk() { return m_bUnpackCleanedUpDisk; }
void SetUnpackCleanedUpDisk(bool bUnpackCleanedUpDisk) { m_bUnpackCleanedUpDisk = bUnpackCleanedUpDisk; }
bool GetAddUrlPaused() { return m_bAddUrlPaused; }
void SetAddUrlPaused(bool bAddUrlPaused) { m_bAddUrlPaused = bAddUrlPaused; }
FileList* GetFileList() { return &m_FileList; } // needs locking (for shared objects)
NZBParameterList* GetParameters() { return &m_ppParameters; } // needs locking (for shared objects)
ScriptStatusList* GetScriptStatuses() { return &m_scriptStatuses; } // needs locking (for shared objects)
ServerStatList* GetServerStats() { return &m_ServerStats; }
ServerStatList* GetCurrentServerStats() { return &m_CurrentServerStats; }
int CalcHealth();
int CalcCriticalHealth(bool bAllowEstimation);
int CalcCriticalHealth();
const char* GetDupeKey() { return m_szDupeKey; } // needs locking (for shared objects)
void SetDupeKey(const char* szDupeKey); // needs locking (for shared objects)
int GetDupeScore() { return m_iDupeScore; }
@@ -578,31 +544,19 @@ public:
void SetFullContentHash(unsigned int iFullContentHash) { m_iFullContentHash = iFullContentHash; }
unsigned int GetFilteredContentHash() { return m_iFilteredContentHash; }
void SetFilteredContentHash(unsigned int iFilteredContentHash) { m_iFilteredContentHash = iFilteredContentHash; }
void CopyFileList(NZBInfo* pSrcNZBInfo);
void UpdateMinMaxTime();
PostInfo* GetPostInfo() { return m_pPostInfo; }
void EnterPostProcess();
void LeavePostProcess();
bool IsDupeSuccess();
const char* MakeTextStatus(bool bIgnoreScriptStatus);
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
Messages* LockMessages();
void UnlockMessages();
};
typedef std::deque<NZBInfo*> NZBQueueBase;
typedef std::deque<NZBInfo*> NZBInfoListBase;
class NZBList : public NZBQueueBase
class NZBInfoList : public NZBInfoListBase
{
private:
bool m_bOwnObjects;
public:
NZBList(bool bOwnObjects = false) { m_bOwnObjects = bOwnObjects; }
~NZBList();
void Clear();
void Add(NZBInfo* pNZBInfo, bool bAddTop);
void Add(NZBInfo* pNZBInfo);
void Remove(NZBInfo* pNZBInfo);
void ReleaseAll();
};
class PostInfo
@@ -623,10 +577,11 @@ public:
};
typedef std::deque<Message*> Messages;
typedef std::vector<char*> ParredFiles;
private:
int m_iID;
NZBInfo* m_pNZBInfo;
char* m_szInfoName;
bool m_bWorking;
bool m_bDeleted;
bool m_bRequestParCheck;
@@ -641,13 +596,18 @@ private:
Mutex m_mutexLog;
Messages m_Messages;
int m_iIDMessageGen;
ParredFiles m_ParredFiles;
static int m_iIDGen;
static int m_iIDMax;
public:
PostInfo();
~PostInfo();
int GetID() { return m_iID; }
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
void SetNZBInfo(NZBInfo* pNZBInfo) { m_pNZBInfo = pNZBInfo; }
void SetNZBInfo(NZBInfo* pNZBInfo);
const char* GetInfoName() { return m_szInfoName; }
void SetInfoName(const char* szInfoName);
EStage GetStage() { return m_eStage; }
void SetStage(EStage eStage) { m_eStage = eStage; }
void SetProgressLabel(const char* szProgressLabel);
@@ -666,18 +626,84 @@ public:
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
bool GetRequestParCheck() { return m_bRequestParCheck; }
void SetRequestParCheck(bool bRequestParCheck) { m_bRequestParCheck = bRequestParCheck; }
void AppendMessage(Message::EKind eKind, const char* szText);
Thread* GetPostThread() { return m_pPostThread; }
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
void AppendMessage(Message::EKind eKind, const char* szText);
Messages* LockMessages();
void UnlockMessages();
ParredFiles* GetParredFiles() { return &m_ParredFiles; }
};
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,
aiScanSkipped,
aiScanFailed
};
private:
int m_iID;
char* m_szURL;
char* m_szNZBFilename;
char* m_szCategory;
int m_iPriority;
char* m_szDupeKey;
int m_iDupeScore;
EDupeMode m_eDupeMode;
bool m_bAddTop;
bool m_bAddPaused;
bool m_bForce;
EStatus m_eStatus;
static int m_iIDGen;
static int m_iIDMax;
public:
UrlInfo();
~UrlInfo();
int GetID() { return m_iID; }
void SetID(int iID);
static void ResetGenID(bool bMax);
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; }
const char* GetDupeKey() { return m_szDupeKey; }
void SetDupeKey(const char* szDupeKey);
int GetDupeScore() { return m_iDupeScore; }
void SetDupeScore(int iDupeScore) { m_iDupeScore = iDupeScore; }
EDupeMode GetDupeMode() { return m_eDupeMode; }
void SetDupeMode(EDupeMode eDupeMode) { m_eDupeMode = eDupeMode; }
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);
bool GetForce() { return m_bForce; }
void SetForce(bool bForce) { m_bForce = bForce; }
EStatus GetStatus() { return m_eStatus; }
void SetStatus(EStatus Status) { m_eStatus = Status; }
};
typedef std::deque<UrlInfo*> UrlQueue;
class DupInfo
{
public:
@@ -693,7 +719,6 @@ public:
};
private:
int m_iID;
char* m_szName;
char* m_szDupeKey;
int m_iDupeScore;
@@ -706,8 +731,6 @@ private:
public:
DupInfo();
~DupInfo();
int GetID() { return m_iID; }
void SetID(int iID);
const char* GetName() { return m_szName; } // needs locking (for shared objects)
void SetName(const char* szName); // needs locking (for shared objects)
const char* GetDupeKey() { return m_szDupeKey; } // needs locking (for shared objects)
@@ -732,25 +755,33 @@ public:
enum EKind
{
hkUnknown,
hkNzb,
hkUrl,
hkDup
hkNZBInfo,
hkUrlInfo,
hkDupInfo
};
private:
int m_iID;
EKind m_eKind;
void* m_pInfo;
time_t m_tTime;
static int m_iIDGen;
static int m_iIDMax;
public:
HistoryInfo(NZBInfo* pNZBInfo);
HistoryInfo(UrlInfo* pUrlInfo);
HistoryInfo(DupInfo* pDupInfo);
~HistoryInfo();
int GetID() { return m_iID; }
void SetID(int iID);
static void ResetGenID(bool bMax);
EKind GetKind() { return m_eKind; }
int GetID();
NZBInfo* GetNZBInfo() { return (NZBInfo*)m_pInfo; }
UrlInfo* GetUrlInfo() { return (UrlInfo*)m_pInfo; }
DupInfo* GetDupInfo() { return (DupInfo*)m_pInfo; }
void DiscardNZBInfo() { m_pInfo = NULL; }
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)
@@ -758,104 +789,32 @@ public:
typedef std::deque<HistoryInfo*> HistoryList;
class DownloadQueue : public Subject
class DownloadQueue
{
protected:
NZBInfoList m_NZBInfoList;
FileQueue m_FileQueue;
PostQueue m_PostQueue;
HistoryList m_HistoryList;
FileQueue m_ParkedFiles;
UrlQueue m_UrlQueue;
public:
NZBInfoList* GetNZBInfoList() { return &m_NZBInfoList; }
FileQueue* GetFileQueue() { return &m_FileQueue; }
PostQueue* GetPostQueue() { return &m_PostQueue; }
HistoryList* GetHistoryList() { return &m_HistoryList; }
FileQueue* GetParkedFiles() { return &m_ParkedFiles; }
UrlQueue* GetUrlQueue() { return &m_UrlQueue; }
void BuildGroups(GroupQueue* pGroupQueue);
};
class DownloadQueueHolder
{
public:
enum EAspectAction
{
eaNzbFound,
eaNzbAdded,
eaFileCompleted,
eaFileDeleted,
eaUrlCompleted
};
struct Aspect
{
EAspectAction eAction;
DownloadQueue* pDownloadQueue;
NZBInfo* pNZBInfo;
FileInfo* pFileInfo;
};
enum EEditAction
{
eaFileMoveOffset = 1, // move files to m_iOffset relative to the current position in download-queue
eaFileMoveTop, // move files to the top of download-queue
eaFileMoveBottom, // move files to the bottom of download-queue
eaFilePause, // pause files
eaFileResume, // resume (unpause) files
eaFileDelete, // delete files
eaFilePauseAllPars, // pause only (all) pars (does not affect other files)
eaFilePauseExtraPars, // pause only (almost all) pars, except main par-file (does not affect other files)
eaFileReorder, // set file order
eaFileSplit, // split - create new group from selected files
eaGroupMoveOffset, // move group to m_iOffset relative to the current position in download-queue
eaGroupMoveTop, // move group to the top of download-queue
eaGroupMoveBottom, // move group to the bottom of download-queue
eaGroupPause, // pause group
eaGroupResume, // resume (unpause) group
eaGroupDelete, // delete group and put to history
eaGroupDupeDelete, // delete group, put to history and mark as duplicate
eaGroupFinalDelete, // delete group without adding to history
eaGroupPauseAllPars, // pause only (all) pars (does not affect other files) in group
eaGroupPauseExtraPars, // pause only (almost all) pars in group, except main par-file (does not affect other files)
eaGroupSetPriority, // set priority for groups
eaGroupSetCategory, // set or change category for a group
eaGroupApplyCategory, // set or change category for a group and reassign pp-params according to category settings
eaGroupMerge, // merge groups
eaGroupSetParameter, // set post-process parameter for group
eaGroupSetName, // set group name (rename group)
eaGroupSetDupeKey, // set duplicate key
eaGroupSetDupeScore, // set duplicate score
eaGroupSetDupeMode, // set duplicate mode
eaPostDelete, // cancel post-processing
eaHistoryDelete, // hide history-item
eaHistoryFinalDelete, // delete history-item
eaHistoryReturn, // move history-item back to download queue
eaHistoryProcess, // move history-item back to download queue and start postprocessing
eaHistoryRedownload, // move history-item back to download queue for redownload
eaHistorySetParameter, // set post-process parameter for history-item
eaHistorySetDupeKey, // set duplicate key
eaHistorySetDupeScore, // set duplicate score
eaHistorySetDupeMode, // set duplicate mode
eaHistorySetDupeBackup, // set duplicate backup flag
eaHistoryMarkBad, // mark history-item as bad (and download other duplicate)
eaHistoryMarkGood // mark history-item as good (and push it into dup-history)
};
enum EMatchMode
{
mmID = 1,
mmName,
mmRegEx
};
private:
NZBList m_Queue;
HistoryList m_History;
Mutex m_LockMutex;
static DownloadQueue* g_pDownloadQueue;
static bool g_bLoaded;
protected:
DownloadQueue() : m_Queue(true) {}
static void Init(DownloadQueue* pGlobalInstance) { g_pDownloadQueue = pGlobalInstance; }
static void Final() { g_pDownloadQueue = NULL; }
static void Loaded() { g_bLoaded = true; }
public:
virtual ~DownloadQueue() {};
static bool IsLoaded() { return g_bLoaded; }
static DownloadQueue* Lock();
static void Unlock();
NZBList* GetQueue() { return &m_Queue; }
HistoryList* GetHistory() { return &m_History; }
virtual bool EditEntry(int ID, EEditAction eAction, int iOffset, const char* szText) = 0;
virtual bool EditList(IDList* pIDList, NameList* pNameList, EMatchMode eMatchMode, EEditAction eAction, int iOffset, const char* szText) = 0;
virtual void Save() = 0;
void CalcRemainingSize(long long* pRemaining, long long* pRemainingForced);
virtual ~DownloadQueueHolder() {};
virtual DownloadQueue* LockQueue() = 0;
virtual void UnlockQueue() = 0;
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -46,12 +46,28 @@
#include "Options.h"
#include "Log.h"
#include "Util.h"
#include "DiskState.h"
#include "NZBFile.h"
#include "HistoryCoordinator.h"
#include "QueueCoordinator.h"
#include "DupeCoordinator.h"
extern HistoryCoordinator* g_pHistoryCoordinator;
extern QueueCoordinator* g_pQueueCoordinator;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
bool DupeCoordinator::IsDupeSuccess(NZBInfo* pNZBInfo)
{
bool bFailure =
pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone ||
pNZBInfo->GetMarkStatus() == NZBInfo::ksBad ||
pNZBInfo->GetParStatus() == NZBInfo::psFailure ||
pNZBInfo->GetUnpackStatus() == NZBInfo::usFailure ||
pNZBInfo->GetUnpackStatus() == NZBInfo::usPassword ||
(pNZBInfo->GetParStatus() == NZBInfo::psSkipped &&
pNZBInfo->GetUnpackStatus() == NZBInfo::usSkipped &&
pNZBInfo->CalcHealth() < pNZBInfo->CalcCriticalHealth());
return !bFailure;
}
bool DupeCoordinator::SameNameOrKey(const char* szName1, const char* szDupeKey1,
const char* szName2, const char* szDupeKey2)
@@ -79,31 +95,64 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
debug("Checking duplicates for %s", pNZBInfo->GetName());
GroupQueue groupQueue;
pDownloadQueue->BuildGroups(&groupQueue);
// find duplicates in download queue with exactly same content
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
{
NZBInfo* pQueuedNZBInfo = *it;
GroupInfo* pGroupInfo = *it;
NZBInfo* pGroupNZBInfo = pGroupInfo->GetNZBInfo();
bool bSameContent = (pNZBInfo->GetFullContentHash() > 0 &&
pNZBInfo->GetFullContentHash() == pQueuedNZBInfo->GetFullContentHash()) ||
pNZBInfo->GetFullContentHash() == pGroupNZBInfo->GetFullContentHash()) ||
(pNZBInfo->GetFilteredContentHash() > 0 &&
pNZBInfo->GetFilteredContentHash() == pQueuedNZBInfo->GetFilteredContentHash());
pNZBInfo->GetFilteredContentHash() == pGroupNZBInfo->GetFilteredContentHash());
// if there is a duplicate with exactly same content (via hash-check)
// in queue - the new item is skipped
if (pQueuedNZBInfo != pNZBInfo && bSameContent && pNZBInfo->GetKind() == NZBInfo::nkNzb)
if (pGroupNZBInfo != pNZBInfo && bSameContent)
{
if (!strcmp(pNZBInfo->GetName(), pQueuedNZBInfo->GetName()))
if (!strcmp(pNZBInfo->GetName(), pGroupNZBInfo->GetName()))
{
warn("Skipping duplicate %s, already queued", pNZBInfo->GetName());
}
else
{
warn("Skipping duplicate %s, already queued as %s",
pNZBInfo->GetName(), pQueuedNZBInfo->GetName());
pNZBInfo->GetName(), pGroupNZBInfo->GetName());
}
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
return;
}
}
// find duplicates in post queue with exactly same content
for (PostQueue::iterator it = pDownloadQueue->GetPostQueue()->begin(); it != pDownloadQueue->GetPostQueue()->end(); it++)
{
PostInfo* pPostInfo = *it;
bool bSameContent = (pNZBInfo->GetFullContentHash() > 0 &&
pNZBInfo->GetFullContentHash() == pPostInfo->GetNZBInfo()->GetFullContentHash()) ||
(pNZBInfo->GetFilteredContentHash() > 0 &&
pNZBInfo->GetFilteredContentHash() == pPostInfo->GetNZBInfo()->GetFilteredContentHash());
// if there is a duplicate with exactly same content (via hash-check)
// in queue - the new item is skipped;
if (bSameContent)
{
if (!strcmp(pNZBInfo->GetName(), pPostInfo->GetNZBInfo()->GetName()))
{
warn("Skipping duplicate %s, already queued", pNZBInfo->GetName());
}
else
{
warn("Skipping duplicate %s, already queued as %s",
pNZBInfo->GetName(), pPostInfo->GetNZBInfo()->GetName());
}
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
return;
}
}
@@ -118,11 +167,11 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
// find duplicates in queue having exactly same content
// also: nzb-files having duplicates marked as good are skipped
// also (only in score mode): nzb-files having success-duplicates in dup-history but don't having duplicates in recent history are skipped
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
((pNZBInfo->GetFullContentHash() > 0 &&
pNZBInfo->GetFullContentHash() == pHistoryInfo->GetNZBInfo()->GetFullContentHash()) ||
(pNZBInfo->GetFilteredContentHash() > 0 &&
@@ -134,7 +183,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
break;
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
((pNZBInfo->GetFullContentHash() > 0 &&
pNZBInfo->GetFullContentHash() == pHistoryInfo->GetDupInfo()->GetFullContentHash()) ||
(pNZBInfo->GetFilteredContentHash() > 0 &&
@@ -146,7 +195,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
break;
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(),
@@ -158,7 +207,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
break;
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
pHistoryInfo->GetDupInfo()->GetDupeMode() != dmForce &&
(pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood ||
(pNZBInfo->GetDupeMode() == dmScore &&
@@ -177,15 +226,15 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
if (!bSameContent && !bGood && pNZBInfo->GetDupeMode() == dmScore)
{
// nzb-files having success-duplicates in recent history (with different content) are added to history for backup
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(),
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()) &&
pNZBInfo->GetDupeScore() <= pHistoryInfo->GetNZBInfo()->GetDupeScore() &&
pHistoryInfo->GetNZBInfo()->IsDupeSuccess())
IsDupeSuccess(pHistoryInfo->GetNZBInfo()))
{
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
@@ -211,7 +260,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
return;
}
@@ -220,53 +269,82 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
if (pNZBInfo->GetDupeMode() == dmScore)
{
// find duplicates in download queue
int index = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); index++)
for (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
{
NZBInfo* pQueuedNZBInfo = *it++;
if (pQueuedNZBInfo != pNZBInfo &&
pQueuedNZBInfo->GetKind() == NZBInfo::nkNzb &&
pQueuedNZBInfo->GetDupeMode() != dmForce &&
SameNameOrKey(pQueuedNZBInfo->GetName(), pQueuedNZBInfo->GetDupeKey(),
GroupInfo* pGroupInfo = *it;
NZBInfo* pGroupNZBInfo = pGroupInfo->GetNZBInfo();
if (pGroupNZBInfo != pNZBInfo &&
pGroupNZBInfo->GetDupeMode() != dmForce &&
SameNameOrKey(pGroupNZBInfo->GetName(), pGroupNZBInfo->GetDupeKey(),
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
{
// if queue has a duplicate with the same or higher score - the new item
// is moved to history as dupe-backup
if (pNZBInfo->GetDupeScore() <= pQueuedNZBInfo->GetDupeScore())
if (pNZBInfo->GetDupeScore() <= pGroupNZBInfo->GetDupeScore())
{
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pQueuedNZBInfo->GetName());
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pGroupNZBInfo->GetName());
return;
}
// if queue has a duplicate with lower score - the existing item is moved
// to history as dupe-backup (unless it is in post-processing stage) and
// the new item is added to queue (unless it is in post-processing stage)
if (!pQueuedNZBInfo->GetPostInfo())
// the new item is added to queue
else
{
// the existing queue item is moved to history as dupe-backup
info("Moving collection %s with lower duplicate score to history", pQueuedNZBInfo->GetName());
pQueuedNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
pDownloadQueue->EditEntry(pQueuedNZBInfo->GetID(),
DownloadQueue::eaGroupDelete, 0, NULL);
it = pDownloadQueue->GetQueue()->begin() + index;
// unless it is in post-processing stage
bool bPostProcess = false;
for (PostQueue::iterator it = pDownloadQueue->GetPostQueue()->begin(); it != pDownloadQueue->GetPostQueue()->end(); it++)
{
PostInfo* pPostInfo = *it;
if (pPostInfo->GetNZBInfo() == pGroupNZBInfo)
{
bPostProcess = true;
break;
}
}
if (!bPostProcess)
{
// the existing queue item is moved to history as dupe-backup
info("Moving collection %s with lower duplicate score to history", pGroupNZBInfo->GetName());
pGroupNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pGroupInfo->GetLastID(), false, QueueEditor::eaGroupDelete, 0, NULL);
}
}
}
}
// find duplicates in post queue
for (PostQueue::iterator it = pDownloadQueue->GetPostQueue()->begin(); it != pDownloadQueue->GetPostQueue()->end(); it++)
{
PostInfo* pPostInfo = *it;
// if queue has a duplicate with the same or higher score - the new item
// is moved to history as dupe-backup;
if (pPostInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
pNZBInfo->GetDupeScore() <= pPostInfo->GetNZBInfo()->GetDupeScore() &&
SameNameOrKey(pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->GetDupeKey(),
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
{
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pPostInfo->GetNZBInfo()->GetName());
return;
}
}
}
}
/**
- if download of an item fails and there are duplicates in history -
return the best duplicate from history to queue for download;
return the best duplicate from historyto queue for download;
- if download of an item completes successfully - nothing extra needs to be done;
*/
void DupeCoordinator::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
debug("Processing duplicates for %s", pNZBInfo->GetName());
if (pNZBInfo->GetDupeMode() == dmScore && !pNZBInfo->IsDupeSuccess())
if (pNZBInfo->GetDupeMode() == dmScore && !IsDupeSuccess(pNZBInfo))
{
ReturnBestDupe(pDownloadQueue, pNZBInfo, pNZBInfo->GetName(), pNZBInfo->GetDupeKey());
}
@@ -280,14 +358,14 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
// check if history (recent or dup) has other success-duplicates or good-duplicates
bool bHistoryDupe = false;
int iHistoryScore = 0;
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
bool bGoodDupe = false;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
(pHistoryInfo->GetNZBInfo()->IsDupeSuccess() ||
(IsDupeSuccess(pHistoryInfo->GetNZBInfo()) ||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood) &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey))
{
@@ -299,7 +377,7 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
bGoodDupe = pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood;
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
pHistoryInfo->GetDupInfo()->GetDupeMode() != dmForce &&
(pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess ||
pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood) &&
@@ -320,19 +398,37 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
}
}
// check if duplicates exist in post-processing queue
bool bPostDupe = false;
int iPostScore = 0;
for (PostQueue::iterator it = pDownloadQueue->GetPostQueue()->begin(); it != pDownloadQueue->GetPostQueue()->end(); it++)
{
PostInfo* pPostInfo = *it;
if (pPostInfo->GetNZBInfo() != pNZBInfo &&
pPostInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
SameNameOrKey(pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey) &&
(!bPostDupe || pPostInfo->GetNZBInfo()->GetDupeScore() > iPostScore))
{
iPostScore = pPostInfo->GetNZBInfo()->GetDupeScore();
bPostDupe = true;
}
}
// check if duplicates exist in download queue
GroupQueue groupQueue;
pDownloadQueue->BuildGroups(&groupQueue);
bool bQueueDupe = false;
int iQueueScore = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
{
NZBInfo* pQueuedNZBInfo = *it;
if (pQueuedNZBInfo != pNZBInfo &&
pQueuedNZBInfo->GetKind() == NZBInfo::nkNzb &&
pQueuedNZBInfo->GetDupeMode() != dmForce &&
SameNameOrKey(pQueuedNZBInfo->GetName(), pQueuedNZBInfo->GetDupeKey(), szNZBName, szDupeKey) &&
(!bQueueDupe || pQueuedNZBInfo->GetDupeScore() > iQueueScore))
GroupInfo* pGroupInfo = *it;
NZBInfo* pGroupNZBInfo = pGroupInfo->GetNZBInfo();
if (pGroupNZBInfo != pNZBInfo &&
pGroupNZBInfo->GetDupeMode() != dmForce &&
SameNameOrKey(pGroupNZBInfo->GetName(), pGroupNZBInfo->GetDupeKey(), szNZBName, szDupeKey) &&
(!bQueueDupe || pGroupNZBInfo->GetDupeScore() > iQueueScore))
{
iQueueScore = pQueuedNZBInfo->GetDupeScore();
iQueueScore = pGroupNZBInfo->GetDupeScore();
bQueueDupe = true;
}
}
@@ -340,15 +436,16 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
// find dupe-backup with highest score, whose score is also higher than other
// success-duplicates and higher than already queued items
HistoryInfo* pHistoryDupe = NULL;
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe &&
pHistoryInfo->GetNZBInfo()->CalcHealth() >= pHistoryInfo->GetNZBInfo()->CalcCriticalHealth(true) &&
pHistoryInfo->GetNZBInfo()->CalcHealth() >= pHistoryInfo->GetNZBInfo()->CalcCriticalHealth() &&
pHistoryInfo->GetNZBInfo()->GetMarkStatus() != NZBInfo::ksBad &&
(!bHistoryDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > iHistoryScore) &&
(!bPostDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > iPostScore) &&
(!bQueueDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > iQueueScore) &&
(!pHistoryDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > pHistoryDupe->GetNZBInfo()->GetDupeScore()) &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey))
@@ -361,7 +458,7 @@ void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
if (pHistoryDupe)
{
info("Found duplicate %s for %s", pHistoryDupe->GetNZBInfo()->GetName(), szNZBName);
g_pHistoryCoordinator->Redownload(pDownloadQueue, pHistoryDupe);
HistoryRedownload(pDownloadQueue, pHistoryDupe);
}
}
@@ -372,11 +469,11 @@ void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pH
info("Marking %s as %s", szNZBName, (bGood ? "good" : "bad"));
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
{
pHistoryInfo->GetNZBInfo()->SetMarkStatus(bGood ? NZBInfo::ksGood : NZBInfo::ksBad);
}
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDup)
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo)
{
pHistoryInfo->GetDupInfo()->SetStatus(bGood ? DupInfo::dsGood : DupInfo::dsBad);
}
@@ -387,9 +484,9 @@ void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pH
}
if (!g_pOptions->GetDupeCheck() ||
(pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
(pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() == dmForce) ||
(pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
(pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
pHistoryInfo->GetDupInfo()->GetDupeMode() == dmForce))
{
return;
@@ -404,8 +501,8 @@ void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pH
else
{
// mark as bad
const char* szDupeKey = pHistoryInfo->GetKind() == HistoryInfo::hkNzb ? pHistoryInfo->GetNZBInfo()->GetDupeKey() :
pHistoryInfo->GetKind() == HistoryInfo::hkDup ? pHistoryInfo->GetDupInfo()->GetDupeKey() :
const char* szDupeKey = pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ? pHistoryInfo->GetNZBInfo()->GetDupeKey() :
pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo ? pHistoryInfo->GetDupInfo()->GetDupeKey() :
NULL;
ReturnBestDupe(pDownloadQueue, NULL, szNZBName, szDupeKey);
}
@@ -413,30 +510,30 @@ void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pH
void DupeCoordinator::HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo* pMarkHistoryInfo)
{
const char* szDupeKey = pMarkHistoryInfo->GetKind() == HistoryInfo::hkNzb ? pMarkHistoryInfo->GetNZBInfo()->GetDupeKey() :
pMarkHistoryInfo->GetKind() == HistoryInfo::hkDup ? pMarkHistoryInfo->GetDupInfo()->GetDupeKey() :
const char* szDupeKey = pMarkHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ? pMarkHistoryInfo->GetNZBInfo()->GetDupeKey() :
pMarkHistoryInfo->GetKind() == HistoryInfo::hkDupInfo ? pMarkHistoryInfo->GetDupInfo()->GetDupeKey() :
NULL;
const char* szNZBName = pMarkHistoryInfo->GetKind() == HistoryInfo::hkNzb ? pMarkHistoryInfo->GetNZBInfo()->GetName() :
pMarkHistoryInfo->GetKind() == HistoryInfo::hkDup ? pMarkHistoryInfo->GetDupInfo()->GetName() :
const char* szNZBName = pMarkHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ? pMarkHistoryInfo->GetNZBInfo()->GetName() :
pMarkHistoryInfo->GetKind() == HistoryInfo::hkDupInfo ? pMarkHistoryInfo->GetDupInfo()->GetName() :
NULL;
bool bChanged = false;
int index = 0;
// traversing in a reverse order to delete items in order they were added to history
// (just to produce the log-messages in a more logical order)
for (HistoryList::reverse_iterator it = pDownloadQueue->GetHistory()->rbegin(); it != pDownloadQueue->GetHistory()->rend(); )
for (HistoryList::reverse_iterator it = pDownloadQueue->GetHistoryList()->rbegin(); it != pDownloadQueue->GetHistoryList()->rend(); )
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe &&
pHistoryInfo != pMarkHistoryInfo &&
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey))
{
g_pHistoryCoordinator->HistoryHide(pDownloadQueue, pHistoryInfo, index);
HistoryTransformToDup(pDownloadQueue, pHistoryInfo, index);
index++;
it = pDownloadQueue->GetHistory()->rbegin() + index;
it = pDownloadQueue->GetHistoryList()->rbegin() + index;
bChanged = true;
}
else
@@ -446,8 +543,41 @@ void DupeCoordinator::HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo*
}
}
if (bChanged)
if (bChanged && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
pDownloadQueue->Save();
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
}
void DupeCoordinator::HistoryTransformToDup(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex)
{
char szNiceName[1024];
pHistoryInfo->GetName(szNiceName, 1024);
// replace history element
DupInfo* pDupInfo = new DupInfo();
pDupInfo->SetName(pHistoryInfo->GetNZBInfo()->GetName());
pDupInfo->SetDupeKey(pHistoryInfo->GetNZBInfo()->GetDupeKey());
pDupInfo->SetDupeScore(pHistoryInfo->GetNZBInfo()->GetDupeScore());
pDupInfo->SetDupeMode(pHistoryInfo->GetNZBInfo()->GetDupeMode());
pDupInfo->SetSize(pHistoryInfo->GetNZBInfo()->GetSize());
pDupInfo->SetFullContentHash(pHistoryInfo->GetNZBInfo()->GetFullContentHash());
pDupInfo->SetFilteredContentHash(pHistoryInfo->GetNZBInfo()->GetFilteredContentHash());
pDupInfo->SetStatus(
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood ? DupInfo::dsGood :
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksBad ? DupInfo::dsBad :
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe ? DupInfo::dsDupe :
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsManual ? DupInfo::dsDeleted :
IsDupeSuccess(pHistoryInfo->GetNZBInfo()) ? DupInfo::dsSuccess :
DupInfo::dsFailed);
HistoryInfo* pNewHistoryInfo = new HistoryInfo(pDupInfo);
pNewHistoryInfo->SetTime(pHistoryInfo->GetTime());
(*pDownloadQueue->GetHistoryList())[pDownloadQueue->GetHistoryList()->size() - 1 - rindex] = pNewHistoryInfo;
DeleteQueuedFile(pHistoryInfo->GetNZBInfo()->GetQueuedFilename());
delete pHistoryInfo;
info("Collection %s removed from history", szNiceName);
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -26,19 +26,28 @@
#ifndef DUPECOORDINATOR_H
#define DUPECOORDINATOR_H
#include <deque>
#include "DownloadInfo.h"
class DupeCoordinator
{
private:
bool IsDupeSuccess(NZBInfo* pNZBInfo);
void ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szNZBName, const char* szDupeKey);
void HistoryReturnDupe(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo);
void HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo* pMarkHistoryInfo);
bool SameNameOrKey(const char* szName1, const char* szDupeKey1, const char* szName2, const char* szDupeKey2);
protected:
virtual void HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo) = 0;
virtual void DeleteQueuedFile(const char* szQueuedFile) = 0;
public:
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, bool bGood);
void HistoryTransformToDup(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -44,14 +44,18 @@
#include "FeedCoordinator.h"
#include "Options.h"
#include "WebDownloader.h"
#include "Log.h"
#include "Util.h"
#include "FeedFile.h"
#include "FeedFilter.h"
#include "UrlCoordinator.h"
#include "DiskState.h"
extern Options* g_pOptions;
extern UrlCoordinator* g_pUrlCoordinator;
extern DiskState* g_pDiskState;
FeedCoordinator::FeedCacheItem::FeedCacheItem(const char* szUrl, int iCacheTimeSec,const char* szCacheId,
time_t tLastUsage, FeedItemInfos* pFeedItemInfos)
{
@@ -76,12 +80,8 @@ FeedCoordinator::FeedCoordinator()
m_bForce = false;
m_bSave = false;
g_pLog->RegisterDebuggable(this);
m_DownloadQueueObserver.m_pOwner = this;
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
pDownloadQueue->Attach(&m_DownloadQueueObserver);
DownloadQueue::Unlock();
m_UrlCoordinatorObserver.m_pOwner = this;
g_pUrlCoordinator->Attach(&m_UrlCoordinatorObserver);
}
FeedCoordinator::~FeedCoordinator()
@@ -89,8 +89,6 @@ FeedCoordinator::~FeedCoordinator()
debug("Destroying FeedCoordinator");
// Cleanup
g_pLog->UnregisterDebuggable(this);
debug("Deleting FeedDownloaders");
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
@@ -124,17 +122,12 @@ void FeedCoordinator::Run()
{
debug("Entering FeedCoordinator-loop");
while (!DownloadQueue::IsLoaded())
{
usleep(20 * 1000);
}
m_mutexDownloads.Lock();
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetReloadQueue())
{
m_mutexDownloads.Lock();
g_pDiskState->LoadFeeds(&m_Feeds, &m_FeedHistory);
m_mutexDownloads.Unlock();
}
m_mutexDownloads.Unlock();
int iSleepInterval = 100;
int iUpdateCounter = 0;
@@ -149,7 +142,7 @@ void FeedCoordinator::Run()
{
// this code should not be called too often, once per second is OK
if (!g_pOptions->GetPauseDownload() || m_bForce || g_pOptions->GetUrlForce())
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()) || m_bForce || g_pOptions->GetUrlForce())
{
m_mutexDownloads.Lock();
time_t tCurrent = time(NULL);
@@ -265,10 +258,11 @@ void FeedCoordinator::ResetHangingDownloads()
void FeedCoordinator::LogDebugInfo()
{
info(" ---------- FeedCoordinator");
debug(" FeedCoordinator");
debug(" ----------------");
m_mutexDownloads.Lock();
info(" Active Downloads: %i", m_ActiveDownloads.size());
debug(" Active Downloads: %i", m_ActiveDownloads.size());
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
FeedDownloader* pFeedDownloader = *it;
@@ -279,7 +273,7 @@ void FeedCoordinator::LogDebugInfo()
void FeedCoordinator::StartFeedDownload(FeedInfo* pFeedInfo, bool bForce)
{
debug("Starting new FeedDownloader for %s", pFeedInfo->GetName());
debug("Starting new FeedDownloader for %", pFeedInfo->GetName());
FeedDownloader* pFeedDownloader = new FeedDownloader();
pFeedDownloader->SetAutoDestroy(true);
@@ -293,7 +287,7 @@ void FeedCoordinator::StartFeedDownload(FeedInfo* pFeedInfo, bool bForce)
else
{
char szUrlName[1024];
NZBInfo::MakeNiceUrlName(pFeedInfo->GetUrl(), "", szUrlName, sizeof(szUrlName));
UrlInfo::MakeNiceName(pFeedInfo->GetUrl(), "", szUrlName, sizeof(szUrlName));
pFeedDownloader->SetInfoName(szUrlName);
}
pFeedDownloader->SetForce(bForce || g_pOptions->GetUrlForce());
@@ -364,27 +358,19 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* pFeedDownloader)
FeedFile* pFeedFile = FeedFile::Create(pFeedInfo->GetOutputFilename());
remove(pFeedInfo->GetOutputFilename());
NZBList addedNZBs;
m_mutexDownloads.Lock();
if (pFeedFile)
{
ProcessFeed(pFeedInfo, pFeedFile->GetFeedItemInfos(), &addedNZBs);
ProcessFeed(pFeedInfo, pFeedFile->GetFeedItemInfos());
delete pFeedFile;
}
pFeedInfo->SetLastUpdate(time(NULL));
pFeedInfo->SetForce(false);
m_bSave = true;
m_mutexDownloads.Unlock();
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
for (NZBList::iterator it = addedNZBs.begin(); it != addedNZBs.end(); it++)
{
NZBInfo* pNZBInfo = *it;
pDownloadQueue->GetQueue()->Add(pNZBInfo, false);
}
pDownloadQueue->Save();
DownloadQueue::Unlock();
}
pFeedInfo->SetStatus(FeedInfo::fsFinished);
}
@@ -424,7 +410,7 @@ void FeedCoordinator::FilterFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemIn
delete pFeedFilter;
}
void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos, NZBList* pAddedNZBs)
void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos)
{
debug("Process feed %s", pFeedInfo->GetName());
@@ -446,8 +432,7 @@ void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemI
}
else if (!pFeedHistoryInfo)
{
NZBInfo* pNZBInfo = CreateNZBInfo(pFeedInfo, pFeedItemInfo);
pAddedNZBs->Add(pNZBInfo, false);
DownloadItem(pFeedInfo, pFeedItemInfo);
eStatus = FeedHistoryInfo::hsFetched;
iAdded++;
}
@@ -473,13 +458,12 @@ void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemI
}
}
NZBInfo* FeedCoordinator::CreateNZBInfo(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo)
void FeedCoordinator::DownloadItem(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo)
{
debug("Download %s from %s", pFeedItemInfo->GetUrl(), pFeedInfo->GetName());
NZBInfo* pNZBInfo = new NZBInfo();
pNZBInfo->SetKind(NZBInfo::nkUrl);
pNZBInfo->SetURL(pFeedItemInfo->GetUrl());
UrlInfo* pUrlInfo = new UrlInfo();
pUrlInfo->SetURL(pFeedItemInfo->GetUrl());
// add .nzb-extension if not present
char szNZBName[1024];
@@ -495,17 +479,17 @@ NZBInfo* FeedCoordinator::CreateNZBInfo(FeedInfo* pFeedInfo, FeedItemInfo* pFeed
Util::MakeValidFilename(szNZBName2, '_', false);
if (strlen(szNZBName) > 0)
{
pNZBInfo->SetFilename(szNZBName2);
pUrlInfo->SetNZBFilename(szNZBName2);
}
pNZBInfo->SetCategory(pFeedItemInfo->GetAddCategory());
pNZBInfo->SetPriority(pFeedItemInfo->GetPriority());
pNZBInfo->SetAddUrlPaused(pFeedItemInfo->GetPauseNzb());
pNZBInfo->SetDupeKey(pFeedItemInfo->GetDupeKey());
pNZBInfo->SetDupeScore(pFeedItemInfo->GetDupeScore());
pNZBInfo->SetDupeMode(pFeedItemInfo->GetDupeMode());
return pNZBInfo;
pUrlInfo->SetCategory(pFeedItemInfo->GetAddCategory());
pUrlInfo->SetPriority(pFeedItemInfo->GetPriority());
pUrlInfo->SetAddPaused(pFeedItemInfo->GetPauseNzb());
pUrlInfo->SetDupeKey(pFeedItemInfo->GetDupeKey());
pUrlInfo->SetDupeScore(pFeedItemInfo->GetDupeScore());
pUrlInfo->SetDupeMode(pFeedItemInfo->GetDupeMode());
pUrlInfo->SetForce(pFeedInfo->GetForce() || g_pOptions->GetUrlForce());
g_pUrlCoordinator->AddUrlToQueue(pUrlInfo, false);
}
bool FeedCoordinator::ViewFeed(int iID, FeedItemInfos** ppFeedItemInfos)
@@ -643,22 +627,22 @@ void FeedCoordinator::FetchFeed(int iID)
m_mutexDownloads.Unlock();
}
void FeedCoordinator::DownloadQueueUpdate(Subject* pCaller, void* pAspect)
void FeedCoordinator::UrlCoordinatorUpdate(Subject* pCaller, void* pAspect)
{
debug("Notification from URL-Coordinator received");
DownloadQueue::Aspect* pQueueAspect = (DownloadQueue::Aspect*)pAspect;
if (pQueueAspect->eAction == DownloadQueue::eaUrlCompleted)
UrlCoordinator::Aspect* pUrlAspect = (UrlCoordinator::Aspect*)pAspect;
if (pUrlAspect->eAction == UrlCoordinator::eaUrlCompleted)
{
m_mutexDownloads.Lock();
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pQueueAspect->pNZBInfo->GetURL());
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pUrlAspect->pUrlInfo->GetURL());
if (pFeedHistoryInfo)
{
pFeedHistoryInfo->SetStatus(FeedHistoryInfo::hsFetched);
}
else
{
m_FeedHistory.Add(pQueueAspect->pNZBInfo->GetURL(), FeedHistoryInfo::hsFetched, time(NULL));
m_FeedHistory.Add(pUrlAspect->pUrlInfo->GetURL(), FeedHistoryInfo::hsFetched, time(NULL));
}
m_bSave = true;
m_mutexDownloads.Unlock();
@@ -705,7 +689,7 @@ void FeedCoordinator::CleanupHistory()
}
}
time_t tBorderDate = tOldestUpdate - g_pOptions->GetFeedHistory() * 60*60*24;
time_t tBorderDate = tOldestUpdate - g_pOptions->GetFeedHistory();
int i = 0;
for (FeedHistory::iterator it = m_FeedHistory.begin(); it != m_FeedHistory.end(); )
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
#include <list>
#include <time.h>
#include "Log.h"
#include "Thread.h"
#include "WebDownloader.h"
#include "DownloadInfo.h"
@@ -40,14 +39,17 @@
class FeedDownloader;
class FeedCoordinator : public Thread, public Observer, public Subject, public Debuggable
class FeedCoordinator : public Thread, public Observer, public Subject
{
public:
typedef std::list<FeedDownloader*> ActiveDownloads;
private:
class DownloadQueueObserver: public Observer
class UrlCoordinatorObserver: public Observer
{
public:
FeedCoordinator* m_pOwner;
virtual void Update(Subject* pCaller, void* pAspect) { m_pOwner->DownloadQueueUpdate(pCaller, pAspect); }
virtual void Update(Subject* pCaller, void* pAspect) { m_pOwner->UrlCoordinatorUpdate(pCaller, pAspect); }
};
class FeedCacheItem
@@ -72,14 +74,13 @@ private:
};
typedef std::deque<FeedCacheItem*> FeedCache;
typedef std::list<FeedDownloader*> ActiveDownloads;
private:
Feeds m_Feeds;
ActiveDownloads m_ActiveDownloads;
FeedHistory m_FeedHistory;
Mutex m_mutexDownloads;
DownloadQueueObserver m_DownloadQueueObserver;
UrlCoordinatorObserver m_UrlCoordinatorObserver;
bool m_bForce;
bool m_bSave;
FeedCache m_FeedCache;
@@ -87,17 +88,14 @@ private:
void StartFeedDownload(FeedInfo* pFeedInfo, bool bForce);
void FeedCompleted(FeedDownloader* pFeedDownloader);
void FilterFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos);
void ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos, NZBList* pAddedNZBs);
NZBInfo* CreateNZBInfo(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo);
void ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos);
void DownloadItem(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo);
void ResetHangingDownloads();
void DownloadQueueUpdate(Subject* pCaller, void* pAspect);
void UrlCoordinatorUpdate(Subject* pCaller, void* pAspect);
void CleanupHistory();
void CleanupCache();
void CheckSaveFeeds();
protected:
virtual void LogDebugInfo();
public:
FeedCoordinator();
virtual ~FeedCoordinator();
@@ -112,6 +110,8 @@ public:
void FetchFeed(int iID);
bool HasActiveDownloads();
Feeds* GetFeeds() { return &m_Feeds; }
void LogDebugInfo();
};
class FeedDownloader : public WebDownloader

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -84,7 +84,7 @@ FeedFile::~FeedFile()
void FeedFile::LogDebugInfo()
{
info(" FeedFile %s", m_szFileName);
debug(" FeedFile %s", m_szFileName);
}
void FeedFile::AddItem(FeedItemInfo* pFeedItemInfo)

View File

View File

@@ -153,17 +153,22 @@ bool FeedFilter::Term::MatchText(const char* szStrValue)
// Word-search
// split szStrValue into tokens
Tokenizer tok(szStrValue, WORD_SEPARATORS);
while (const char* szWord = tok.Next())
char* szStrValue2 = strdup(szStrValue);
char* saveptr;
char* szWord = strtok_r(szStrValue2, WORD_SEPARATORS, &saveptr);
while (szWord)
{
szWord = Util::Trim(szWord);
WildMask mask(m_szParam, m_pRefValues != NULL);
bMatch = mask.Match(szWord);
bMatch = *szWord && mask.Match(szWord);
if (bMatch)
{
FillWildMaskRefValues(szWord, &mask, 0);
break;
}
szWord = strtok_r(NULL, WORD_SEPARATORS, &saveptr);
}
free(szStrValue2);
}
else
{
@@ -727,139 +732,146 @@ char* FeedFilter::Rule::CompileOptions(char* szRule)
// split command into tokens
*p = '\0';
Tokenizer tok(szRule, ",", true);
while (char* szOption = tok.Next())
char* saveptr;
char* szToken = strtok_r(szRule, ",", &saveptr);
while (szToken)
{
const char* szValue = "";
char* szColon = strchr(szOption, ':');
if (szColon)
szToken = Util::Trim(szToken);
if (*szToken)
{
*szColon = '\0';
szValue = Util::Trim(szColon + 1);
}
char* szOption = szToken;
const char* szValue = "";
char* szColon = strchr(szToken, ':');
if (szColon)
{
*szColon = '\0';
szValue = Util::Trim(szColon + 1);
}
if (!strcasecmp(szOption, "category") || !strcasecmp(szOption, "cat") || !strcasecmp(szOption, "c"))
{
m_bHasCategory = true;
free(m_szCategory);
m_szCategory = strdup(szValue);
m_bPatCategory = strstr(szValue, "${");
}
else if (!strcasecmp(szOption, "pause") || !strcasecmp(szOption, "p"))
{
m_bHasPause = true;
m_bPause = !*szValue || !strcasecmp(szValue, "yes") || !strcasecmp(szValue, "y");
if (!m_bPause && !(!strcasecmp(szValue, "no") || !strcasecmp(szValue, "n")))
if (!strcasecmp(szOption, "category") || !strcasecmp(szOption, "cat") || !strcasecmp(szOption, "c"))
{
// error
return NULL;
m_bHasCategory = true;
free(m_szCategory);
m_szCategory = strdup(szValue);
m_bPatCategory = strstr(szValue, "${");
}
}
else if (!strcasecmp(szOption, "priority") || !strcasecmp(szOption, "pr") || !strcasecmp(szOption, "r"))
{
if (!strchr("0123456789-+", *szValue))
else if (!strcasecmp(szOption, "pause") || !strcasecmp(szOption, "p"))
{
// error
return NULL;
m_bHasPause = true;
m_bPause = !*szValue || !strcasecmp(szValue, "yes") || !strcasecmp(szValue, "y");
if (!m_bPause && !(!strcasecmp(szValue, "no") || !strcasecmp(szValue, "n")))
{
// error
return NULL;
}
}
m_bHasPriority = true;
m_iPriority = atoi(szValue);
}
else if (!strcasecmp(szOption, "priority+") || !strcasecmp(szOption, "pr+") || !strcasecmp(szOption, "r+"))
{
if (!strchr("0123456789-+", *szValue))
else if (!strcasecmp(szOption, "priority") || !strcasecmp(szOption, "pr") || !strcasecmp(szOption, "r"))
{
// error
return NULL;
if (!strchr("0123456789-+", *szValue))
{
// error
return NULL;
}
m_bHasPriority = true;
m_iPriority = atoi(szValue);
}
m_bHasAddPriority = true;
m_iAddPriority = atoi(szValue);
}
else if (!strcasecmp(szOption, "dupescore") || !strcasecmp(szOption, "ds") || !strcasecmp(szOption, "s"))
{
if (!strchr("0123456789-+", *szValue))
else if (!strcasecmp(szOption, "priority+") || !strcasecmp(szOption, "pr+") || !strcasecmp(szOption, "r+"))
{
// error
return NULL;
if (!strchr("0123456789-+", *szValue))
{
// error
return NULL;
}
m_bHasAddPriority = true;
m_iAddPriority = atoi(szValue);
}
m_bHasDupeScore = true;
m_iDupeScore = atoi(szValue);
}
else if (!strcasecmp(szOption, "dupescore+") || !strcasecmp(szOption, "ds+") || !strcasecmp(szOption, "s+"))
{
if (!strchr("0123456789-+", *szValue))
else if (!strcasecmp(szOption, "dupescore") || !strcasecmp(szOption, "ds") || !strcasecmp(szOption, "s"))
{
// error
return NULL;
if (!strchr("0123456789-+", *szValue))
{
// error
return NULL;
}
m_bHasDupeScore = true;
m_iDupeScore = atoi(szValue);
}
m_bHasAddDupeScore = true;
m_iAddDupeScore = atoi(szValue);
}
else if (!strcasecmp(szOption, "dupekey") || !strcasecmp(szOption, "dk") || !strcasecmp(szOption, "k"))
{
m_bHasDupeKey = true;
free(m_szDupeKey);
m_szDupeKey = strdup(szValue);
m_bPatDupeKey = strstr(szValue, "${");
}
else if (!strcasecmp(szOption, "dupekey+") || !strcasecmp(szOption, "dk+") || !strcasecmp(szOption, "k+"))
{
m_bHasAddDupeKey = true;
free(m_szAddDupeKey);
m_szAddDupeKey = strdup(szValue);
m_bPatAddDupeKey = strstr(szValue, "${");
}
else if (!strcasecmp(szOption, "dupemode") || !strcasecmp(szOption, "dm") || !strcasecmp(szOption, "m"))
{
m_bHasDupeMode = true;
if (!strcasecmp(szValue, "score") || !strcasecmp(szValue, "s"))
else if (!strcasecmp(szOption, "dupescore+") || !strcasecmp(szOption, "ds+") || !strcasecmp(szOption, "s+"))
{
m_eDupeMode = dmScore;
if (!strchr("0123456789-+", *szValue))
{
// error
return NULL;
}
m_bHasAddDupeScore = true;
m_iAddDupeScore = atoi(szValue);
}
else if (!strcasecmp(szValue, "all") || !strcasecmp(szValue, "a"))
else if (!strcasecmp(szOption, "dupekey") || !strcasecmp(szOption, "dk") || !strcasecmp(szOption, "k"))
{
m_eDupeMode = dmAll;
m_bHasDupeKey = true;
free(m_szDupeKey);
m_szDupeKey = strdup(szValue);
m_bPatDupeKey = strstr(szValue, "${");
}
else if (!strcasecmp(szValue, "force") || !strcasecmp(szValue, "f"))
else if (!strcasecmp(szOption, "dupekey+") || !strcasecmp(szOption, "dk+") || !strcasecmp(szOption, "k+"))
{
m_eDupeMode = dmForce;
m_bHasAddDupeKey = true;
free(m_szAddDupeKey);
m_szAddDupeKey = strdup(szValue);
m_bPatAddDupeKey = strstr(szValue, "${");
}
else if (!strcasecmp(szOption, "dupemode") || !strcasecmp(szOption, "dm") || !strcasecmp(szOption, "m"))
{
m_bHasDupeMode = true;
if (!strcasecmp(szValue, "score") || !strcasecmp(szValue, "s"))
{
m_eDupeMode = dmScore;
}
else if (!strcasecmp(szValue, "all") || !strcasecmp(szValue, "a"))
{
m_eDupeMode = dmAll;
}
else if (!strcasecmp(szValue, "force") || !strcasecmp(szValue, "f"))
{
m_eDupeMode = dmForce;
}
else
{
// error
return NULL;
}
}
else if (!strcasecmp(szOption, "rageid"))
{
m_bHasRageId = true;
free(m_szRageId);
m_szRageId = strdup(szValue);
}
else if (!strcasecmp(szOption, "series"))
{
m_bHasSeries = true;
free(m_szSeries);
m_szSeries = strdup(szValue);
}
// for compatibility with older version we support old commands too
else if (!strcasecmp(szOption, "paused") || !strcasecmp(szOption, "unpaused"))
{
m_bHasPause = true;
m_bPause = !strcasecmp(szOption, "paused");
}
else if (strchr("0123456789-+", *szOption))
{
m_bHasPriority = true;
m_iPriority = atoi(szOption);
}
else
{
// error
return NULL;
m_bHasCategory = true;
free(m_szCategory);
m_szCategory = strdup(szOption);
}
}
else if (!strcasecmp(szOption, "rageid"))
{
m_bHasRageId = true;
free(m_szRageId);
m_szRageId = strdup(szValue);
}
else if (!strcasecmp(szOption, "series"))
{
m_bHasSeries = true;
free(m_szSeries);
m_szSeries = strdup(szValue);
}
// for compatibility with older version we support old commands too
else if (!strcasecmp(szOption, "paused") || !strcasecmp(szOption, "unpaused"))
{
m_bHasPause = true;
m_bPause = !strcasecmp(szOption, "paused");
}
else if (strchr("0123456789-+", *szOption))
{
m_bHasPriority = true;
m_iPriority = atoi(szOption);
}
else
{
m_bHasCategory = true;
free(m_szCategory);
m_szCategory = strdup(szOption);
}
szToken = strtok_r(NULL, ",", &saveptr);
}
szRule = p + 1;

View File

View File

View File

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -47,12 +47,12 @@
#include "Log.h"
#include "Connection.h"
#include "MessageBase.h"
#include "QueueCoordinator.h"
#include "RemoteClient.h"
#include "Util.h"
#include "StatMeter.h"
extern QueueCoordinator* g_pQueueCoordinator;
extern Options* g_pOptions;
extern StatMeter* g_pStatMeter;
Frontend::Frontend()
{
@@ -65,6 +65,7 @@ Frontend::Frontend()
m_iCurrentDownloadSpeed = 0;
m_lRemainingSize = 0;
m_bPauseDownload = false;
m_bPauseDownload2 = false;
m_iDownloadLimit = 0;
m_iThreadCount = 0;
m_iPostJobCount = 0;
@@ -94,22 +95,16 @@ bool Frontend::PrepareData()
{
if (m_bSummary)
{
m_iCurrentDownloadSpeed = g_pStatMeter->CalcCurrentDownloadSpeed();
m_iCurrentDownloadSpeed = g_pQueueCoordinator->CalcCurrentDownloadSpeed();
m_lRemainingSize = g_pQueueCoordinator->CalcRemainingSize();
m_bPauseDownload = g_pOptions->GetPauseDownload();
m_bPauseDownload2 = g_pOptions->GetPauseDownload2();
m_iDownloadLimit = g_pOptions->GetDownloadRate();
m_iThreadCount = Thread::GetThreadCount();
g_pStatMeter->CalcTotalStat(&m_iUpTimeSec, &m_iDnTimeSec, &m_iAllBytes, &m_bStandBy);
DownloadQueue *pDownloadQueue = DownloadQueue::Lock();
m_iPostJobCount = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
m_iPostJobCount += pNZBInfo->GetPostInfo() ? 1 : 0;
}
pDownloadQueue->CalcRemainingSize(&m_lRemainingSize, NULL);
DownloadQueue::Unlock();
PostQueue* pPostQueue = g_pQueueCoordinator->LockQueue()->GetPostQueue();
m_iPostJobCount = pPostQueue->size();
g_pQueueCoordinator->UnlockQueue();
g_pQueueCoordinator->CalcStat(&m_iUpTimeSec, &m_iDnTimeSec, &m_iAllBytes, &m_bStandBy);
}
}
return true;
@@ -125,13 +120,15 @@ void Frontend::FreeData()
}
m_RemoteMessages.clear();
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
pDownloadQueue->GetQueue()->Clear();
DownloadQueue::Unlock();
for (FileQueue::iterator it = m_RemoteQueue.GetFileQueue()->begin(); it != m_RemoteQueue.GetFileQueue()->end(); it++)
{
delete *it;
}
m_RemoteQueue.GetFileQueue()->clear();
}
}
Log::Messages* Frontend::LockMessages()
Log::Messages * Frontend::LockMessages()
{
if (IsRemoteMode())
{
@@ -153,12 +150,22 @@ void Frontend::UnlockMessages()
DownloadQueue* Frontend::LockQueue()
{
return DownloadQueue::Lock();
if (IsRemoteMode())
{
return &m_RemoteQueue;
}
else
{
return g_pQueueCoordinator->LockQueue();
}
}
void Frontend::UnlockQueue()
{
DownloadQueue::Unlock();
if (!IsRemoteMode())
{
g_pQueueCoordinator->UnlockQueue();
}
}
bool Frontend::IsRemoteMode()
@@ -166,16 +173,23 @@ bool Frontend::IsRemoteMode()
return g_pOptions->GetRemoteClientMode();
}
void Frontend::ServerPauseUnpause(bool bPause)
void Frontend::ServerPauseUnpause(bool bPause, bool bSecondRegister)
{
if (IsRemoteMode())
{
RequestPauseUnpause(bPause);
RequestPauseUnpause(bPause, bSecondRegister);
}
else
{
g_pOptions->SetResumeTime(0);
g_pOptions->SetPauseDownload(bPause);
if (bSecondRegister)
{
g_pOptions->SetPauseDownload2(bPause);
}
else
{
g_pOptions->SetPauseDownload(bPause);
}
}
}
@@ -191,18 +205,27 @@ void Frontend::ServerSetDownloadRate(int iRate)
}
}
bool Frontend::ServerEditQueue(DownloadQueue::EEditAction eAction, int iOffset, int iID)
void Frontend::ServerDumpDebug()
{
if (IsRemoteMode())
{
return RequestEditQueue(eAction, iOffset, iID);
RequestDumpDebug();
}
else
{
DownloadQueue* pDownloadQueue = LockQueue();
bool bOK = pDownloadQueue->EditEntry(iID, eAction, iOffset, NULL);
UnlockQueue();
return bOK;
g_pQueueCoordinator->LogDebugInfo();
}
}
bool Frontend::ServerEditQueue(QueueEditor::EEditAction eAction, int iOffset, int iID)
{
if (IsRemoteMode())
{
return RequestEditQueue((eRemoteEditAction)eAction, iOffset, iID);
}
else
{
return g_pQueueCoordinator->GetQueueEditor()->EditEntry(iID, true, eAction, iOffset, NULL);
}
return false;
}
@@ -337,6 +360,7 @@ bool Frontend::RequestFileList()
if (m_bSummary)
{
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);
@@ -352,10 +376,7 @@ bool Frontend::RequestFileList()
{
RemoteClient client;
client.SetVerbose(false);
DownloadQueue* pDownloadQueue = LockQueue();
client.BuildFileList(&ListResponse, pBuf, pDownloadQueue);
UnlockQueue();
client.BuildFileList(&ListResponse, pBuf, &m_RemoteQueue);
}
if (pBuf)
@@ -366,11 +387,11 @@ bool Frontend::RequestFileList()
return true;
}
bool Frontend::RequestPauseUnpause(bool bPause)
bool Frontend::RequestPauseUnpause(bool bPause, bool bSecondRegister)
{
RemoteClient client;
client.SetVerbose(false);
return client.RequestServerPauseUnpause(bPause, eRemotePauseUnpauseActionDownload);
return client.RequestServerPauseUnpause(bPause, bSecondRegister ? eRemotePauseUnpauseActionDownload2 : eRemotePauseUnpauseActionDownload);
}
bool Frontend::RequestSetDownloadRate(int iRate)
@@ -380,9 +401,16 @@ bool Frontend::RequestSetDownloadRate(int iRate)
return client.RequestServerSetDownloadRate(iRate);
}
bool Frontend::RequestEditQueue(DownloadQueue::EEditAction eAction, int iOffset, int iID)
bool Frontend::RequestDumpDebug()
{
RemoteClient client;
client.SetVerbose(false);
return client.RequestServerEditQueue(eAction, iOffset, NULL, &iID, 1, NULL, eRemoteMatchModeID);
return client.RequestServerDumpDebug();
}
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);
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@ class Frontend : public Thread
{
private:
Log::Messages m_RemoteMessages;
DownloadQueue m_RemoteQueue;
bool RequestMessages();
bool RequestFileList();
@@ -52,6 +53,7 @@ protected:
int m_iCurrentDownloadSpeed;
long long m_lRemainingSize;
bool m_bPauseDownload;
bool m_bPauseDownload2;
int m_iDownloadLimit;
int m_iThreadCount;
int m_iPostJobCount;
@@ -68,12 +70,14 @@ protected:
void UnlockQueue();
bool IsRemoteMode();
void InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest, int iSize);
void ServerPauseUnpause(bool bPause);
bool RequestPauseUnpause(bool bPause);
void ServerPauseUnpause(bool bPause, bool bSecondRegister);
bool RequestPauseUnpause(bool bPause, bool bSecondRegister);
void ServerSetDownloadRate(int iRate);
bool RequestSetDownloadRate(int iRate);
bool ServerEditQueue(DownloadQueue::EEditAction eAction, int iOffset, int iEntry);
bool RequestEditQueue(DownloadQueue::EEditAction eAction, int iOffset, int iID);
void ServerDumpDebug();
bool RequestDumpDebug();
bool ServerEditQueue(QueueEditor::EEditAction eAction, int iOffset, int iEntry);
bool RequestEditQueue(eRemoteEditAction iAction, int iOffset, int iID);
public:
Frontend();

View File

@@ -63,23 +63,6 @@ Log::~Log()
free(m_szLogFilename);
}
void Log::LogDebugInfo()
{
info("--------------------------------------------");
info("Dumping debug info to log");
info("--------------------------------------------");
m_mutexDebug.Lock();
for (Debuggables::iterator it = m_Debuggables.begin(); it != m_Debuggables.end(); it++)
{
Debuggable* pDebuggable = *it;
pDebuggable->LogDebugInfo();
}
m_mutexDebug.Unlock();
info("--------------------------------------------");
}
void Log::Filelog(const char* msg, ...)
{
if (m_szLogFilename)
@@ -105,7 +88,7 @@ void Log::Filelog(const char* msg, ...)
szTime[50-1] = '\0';
szTime[strlen(szTime) - 1] = '\0'; // trim LF
FILE* file = fopen(m_szLogFilename, FOPEN_ABP);
FILE* file = fopen(m_szLogFilename, "ab+");
if (file)
{
#ifdef WIN32
@@ -429,17 +412,3 @@ void Log::InitOptions()
}
}
}
void Log::RegisterDebuggable(Debuggable* pDebuggable)
{
m_mutexDebug.Lock();
m_Debuggables.push_back(pDebuggable);
m_mutexDebug.Unlock();
}
void Log::UnregisterDebuggable(Debuggable* pDebuggable)
{
m_mutexDebug.Lock();
m_Debuggables.remove(pDebuggable);
m_mutexDebug.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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#define LOG_H
#include <deque>
#include <list>
#include <time.h>
#include "Thread.h"
@@ -76,24 +75,14 @@ public:
const char* GetText() { return m_szText; }
};
class Debuggable
{
protected:
virtual void LogDebugInfo() = 0;
friend class Log;
};
class Log
{
public:
typedef std::deque<Message*> Messages;
typedef std::list<Debuggable*> Debuggables;
private:
Mutex m_mutexLog;
Messages m_Messages;
Debuggables m_Debuggables;
Mutex m_mutexDebug;
char* m_szLogFilename;
unsigned int m_iIDGen;
#ifdef DEBUG
@@ -124,9 +113,6 @@ public:
void Clear();
void ResetLog();
void InitOptions();
void RegisterDebuggable(Debuggable* pDebuggable);
void UnregisterDebuggable(Debuggable* pDebuggable);
void LogDebugInfo();
};
#ifdef DEBUG

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -44,11 +44,11 @@
#include "Log.h"
#include "Util.h"
#include "Maintenance.h"
#include "Options.h"
extern Options* g_pOptions;
extern Maintenance* g_pMaintenance;
Maintenance::Maintenance()
{
m_iIDMessageGen = 0;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -26,10 +26,11 @@
#define MAINTENANCE_H
#include "Thread.h"
#include "Script.h"
#include "ScriptController.h"
#include "Log.h"
#include "Util.h"
class UpdateScriptController;
class Maintenance

View File

@@ -1,7 +1,7 @@
#
# This file if part of nzbget
#
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -22,204 +22,67 @@
bin_PROGRAMS = nzbget
nzbget_SOURCES = \
daemon/connect/Connection.cpp \
daemon/connect/Connection.h \
daemon/connect/TLS.cpp \
daemon/connect/TLS.h \
daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h \
daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h \
daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h \
daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h \
daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h \
daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h \
daemon/frontend/Frontend.cpp \
daemon/frontend/Frontend.h \
daemon/frontend/LoggableFrontend.cpp \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h \
daemon/main/nzbget.cpp \
daemon/main/nzbget.h \
daemon/main/Options.cpp \
daemon/main/Options.h \
daemon/main/Scheduler.cpp \
daemon/main/Scheduler.h \
daemon/nntp/ArticleDownloader.cpp \
daemon/nntp/ArticleDownloader.h \
daemon/nntp/Decoder.cpp \
daemon/nntp/Decoder.h \
daemon/nntp/NewsServer.cpp \
daemon/nntp/NewsServer.h \
daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h \
daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h \
daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h \
daemon/postprocess/ParChecker.cpp \
daemon/postprocess/ParChecker.h \
daemon/postprocess/ParCoordinator.cpp \
daemon/postprocess/ParCoordinator.h \
daemon/postprocess/ParRenamer.cpp \
daemon/postprocess/ParRenamer.h \
daemon/postprocess/PostScript.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp \
daemon/postprocess/Unpack.h \
daemon/queue/DiskState.cpp \
daemon/queue/DiskState.h \
daemon/queue/DownloadInfo.cpp \
daemon/queue/DownloadInfo.h \
daemon/queue/DupeCoordinator.cpp \
daemon/queue/DupeCoordinator.h \
daemon/queue/HistoryCoordinator.cpp \
daemon/queue/HistoryCoordinator.h \
daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h \
daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h \
daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h \
daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h \
daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h \
daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h \
daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h \
daemon/remote/MessageBase.h \
daemon/remote/RemoteClient.cpp \
daemon/remote/RemoteClient.h \
daemon/remote/RemoteServer.cpp \
daemon/remote/RemoteServer.h \
daemon/remote/WebServer.cpp \
daemon/remote/WebServer.h \
daemon/remote/XmlRpc.cpp \
daemon/remote/XmlRpc.h \
daemon/util/Log.cpp \
daemon/util/Log.h \
daemon/util/Observer.cpp \
daemon/util/Observer.h \
daemon/util/Script.cpp \
daemon/util/Script.h \
daemon/util/Thread.cpp \
daemon/util/Thread.h \
daemon/util/Util.cpp \
daemon/util/Util.h \
svn_version.cpp
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-I$(srcdir)/daemon/feed \
-I$(srcdir)/daemon/frontend \
-I$(srcdir)/daemon/main \
-I$(srcdir)/daemon/nntp \
-I$(srcdir)/daemon/postprocess \
-I$(srcdir)/daemon/queue \
-I$(srcdir)/daemon/remote \
-I$(srcdir)/daemon/util
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 DupeCoordinator.cpp DupeCoordinator.h \
Frontend.cpp Frontend.h FeedCoordinator.cpp FeedCoordinator.h FeedFile.cpp FeedFile.h \
FeedFilter.cpp FeedFilter.h FeedInfo.cpp FeedInfo.h Log.cpp Log.h LoggableFrontend.cpp \
LoggableFrontend.h Maintenance.cpp Maintenance.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 \
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
EXTRA_DIST = \
Makefile.cvs \
nzbgetd \
$(windows_FILES) \
$(osx_FILES)
Makefile.cvs nzbgetd \
$(patches_FILES) $(windows_FILES) $(osx_FILES)
patches_FILES = \
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
libpar2-0.2-MSVC8.patch libsigc++-2.0.18-MSVC8.patch
windows_FILES = \
daemon/windows/NTService.cpp \
daemon/windows/NTService.h \
daemon/windows/win32.h \
nzbget.sln \
nzbget.vcproj \
nzbget-shell.bat
win32.h NTService.cpp NTService.h nzbget.sln nzbget.vcproj nzbget-shell.bat
osx_FILES = \
osx/App_Prefix.pch \
osx/NZBGet-Info.plist \
osx/DaemonController.h \
osx/DaemonController.m \
osx/MainApp.h \
osx/MainApp.m \
osx/MainApp.xib \
osx/PFMoveApplication.h \
osx/PFMoveApplication.m \
osx/PreferencesDialog.h \
osx/PreferencesDialog.m \
osx/PreferencesDialog.xib \
osx/RPC.h \
osx/RPC.m \
osx/WebClient.h \
osx/WebClient.m \
osx/WelcomeDialog.h \
osx/WelcomeDialog.m \
osx/WelcomeDialog.xib \
osx/App_Prefix.pch osx/NZBGet-Info.plist \
osx/DaemonController.h osx/DaemonController.m \
osx/MainApp.h osx/MainApp.m osx/MainApp.xib \
osx/PFMoveApplication.h osx/PFMoveApplication.m \
osx/PreferencesDialog.h osx/PreferencesDialog.m osx/PreferencesDialog.xib \
osx/RPC.h osx/RPC.m osx/WebClient.h osx/WebClient.m \
osx/WelcomeDialog.h osx/WelcomeDialog.m osx/WelcomeDialog.xib \
osx/NZBGet.xcodeproj/project.pbxproj \
osx/Resources/Images/mainicon.icns \
osx/Resources/Images/statusicon.png \
osx/Resources/Images/statusicon@2x.png \
osx/Resources/Images/statusicon-inv.png \
osx/Resources/Images/statusicon-inv@2x.png \
osx/Resources/licenses/license-bootstrap.txt \
osx/Resources/licenses/license-jquery-GPL.txt \
osx/Resources/licenses/license-jquery-MIT.txt \
osx/Resources/Credits.rtf \
osx/Resources/Localizable.strings \
osx/Resources/Welcome.rtf
osx/Resources/Images/mainicon.icns osx/Resources/Images/statusicon.png \
osx/Resources/Images/statusicon@2x.png osx/Resources/Images/statusicon-inv.png \
osx/Resources/Images/statusicon-inv@2x.png osx/Resources/licenses/license-bootstrap.txt \
osx/Resources/licenses/license-jquery-GPL.txt osx/Resources/licenses/license-jquery-MIT.txt \
osx/Resources/Credits.rtf osx/Resources/Localizable.strings osx/Resources/Welcome.rtf
doc_FILES = \
README \
ChangeLog \
COPYING
README ChangeLog COPYING
exampleconf_FILES = \
nzbget.conf
webui_FILES = \
webui/index.html \
webui/index.js \
webui/downloads.js \
webui/edit.js \
webui/fasttable.js \
webui/history.js \
webui/messages.js \
webui/status.js \
webui/style.css \
webui/upload.js \
webui/util.js \
webui/config.js \
webui/feed.js \
webui/lib/bootstrap.js \
webui/lib/bootstrap.min.js \
webui/lib/bootstrap.css \
webui/lib/jquery.js \
webui/lib/jquery.min.js \
webui/lib/raphael.js \
webui/lib/raphael.min.js \
webui/lib/elycharts.js \
webui/lib/elycharts.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/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/feed.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
scripts_FILES = \
scripts/EMail.py \
scripts/Logger.py
ppscripts_FILES = \
ppscripts/EMail.py ppscripts/Logger.py
# Install
sbin_SCRIPTS = nzbgetd
@@ -228,8 +91,8 @@ exampleconfdir = $(datadir)/nzbget
dist_exampleconf_DATA = $(exampleconf_FILES)
webuidir = $(datadir)/nzbget
nobase_dist_webui_DATA = $(webui_FILES)
scriptsdir = $(datadir)/nzbget
nobase_dist_scripts_SCRIPTS = $(scripts_FILES)
ppscriptsdir = $(datadir)/nzbget
nobase_dist_ppscripts_SCRIPTS = $(ppscripts_FILES)
# Note about "sed":
# We need to make some changes in installed files.
@@ -255,7 +118,7 @@ install-data-hook:
sed 's:configuration file (typically installed:configuration file (installed:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:/usr/local/share/nzbget/nzbget.conf):$(exampleconfdir)/nzbget.conf):' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
sed 's:^WebDir=:WebDir=$(webuidir)/webui:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
sed 's:typically installed to /usr/local/share/nzbget/scripts:installed to $(scriptsdir)/scripts:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
sed 's:typically installed to /usr/local/share/nzbget/ppscripts:installed to $(ppscriptsdir)/ppscripts:' < "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp" > "$(DESTDIR)$(exampleconfdir)/nzbget.conf"
rm "$(DESTDIR)$(exampleconfdir)/nzbget.conf.temp"
# Install configuration files into /etc
@@ -315,6 +178,6 @@ clean-bak: rm *~
# Fix premissions
dist-hook:
find $(distdir)/daemon -type f -print -exec chmod -x {} \;
chmod -x $(distdir)/*.cpp $(distdir)/*.h
find $(distdir)/webui -type f -print -exec chmod -x {} \;

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) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@
#ifndef MESSAGEBASE_H
#define MESSAGEBASE_H
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6224; // = "nzb-XX" (protocol version)
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A621B; // = "nzb-XX" (protocol version)
static const int NZBREQUESTFILENAMESIZE = 512;
static const int NZBREQUESTPASSWORDSIZE = 32;
@@ -62,13 +62,67 @@ enum eRemoteRequest
eRemoteRequestWriteLog,
eRemoteRequestScan,
eRemoteRequestHistory,
eRemoteRequestDownloadUrl
eRemoteRequestDownloadUrl,
eRemoteRequestUrlQueue
};
// Possible values for field "m_iAction" of struct "SNZBEditQueueRequest":
// File-Actions affect one file, Group-Actions affect all files in group.
// Group is a list of files, added to queue from one NZB-File.
enum eRemoteEditAction
{
eRemoteEditActionFileMoveOffset = 1, // move files to m_iOffset relative to the current position in download-queue
eRemoteEditActionFileMoveTop, // move files to the top of download-queue
eRemoteEditActionFileMoveBottom, // move files to the bottom of download-queue
eRemoteEditActionFilePause, // pause files
eRemoteEditActionFileResume, // resume (unpause) files
eRemoteEditActionFileDelete, // delete files
eRemoteEditActionFilePauseAllPars, // pause only (all) pars (does not affect other files)
eRemoteEditActionFilePauseExtraPars, // pause only (almost all) pars, except main par-file (does not affect other files)
eRemoteEditActionFileSetPriority, // set priority for files
eRemoteEditActionFileReorder, // (not supported)
eRemoteEditActionFileSplit, // split - create new group from selected files
eRemoteEditActionGroupMoveOffset, // move group to m_iOffset relative to the current position in download-queue
eRemoteEditActionGroupMoveTop, // move group to the top of download-queue
eRemoteEditActionGroupMoveBottom, // move group to the bottom of download-queue
eRemoteEditActionGroupPause, // pause group
eRemoteEditActionGroupResume, // resume (unpause) group
eRemoteEditActionGroupDelete, // delete group
eRemoteEditActionGroupDupeDelete, // delete group
eRemoteEditActionGroupFinalDelete, // 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)
eRemoteEditActionGroupSetDupeKey, // (reserved)
eRemoteEditActionGroupSetDupeScore, // (reserved)
eRemoteEditActionGroupSetDupeMode, // (reserved)
eRemoteEditActionPostMoveOffset = 51, // move post-job to m_iOffset relative to the current position in post-queue
eRemoteEditActionPostMoveTop, // move post-job to the top of post-queue
eRemoteEditActionPostMoveBottom, // move post-job to the bottom of post-queue
eRemoteEditActionPostDelete, // delete post-job
eRemoteEditActionHistoryDelete, // hide history-item
eRemoteEditActionHistoryFinalDelete, // delete history-item
eRemoteEditActionHistoryReturn, // move history-item back to download queue
eRemoteEditActionHistoryProcess, // move history-item back to download queue and start postprocessing
eRemoteEditActionHistoryRedownload, // move history-item back to download queue for redownload
eRemoteEditActionHistorySetParameter, // set post-process parameter for history-item
eRemoteEditActionHistorySetDupeKey, // (reserved)
eRemoteEditActionHistorySetDupeScore, // (reserved)
eRemoteEditActionHistorySetDupeMode, // (reserved)
eRemoteEditActionHistorySetDupeBackup, // (reserved)
eRemoteEditActionHistoryMarkBad, // mark history-item as bad (and download other duplicate)
eRemoteEditActionHistoryMarkGood // mark history-item as good (and push it into dup-history)
};
// Possible values for field "m_iAction" of struct "SNZBPauseUnpauseRequest":
enum eRemotePauseUnpauseAction
{
eRemotePauseUnpauseActionDownload = 1, // pause/unpause download queue
eRemotePauseUnpauseActionDownload2, // pause/unpause download queue (second pause-register)
eRemotePauseUnpauseActionPostProcess, // pause/unpause post-processor queue
eRemotePauseUnpauseActionScan // pause/unpause scan of incoming nzb-directory
};
@@ -164,16 +218,8 @@ struct SNZBListResponse
// A list response nzb entry
struct SNZBListResponseNZBEntry
{
int32_t m_iID; // NZB-ID
int32_t m_iKind; // Item Kind (see NZBInfo::Kind)
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_iRemainingSizeLo; // Size of remaining (unpaused) files in bytes, Low 32-bits of 64-bit value
int32_t m_iRemainingSizeHi; // Size of remaining (unpaused) files in bytes, High 32-bits of 64-bit value
int32_t m_iPausedSizeLo; // Size of npaused files in bytes, Low 32-bits of 64-bit value
int32_t m_iPausedSizeHi; // Size of paused files in bytes, High 32-bits of 64-bit value
int32_t m_iPausedCount; // Number of paused files
int32_t m_iPriority; // Download priority
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
@@ -208,6 +254,7 @@ 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
@@ -281,8 +328,10 @@ struct SNZBSetDownloadRateResponse
struct SNZBEditQueueRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
int32_t m_iAction; // Action to be executed, see enum DownloadQueue::EEditAction
int32_t m_iAction; // Action to be executed, see enum eRemoteEditAction
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
@@ -462,7 +511,7 @@ struct SNZBHistoryResponseEntry
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 NZBInfo::EUrlStatus
int32_t m_iUrlStatus; // See UrlInfo::EStatus
// trailing data
//char m_szNicename[m_iNicenameLen]; // variable sized
};
@@ -488,4 +537,30 @@ struct SNZBDownloadUrlResponse
//char m_szText[m_iTrailingDataLength]; // variable sized
};
// UrlQueue request
struct SNZBUrlQueueRequest
{
SNZBRequestBase m_MessageBase; // Must be the first in the struct
};
// UrlQueue response
struct SNZBUrlQueueResponse
{
SNZBResponseBase m_MessageBase; // Must be the first in the struct
int32_t m_iEntrySize; // Size of the SNZBUrlQueueResponseEntry-struct
int32_t m_iNrTrailingEntries; // Number of UrlQueue-entries, following to this structure
int32_t m_iTrailingDataLength; // Length of all UrlQueue-entries, following to this structure
// SNZBUrlQueueResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
};
// UrlQueue response entry
struct SNZBUrlQueueResponseEntry
{
int32_t m_iID; // ID of Url-entry
int32_t m_iURLLen; // Length of URL-string (m_szURL), following to this record
int32_t m_iNZBFilenameLen; // Length of NZBFilename-string (m_szNZBFilename), following to this record
//char m_szURL[m_iURLLen]; // variable sized
//char m_szNZBFilename[m_iNZBFilenameLen]; // variable sized
};
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -269,6 +269,7 @@ void NCursesFrontend::Run()
}
FreeData();
ClearGroupQueue();
debug("Exiting NCursesFrontend-loop");
}
@@ -287,11 +288,13 @@ void NCursesFrontend::Update(int iKey)
if (m_iDataUpdatePos <= 0)
{
FreeData();
ClearGroupQueue();
m_iNeededLogEntries = m_iMessagesWinClientHeight;
if (!PrepareData())
{
return;
}
PrepareGroupQueue();
// recalculate frame sizes
CalcWindowSizes();
@@ -384,22 +387,17 @@ void NCursesFrontend::CalcWindowSizes()
int NCursesFrontend::CalcQueueSize()
{
int iQueueSize = 0;
DownloadQueue* pDownloadQueue = LockQueue();
if (m_bGroupFiles)
{
iQueueSize = pDownloadQueue->GetQueue()->size();
return m_groupQueue.size();
}
else
{
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
iQueueSize += pNZBInfo->GetFileList()->size();
}
DownloadQueue* pDownloadQueue = LockQueue();
int iQueueSize = pDownloadQueue->GetFileQueue()->size();
UnlockQueue();
return iQueueSize;
}
UnlockQueue();
return iQueueSize;
}
void NCursesFrontend::PlotLine(const char * szString, int iRow, int iPos, int iColorPair)
@@ -613,7 +611,7 @@ void NCursesFrontend::PrintStatus()
timeString[0] = '\0';
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
if (iCurrentDownloadSpeed > 0 && !m_bPauseDownload)
if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
{
long long remain_sec = (long long)(m_lRemainingSize / iCurrentDownloadSpeed);
int h = (int)(remain_sec / 3600);
@@ -644,10 +642,12 @@ 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, Avg. %.*f KB/s",
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,
(float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString, szPostStatus,
m_bPauseDownload ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
m_bPauseDownload || m_bPauseDownload2 ? (m_bStandBy ? ", Paused" : ", Pausing") : "",
m_bPauseDownload || m_bPauseDownload2 ?
(m_bPauseDownload && m_bPauseDownload2 ? " (+2)" : m_bPauseDownload2 ? " (2)" : "") : "",
szDownloadLimit, (fAverageSpeed >= 10 ? 0 : 1), fAverageSpeed);
tmp[MAX_SCREEN_WIDTH - 1] = '\0';
PlotLine(tmp, iStatusRow, 0, NCURSES_COLORPAIR_STATUS);
@@ -743,24 +743,31 @@ void NCursesFrontend::PrintQueue()
void NCursesFrontend::PrintFileQueue()
{
int iLineNr = m_iQueueWinTop;
DownloadQueue* pDownloadQueue = LockQueue();
if (pDownloadQueue->GetFileQueue()->empty())
{
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), "%s Files for downloading", m_bUseColor ? "" : "*** ");
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, iLineNr++, true);
PlotLine("Ready to receive nzb-job", iLineNr++, 0, NCURSES_COLORPAIR_TEXT);
}
else
{
iLineNr++;
long long lRemaining = 0;
long long lPaused = 0;
int iPausedFiles = 0;
int i = 0;
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++, i++)
{
FileInfo* pFileInfo = *it;
int iLineNr = m_iQueueWinTop + 1;
long long lRemaining = 0;
long long lPaused = 0;
int iPausedFiles = 0;
int iFileNum = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++, iFileNum++)
{
FileInfo* pFileInfo = *it2;
if (iFileNum >= m_iQueueScrollOffset && iFileNum < m_iQueueScrollOffset + m_iQueueWinHeight -1)
if (i >= m_iQueueScrollOffset && i < m_iQueueScrollOffset + m_iQueueWinHeight -1)
{
PrintFilename(pFileInfo, iLineNr++, iFileNum == m_iSelectedQueueEntry);
PrintFilename(pFileInfo, iLineNr++, i == m_iSelectedQueueEntry);
}
if (pFileInfo->GetPaused())
@@ -769,11 +776,8 @@ void NCursesFrontend::PrintFileQueue()
lPaused += pFileInfo->GetRemainingSize();
}
lRemaining += pFileInfo->GetRemainingSize();
}
}
if (iFileNum > 0)
{
}
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lRemaining);
@@ -782,21 +786,11 @@ void NCursesFrontend::PrintFileQueue()
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), " %sFiles for downloading - %i / %i files in queue - %s / %s",
m_bUseColor ? "" : "*** ", iFileNum,
iFileNum - iPausedFiles, szRemaining, szUnpaused);
m_bUseColor ? "" : "*** ", (int)pDownloadQueue->GetFileQueue()->size(),
(int)pDownloadQueue->GetFileQueue()->size() - iPausedFiles, szRemaining, szUnpaused);
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, m_iQueueWinTop, true);
}
else
{
iLineNr--;
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), "%s Files for downloading", m_bUseColor ? "" : "*** ");
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, iLineNr++, true);
PlotLine("Ready to receive nzb-job", iLineNr++, 0, NCURSES_COLORPAIR_TEXT);
}
UnlockQueue();
}
@@ -827,9 +821,9 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
char szPriority[100];
szPriority[0] = '\0';
if (pFileInfo->GetNZBInfo()->GetPriority() != 0)
if (pFileInfo->GetPriority() != 0)
{
sprintf(szPriority, " [%+i]", pFileInfo->GetNZBInfo()->GetPriority());
sprintf(szPriority, " [%+i]", pFileInfo->GetPriority());
}
char szCompleted[20];
@@ -926,8 +920,9 @@ void NCursesFrontend::PrintGroupQueue()
{
int iLineNr = m_iQueueWinTop;
DownloadQueue* pDownloadQueue = LockQueue();
if (pDownloadQueue->GetQueue()->empty())
LockQueue();
GroupQueue* pGroupQueue = &m_groupQueue;
if (pGroupQueue->empty())
{
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), "%s NZBs for downloading", m_bUseColor ? "" : "*** ");
@@ -942,27 +937,30 @@ void NCursesFrontend::PrintGroupQueue()
ResetColWidths();
int iCalcLineNr = iLineNr;
int i = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++, i++)
for (GroupQueue::iterator it = pGroupQueue->begin(); it != pGroupQueue->end(); it++, i++)
{
NZBInfo* pNZBInfo = *it;
GroupInfo* pGroupInfo = *it;
if (i >= m_iQueueScrollOffset && i < m_iQueueScrollOffset + m_iQueueWinHeight -1)
{
PrintGroupname(pNZBInfo, iCalcLineNr++, false, true);
PrintGroupname(pGroupInfo, iCalcLineNr++, false, true);
}
}
long long lRemaining = 0;
long long lPaused = 0;
i = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++, i++)
for (GroupQueue::iterator it = pGroupQueue->begin(); it != pGroupQueue->end(); it++, i++)
{
NZBInfo* pNZBInfo = *it;
GroupInfo* pGroupInfo = *it;
if (i >= m_iQueueScrollOffset && i < m_iQueueScrollOffset + m_iQueueWinHeight -1)
{
PrintGroupname(pNZBInfo, iLineNr++, i == m_iSelectedQueueEntry, false);
PrintGroupname(pGroupInfo, iLineNr++, i == m_iSelectedQueueEntry, false);
}
lRemaining += pNZBInfo->GetRemainingSize();
lPaused += pNZBInfo->GetPausedSize();
lRemaining += pGroupInfo->GetRemainingSize();
lPaused += pGroupInfo->GetPausedSize();
}
char szRemaining[20];
@@ -973,7 +971,7 @@ void NCursesFrontend::PrintGroupQueue()
char szBuffer[MAX_SCREEN_WIDTH];
snprintf(szBuffer, sizeof(szBuffer), " %sNZBs for downloading - %i NZBs in queue - %s / %s",
m_bUseColor ? "" : "*** ", (int)pDownloadQueue->GetQueue()->size(), szRemaining, szUnpaused);
m_bUseColor ? "" : "*** ", (int)pGroupQueue->size(), szRemaining, szUnpaused);
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
PrintTopHeader(szBuffer, m_iQueueWinTop, false);
}
@@ -987,7 +985,7 @@ void NCursesFrontend::ResetColWidths()
m_iColWidthLeft = 0;
}
void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected, bool bCalcColWidth)
void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSelected, bool bCalcColWidth)
{
int color = NCURSES_COLORPAIR_TEXT;
char chBrace1 = '[';
@@ -1003,21 +1001,28 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
}
const char* szDownloading = "";
if (pNZBInfo->GetActiveDownloads() > 0)
if (pGroupInfo->GetActiveDownloads() > 0)
{
szDownloading = " *";
}
long long lUnpausedRemainingSize = pNZBInfo->GetRemainingSize() - pNZBInfo->GetPausedSize();
long long lUnpausedRemainingSize = pGroupInfo->GetRemainingSize() - pGroupInfo->GetPausedSize();
char szRemaining[20];
Util::FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
char szPriority[100];
szPriority[0] = '\0';
if (pNZBInfo->GetPriority() != 0)
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
{
sprintf(szPriority, " [%+i]", pNZBInfo->GetPriority());
if (pGroupInfo->GetMinPriority() == pGroupInfo->GetMaxPriority())
{
sprintf(szPriority, " [%+i]", pGroupInfo->GetMinPriority());
}
else
{
sprintf(szPriority, " [%+i..%+i]", pGroupInfo->GetMinPriority(), pGroupInfo->GetMaxPriority());
}
}
char szBuffer[MAX_SCREEN_WIDTH];
@@ -1041,26 +1046,26 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
if (bPrintFormatted)
{
char szFiles[20];
snprintf(szFiles, 20, "%i/%i", (int)pNZBInfo->GetFileList()->size(), pNZBInfo->GetPausedFileCount());
snprintf(szFiles, 20, "%i/%i", pGroupInfo->GetRemainingFileCount(), pGroupInfo->GetPausedFileCount());
szFiles[20-1] = '\0';
char szTotal[20];
Util::FormatFileSize(szTotal, sizeof(szTotal), pNZBInfo->GetSize());
Util::FormatFileSize(szTotal, sizeof(szTotal), pGroupInfo->GetNZBInfo()->GetSize());
char szNameWithIds[1024];
snprintf(szNameWithIds, 1024, "%c%i%c%s%s %s", chBrace1, pNZBInfo->GetID(), chBrace2,
szPriority, szDownloading, pNZBInfo->GetName());
snprintf(szNameWithIds, 1024, "%c%i-%i%c%s%s %s", chBrace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), chBrace2,
szPriority, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
szNameWithIds[iNameLen] = '\0';
char szTime[100];
szTime[0] = '\0';
int iCurrentDownloadSpeed = m_bStandBy ? 0 : m_iCurrentDownloadSpeed;
if (pNZBInfo->GetPausedSize() > 0 && lUnpausedRemainingSize == 0)
if (pGroupInfo->GetPausedSize() > 0 && lUnpausedRemainingSize == 0)
{
snprintf(szTime, 100, "[paused]");
Util::FormatFileSize(szRemaining, sizeof(szRemaining), pNZBInfo->GetRemainingSize());
Util::FormatFileSize(szRemaining, sizeof(szRemaining), pGroupInfo->GetRemainingSize());
}
else if (iCurrentDownloadSpeed > 0 && !m_bPauseDownload)
else if (iCurrentDownloadSpeed > 0 && !(m_bPauseDownload || m_bPauseDownload2))
{
long long remain_sec = (long long)(lUnpausedRemainingSize / iCurrentDownloadSpeed);
int h = (int)(remain_sec / 3600);
@@ -1094,8 +1099,8 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
}
else
{
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%c%i%c%s %s", chBrace1, pNZBInfo->GetID(),
chBrace2, szDownloading, pNZBInfo->GetName());
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%c%i-%i%c%s %s", chBrace1, pGroupInfo->GetFirstID(),
pGroupInfo->GetLastID(), chBrace2, szDownloading, pGroupInfo->GetNZBInfo()->GetName());
}
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
@@ -1106,73 +1111,75 @@ void NCursesFrontend::PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected
}
}
bool NCursesFrontend::EditQueue(DownloadQueue::EEditAction eAction, int iOffset)
void NCursesFrontend::PrepareGroupQueue()
{
m_groupQueue.clear();
DownloadQueue* pDownloadQueue = LockQueue();
pDownloadQueue->BuildGroups(&m_groupQueue);
UnlockQueue();
}
void NCursesFrontend::ClearGroupQueue()
{
m_groupQueue.Clear();
}
bool NCursesFrontend::EditQueue(QueueEditor::EEditAction eAction, int iOffset)
{
int ID = 0;
if (m_bGroupFiles)
{
DownloadQueue* pDownloadQueue = LockQueue();
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)pDownloadQueue->GetQueue()->size())
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)m_groupQueue.size())
{
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->at(m_iSelectedQueueEntry);
ID = pNZBInfo->GetID();
if (eAction == DownloadQueue::eaFilePause)
GroupInfo* pGroupInfo = m_groupQueue[m_iSelectedQueueEntry];
ID = pGroupInfo->GetLastID();
if (eAction == QueueEditor::eaFilePause)
{
if (pNZBInfo->GetRemainingSize() == pNZBInfo->GetPausedSize())
if (pGroupInfo->GetRemainingSize() == pGroupInfo->GetPausedSize())
{
eAction = DownloadQueue::eaFileResume;
eAction = QueueEditor::eaFileResume;
}
else if (pNZBInfo->GetPausedSize() == 0 && (pNZBInfo->GetRemainingParCount() > 0) &&
else if (pGroupInfo->GetPausedSize() == 0 && (pGroupInfo->GetRemainingParCount() > 0) &&
!(m_bLastPausePars && m_iLastEditEntry == m_iSelectedQueueEntry))
{
eAction = DownloadQueue::eaFilePauseExtraPars;
eAction = QueueEditor::eaFilePauseExtraPars;
m_bLastPausePars = true;
}
else
{
eAction = DownloadQueue::eaFilePause;
eAction = QueueEditor::eaFilePause;
m_bLastPausePars = false;
}
}
}
UnlockQueue();
// map file-edit-actions to group-edit-actions
DownloadQueue::EEditAction FileToGroupMap[] = {
(DownloadQueue::EEditAction)0,
DownloadQueue::eaGroupMoveOffset,
DownloadQueue::eaGroupMoveTop,
DownloadQueue::eaGroupMoveBottom,
DownloadQueue::eaGroupPause,
DownloadQueue::eaGroupResume,
DownloadQueue::eaGroupDelete,
DownloadQueue::eaGroupPauseAllPars,
DownloadQueue::eaGroupPauseExtraPars };
QueueEditor::EEditAction FileToGroupMap[] = {
(QueueEditor::EEditAction)0,
QueueEditor::eaGroupMoveOffset,
QueueEditor::eaGroupMoveTop,
QueueEditor::eaGroupMoveBottom,
QueueEditor::eaGroupPause,
QueueEditor::eaGroupResume,
QueueEditor::eaGroupDelete,
QueueEditor::eaGroupPauseAllPars,
QueueEditor::eaGroupPauseExtraPars };
eAction = FileToGroupMap[eAction];
}
else
{
DownloadQueue* pDownloadQueue = LockQueue();
int iFileNum = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)pDownloadQueue->GetFileQueue()->size())
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++, iFileNum++)
FileInfo* pFileInfo = pDownloadQueue->GetFileQueue()->at(m_iSelectedQueueEntry);
ID = pFileInfo->GetID();
if (eAction == QueueEditor::eaFilePause)
{
if (m_iSelectedQueueEntry == iFileNum)
{
FileInfo* pFileInfo = *it2;
ID = pFileInfo->GetID();
if (eAction == DownloadQueue::eaFilePause)
{
eAction = !pFileInfo->GetPaused() ? DownloadQueue::eaFilePause : DownloadQueue::eaFileResume;
}
}
eAction = !pFileInfo->GetPaused() ? QueueEditor::eaFilePause : QueueEditor::eaFileResume;
}
}
UnlockQueue();
}
@@ -1289,9 +1296,12 @@ void NCursesFrontend::UpdateInput(int initialKey)
// Key 'p' for pause
if (!IsRemoteMode())
{
info(m_bPauseDownload ? "Unpausing download" : "Pausing download");
info(m_bPauseDownload || m_bPauseDownload2 ? "Unpausing download" : "Pausing download");
}
ServerPauseUnpause(!m_bPauseDownload);
ServerPauseUnpause(!(m_bPauseDownload || m_bPauseDownload2), m_bPauseDownload2 && !m_bPauseDownload);
break;
case '\'':
ServerDumpDebug();
break;
case 'e':
case 10: // return
@@ -1377,38 +1387,38 @@ void NCursesFrontend::UpdateInput(int initialKey)
break;
case 'p':
// Key 'p' for pause
EditQueue(DownloadQueue::eaFilePause, 0);
EditQueue(QueueEditor::eaFilePause, 0);
break;
case 'd':
SetHint(" Use Uppercase \"D\" for delete");
break;
case 'D':
// Delete entry
if (EditQueue(DownloadQueue::eaFileDelete, 0))
if (EditQueue(QueueEditor::eaFileDelete, 0))
{
SetCurrentQueueEntry(m_iSelectedQueueEntry);
}
break;
case 'u':
if (EditQueue(DownloadQueue::eaFileMoveOffset, -1))
if (EditQueue(QueueEditor::eaFileMoveOffset, -1))
{
SetCurrentQueueEntry(m_iSelectedQueueEntry - 1);
}
break;
case 'n':
if (EditQueue(DownloadQueue::eaFileMoveOffset, +1))
if (EditQueue(QueueEditor::eaFileMoveOffset, +1))
{
SetCurrentQueueEntry(m_iSelectedQueueEntry + 1);
}
break;
case 't':
if (EditQueue(DownloadQueue::eaFileMoveTop, 0))
if (EditQueue(QueueEditor::eaFileMoveTop, 0))
{
SetCurrentQueueEntry(0);
}
break;
case 'b':
if (EditQueue(DownloadQueue::eaFileMoveBottom, 0))
if (EditQueue(QueueEditor::eaFileMoveBottom, 0))
{
SetCurrentQueueEntry(iQueueSize > 0 ? iQueueSize - 1 : 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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -62,6 +62,7 @@ private:
int m_iLastEditEntry;
bool m_bLastPausePars;
int m_iQueueScrollOffset;
GroupQueue m_groupQueue;
char* m_szHint;
time_t m_tStartHint;
int m_iColWidthFiles;
@@ -98,8 +99,10 @@ private:
void PrintFilename(FileInfo* pFileInfo, int iRow, bool bSelected);
void PrintGroupQueue();
void ResetColWidths();
void PrintGroupname(NZBInfo* pNZBInfo, int iRow, bool bSelected, bool bCalcColWidth);
void PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSelected, bool bCalcColWidth);
void PrepareGroupQueue();
void PrintTopHeader(char* szHeader, int iLineNr, bool bUpTime);
void ClearGroupQueue();
int PrintMessage(Message* Msg, int iRow, int iMaxLines);
void PrintKeyInputBar();
void PrintStatus();
@@ -111,7 +114,7 @@ private:
int ReadConsoleKey();
int CalcQueueSize();
void NeedUpdateData();
bool EditQueue(DownloadQueue::EEditAction eAction, int iOffset);
bool EditQueue(QueueEditor::EEditAction eAction, int iOffset);
void SetHint(const char* szHint);
protected:

View File

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -64,6 +64,7 @@ NZBFile::NZBFile(const char* szFileName, const char* szCategory)
m_szFileName = strdup(szFileName);
m_szPassword = NULL;
m_pNZBInfo = new NZBInfo();
m_pNZBInfo->Retain();
m_pNZBInfo->SetFilename(szFileName);
m_pNZBInfo->SetCategory(szCategory);
m_pNZBInfo->BuildDestDirName();
@@ -75,6 +76,8 @@ NZBFile::NZBFile(const char* szFileName, const char* szCategory)
m_szTagContent = NULL;
m_iTagContentLen = 0;
#endif
m_FileInfos.clear();
}
NZBFile::~NZBFile()
@@ -85,17 +88,31 @@ NZBFile::~NZBFile()
free(m_szFileName);
free(m_szPassword);
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
delete *it;
}
m_FileInfos.clear();
if (m_pNZBInfo)
{
m_pNZBInfo->Release();
}
#ifndef WIN32
delete m_pFileInfo;
free(m_szTagContent);
#endif
delete m_pNZBInfo;
}
void NZBFile::LogDebugInfo()
{
info(" NZBFile %s", m_szFileName);
debug(" NZBFile %s", m_szFileName);
}
void NZBFile::DetachFileInfos()
{
m_FileInfos.clear();
}
void NZBFile::AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo)
@@ -161,7 +178,7 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
lMissedSize += iUncountedArticles * lOneSize;
lSize += lMissedSize;
m_pNZBInfo->GetFileList()->push_back(pFileInfo);
m_FileInfos.push_back(pFileInfo);
pFileInfo->SetNZBInfo(m_pNZBInfo);
pFileInfo->SetSize(lSize);
pFileInfo->SetRemainingSize(lSize - lMissedSize);
@@ -284,11 +301,11 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
bool NZBFile::HasDuplicateFilenames()
{
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo1 = *it;
int iDupe = 1;
for (FileList::iterator it2 = it + 1; it2 != m_pNZBInfo->GetFileList()->end(); it2++)
for (FileInfos::iterator it2 = it + 1; it2 != m_FileInfos.end(); it2++)
{
FileInfo* pFileInfo2 = *it2;
if (!strcmp(pFileInfo1->GetFilename(), pFileInfo2->GetFilename()) &&
@@ -304,7 +321,7 @@ bool NZBFile::HasDuplicateFilenames()
// false "duplicate files"-alarm.
// It's Ok for just two files to have the same filename, this is
// an often case by posting-errors to repost bad files
if (iDupe > 2 || (iDupe == 2 && m_pNZBInfo->GetFileList()->size() == 2))
if (iDupe > 2 || (iDupe == 2 && m_FileInfos.size() == 2))
{
return true;
}
@@ -318,7 +335,7 @@ bool NZBFile::HasDuplicateFilenames()
*/
void NZBFile::BuildFilenames()
{
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
ParseSubject(pFileInfo, true);
@@ -326,7 +343,7 @@ void NZBFile::BuildFilenames()
if (HasDuplicateFilenames())
{
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
ParseSubject(pFileInfo, false);
@@ -336,7 +353,7 @@ void NZBFile::BuildFilenames()
if (HasDuplicateFilenames())
{
m_pNZBInfo->SetManyDupeFiles(true);
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetFilename(pFileInfo->GetSubject());
@@ -351,26 +368,49 @@ bool CompareFileInfo(FileInfo* pFirst, FileInfo* pSecond)
void NZBFile::CalcHashes()
{
TempFileList fileList;
FileInfoList fileList;
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
fileList.push_back(*it);
}
fileList.sort(CompareFileInfo);
// split ExtCleanupDisk into tokens and create a list
ExtList extList;
char* szExtCleanupDisk = strdup(g_pOptions->GetExtCleanupDisk());
char* saveptr;
char* szExt = strtok_r(szExtCleanupDisk, ",; ", &saveptr);
while (szExt)
{
extList.push_back(szExt);
szExt = strtok_r(NULL, ",; ", &saveptr);
}
unsigned int iFullContentHash = 0;
unsigned int iFilteredContentHash = 0;
int iUseForFilteredCount = 0;
for (TempFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
for (FileInfoList::iterator it = fileList.begin(); it != fileList.end(); it++)
{
FileInfo* pFileInfo = *it;
// check file extension
bool bSkip = !pFileInfo->GetParFile() &&
Util::MatchFileExt(pFileInfo->GetFilename(), g_pOptions->GetExtCleanupDisk(), ",;");
int iFilenameLen = strlen(pFileInfo->GetFilename());
bool bSkip = false;
for (ExtList::iterator it = extList.begin(); it != extList.end(); it++)
{
const char* szExt = *it;
int iExtLen = strlen(szExt);
if (iFilenameLen >= iExtLen && !strcasecmp(szExt, pFileInfo->GetFilename() + iFilenameLen - iExtLen))
{
bSkip = true;
break;
}
}
bSkip = bSkip && !pFileInfo->GetParFile();
for (FileInfo::Articles::iterator it = pFileInfo->GetArticles()->begin(); it != pFileInfo->GetArticles()->end(); it++)
{
@@ -385,6 +425,8 @@ void NZBFile::CalcHashes()
}
}
free(szExtCleanupDisk);
// if filtered hash is based on less than a half of files - do not use filtered hash at all
if (iUseForFilteredCount < (int)fileList.size() / 2)
{
@@ -399,7 +441,7 @@ void NZBFile::ProcessFiles()
{
BuildFilenames();
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->MakeValidFilename();
@@ -413,7 +455,6 @@ void NZBFile::ProcessFiles()
m_pNZBInfo->SetFileCount(m_pNZBInfo->GetFileCount() + 1);
m_pNZBInfo->SetTotalArticles(m_pNZBInfo->GetTotalArticles() + pFileInfo->GetTotalArticles());
m_pNZBInfo->SetSize(m_pNZBInfo->GetSize() + pFileInfo->GetSize());
m_pNZBInfo->SetRemainingSize(m_pNZBInfo->GetRemainingSize() + pFileInfo->GetRemainingSize());
m_pNZBInfo->SetFailedSize(m_pNZBInfo->GetFailedSize() + pFileInfo->GetMissedSize());
m_pNZBInfo->SetCurrentFailedSize(m_pNZBInfo->GetFailedSize());
@@ -423,17 +464,14 @@ void NZBFile::ProcessFiles()
m_pNZBInfo->SetParSize(m_pNZBInfo->GetParSize() + pFileInfo->GetSize());
m_pNZBInfo->SetParFailedSize(m_pNZBInfo->GetParFailedSize() + pFileInfo->GetMissedSize());
m_pNZBInfo->SetParCurrentFailedSize(m_pNZBInfo->GetParFailedSize());
m_pNZBInfo->SetRemainingParCount(m_pNZBInfo->GetRemainingParCount() + 1);
}
}
m_pNZBInfo->UpdateMinMaxTime();
CalcHashes();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
for (FileList::iterator it = m_pNZBInfo->GetFileList()->begin(); it != m_pNZBInfo->GetFileList()->end(); it++)
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
{
FileInfo* pFileInfo = *it;
g_pDiskState->SaveFile(pFileInfo);
@@ -453,7 +491,7 @@ void NZBFile::ProcessFiles()
*/
void NZBFile::ReadPassword()
{
FILE* pFile = fopen(m_szFileName, FOPEN_RB);
FILE* pFile = fopen(m_szFileName, "rb");
if (!pFile)
{
return;
@@ -682,12 +720,6 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
m_pFileInfo = new FileInfo();
m_pFileInfo->SetFilename(m_szFileName);
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
return;
}
for (int i = 0; atts[i]; i += 2)
{
const char* attrname = atts[i];
@@ -706,16 +738,10 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
{
if (!m_pFileInfo)
{
warn("Malformed nzb-file, tag <segment> without tag <file>");
// error: bad nzb-file
return;
}
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
return;
}
long long lsize = -1;
int partNumber = -1;
@@ -744,11 +770,6 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
}
else if (!strcmp("meta", name))
{
if (!atts)
{
warn("Malformed nzb-file, tag <%s> must have attributes", name);
return;
}
m_bPassword = atts[0] && atts[1] && !strcmp("type", atts[0]) && !strcmp("password", atts[1]);
}
}

View File

@@ -27,6 +27,7 @@
#ifndef NZBFILE_H
#define NZBFILE_H
#include <vector>
#include <list>
#include "DownloadInfo.h"
@@ -34,9 +35,12 @@
class NZBFile
{
public:
typedef std::list<FileInfo*> TempFileList;
typedef std::vector<FileInfo*> FileInfos;
typedef std::list<FileInfo*> FileInfoList;
typedef std::list<char*> ExtList;
private:
FileInfos m_FileInfos;
NZBInfo* m_pNZBInfo;
char* m_szFileName;
char* m_szPassword;
@@ -75,9 +79,10 @@ public:
virtual ~NZBFile();
static NZBFile* Create(const char* szFileName, const char* szCategory);
const char* GetFileName() const { return m_szFileName; }
FileInfos* GetFileInfos() { return &m_FileInfos; }
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
const char* GetPassword() { return m_szPassword; }
void DetachNZBInfo() { m_pNZBInfo = NULL; }
void DetachFileInfos();
void LogDebugInfo();
};

View File

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 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
@@ -40,23 +40,23 @@ Subject::Subject()
m_Observers.clear();
}
void Subject::Attach(Observer* pObserver)
void Subject::Attach(Observer* Observer)
{
m_Observers.push_back(pObserver);
m_Observers.push_back(Observer);
}
void Subject::Detach(Observer* pObserver)
void Subject::Detach(Observer* Observer)
{
m_Observers.remove(pObserver);
m_Observers.remove(Observer);
}
void Subject::Notify(void* pAspect)
void Subject::Notify(void* Aspect)
{
debug("Notifying observers");
for (std::list<Observer*>::iterator it = m_Observers.begin(); it != m_Observers.end(); it++)
{
Observer* Observer = *it;
Observer->Update(this, pAspect);
Observer->Update(this, Aspect);
}
}

View File

@@ -2,7 +2,7 @@
* This file if part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 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
@@ -38,16 +38,16 @@ private:
public:
Subject();
void Attach(Observer* pObserver);
void Detach(Observer* pObserver);
void Notify(void* pAspect);
void Attach(Observer* Observer);
void Detach(Observer* Observer);
void Notify(void* Aspect);
};
class Observer
{
protected:
virtual void Update(Subject* pCaller, void* pAspect) = 0;
friend class Subject;
public:
virtual ~Observer() {};
virtual void Update(Subject* Caller, void* Aspect) = 0;
};
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -52,7 +52,6 @@
#include "ServerPool.h"
#include "NewsServer.h"
#include "MessageBase.h"
#include "DownloadInfo.h"
#include "Scheduler.h"
#include "FeedCoordinator.h"
@@ -127,6 +126,8 @@ static const char* OPTION_AUTHORIZEDIP = "AuthorizedIP";
static const char* OPTION_CONNECTIONTIMEOUT = "ConnectionTimeout";
static const char* OPTION_SAVEQUEUE = "SaveQueue";
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
static const char* OPTION_RELOADURLQUEUE = "ReloadUrlQueue";
static const char* OPTION_RELOADPOSTQUEUE = "ReloadPostQueue";
static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog";
static const char* OPTION_RESETLOG = "ResetLog";
static const char* OPTION_DECODE = "Decode";
@@ -146,8 +147,8 @@ static const char* OPTION_PARREPAIR = "ParRepair";
static const char* OPTION_PARSCAN = "ParScan";
static const char* OPTION_PARRENAME = "ParRename";
static const char* OPTION_HEALTHCHECK = "HealthCheck";
static const char* OPTION_SCANSCRIPT = "ScanScript";
static const char* OPTION_QUEUESCRIPT = "QueueScript";
static const char* OPTION_NZBPROCESS = "NZBProcess";
static const char* OPTION_NZBADDEDPROCESS = "NZBAddedProcess";
static const char* OPTION_UMASK = "UMask";
static const char* OPTION_UPDATEINTERVAL = "UpdateInterval";
static const char* OPTION_CURSESNZBNAME = "CursesNzbName";
@@ -174,13 +175,11 @@ static const char* OPTION_UNRARCMD = "UnrarCmd";
static const char* OPTION_SEVENZIPCMD = "SevenZipCmd";
static const char* OPTION_UNPACKPAUSEQUEUE = "UnpackPauseQueue";
static const char* OPTION_SCRIPTORDER = "ScriptOrder";
static const char* OPTION_POSTSCRIPT = "PostScript";
static const char* OPTION_DEFSCRIPT = "DefScript";
static const char* OPTION_EXTCLEANUPDISK = "ExtCleanupDisk";
static const char* OPTION_PARIGNOREEXT = "ParIgnoreExt";
static const char* OPTION_FEEDHISTORY = "FeedHistory";
static const char* OPTION_URLFORCE = "UrlForce";
static const char* OPTION_TIMECORRECTION = "TimeCorrection";
static const char* OPTION_PROPAGATIONDELAY = "PropagationDelay";
// obsolete options
static const char* OPTION_POSTLOGKIND = "PostLogKind";
@@ -195,21 +194,12 @@ static const char* OPTION_APPENDNZBDIR = "AppendNzbDir";
static const char* OPTION_RENAMEBROKEN = "RenameBroken";
static const char* OPTION_MERGENZB = "MergeNzb";
static const char* OPTION_STRICTPARNAME = "StrictParName";
static const char* OPTION_RELOADURLQUEUE = "ReloadUrlQueue";
static const char* OPTION_RELOADPOSTQUEUE = "ReloadPostQueue";
static const char* OPTION_NZBPROCESS = "NZBProcess";
static const char* OPTION_NZBADDEDPROCESS = "NZBAddedProcess";
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable", "enabled", "disabled" };
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
const int BoolCount = 12;
static const char* BEGIN_SCRIPT_SIGNATURE = "### NZBGET ";
static const char* POST_SCRIPT_SIGNATURE = "POST-PROCESSING";
static const char* SCAN_SCRIPT_SIGNATURE = "SCAN";
static const char* QUEUE_SCRIPT_SIGNATURE = "QUEUE";
static const char* SCHEDULER_SCRIPT_SIGNATURE = "SCHEDULER";
static const char* END_SCRIPT_SIGNATURE = " SCRIPT";
static const char* PPSCRIPT_SIGNATURE = "### NZBGET POST-PROCESSING SCRIPT";
#ifndef WIN32
const char* PossibleConfigLocations[] =
@@ -291,15 +281,17 @@ Options::OptEntry* Options::OptEntries::FindOption(const char* szName)
}
Options::ConfigTemplate::ConfigTemplate(Script* pScript, const char* szTemplate)
Options::ConfigTemplate::ConfigTemplate(const char* szName, const char* szDisplayName, const char* szTemplate)
{
m_pScript = pScript;
m_szName = strdup(szName);
m_szDisplayName = strdup(szDisplayName);
m_szTemplate = strdup(szTemplate ? szTemplate : "");
}
Options::ConfigTemplate::~ConfigTemplate()
{
delete m_pScript;
free(m_szName);
free(m_szDisplayName);
free(m_szTemplate);
}
@@ -312,19 +304,19 @@ Options::ConfigTemplates::~ConfigTemplates()
}
Options::Category::Category(const char* szName, const char* szDestDir, bool bUnpack, const char* szPostScript)
Options::Category::Category(const char* szName, const char* szDestDir, bool bUnpack, const char* szDefScript)
{
m_szName = strdup(szName);
m_szDestDir = szDestDir ? strdup(szDestDir) : NULL;
m_bUnpack = bUnpack;
m_szPostScript = szPostScript ? strdup(szPostScript) : NULL;
m_szDefScript = szDefScript ? strdup(szDefScript) : NULL;
}
Options::Category::~Category()
{
free(m_szName);
free(m_szDestDir);
free(m_szPostScript);
free(m_szDefScript);
for (NameList::iterator it = m_Aliases.begin(); it != m_Aliases.end(); it++)
{
@@ -382,10 +374,6 @@ Options::Script::Script(const char* szName, const char* szLocation)
m_szName = strdup(szName);
m_szLocation = strdup(szLocation);
m_szDisplayName = strdup(szName);
m_bPostScript = false;
m_bScanScript = false;
m_bQueueScript = false;
m_bSchedulerScript = false;
}
Options::Script::~Script()
@@ -448,9 +436,9 @@ Options::Options(int argc, char* argv[])
m_eDetailTarget = mtScreen;
m_bDecode = true;
m_bPauseDownload = false;
m_bPauseDownload2 = false;
m_bPausePostProcess = false;
m_bPauseScan = false;
m_bTempPauseDownload = false;
m_bCreateBrokenLog = false;
m_bResetLog = false;
m_iDownloadRate = 0;
@@ -491,6 +479,8 @@ Options::Options(int argc, char* argv[])
m_szDaemonUsername = NULL;
m_eOutputMode = omLoggable;
m_bReloadQueue = false;
m_bReloadUrlQueue = false;
m_bReloadPostQueue = false;
m_iUrlConnections = 0;
m_iLogBufferSize = 0;
m_iLogLines = 0;
@@ -503,9 +493,9 @@ Options::Options(int argc, char* argv[])
m_bParRename = false;
m_eHealthCheck = hcNone;
m_szScriptOrder = NULL;
m_szPostScript = NULL;
m_szScanScript = NULL;
m_szQueueScript = NULL;
m_szDefScript = NULL;
m_szNZBProcess = NULL;
m_szNZBAddedProcess = NULL;
m_bNoConfig = false;
m_iUMask = 0;
m_iUpdateInterval = 0;
@@ -537,12 +527,9 @@ Options::Options(int argc, char* argv[])
m_szSevenZipCmd = NULL;
m_bUnpackPauseQueue = false;
m_szExtCleanupDisk = NULL;
m_szParIgnoreExt = NULL;
m_iFeedHistory = 0;
m_bUrlForce = false;
m_iTimeCorrection = 0;
m_iLocalTimeOffset = 0;
m_iPropagationDelay = 0;
// Option "ConfigFile" will be initialized later, but we want
// to see it at the top of option list, so we add it first
@@ -616,6 +603,7 @@ Options::Options(int argc, char* argv[])
{
info("Pausing all activities due to errors in configuration");
m_bPauseDownload = true;
m_bPauseDownload2= true;
m_bPausePostProcess = true;
m_bPauseScan = true;
}
@@ -646,15 +634,14 @@ Options::~Options()
free(m_szLockFile);
free(m_szDaemonUsername);
free(m_szScriptOrder);
free(m_szPostScript);
free(m_szScanScript);
free(m_szQueueScript);
free(m_szDefScript);
free(m_szNZBProcess);
free(m_szNZBAddedProcess);
free(m_pEditQueueIDList);
free(m_szAddNZBFilename);
free(m_szUnrarCmd);
free(m_szSevenZipCmd);
free(m_szExtCleanupDisk);
free(m_szParIgnoreExt);
for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++)
{
@@ -731,7 +718,7 @@ void Options::InitDefault()
SetOption(OPTION_LOGFILE, "${DestDir}/nzbget.log");
SetOption(OPTION_WEBDIR, "");
SetOption(OPTION_CONFIGTEMPLATE, "");
SetOption(OPTION_SCRIPTDIR, "${MainDir}/scripts");
SetOption(OPTION_SCRIPTDIR, "${MainDir}/ppscripts");
SetOption(OPTION_CREATELOG, "yes");
SetOption(OPTION_APPENDCATEGORYDIR, "yes");
SetOption(OPTION_OUTPUTMODE, "curses");
@@ -749,6 +736,8 @@ void Options::InitDefault()
SetOption(OPTION_CONNECTIONTIMEOUT, "60");
SetOption(OPTION_SAVEQUEUE, "yes");
SetOption(OPTION_RELOADQUEUE, "yes");
SetOption(OPTION_RELOADURLQUEUE, "yes");
SetOption(OPTION_RELOADPOSTQUEUE, "yes");
SetOption(OPTION_CREATEBROKENLOG, "yes");
SetOption(OPTION_RESETLOG, "no");
SetOption(OPTION_DECODE, "yes");
@@ -769,9 +758,9 @@ void Options::InitDefault()
SetOption(OPTION_PARRENAME, "yes");
SetOption(OPTION_HEALTHCHECK, "none");
SetOption(OPTION_SCRIPTORDER, "");
SetOption(OPTION_POSTSCRIPT, "");
SetOption(OPTION_SCANSCRIPT, "");
SetOption(OPTION_QUEUESCRIPT, "");
SetOption(OPTION_DEFSCRIPT, "");
SetOption(OPTION_NZBPROCESS, "");
SetOption(OPTION_NZBADDEDPROCESS, "");
SetOption(OPTION_DAEMONUSERNAME, "root");
SetOption(OPTION_UMASK, "1000");
SetOption(OPTION_UPDATEINTERVAL, "200");
@@ -804,11 +793,9 @@ void Options::InitDefault()
#endif
SetOption(OPTION_UNPACKPAUSEQUEUE, "no");
SetOption(OPTION_EXTCLEANUPDISK, "");
SetOption(OPTION_PARIGNOREEXT, "");
SetOption(OPTION_FEEDHISTORY, "7");
SetOption(OPTION_URLFORCE, "yes");
SetOption(OPTION_TIMECORRECTION, "0");
SetOption(OPTION_PROPAGATIONDELAY, "0");
}
void Options::InitOptFile()
@@ -931,9 +918,9 @@ void Options::InitOptions()
m_szConfigTemplate = strdup(GetOption(OPTION_CONFIGTEMPLATE));
m_szScriptOrder = strdup(GetOption(OPTION_SCRIPTORDER));
m_szPostScript = strdup(GetOption(OPTION_POSTSCRIPT));
m_szScanScript = strdup(GetOption(OPTION_SCANSCRIPT));
m_szQueueScript = strdup(GetOption(OPTION_QUEUESCRIPT));
m_szDefScript = strdup(GetOption(OPTION_DEFSCRIPT));
m_szNZBProcess = strdup(GetOption(OPTION_NZBPROCESS));
m_szNZBAddedProcess = strdup(GetOption(OPTION_NZBADDEDPROCESS));
m_szControlIP = strdup(GetOption(OPTION_CONTROLIP));
m_szControlUsername = strdup(GetOption(OPTION_CONTROLUSERNAME));
m_szControlPassword = strdup(GetOption(OPTION_CONTROLPASSWORD));
@@ -946,7 +933,6 @@ void Options::InitOptions()
m_szUnrarCmd = strdup(GetOption(OPTION_UNRARCMD));
m_szSevenZipCmd = strdup(GetOption(OPTION_SEVENZIPCMD));
m_szExtCleanupDisk = strdup(GetOption(OPTION_EXTCLEANUPDISK));
m_szParIgnoreExt = strdup(GetOption(OPTION_PARIGNOREEXT));
m_iDownloadRate = (int)(ParseFloatValue(OPTION_DOWNLOADRATE) * 1024);
m_iConnectionTimeout = ParseIntValue(OPTION_CONNECTIONTIMEOUT, 10);
@@ -972,7 +958,6 @@ void Options::InitOptions()
m_iTimeCorrection *= 60;
}
m_iTimeCorrection *= 60;
m_iPropagationDelay = ParseIntValue(OPTION_PROPAGATIONDELAY, 10) * 60;
CheckDir(&m_szNzbDir, OPTION_NZBDIR, m_iNzbDirInterval == 0, true);
@@ -986,6 +971,8 @@ void Options::InitOptions()
m_bParRepair = (bool)ParseEnumValue(OPTION_PARREPAIR, BoolCount, BoolNames, BoolValues);
m_bParRename = (bool)ParseEnumValue(OPTION_PARRENAME, BoolCount, BoolNames, BoolValues);
m_bReloadQueue = (bool)ParseEnumValue(OPTION_RELOADQUEUE, BoolCount, BoolNames, BoolValues);
m_bReloadUrlQueue = (bool)ParseEnumValue(OPTION_RELOADURLQUEUE, BoolCount, BoolNames, BoolValues);
m_bReloadPostQueue = (bool)ParseEnumValue(OPTION_RELOADPOSTQUEUE, BoolCount, BoolNames, BoolValues);
m_bCursesNZBName = (bool)ParseEnumValue(OPTION_CURSESNZBNAME, BoolCount, BoolNames, BoolValues);
m_bCursesTime = (bool)ParseEnumValue(OPTION_CURSESTIME, BoolCount, BoolNames, BoolValues);
m_bCursesGroup = (bool)ParseEnumValue(OPTION_CURSESGROUP, BoolCount, BoolNames, BoolValues);
@@ -1010,9 +997,9 @@ void Options::InitOptions()
const int OutputModeCount = 7;
m_eOutputMode = (EOutputMode)ParseEnumValue(OPTION_OUTPUTMODE, OutputModeCount, OutputModeNames, OutputModeValues);
const char* ParCheckNames[] = { "auto", "always", "force", "manual", "yes", "no" }; // yes/no for compatibility with older versions
const int ParCheckValues[] = { pcAuto, pcAlways, pcForce, pcManual, pcAlways, pcAuto };
const int ParCheckCount = 6;
const char* ParCheckNames[] = { "auto", "force", "manual", "yes", "no" }; // yes/no for compatibility with older versions
const int ParCheckValues[] = { pcAuto, pcForce, pcManual, pcForce, pcAuto };
const int ParCheckCount = 5;
m_eParCheck = (EParCheck)ParseEnumValue(OPTION_PARCHECK, ParCheckCount, ParCheckNames, ParCheckValues);
const char* ParScanNames[] = { "limited", "full", "auto" };
@@ -1264,6 +1251,10 @@ void Options::InitCommandLine(int argc, char* argv[])
{
m_eClientOperation = opClientRequestHistory;
}
else if (!strcasecmp(optarg, "U"))
{
m_eClientOperation = opClientRequestUrlQueue;
}
else
{
abort("FATAL ERROR: Could not parse value of option 'L'\n");
@@ -1294,6 +1285,10 @@ void Options::InitCommandLine(int argc, char* argv[])
{
m_eClientOperation = c == 'P' ? opClientRequestDownloadPause : opClientRequestDownloadUnpause;
}
else if (!strcasecmp(optarg, "D2"))
{
m_eClientOperation = c == 'P' ? opClientRequestDownload2Pause : opClientRequestDownload2Unpause;
}
else if (!strcasecmp(optarg, "O"))
{
m_eClientOperation = c == 'P' ? opClientRequestPostPause : opClientRequestPostUnpause;
@@ -1371,13 +1366,26 @@ void Options::InitCommandLine(int argc, char* argv[])
if (bPost)
{
// edit-commands for post-processor-queue
if (!strcasecmp(optarg, "D"))
if (!strcasecmp(optarg, "T"))
{
m_iEditQueueAction = DownloadQueue::eaPostDelete;
m_iEditQueueAction = eRemoteEditActionPostMoveTop;
}
else if (!strcasecmp(optarg, "B"))
{
m_iEditQueueAction = eRemoteEditActionPostMoveBottom;
}
else if (!strcasecmp(optarg, "D"))
{
m_iEditQueueAction = eRemoteEditActionPostDelete;
}
else
{
abort("FATAL ERROR: Could not parse value of option 'E'\n");
m_iEditQueueOffset = atoi(optarg);
if (m_iEditQueueOffset == 0)
{
abort("FATAL ERROR: Could not parse value of option 'E'\n");
}
m_iEditQueueAction = eRemoteEditActionPostMoveOffset;
}
}
else if (bHistory)
@@ -1385,23 +1393,23 @@ void Options::InitCommandLine(int argc, char* argv[])
// edit-commands for history
if (!strcasecmp(optarg, "D"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryDelete;
m_iEditQueueAction = eRemoteEditActionHistoryDelete;
}
else if (!strcasecmp(optarg, "R"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryReturn;
m_iEditQueueAction = eRemoteEditActionHistoryReturn;
}
else if (!strcasecmp(optarg, "P"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryProcess;
m_iEditQueueAction = eRemoteEditActionHistoryProcess;
}
else if (!strcasecmp(optarg, "A"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryRedownload;
m_iEditQueueAction = eRemoteEditActionHistoryRedownload;
}
else if (!strcasecmp(optarg, "O"))
{
m_iEditQueueAction = DownloadQueue::eaHistorySetParameter;
m_iEditQueueAction = eRemoteEditActionHistorySetParameter;
optind++;
if (optind > argc)
@@ -1417,11 +1425,11 @@ void Options::InitCommandLine(int argc, char* argv[])
}
else if (!strcasecmp(optarg, "B"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryMarkBad;
m_iEditQueueAction = eRemoteEditActionHistoryMarkBad;
}
else if (!strcasecmp(optarg, "G"))
{
m_iEditQueueAction = DownloadQueue::eaHistoryMarkGood;
m_iEditQueueAction = eRemoteEditActionHistoryMarkGood;
}
else
{
@@ -1433,40 +1441,40 @@ void Options::InitCommandLine(int argc, char* argv[])
// edit-commands for download-queue
if (!strcasecmp(optarg, "T"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupMoveTop : DownloadQueue::eaFileMoveTop;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupMoveTop : eRemoteEditActionFileMoveTop;
}
else if (!strcasecmp(optarg, "B"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupMoveBottom : DownloadQueue::eaFileMoveBottom;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupMoveBottom : eRemoteEditActionFileMoveBottom;
}
else if (!strcasecmp(optarg, "P"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupPause : DownloadQueue::eaFilePause;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupPause : eRemoteEditActionFilePause;
}
else if (!strcasecmp(optarg, "A"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupPauseAllPars : DownloadQueue::eaFilePauseAllPars;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupPauseAllPars : eRemoteEditActionFilePauseAllPars;
}
else if (!strcasecmp(optarg, "R"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupPauseExtraPars : DownloadQueue::eaFilePauseExtraPars;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupPauseExtraPars : eRemoteEditActionFilePauseExtraPars;
}
else if (!strcasecmp(optarg, "U"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupResume : DownloadQueue::eaFileResume;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupResume : eRemoteEditActionFileResume;
}
else if (!strcasecmp(optarg, "D"))
{
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupDelete : DownloadQueue::eaFileDelete;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupDelete : eRemoteEditActionFileDelete;
}
else if (!strcasecmp(optarg, "C") || !strcasecmp(optarg, "K") || !strcasecmp(optarg, "CP"))
else if (!strcasecmp(optarg, "C") || !strcasecmp(optarg, "K"))
{
// switch "K" is provided for compatibility with v. 0.8.0 and can be removed in future versions
if (!bGroup)
{
abort("FATAL ERROR: Category can be set only for groups\n");
}
m_iEditQueueAction = !strcasecmp(optarg, "CP") ? DownloadQueue::eaGroupApplyCategory : DownloadQueue::eaGroupSetCategory;
m_iEditQueueAction = eRemoteEditActionGroupSetCategory;
optind++;
if (optind > argc)
@@ -1481,7 +1489,7 @@ void Options::InitCommandLine(int argc, char* argv[])
{
abort("FATAL ERROR: Only groups can be renamed\n");
}
m_iEditQueueAction = DownloadQueue::eaGroupSetName;
m_iEditQueueAction = eRemoteEditActionGroupSetName;
optind++;
if (optind > argc)
@@ -1496,11 +1504,11 @@ void Options::InitCommandLine(int argc, char* argv[])
{
abort("FATAL ERROR: Only groups can be merged\n");
}
m_iEditQueueAction = DownloadQueue::eaGroupMerge;
m_iEditQueueAction = eRemoteEditActionGroupMerge;
}
else if (!strcasecmp(optarg, "S"))
{
m_iEditQueueAction = DownloadQueue::eaFileSplit;
m_iEditQueueAction = eRemoteEditActionFileSplit;
optind++;
if (optind > argc)
@@ -1515,7 +1523,7 @@ void Options::InitCommandLine(int argc, char* argv[])
{
abort("FATAL ERROR: Post-process parameter can be set only for groups\n");
}
m_iEditQueueAction = DownloadQueue::eaGroupSetParameter;
m_iEditQueueAction = eRemoteEditActionGroupSetParameter;
optind++;
if (optind > argc)
@@ -1531,11 +1539,7 @@ void Options::InitCommandLine(int argc, char* argv[])
}
else if (!strcasecmp(optarg, "I"))
{
if (!bGroup)
{
abort("FATAL ERROR: Priority can be set only for groups\n");
}
m_iEditQueueAction = DownloadQueue::eaGroupSetPriority;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupSetPriority : eRemoteEditActionFileSetPriority;
optind++;
if (optind > argc)
@@ -1556,7 +1560,7 @@ void Options::InitCommandLine(int argc, char* argv[])
{
abort("FATAL ERROR: Could not parse value of option 'E'\n");
}
m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupMoveOffset : DownloadQueue::eaFileMoveOffset;
m_iEditQueueAction = bGroup ? eRemoteEditActionGroupMoveOffset : eRemoteEditActionFileMoveOffset;
}
}
break;
@@ -1620,9 +1624,11 @@ void Options::InitCommandLine(int argc, char* argv[])
}
}
if (m_bServerMode && m_eClientOperation == opClientRequestDownloadPause)
if (m_bServerMode && (m_eClientOperation == opClientRequestDownloadPause ||
m_eClientOperation == opClientRequestDownload2Pause))
{
m_bPauseDownload = true;
m_bPauseDownload = m_eClientOperation == opClientRequestDownloadPause;
m_bPauseDownload2 = m_eClientOperation == opClientRequestDownload2Pause;
m_eClientOperation = opClientNoOperation;
}
@@ -1659,22 +1665,25 @@ void Options::PrintUsage(char* com)
" N <name> Use this name as nzb-filename (only for URLs)\n"
" I <priority> Set priority (signed integer)\n"
" -C, --connect Attach client to server\n"
" -L, --list [F|FR|G|GR|O|H|S] [RegEx] Request list of items from server\n"
" -L, --list [F|FR|G|GR|O|U|H|S] [RegEx] Request list of items from server\n"
" F List individual files and server status (default)\n"
" FR Like \"F\" but apply regular expression filter\n"
" G List groups (nzb-files) and server status\n"
" GR Like \"G\" but apply regular expression filter\n"
" O List post-processor-queue\n"
" U List url-queue\n"
" H List history\n"
" S Print only server status\n"
" <RegEx> Regular expression (only with options \"FR\", \"GR\")\n"
" using POSIX Extended Regular Expression Syntax\n"
" -P, --pause [D|O|S] Pause server\n"
" -P, --pause [D|D2|O|S] Pause server\n"
" D Pause download queue (default)\n"
" D2 Pause download queue via second pause-register\n"
" O Pause post-processor queue\n"
" S Pause scan of incoming nzb-directory\n"
" -U, --unpause [D|O|S] Unpause server\n"
" -U, --unpause [D|D2|O|S] Unpause server\n"
" D Unpause download queue (default)\n"
" D2 Unpause download queue via second pause-register\n"
" O Unpause post-processor queue\n"
" S Unpause scan of incoming nzb-directory\n"
" -R, --rate <speed> Set download rate on server, in KB/s\n"
@@ -1694,7 +1703,7 @@ void Options::PrintUsage(char* com)
" O Edit post-processor-queue\n"
" H Edit history\n"
" <action> is one of:\n"
" - for files (F) and groups (G):\n"
" - for files (F), groups (G) and post-jobs (O):\n"
" <+offset|-offset> Move in queue relative to current position,\n"
" offset is an integer value\n"
" T Move to top of queue\n"
@@ -1703,18 +1712,15 @@ void Options::PrintUsage(char* com)
" - for files (F) and groups (G):\n"
" P Pause\n"
" U Resume (unpause)\n"
" I <priority> Set priority (signed integer)\n"
" - for groups (G):\n"
" A Pause all pars\n"
" R Pause extra pars\n"
" I <priority> Set priority (signed integer)\n"
" C <name> Set category\n"
" CP <name> Set category and apply post-process parameters\n"
" N <name> Rename\n"
" M Merge\n"
" S <name> Split - create new group from selected files\n"
" O <name>=<value> Set post-process parameter\n"
" - for post-jobs (O):\n"
" D Delete (cancel post-processing)\n"
" - for history (H):\n"
" D Delete\n"
" P Post-process again\n"
@@ -1723,8 +1729,8 @@ void Options::PrintUsage(char* com)
" O <name>=<value> Set post-process parameter\n"
" B Mark as bad\n"
" G Mark as good\n"
" <IDs> Comma-separated list of file- or group- ids or\n"
" ranges of file-ids, e. g.: 1-5,3,10-22\n"
" <IDs> Comma-separated list of file-ids or ranges\n"
" of file-ids, e. g.: 1-5,3,10-22\n"
" <Names> List of names (with options \"FN\" and \"GN\"),\n"
" e. g.: \"my nzb download%cmyfile.nfo\" \"another nzb\"\n"
" <RegExs> List of regular expressions (options \"FR\", \"GR\")\n"
@@ -1831,6 +1837,7 @@ void Options::SetOption(const char* optname, const char* value)
}
pOptEntry->SetLineNo(m_iConfigLine);
bool bOK = true;
// expand variables
while (char* dollar = strstr(curvalue, "${"))
@@ -1856,11 +1863,13 @@ void Options::SetOption(const char* optname, const char* value)
}
else
{
bOK = false;
break;
}
}
else
{
bOK = false;
break;
}
}
@@ -2014,13 +2023,13 @@ void Options::InitCategories()
bUnpack = (bool)ParseEnumValue(optname, BoolCount, BoolNames, BoolValues);
}
sprintf(optname, "Category%i.PostScript", n);
const char* npostscript = GetOption(optname);
sprintf(optname, "Category%i.DefScript", n);
const char* ndefscript = GetOption(optname);
sprintf(optname, "Category%i.Aliases", n);
const char* naliases = GetOption(optname);
bool definition = nname || ndestdir || nunpack || npostscript || naliases;
bool definition = nname || ndestdir || nunpack || ndefscript || naliases;
bool completed = nname && strlen(nname) > 0;
if (!definition)
@@ -2036,7 +2045,7 @@ void Options::InitCategories()
CheckDir(&szDestDir, destdiroptname, false, false);
}
Category* pCategory = new Category(nname, szDestDir, bUnpack, npostscript);
Category* pCategory = new Category(nname, szDestDir, bUnpack, ndefscript);
m_Categories.push_back(pCategory);
free(szDestDir);
@@ -2044,11 +2053,19 @@ void Options::InitCategories()
// split Aliases into tokens and create items for each token
if (naliases)
{
Tokenizer tok(naliases, ",;");
while (const char* szAliasName = tok.Next())
char* szAliases = strdup(naliases);
char* saveptr;
char* szAliasName = strtok_r(szAliases, ",;", &saveptr);
while (szAliasName)
{
pCategory->GetAliases()->push_back(strdup(szAliasName));
szAliasName = Util::Trim(szAliasName);
if (szAliasName[0] != '\0')
{
pCategory->GetAliases()->push_back(strdup(szAliasName));
}
szAliasName = strtok_r(NULL, ",;", &saveptr);
}
free(szAliases);
}
}
else
@@ -2174,7 +2191,7 @@ void Options::InitScheduler()
"activateserver", "activateservers", "deactivateserver", "deactivateservers", "fetchfeed", "fetchfeeds" };
const int CommandValues[] = { Scheduler::scPauseDownload, Scheduler::scPauseDownload, Scheduler::scUnpauseDownload,
Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload, Scheduler::scDownloadRate,
Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scScript,
Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scProcess,
Scheduler::scProcess, Scheduler::scPauseScan, Scheduler::scUnpauseScan, Scheduler::scUnpauseScan,
Scheduler::scActivateServer, Scheduler::scActivateServer, Scheduler::scDeactivateServer,
Scheduler::scDeactivateServer, Scheduler::scFetchFeed, Scheduler::scFetchFeed };
@@ -2214,8 +2231,7 @@ void Options::InitScheduler()
}
}
if ((eCommand == Scheduler::scScript ||
eCommand == Scheduler::scProcess ||
if ((eCommand == Scheduler::scProcess ||
eCommand == Scheduler::scActivateServer ||
eCommand == Scheduler::scDeactivateServer ||
eCommand == Scheduler::scFetchFeed) &&
@@ -2241,13 +2257,13 @@ void Options::InitScheduler()
{
for (int iEveryHour = 0; iEveryHour < 24; iEveryHour++)
{
Scheduler::Task* pTask = new Scheduler::Task(n, iEveryHour, iMinutes, iWeekDays, eCommand, szParam);
Scheduler::Task* pTask = new Scheduler::Task(iEveryHour, iMinutes, iWeekDays, eCommand, szParam);
g_pScheduler->AddTask(pTask);
}
}
else
{
Scheduler::Task* pTask = new Scheduler::Task(n, iHours, iMinutes, iWeekDays, eCommand, szParam);
Scheduler::Task* pTask = new Scheduler::Task(iHours, iMinutes, iWeekDays, eCommand, szParam);
g_pScheduler->AddTask(pTask);
}
}
@@ -2379,7 +2395,7 @@ bool Options::ParseWeekDays(const char* szWeekDays, int* pWeekDaysBits)
void Options::LoadConfigFile()
{
FILE* infile = fopen(m_szConfigFilename, FOPEN_RB);
FILE* infile = fopen(m_szConfigFilename, "rb");
if (!infile)
{
@@ -2429,7 +2445,7 @@ bool Options::SetOptionString(const char* option)
return false;
}
bool bOK = ValidateOptionName(optname, optvalue);
bool bOK = ValidateOptionName(optname);
if (bOK)
{
SetOption(optname, optvalue);
@@ -2489,7 +2505,7 @@ bool Options::SplitOptionString(const char* option, char** pOptName, char** pOpt
return true;
}
bool Options::ValidateOptionName(const char* optname, const char* optvalue)
bool Options::ValidateOptionName(const char * optname)
{
if (!strcasecmp(optname, OPTION_CONFIGFILE) || !strcasecmp(optname, OPTION_APPBIN) ||
!strcasecmp(optname, OPTION_APPDIR) || !strcasecmp(optname, OPTION_VERSION))
@@ -2537,7 +2553,7 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
{
char* p = (char*)optname + 8;
while (*p >= '0' && *p <= '9') p++;
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".destdir") || !strcasecmp(p, ".postscript") ||
if (p && (!strcasecmp(p, ".name") || !strcasecmp(p, ".destdir") || !strcasecmp(p, ".defscript") ||
!strcasecmp(p, ".unpack") || !strcasecmp(p, ".aliases")))
{
return true;
@@ -2556,7 +2572,7 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
}
}
// scripts options
// post-processing scripts options
if (strchr(optname, ':'))
{
return true;
@@ -2573,25 +2589,14 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
!strcasecmp(optname, OPTION_APPENDNZBDIR) ||
!strcasecmp(optname, OPTION_RENAMEBROKEN) ||
!strcasecmp(optname, OPTION_MERGENZB) ||
!strcasecmp(optname, OPTION_STRICTPARNAME) ||
!strcasecmp(optname, OPTION_RELOADURLQUEUE) ||
!strcasecmp(optname, OPTION_RELOADPOSTQUEUE))
!strcasecmp(optname, OPTION_STRICTPARNAME))
{
ConfigWarn("Option \"%s\" is obsolete, ignored", optname);
return true;
}
if (!strcasecmp(optname, OPTION_POSTPROCESS) ||
!strcasecmp(optname, OPTION_NZBPROCESS) ||
!strcasecmp(optname, OPTION_NZBADDEDPROCESS))
if (!strcasecmp(optname, OPTION_POSTPROCESS))
{
if (optvalue && strlen(optvalue) > 0)
{
ConfigError("Option \"%s\" is obsolete, ignored, use \"%s\" and \"%s\" instead", optname, OPTION_SCRIPTDIR,
!strcasecmp(optname, OPTION_POSTPROCESS) ? OPTION_POSTSCRIPT :
!strcasecmp(optname, OPTION_NZBPROCESS) ? OPTION_SCANSCRIPT :
!strcasecmp(optname, OPTION_NZBADDEDPROCESS) ? OPTION_QUEUESCRIPT :
"ERROR");
}
ConfigError("Option \"%s\" is obsolete, ignored, use \"%s\" and \"%s\" instead", optname, OPTION_SCRIPTDIR, OPTION_DEFSCRIPT);
return true;
}
@@ -2629,7 +2634,7 @@ void Options::ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue,
if (!strcasecmp(szOption, "ParCheck") && !strcasecmp(szValue, "yes"))
{
strncpy(szValue, "always", iValueBufLen);
strncpy(szValue, "force", iValueBufLen);
}
if (!strcasecmp(szOption, "ParCheck") && !strcasecmp(szValue, "no"))
@@ -2637,18 +2642,6 @@ void Options::ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue,
strncpy(szValue, "auto", iValueBufLen);
}
if (!strcasecmp(szOption, "DefScript"))
{
strncpy(szOption, "PostScript", iOptionBufLen);
}
int iNameLen = strlen(szOption);
if (!strncasecmp(szOption, "Category", 8) && iNameLen > 10 &&
!strcasecmp(szOption + iNameLen - 10, ".DefScript"))
{
strncpy(szOption + iNameLen - 10, ".PostScript", iOptionBufLen - 9 /* strlen("Category.") */);
}
szOption[iOptionBufLen-1] = '\0';
szOption[iValueBufLen-1] = '\0';
}
@@ -2809,7 +2802,7 @@ void Options::UnlockOptEntries()
bool Options::LoadConfig(OptEntries* pOptEntries)
{
// read config file
FILE* infile = fopen(m_szConfigFilename, FOPEN_RB);
FILE* infile = fopen(m_szConfigFilename, "rb");
if (!infile)
{
@@ -2853,7 +2846,7 @@ bool Options::LoadConfig(OptEntries* pOptEntries)
bool Options::SaveConfig(OptEntries* pOptEntries)
{
// save to config file
FILE* infile = fopen(m_szConfigFilename, FOPEN_RBP);
FILE* infile = fopen(m_szConfigFilename, "r+b");
if (!infile)
{
@@ -2941,7 +2934,7 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
{
return false;
}
ConfigTemplate* pConfigTemplate = new ConfigTemplate(NULL, szBuffer);
ConfigTemplate* pConfigTemplate = new ConfigTemplate("", "", szBuffer);
pConfigTemplates->push_back(pConfigTemplate);
free(szBuffer);
@@ -2953,32 +2946,26 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
ScriptList scriptList;
LoadScriptList(&scriptList);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
for (ScriptList::iterator it = scriptList.begin(); it != scriptList.end(); it++)
{
Script* pScript = *it;
FILE* infile = fopen(pScript->GetLocation(), FOPEN_RB);
FILE* infile = fopen(pScript->GetLocation(), "rb");
if (!infile)
{
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript, "");
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript->GetName(), pScript->GetDisplayName(), "");
pConfigTemplates->push_back(pConfigTemplate);
continue;
}
const int iConfigSignatureLen = strlen(PPSCRIPT_SIGNATURE);
StringBuilder stringBuilder;
char buf[1024];
bool bInConfig = false;
while (fgets(buf, sizeof(buf) - 1, infile))
{
if (!strncmp(buf, BEGIN_SCRIPT_SIGNATURE, iBeginSignatureLen) &&
strstr(buf, END_SCRIPT_SIGNATURE) &&
(strstr(buf, POST_SCRIPT_SIGNATURE) ||
strstr(buf, SCAN_SCRIPT_SIGNATURE) ||
strstr(buf, QUEUE_SCRIPT_SIGNATURE) ||
strstr(buf, SCHEDULER_SCRIPT_SIGNATURE)))
if (!strncmp(buf, PPSCRIPT_SIGNATURE, iConfigSignatureLen))
{
if (bInConfig)
{
@@ -2996,13 +2983,10 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
fclose(infile);
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript, stringBuilder.GetBuffer());
ConfigTemplate* pConfigTemplate = new ConfigTemplate(pScript->GetName(), pScript->GetDisplayName(), stringBuilder.GetBuffer());
pConfigTemplates->push_back(pConfigTemplate);
}
// clearing the list without deleting of objects, which are in pConfigTemplates now
scriptList.clear();
return true;
}
@@ -3018,16 +3002,23 @@ void Options::LoadScriptList(ScriptList* pScriptList)
tmpScriptList.sort(CompareScripts);
// first add all scripts from m_szScriptOrder
Tokenizer tok(m_szScriptOrder, ",;");
while (const char* szScriptName = tok.Next())
char* szScriptOrder = strdup(m_szScriptOrder);
char* saveptr;
char* szScriptName = strtok_r(szScriptOrder, ",;", &saveptr);
while (szScriptName)
{
Script* pScript = tmpScriptList.Find(szScriptName);
if (pScript)
szScriptName = Util::Trim(szScriptName);
if (szScriptName[0] != '\0')
{
tmpScriptList.remove(pScript);
pScriptList->push_back(pScript);
Script* pScript = tmpScriptList.Find(szScriptName);
if (pScript)
{
pScriptList->push_back(new Script(pScript->GetName(), pScript->GetLocation()));
}
}
szScriptName = strtok_r(NULL, ",;", &saveptr);
}
free(szScriptOrder);
// second add all other scripts from scripts directory
for (ScriptList::iterator it = tmpScriptList.begin(); it != tmpScriptList.end(); it++)
@@ -3035,12 +3026,10 @@ void Options::LoadScriptList(ScriptList* pScriptList)
Script* pScript = *it;
if (!pScriptList->Find(pScript->GetName()))
{
pScriptList->push_back(pScript);
pScriptList->push_back(new Script(pScript->GetName(), pScript->GetLocation()));
}
}
tmpScriptList.clear();
BuildScriptDisplayNames(pScriptList);
}
@@ -3049,8 +3038,6 @@ void Options::LoadScriptDir(ScriptList* pScriptList, const char* szDirectory, bo
int iBufSize = 1024*10;
char* szBuffer = (char*)malloc(iBufSize+1);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
DirBrowser dir(szDirectory);
while (const char* szFilename = dir.Next())
{
@@ -3063,57 +3050,38 @@ void Options::LoadScriptDir(ScriptList* pScriptList, const char* szDirectory, bo
if (!Util::DirectoryExists(szFullFilename))
{
// check if the file contains pp-script-signature
FILE* infile = fopen(szFullFilename, FOPEN_RB);
FILE* infile = fopen(szFullFilename, "rb");
if (infile)
{
// read first 10KB of the file and look for signature
int iReadBytes = fread(szBuffer, 1, iBufSize, infile);
fclose(infile);
szBuffer[iReadBytes] = 0;
// split buffer into lines
Tokenizer tok(szBuffer, "\n\r", true);
while (char* szLine = tok.Next())
if (strstr(szBuffer, PPSCRIPT_SIGNATURE))
{
if (!strncmp(szLine, BEGIN_SCRIPT_SIGNATURE, iBeginSignatureLen) &&
strstr(szLine, END_SCRIPT_SIGNATURE))
char szScriptName[1024];
if (bIsSubDir)
{
bool bPostScript = strstr(szLine, POST_SCRIPT_SIGNATURE);
bool bScanScript = strstr(szLine, SCAN_SCRIPT_SIGNATURE);
bool bQueueScript = strstr(szLine, QUEUE_SCRIPT_SIGNATURE);
bool bSchedulerScript = strstr(szLine, SCHEDULER_SCRIPT_SIGNATURE);
if (bPostScript || bScanScript || bQueueScript || bSchedulerScript)
char szDirectory2[1024];
snprintf(szDirectory2, 1024, "%s", szDirectory);
szDirectory2[1024-1] = '\0';
int iLen = strlen(szDirectory2);
if (szDirectory2[iLen-1] == PATH_SEPARATOR || szDirectory2[iLen-1] == ALT_PATH_SEPARATOR)
{
char szScriptName[1024];
if (bIsSubDir)
{
char szDirectory2[1024];
snprintf(szDirectory2, 1024, "%s", szDirectory);
szDirectory2[1024-1] = '\0';
int iLen = strlen(szDirectory2);
if (szDirectory2[iLen-1] == PATH_SEPARATOR || szDirectory2[iLen-1] == ALT_PATH_SEPARATOR)
{
// trim last path-separator
szDirectory2[iLen-1] = '\0';
}
snprintf(szScriptName, 1024, "%s%c%s", Util::BaseFileName(szDirectory2), PATH_SEPARATOR, szFilename);
}
else
{
snprintf(szScriptName, 1024, "%s", szFilename);
}
szScriptName[1024-1] = '\0';
Script* pScript = new Script(szScriptName, szFullFilename);
pScript->SetPostScript(bPostScript);
pScript->SetScanScript(bScanScript);
pScript->SetQueueScript(bQueueScript);
pScript->SetSchedulerScript(bSchedulerScript);
pScriptList->push_back(pScript);
break;
// trim last path-separator
szDirectory2[iLen-1] = '\0';
}
snprintf(szScriptName, 1024, "%s%c%s", Util::BaseFileName(szDirectory2), PATH_SEPARATOR, szFilename);
}
else
{
snprintf(szScriptName, 1024, "%s", szFilename);
}
szScriptName[1024-1] = '\0';
Script* pScript = new Script(szScriptName, szFullFilename);
pScriptList->push_back(pScript);
}
}
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -57,12 +57,15 @@ public:
opClientRequestScanAsync,
opClientRequestDownloadPause,
opClientRequestDownloadUnpause,
opClientRequestDownload2Pause,
opClientRequestDownload2Unpause,
opClientRequestPostPause,
opClientRequestPostUnpause,
opClientRequestScanPause,
opClientRequestScanUnpause,
opClientRequestHistory,
opClientRequestDownloadUrl
opClientRequestDownloadUrl,
opClientRequestUrlQueue
};
enum EMessageTarget
{
@@ -80,7 +83,6 @@ public:
enum EParCheck
{
pcAuto,
pcAlways,
pcForce,
pcManual
};
@@ -96,6 +98,15 @@ public:
hcDelete,
hcNone
};
enum EScriptLogKind
{
slNone,
slDetail,
slInfo,
slWarning,
slError,
slDebug
};
enum EMatchMode
{
mmID = 1,
@@ -136,6 +147,31 @@ public:
OptEntry* FindOption(const char* szName);
};
class ConfigTemplate
{
private:
char* m_szName;
char* m_szDisplayName;
char* m_szTemplate;
friend class Options;
public:
ConfigTemplate(const char* szName, const char* szDisplayName, const char* szTemplate);
~ConfigTemplate();
const char* GetName() { return m_szName; }
const char* GetDisplayName() { return m_szDisplayName; }
const char* GetTemplate() { return m_szTemplate; }
};
typedef std::vector<ConfigTemplate*> ConfigTemplatesBase;
class ConfigTemplates: public ConfigTemplatesBase
{
public:
~ConfigTemplates();
};
typedef std::vector<char*> NameList;
class Category
@@ -144,16 +180,16 @@ public:
char* m_szName;
char* m_szDestDir;
bool m_bUnpack;
char* m_szPostScript;
char* m_szDefScript;
NameList m_Aliases;
public:
Category(const char* szName, const char* szDestDir, bool bUnpack, const char* szPostScript);
Category(const char* szName, const char* szDestDir, bool bUnpack, const char* szDefScript);
~Category();
const char* GetName() { return m_szName; }
const char* GetDestDir() { return m_szDestDir; }
bool GetUnpack() { return m_bUnpack; }
const char* GetPostScript() { return m_szPostScript; }
const char* GetDefScript() { return m_szDefScript; }
NameList* GetAliases() { return &m_Aliases; }
};
@@ -172,10 +208,6 @@ public:
char* m_szName;
char* m_szLocation;
char* m_szDisplayName;
bool m_bPostScript;
bool m_bScanScript;
bool m_bQueueScript;
bool m_bSchedulerScript;
public:
Script(const char* szName, const char* szLocation);
@@ -184,14 +216,6 @@ public:
const char* GetLocation() { return m_szLocation; }
void SetDisplayName(const char* szDisplayName);
const char* GetDisplayName() { return m_szDisplayName; }
bool GetPostScript() { return m_bPostScript; }
void SetPostScript(bool bPostScript) { m_bPostScript = bPostScript; }
bool GetScanScript() { return m_bScanScript; }
void SetScanScript(bool bScanScript) { m_bScanScript = bScanScript; }
bool GetQueueScript() { return m_bQueueScript; }
void SetQueueScript(bool bQueueScript) { m_bQueueScript = bQueueScript; }
bool GetSchedulerScript() { return m_bSchedulerScript; }
void SetSchedulerScript(bool bSchedulerScript) { m_bSchedulerScript = bSchedulerScript; }
};
typedef std::list<Script*> ScriptListBase;
@@ -203,29 +227,6 @@ public:
Script* Find(const char* szName);
};
class ConfigTemplate
{
private:
Script* m_pScript;
char* m_szTemplate;
friend class Options;
public:
ConfigTemplate(Script* pScript, const char* szTemplate);
~ConfigTemplate();
Script* GetScript() { return m_pScript; }
const char* GetTemplate() { return m_szTemplate; }
};
typedef std::vector<ConfigTemplate*> ConfigTemplatesBase;
class ConfigTemplates: public ConfigTemplatesBase
{
public:
~ConfigTemplates();
};
private:
OptEntries m_OptEntries;
bool m_bConfigInitialized;
@@ -273,6 +274,8 @@ private:
char* m_szDaemonUsername;
EOutputMode m_eOutputMode;
bool m_bReloadQueue;
bool m_bReloadUrlQueue;
bool m_bReloadPostQueue;
int m_iUrlConnections;
int m_iLogBufferSize;
bool m_bCreateLog;
@@ -282,10 +285,10 @@ private:
EParScan m_eParScan;
bool m_bParRename;
EHealthCheck m_eHealthCheck;
char* m_szPostScript;
char* m_szDefScript;
char* m_szScriptOrder;
char* m_szScanScript;
char* m_szQueueScript;
char* m_szNZBProcess;
char* m_szNZBAddedProcess;
bool m_bNoConfig;
int m_iUMask;
int m_iUpdateInterval;
@@ -314,11 +317,9 @@ private:
char* m_szSevenZipCmd;
bool m_bUnpackPauseQueue;
char* m_szExtCleanupDisk;
char* m_szParIgnoreExt;
int m_iFeedHistory;
bool m_bUrlForce;
int m_iTimeCorrection;
int m_iPropagationDelay;
// Parsed command-line parameters
bool m_bServerMode;
@@ -346,13 +347,12 @@ private:
// Current state
bool m_bPauseDownload;
bool m_bPauseDownload2;
bool m_bPausePostProcess;
bool m_bPauseScan;
bool m_bTempPauseDownload;
int m_iDownloadRate;
EClientOperation m_eClientOperation;
time_t m_tResumeTime;
int m_iLocalTimeOffset;
void InitDefault();
void InitOptFile();
@@ -374,7 +374,7 @@ private:
void SetOption(const char* optname, const char* value);
bool SetOptionString(const char* option);
bool SplitOptionString(const char* option, char** pOptName, char** pOptValue);
bool ValidateOptionName(const char* optname, const char* optvalue);
bool ValidateOptionName(const char* optname);
void LoadConfigFile();
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate);
void ParseFileIDList(int argc, char* argv[], int optind);
@@ -439,6 +439,8 @@ public:
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; }
@@ -449,9 +451,9 @@ public:
bool GetParRename() { return m_bParRename; }
EHealthCheck GetHealthCheck() { return m_eHealthCheck; }
const char* GetScriptOrder() { return m_szScriptOrder; }
const char* GetPostScript() { return m_szPostScript; }
const char* GetScanScript() { return m_szScanScript; }
const char* GetQueueScript() { return m_szQueueScript; }
const char* GetDefScript() { return m_szDefScript; }
const char* GetNZBProcess() { return m_szNZBProcess; }
const char* GetNZBAddedProcess() { return m_szNZBAddedProcess; }
int GetUMask() { return m_iUMask; }
int GetUpdateInterval() {return m_iUpdateInterval; }
bool GetCursesNZBName() { return m_bCursesNZBName; }
@@ -479,11 +481,9 @@ public:
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
const char* GetExtCleanupDisk() { return m_szExtCleanupDisk; }
const char* GetParIgnoreExt() { return m_szParIgnoreExt; }
int GetFeedHistory() { return m_iFeedHistory; }
bool GetUrlForce() { return m_bUrlForce; }
int GetTimeCorrection() { return m_iTimeCorrection; }
int GetPropagationDelay() { return m_iPropagationDelay; }
Category* FindCategory(const char* szName, bool bSearchAliases) { return m_Categories.FindCategory(szName, bSearchAliases); }
@@ -514,18 +514,16 @@ public:
// Current state
void SetPauseDownload(bool bPauseDownload) { m_bPauseDownload = bPauseDownload; }
bool GetPauseDownload() const { return m_bPauseDownload; }
void SetPauseDownload2(bool bPauseDownload2) { m_bPauseDownload2 = bPauseDownload2; }
bool GetPauseDownload2() const { return m_bPauseDownload2; }
void SetPausePostProcess(bool bPausePostProcess) { m_bPausePostProcess = bPausePostProcess; }
bool GetPausePostProcess() const { return m_bPausePostProcess; }
void SetPauseScan(bool bPauseScan) { m_bPauseScan = bPauseScan; }
bool GetPauseScan() const { return m_bPauseScan; }
void SetTempPauseDownload(bool bTempPauseDownload) { m_bTempPauseDownload = bTempPauseDownload; }
bool GetTempPauseDownload() const { return m_bTempPauseDownload; }
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 SetLocalTimeOffset(int iLocalTimeOffset) { m_iLocalTimeOffset = iLocalTimeOffset; }
int GetLocalTimeOffset() { return m_iLocalTimeOffset; }
};
#endif

View File

@@ -227,7 +227,7 @@ void ParChecker::SetInfoName(const char * szInfoName)
void ParChecker::Run()
{
ParCoordinator::ParFileList fileList;
ParCoordinator::FileList fileList;
if (!ParCoordinator::FindMainPars(m_szDestDir, &fileList))
{
PrintMessage(Message::mkError, "Could not start par-check for %s. Could not find any par-files", m_szNZBName);
@@ -239,7 +239,7 @@ void ParChecker::Run()
m_eStatus = psRepairNotNeeded;
m_bCancelled = false;
for (ParCoordinator::ParFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
for (ParCoordinator::FileList::iterator it = fileList.begin(); it != fileList.end(); it++)
{
char* szParFilename = *it;
debug("Found par: %s", szParFilename);
@@ -315,26 +315,17 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
bool bAddedSplittedFragments = false;
if (!IsStopped() && res == eRepairNotPossible)
if (!IsStopped() && pRepairer->missingfilecount > 0 && g_pOptions->GetParScan() == Options::psAuto && AddMissingFiles())
{
bAddedSplittedFragments = AddSplittedFragments();
if (bAddedSplittedFragments)
{
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
if (!IsStopped() && pRepairer->missingfilecount > 0 &&
!(bAddedSplittedFragments && res == eRepairPossible) &&
g_pOptions->GetParScan() == Options::psAuto)
if (!IsStopped() && res == eRepairNotPossible && CheckSplittedFragments())
{
if (AddMissingFiles())
{
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
pRepairer->UpdateVerificationResults();
res = pRepairer->Process(false);
debug("ParChecker: Process-result=%i", res);
}
if (!IsStopped() && res == eRepairNotPossible)
@@ -510,7 +501,7 @@ bool ParChecker::LoadMainParBak()
{
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
bool bQueuedParFilesChanged = false;
while (!bQueuedParFilesChanged && !IsStopped() && !m_bCancelled)
while (!bQueuedParFilesChanged && !IsStopped())
{
m_mutexQueuedParFiles.Lock();
bQueuedParFilesChanged = m_bQueuedParFilesChanged;
@@ -532,11 +523,6 @@ int ParChecker::ProcessMorePars()
while (!IsStopped() && res == eRepairNotPossible)
{
int missingblockcount = pRepairer->missingblockcount - pRepairer->recoverypacketmap.size();
if (missingblockcount <= 0)
{
return eRepairPossible;
}
if (bMoreFilesLoaded)
{
PrintMessage(Message::mkInfo, "Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
@@ -575,7 +561,7 @@ int ParChecker::ProcessMorePars()
{
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
bool bQueuedParFilesChanged = false;
while (!bQueuedParFilesChanged && !IsStopped() && !m_bCancelled)
while (!bQueuedParFilesChanged && !IsStopped())
{
m_mutexQueuedParFiles.Lock();
bQueuedParFilesChanged = m_bQueuedParFilesChanged;
@@ -585,7 +571,7 @@ int ParChecker::ProcessMorePars()
}
}
if (IsStopped() || m_bCancelled)
if (IsStopped())
{
break;
}
@@ -643,10 +629,27 @@ void ParChecker::QueueChanged()
m_mutexQueuedParFiles.Unlock();
}
bool ParChecker::AddSplittedFragments()
bool ParChecker::CheckSplittedFragments()
{
bool bFragmentsAdded = false;
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
{
Par2RepairerSourceFile *sourcefile = *it;
if (AddSplittedFragments(sourcefile->TargetFileName().c_str()))
{
bFragmentsAdded = true;
}
}
return bFragmentsAdded;
}
bool ParChecker::AddSplittedFragments(const char* szFilename)
{
char szDirectory[1024];
strncpy(szDirectory, m_szParFilename, 1024);
strncpy(szDirectory, szFilename, 1024);
szDirectory[1024-1] = '\0';
char* szBasename = Util::BaseFileName(szDirectory);
@@ -655,43 +658,29 @@ bool ParChecker::AddSplittedFragments()
return false;
}
szBasename[-1] = '\0';
int iBaseLen = strlen(szBasename);
std::list<CommandLine::ExtraFile> extrafiles;
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt") &&
!IsParredFile(filename) && !IsProcessedFile(filename))
if (!strncasecmp(filename, szBasename, iBaseLen))
{
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
const char* p = filename + iBaseLen;
if (*p == '.')
{
Par2RepairerSourceFile *sourcefile = *it;
std::string target = sourcefile->TargetFileName();
const char* szFilename2 = target.c_str();
const char* szBasename2 = Util::BaseFileName(szFilename2);
int iBaseLen = strlen(szBasename2);
if (!strncasecmp(filename, szBasename2, iBaseLen))
for (p++; *p && strchr("0123456789", *p); p++) ;
if (!*p)
{
const char* p = filename + iBaseLen;
if (*p == '.')
{
for (p++; *p && strchr("0123456789", *p); p++) ;
if (!*p)
{
debug("Found splitted fragment %s", filename);
debug("Found splitted fragment %s", filename);
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
fullfilename[1024-1] = '\0';
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
fullfilename[1024-1] = '\0';
CommandLine::ExtraFile extrafile(fullfilename, Util::FileSize(fullfilename));
extrafiles.push_back(extrafile);
}
}
CommandLine::ExtraFile extrafile(fullfilename, Util::FileSize(fullfilename));
extrafiles.push_back(extrafile);
}
}
}
@@ -703,9 +692,7 @@ bool ParChecker::AddSplittedFragments()
{
m_iExtraFiles += extrafiles.size();
m_bVerifyingExtraFiles = true;
info("Found %i splitted fragments for %s", (int)extrafiles.size(), m_szInfoName);
bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
((Repairer*)m_pRepairer)->UpdateVerificationResults();
m_bVerifyingExtraFiles = false;
}
@@ -732,14 +719,27 @@ bool ParChecker::AddMissingFiles()
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt") &&
!IsParredFile(filename) && !IsProcessedFile(filename))
if (strcmp(filename, ".") && strcmp(filename, "..") && strcmp(filename, "_brokenlog.txt"))
{
char fullfilename[1024];
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
fullfilename[1024-1] = '\0';
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;
}
}
extrafiles.push_back(new CommandLine::ExtraFile(fullfilename, Util::FileSize(fullfilename)));
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)));
}
}
}
@@ -768,16 +768,7 @@ bool ParChecker::AddMissingFiles()
extrafiles1.clear();
extrafiles1.push_back(*pExtraFile);
int iWasMissing = ((Repairer*)m_pRepairer)->missingfilecount;
((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles1);
bool bAdded = iWasMissing > (int)((Repairer*)m_pRepairer)->missingfilecount;
if (bAdded)
{
info("Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str()));
RegisterParredFile(Util::BaseFileName(pExtraFile->FileName().c_str()));
}
bFilesAdded |= bAdded;
bFilesAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles1) || bFilesAdded;
((Repairer*)m_pRepairer)->UpdateVerificationResults();
delete pExtraFile;
@@ -795,20 +786,6 @@ bool ParChecker::AddMissingFiles()
return bFilesAdded;
}
bool ParChecker::IsProcessedFile(const char* szFilename)
{
for (FileList::iterator it = m_ProcessedFiles.begin(); it != m_ProcessedFiles.end(); it++)
{
const char* szProcessedFilename = *it;
if (!strcasecmp(Util::BaseFileName(szProcessedFilename), szFilename))
{
return true;
}
}
return false;
}
void ParChecker::signal_filename(std::string str)
{
const char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
@@ -917,7 +894,6 @@ void ParChecker::Cancel()
#ifdef HAVE_PAR2_CANCEL
((Repairer*)m_pRepairer)->cancelled = true;
m_bCancelled = true;
QueueChanged();
#else
PrintMessage(Message::mkError, "Could not cancel par-repair. The program was compiled using version of libpar2 which doesn't support cancelling of par-repair. Please apply libpar2-patches supplied with NZBGet and recompile libpar2 and NZBGet (see README for details).");
#endif
@@ -931,7 +907,7 @@ void ParChecker::WriteBrokenLog(EStatus eStatus)
if (eStatus != psRepairNotNeeded || Util::FileExists(szBrokenLogName))
{
FILE* file = fopen(szBrokenLogName, FOPEN_AB);
FILE* file = fopen(szBrokenLogName, "ab");
if (file)
{
if (eStatus == psFailed)

View File

@@ -85,9 +85,9 @@ private:
bool LoadMainParBak();
int ProcessMorePars();
bool LoadMorePars();
bool AddSplittedFragments();
bool CheckSplittedFragments();
bool AddSplittedFragments(const char* szFilename);
bool AddMissingFiles();
bool IsProcessedFile(const char* szFilename);
void WriteBrokenLog(EStatus eStatus);
void SaveSourceList();
void DeleteLeftovers();
@@ -105,8 +105,6 @@ protected:
virtual void UpdateProgress() {}
virtual void Completed() {}
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
virtual void RegisterParredFile(const char* szFilename) {}
virtual bool IsParredFile(const char* szFilename) { return false; }
EStage GetStage() { return m_eStage; }
const char* GetProgressLabel() { return m_szProgressLabel; }
int GetFileProgress() { return m_iFileProgress; }

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -47,8 +47,12 @@
#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)
@@ -73,24 +77,6 @@ void ParCoordinator::PostParChecker::PrintMessage(Message::EKind eKind, const ch
m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
}
void ParCoordinator::PostParChecker::RegisterParredFile(const char* szFilename)
{
m_pPostInfo->GetParredFiles()->push_back(strdup(szFilename));
}
bool ParCoordinator::PostParChecker::IsParredFile(const char* szFilename)
{
for (PostInfo::ParredFiles::iterator it = m_pPostInfo->GetParredFiles()->begin(); it != m_pPostInfo->GetParredFiles()->end(); it++)
{
const char* szParredFile = *it;
if (!strcasecmp(szParredFile, szFilename))
{
return true;
}
}
return false;
}
void ParCoordinator::PostParRenamer::UpdateProgress()
{
m_pOwner->UpdateParRenameProgress();
@@ -107,12 +93,6 @@ void ParCoordinator::PostParRenamer::PrintMessage(Message::EKind eKind, const ch
m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
}
void ParCoordinator::PostParRenamer::RegisterParredFile(const char* szFilename)
{
m_pPostInfo->GetParredFiles()->push_back(strdup(szFilename));
}
#endif
ParCoordinator::ParCoordinator()
@@ -159,12 +139,20 @@ void ParCoordinator::Stop()
void ParCoordinator::PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
debug("ParCoordinator: Pausing pars");
pDownloadQueue->EditEntry(pNZBInfo->GetID(),
DownloadQueue::eaGroupPauseExtraPars, 0, NULL);
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (pFileInfo->GetNZBInfo() == pNZBInfo)
{
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false,
QueueEditor::eaGroupPauseExtraPars, 0, NULL);
break;
}
}
}
bool ParCoordinator::FindMainPars(const char* szPath, ParFileList* pFileList)
bool ParCoordinator::FindMainPars(const char* szPath, FileList* pFileList)
{
if (pFileList)
{
@@ -184,7 +172,7 @@ bool ParCoordinator::FindMainPars(const char* szPath, ParFileList* pFileList)
// check if the base file already added to list
bool exists = false;
for (ParFileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
for (FileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
{
const char* filename2 = *it;
exists = SameParCollection(filename, filename2);
@@ -280,7 +268,7 @@ void ParCoordinator::StartParCheckJob(PostInfo* pPostInfo)
m_ParChecker.SetPostInfo(pPostInfo);
m_ParChecker.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
m_ParChecker.SetNZBName(pPostInfo->GetNZBInfo()->GetName());
m_ParChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", pPostInfo->GetNZBInfo()->GetName());
m_ParChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", pPostInfo->GetInfoName());
pPostInfo->SetWorking(true);
m_ParChecker.Start();
}
@@ -304,7 +292,6 @@ void ParCoordinator::StartParRenameJob(PostInfo* pPostInfo)
m_ParRenamer.SetPostInfo(pPostInfo);
m_ParRenamer.SetDestDir(szDestDir);
m_ParRenamer.SetInfoName(pPostInfo->GetNZBInfo()->GetName());
m_ParRenamer.SetDetectMissing(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone);
m_ParRenamer.PrintMessage(Message::mkInfo, "Checking renamed files for %s", pPostInfo->GetNZBInfo()->GetName());
pPostInfo->SetWorking(true);
m_ParRenamer.Start();
@@ -343,13 +330,19 @@ bool ParCoordinator::Cancel()
bool ParCoordinator::AddPar(FileInfo* pFileInfo, bool bDeleted)
{
bool bSameCollection = m_ParChecker.IsRunning() &&
pFileInfo->GetNZBInfo() == m_ParChecker.GetPostInfo()->GetNZBInfo();
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
{
@@ -360,7 +353,7 @@ bool ParCoordinator::AddPar(FileInfo* pFileInfo, bool bDeleted)
void ParCoordinator::ParCheckCompleted()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
@@ -384,9 +377,12 @@ void ParCoordinator::ParCheckCompleted()
pPostInfo->SetWorking(false);
pPostInfo->SetStage(PostInfo::ptQueued);
pDownloadQueue->Save();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
}
/**
@@ -396,7 +392,7 @@ void ParCoordinator::ParCheckCompleted()
*/
bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound)
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
Blocks blocks;
blocks.clear();
@@ -470,7 +466,7 @@ bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilenam
}
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
if (pBlockFound)
{
@@ -485,6 +481,11 @@ bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilenam
bool bOK = iBlockNeeded <= 0;
if (bOK && g_pOptions->GetParPauseQueue())
{
UnpauseDownload();
}
return bOK;
}
@@ -508,11 +509,12 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
szMainBaseFilename[maxlen] = '\0';
for (char* p = szMainBaseFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
{
FileInfo* pFileInfo = *it;
int iBlocks = 0;
if (ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
if (pFileInfo->GetNZBInfo() == pNZBInfo &&
ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
iBlocks > 0)
{
bool bUseFile = true;
@@ -574,7 +576,7 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
void ParCoordinator::UpdateParCheckProgress()
{
DownloadQueue::Lock();
g_pQueueCoordinator->LockQueue();
PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
if (m_ParChecker.GetFileProgress() == 0)
@@ -625,21 +627,21 @@ void ParCoordinator::UpdateParCheckProgress()
m_ParChecker.Cancel();
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
CheckPauseState(pPostInfo);
}
void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
{
if (g_pOptions->GetPausePostProcess() && !pPostInfo->GetNZBInfo()->GetForcePriority())
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() && !pPostInfo->GetNZBInfo()->GetForcePriority() && !m_bStopped)
while (g_pOptions->GetPausePostProcess() && !m_bStopped)
{
usleep(100 * 1000);
@@ -662,33 +664,24 @@ void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
void ParCoordinator::ParRenameCompleted()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
pPostInfo->GetNZBInfo()->SetRenameStatus(m_ParRenamer.GetStatus() == ParRenamer::psSuccess ? NZBInfo::rsSuccess : NZBInfo::rsFailure);
if (m_ParRenamer.HasMissedFiles() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
{
PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName());
pPostInfo->SetRequestParCheck(true);
}
else if (m_ParRenamer.HasSplittedFragments() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
{
PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to join splitted fragments", m_ParRenamer.GetInfoName());
pPostInfo->SetRequestParCheck(true);
}
pPostInfo->SetWorking(false);
pPostInfo->SetStage(PostInfo::ptQueued);
pDownloadQueue->Save();
DownloadQueue::Unlock();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
g_pQueueCoordinator->UnlockQueue();
}
void ParCoordinator::UpdateParRenameProgress()
{
DownloadQueue::Lock();
g_pQueueCoordinator->LockQueue();
PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
pPostInfo->SetProgressLabel(m_ParRenamer.GetProgressLabel());
@@ -706,7 +699,7 @@ void ParCoordinator::UpdateParRenameProgress()
pPostInfo->SetStageTime(tCurrent);
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
CheckPauseState(pPostInfo);
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -50,8 +50,6 @@ private:
virtual void UpdateProgress();
virtual void Completed() { m_pOwner->ParCheckCompleted(); }
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
virtual void RegisterParredFile(const char* szFilename);
virtual bool IsParredFile(const char* szFilename);
public:
PostInfo* GetPostInfo() { return m_pPostInfo; }
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
@@ -68,7 +66,6 @@ private:
virtual void UpdateProgress();
virtual void Completed() { m_pOwner->ParRenameCompleted(); }
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
virtual void RegisterParredFile(const char* szFilename);
public:
PostInfo* GetPostInfo() { return m_pPostInfo; }
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
@@ -97,6 +94,8 @@ private:
EJobKind m_eCurrentJob;
protected:
virtual bool PauseDownload() = 0;
virtual bool UnpauseDownload() = 0;
void UpdateParCheckProgress();
void UpdateParRenameProgress();
void ParCheckCompleted();
@@ -107,12 +106,12 @@ protected:
#endif
public:
typedef std::deque<char*> ParFileList;
typedef std::deque<char*> FileList;
public:
ParCoordinator();
virtual ~ParCoordinator();
static bool FindMainPars(const char* szPath, ParFileList* pFileList);
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);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -67,7 +67,6 @@ ParRenamer::FileHash::FileHash(const char* szFilename, const char* szHash)
{
m_szFilename = strdup(szFilename);
m_szHash = strdup(szHash);
m_bFileExists = false;
}
ParRenamer::FileHash::~FileHash()
@@ -78,7 +77,7 @@ ParRenamer::FileHash::~FileHash()
ParRenamer::ParRenamer()
{
debug("Creating ParRenamer");
debug("Creating ParRenamer");
m_eStatus = psFailed;
m_szDestDir = NULL;
@@ -86,14 +85,11 @@ ParRenamer::ParRenamer()
m_szProgressLabel = (char*)malloc(1024);
m_iStageProgress = 0;
m_bCancelled = false;
m_bHasSplittedFragments = false;
m_bHasMissedFiles = false;
m_bDetectMissing = false;
}
ParRenamer::~ParRenamer()
{
debug("Destroying ParRenamer");
debug("Destroying ParRenamer");
free(m_szDestDir);
free(m_szInfoName);
@@ -146,8 +142,6 @@ void ParRenamer::Run()
m_iFileCount = 0;
m_iCurFile = 0;
m_iRenamedCount = 0;
m_bHasSplittedFragments = false;
m_bHasMissedFiles = false;
m_eStatus = psFailed;
snprintf(m_szProgressLabel, 1024, "Checking renamed files for %s", m_szInfoName);
@@ -163,23 +157,9 @@ void ParRenamer::Run()
debug("Checking %s", szDestDir);
ClearHashList();
LoadParFiles(szDestDir);
if (m_FileHashList.empty())
{
int iSavedCurFile = m_iCurFile;
CheckFiles(szDestDir, true);
m_iCurFile = iSavedCurFile; // restore progress indicator
LoadParFiles(szDestDir);
}
CheckFiles(szDestDir, false);
if (m_bDetectMissing)
{
CheckMissing();
}
CheckFiles(szDestDir);
}
if (m_bCancelled)
{
PrintMessage(Message::mkWarning, "Renaming cancelled for %s", m_szInfoName);
@@ -229,10 +209,10 @@ void ParRenamer::BuildDirList(const char* szDestDir)
void ParRenamer::LoadParFiles(const char* szDestDir)
{
ParCoordinator::ParFileList parFileList;
ParCoordinator::FileList parFileList;
ParCoordinator::FindMainPars(szDestDir, &parFileList);
for (ParCoordinator::ParFileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
for (ParCoordinator::FileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
{
char* szParFilename = *it;
@@ -265,20 +245,14 @@ void ParRenamer::LoadParFile(const char* szParFilename)
}
Par2RepairerSourceFile* sourceFile = (*it).second;
if (!sourceFile || !sourceFile->GetDescriptionPacket())
{
warn("Damaged par2-file detected: %s", szParFilename);
continue;
}
m_FileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(),
sourceFile->GetDescriptionPacket()->Hash16k().print().c_str()));
RegisterParredFile(sourceFile->GetDescriptionPacket()->FileName().c_str());
}
delete pRepairer;
}
void ParRenamer::CheckFiles(const char* szDestDir, bool bRenamePars)
void ParRenamer::CheckFiles(const char* szDestDir)
{
DirBrowser dir(szDestDir);
while (const char* filename = dir.Next())
@@ -297,80 +271,30 @@ void ParRenamer::CheckFiles(const char* szDestDir, bool bRenamePars)
UpdateProgress();
m_iCurFile++;
if (bRenamePars)
{
CheckParFile(szDestDir, szFullFilename);
}
else
{
CheckRegularFile(szDestDir, szFullFilename);
}
CheckFile(szDestDir, szFullFilename);
}
}
}
}
void ParRenamer::CheckMissing()
{
for (FileHashList::iterator it = m_FileHashList.begin(); it != m_FileHashList.end(); it++)
{
FileHash* pFileHash = *it;
if (!pFileHash->GetFileExists())
{
if (Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetParIgnoreExt(), ",;") ||
Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetExtCleanupDisk(), ",;"))
{
info("File %s is missing, ignoring", pFileHash->GetFilename());
}
else
{
info("File %s is missing", pFileHash->GetFilename());
m_bHasMissedFiles = true;
}
}
}
}
bool ParRenamer::IsSplittedFragment(const char* szFilename, const char* szCorrectName)
{
bool bSplittedFragement = false;
const char* szDiskBasename = Util::BaseFileName(szFilename);
const char* szExtension = strrchr(szDiskBasename, '.');
int iBaseLen = strlen(szCorrectName);
if (szExtension && !strncasecmp(szDiskBasename, szCorrectName, iBaseLen))
{
const char* p = szDiskBasename + iBaseLen;
if (*p == '.')
{
for (p++; *p && strchr("0123456789", *p); p++) ;
bSplittedFragement = !*p;
bSplittedFragement = bSplittedFragement && atoi(szDiskBasename + iBaseLen + 1) == 1;
}
}
m_bHasSplittedFragments = m_bHasSplittedFragments || bSplittedFragement;
return bSplittedFragement;
}
void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
void ParRenamer::CheckFile(const char* szDestDir, const char* szFilename)
{
debug("Computing hash for %s", szFilename);
const int iBlockSize = 16*1024;
FILE* pFile = fopen(szFilename, FOPEN_RB);
if (!pFile)
{
FILE* pFile = fopen(szFilename, "rb");
if (!pFile)
{
PrintMessage(Message::mkError, "Could not open file %s", szFilename);
return;
}
return;
}
// load first 16K of the file into buffer
void* pBuffer = malloc(iBlockSize);
int iReadBytes = fread(pBuffer, 1, iBlockSize, pFile);
int iReadBytes = fread(pBuffer, 1, iBlockSize, pFile);
int iError = ferror(pFile);
if (iReadBytes != iBlockSize && iError)
{
@@ -378,7 +302,7 @@ void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
return;
}
fclose(pFile);
fclose(pFile);
MD5Hash hash16k;
MD5Context context;
@@ -395,13 +319,12 @@ void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
if (!strcmp(pFileHash->GetHash(), hash16k.print().c_str()))
{
debug("Found correct filename: %s", pFileHash->GetFilename());
pFileHash->SetFileExists(true);
char szDstFilename[1024];
snprintf(szDstFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, pFileHash->GetFilename());
szDstFilename[1024-1] = '\0';
if (!Util::FileExists(szDstFilename) && !IsSplittedFragment(szFilename, pFileHash->GetFilename()))
if (!Util::FileExists(szDstFilename))
{
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szFilename), pFileHash->GetFilename());
if (Util::MoveFile(szFilename, szDstFilename))
@@ -410,9 +333,7 @@ void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
}
else
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", szFilename, szDstFilename,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
PrintMessage(Message::mkError, "Could not rename %s to %s", szFilename, szDstFilename);
}
}
@@ -421,79 +342,4 @@ void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
}
}
/*
* For files not having par2-extensions: checks if the file is a par2-file and renames
* it according to its set-id.
*/
void ParRenamer::CheckParFile(const char* szDestDir, const char* szFilename)
{
debug("Checking par2-header for %s", szFilename);
const char* szBasename = Util::BaseFileName(szFilename);
const char* szExtension = strrchr(szBasename, '.');
if (szExtension && !strcasecmp(szExtension, ".par2"))
{
// do not process files already having par2-extension
return;
}
FILE* pFile = fopen(szFilename, FOPEN_RB);
if (!pFile)
{
PrintMessage(Message::mkError, "Could not open file %s", szFilename);
return;
}
// load par2-header
PACKET_HEADER header;
int iReadBytes = fread(&header, 1, sizeof(header), pFile);
int iError = ferror(pFile);
if (iReadBytes != sizeof(header) && iError)
{
PrintMessage(Message::mkError, "Could not read file %s", szFilename);
return;
}
fclose(pFile);
// Check the packet header
if (packet_magic != header.magic || // not par2-file
sizeof(PACKET_HEADER) > header.length || // packet length is too small
0 != (header.length & 3) || // packet length is not a multiple of 4
Util::FileSize(szFilename) < (int)header.length) // packet would extend beyond the end of the file
{
// not par2-file or damaged header, ignoring the file
return;
}
char szSetId[33];
strncpy(szSetId, header.setid.print().c_str(), sizeof(szSetId));
szSetId[33-1] = '\0';
for (char* p = szSetId; *p; p++) *p = tolower(*p); // convert string to lowercase
debug("Renaming: %s; setid: %s", Util::BaseFileName(szFilename), szSetId);
char szDestFileName[1024];
int iNum = 1;
while (iNum == 1 || Util::FileExists(szDestFileName))
{
snprintf(szDestFileName, 1024, "%s%c%s.vol%03i+01.PAR2", szDestDir, PATH_SEPARATOR, szSetId, iNum);
szDestFileName[1024-1] = '\0';
iNum++;
}
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szFilename), Util::BaseFileName(szDestFileName));
if (Util::MoveFile(szFilename, szDestFileName))
{
m_iRenamedCount++;
}
else
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", szFilename, szDestFileName,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,15 +47,12 @@ public:
private:
char* m_szFilename;
char* m_szHash;
bool m_bFileExists;
public:
FileHash(const char* szFilename, const char* szHash);
~FileHash();
const char* GetFilename() { return m_szFilename; }
const char* GetHash() { return m_szHash; }
bool GetFileExists() { return m_bFileExists; }
void SetFileExists(bool bFileExists) { m_bFileExists = bFileExists; }
};
typedef std::deque<FileHash*> FileHashList;
@@ -74,9 +71,6 @@ private:
int m_iFileCount;
int m_iCurFile;
int m_iRenamedCount;
bool m_bHasSplittedFragments;
bool m_bHasMissedFiles;
bool m_bDetectMissing;
void Cleanup();
void ClearHashList();
@@ -84,17 +78,13 @@ private:
void CheckDir(const char* szDestDir);
void LoadParFiles(const char* szDestDir);
void LoadParFile(const char* szParFilename);
void CheckFiles(const char* szDestDir, bool bRenamePars);
void CheckRegularFile(const char* szDestDir, const char* szFilename);
void CheckParFile(const char* szDestDir, const char* szFilename);
bool IsSplittedFragment(const char* szFilename, const char* szCorrectName);
void CheckMissing();
void CheckFiles(const char* szDestDir);
void CheckFile(const char* szDestDir, const char* szFilename);
protected:
virtual void UpdateProgress() {}
virtual void Completed() {}
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
virtual void RegisterParredFile(const char* szFilename) {}
const char* GetProgressLabel() { return m_szProgressLabel; }
int GetStageProgress() { return m_iStageProgress; }
@@ -109,9 +99,6 @@ public:
EStatus GetStatus() { return m_eStatus; }
void Cancel();
bool GetCancelled() { return m_bCancelled; }
bool HasSplittedFragments() { return m_bHasSplittedFragments; }
bool HasMissedFiles() { return m_bHasMissedFiles; }
void SetDetectMissing(bool bDetectMissing) { m_bDetectMissing = bDetectMissing; }
};
#endif

1541
PrePostProcessor.cpp Normal file
View File

File diff suppressed because it is too large Load Diff

143
PrePostProcessor.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* 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 PREPOSTPROCESSOR_H
#define PREPOSTPROCESSOR_H
#include <deque>
#include "Thread.h"
#include "Observer.h"
#include "DownloadInfo.h"
#include "ParCoordinator.h"
#include "DupeCoordinator.h"
class PrePostProcessor : public Thread
{
public:
// NOTE: changes to this enum must be synced with "eRemoteEditAction" in unit "MessageBase.h"
enum EEditAction
{
eaPostMoveOffset = 51, // move post to m_iOffset relative to the current position in post-queue
eaPostMoveTop,
eaPostMoveBottom,
eaPostDelete,
eaHistoryDelete,
eaHistoryFinalDelete,
eaHistoryReturn,
eaHistoryProcess,
eaHistoryRedownload,
eaHistorySetParameter,
eaHistorySetDupeKey,
eaHistorySetDupeScore,
eaHistorySetDupeMode,
eaHistorySetDupeBackup,
eaHistoryMarkBad,
eaHistoryMarkGood
};
private:
class QueueCoordinatorObserver: public Observer
{
public:
PrePostProcessor* m_pOwner;
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->QueueCoordinatorUpdate(Caller, Aspect); }
};
class PostParCoordinator: public ParCoordinator
{
private:
PrePostProcessor* m_pOwner;
protected:
virtual bool PauseDownload() { return m_pOwner->PauseDownload(); }
virtual bool UnpauseDownload() { return m_pOwner->UnpauseDownload(); }
friend class PrePostProcessor;
};
class PostDupeCoordinator: public DupeCoordinator
{
private:
PrePostProcessor* m_pOwner;
protected:
virtual void HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo);
virtual void DeleteQueuedFile(const char* szQueuedFile) { m_pOwner->DeleteQueuedFile(szQueuedFile); }
friend class PrePostProcessor;
};
private:
PostParCoordinator m_ParCoordinator;
PostDupeCoordinator m_DupeCoordinator;
QueueCoordinatorObserver m_QueueCoordinatorObserver;
bool m_bHasMoreJobs;
bool m_bSchedulerPauseChanged;
bool m_bSchedulerPause;
bool m_bPostPause;
const char* m_szPauseReason;
bool IsNZBFileCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
bool bIgnorePausedPars, bool bAllowOnlyOneDeleted);
void CheckPostQueue();
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
void StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
void SaveQueue(DownloadQueue* pDownloadQueue);
void SanitisePostQueue(PostQueue* pPostQueue);
void CheckDiskSpace();
void ApplySchedulerState();
void CheckScheduledResume();
void UpdatePauseState(bool bNeedPause, const char* szReason);
bool PauseDownload();
bool UnpauseDownload();
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
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);
void DeleteQueuedFile(const char* szQueuedFile);
int FindGroupID(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
bool PostQueueMove(IDList* pIDList, EEditAction eAction, int iOffset);
bool PostQueueDelete(IDList* pIDList);
bool HistoryEdit(IDList* pIDList, EEditAction eAction, int iOffset, const char* szText);
void HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bFinal);
void HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bReprocess);
void HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bRestorePauseState);
void HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText);
void HistorySetDupeParam(HistoryInfo* pHistoryInfo, EEditAction eAction, const char* szText);
void HistoryTransformToDup(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
void CheckHistory();
void Cleanup();
FileInfo* GetQueueGroup(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void DeletePostThread(PostInfo* pPostInfo);
public:
PrePostProcessor();
virtual ~PrePostProcessor();
virtual void Run();
virtual void Stop();
void QueueCoordinatorUpdate(Subject* Caller, void* Aspect);
bool HasMoreJobs() { return m_bHasMoreJobs; }
bool QueueEditList(IDList* pIDList, EEditAction eAction, int iOffset, const char* szText);
};
#endif

View File

File diff suppressed because it is too large Load Diff

138
QueueCoordinator.h Normal file
View File

@@ -0,0 +1,138 @@
/*
* 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>
*
* This 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 QUEUECOORDINATOR_H
#define QUEUECOORDINATOR_H
#include <deque>
#include <list>
#include <time.h>
#include "Thread.h"
#include "NZBFile.h"
#include "ArticleDownloader.h"
#include "DownloadInfo.h"
#include "Observer.h"
#include "QueueEditor.h"
#include "NNTPConnection.h"
class QueueCoordinator : public Thread, public Observer, public Subject, public DownloadSpeedMeter, public DownloadQueueHolder
{
public:
typedef std::list<ArticleDownloader*> ActiveDownloads;
enum EAspectAction
{
eaNZBFileFound,
eaNZBFileAdded,
eaFileCompleted,
eaFileDeleted
};
struct Aspect
{
EAspectAction eAction;
DownloadQueue* pDownloadQueue;
NZBInfo* pNZBInfo;
FileInfo* pFileInfo;
};
private:
DownloadQueue m_DownloadQueue;
ActiveDownloads m_ActiveDownloads;
QueueEditor m_QueueEditor;
Mutex m_mutexDownloadQueue;
bool m_bHasMoreJobs;
int m_iDownloadsLimit;
int m_iServerConfigGeneration;
// statistics
static const int SPEEDMETER_SLOTS = 30;
static const int SPEEDMETER_SLOTSIZE = 1; //Split elapsed time into this number of secs.
int m_iSpeedBytes[SPEEDMETER_SLOTS];
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;
time_t m_tStartServer;
time_t m_tLastCheck;
time_t m_tStartDownload;
time_t m_tPausedFrom;
bool m_bStandBy;
Mutex m_mutexStat;
bool GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArticleInfo);
void StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pArticleInfo, NNTPConnection* pConnection);
void ArticleCompleted(ArticleDownloader* pArticleDownloader);
void DeleteFileInfo(FileInfo* pFileInfo, bool bCompleted);
void StatFileInfo(FileInfo* pFileInfo, bool bCompleted);
void CheckHealth(FileInfo* pFileInfo);
void ResetHangingDownloads();
void ResetSpeedStat();
void EnterLeaveStandBy(bool bEnter);
void AdjustStartTime();
void AdjustDownloadsLimit();
public:
QueueCoordinator();
virtual ~QueueCoordinator();
virtual void Run();
virtual void Stop();
void Update(Subject* Caller, void* Aspect);
// statistics
long long CalcRemainingSize();
virtual int CalcCurrentDownloadSpeed();
virtual void AddSpeedReading(int iBytes);
void CalcStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy);
// Editing the queue
DownloadQueue* LockQueue();
void UnlockQueue() ;
void AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst);
void AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFileQueue, bool bAddFirst);
bool HasMoreJobs() { return m_bHasMoreJobs; }
bool GetStandBy() { return m_bStandBy; }
bool DeleteQueueEntry(FileInfo* pFileInfo);
bool SetQueueEntryNZBCategory(NZBInfo* pNZBInfo, const char* szCategory);
bool SetQueueEntryNZBName(NZBInfo* pNZBInfo, const char* szName);
bool MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZBInfo);
bool SplitQueueEntries(FileQueue* pFileList, const char* szName, NZBInfo** pNewNZBInfo);
void DiscardDiskFile(FileInfo* pFileInfo);
QueueEditor* GetQueueEditor() { return &m_QueueEditor; }
void LogDebugInfo();
};
#endif

1031
QueueEditor.cpp Normal file
View File

File diff suppressed because it is too large Load Diff

128
QueueEditor.h Normal file
View File

@@ -0,0 +1,128 @@
/*
* 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 QUEUEEDITOR_H
#define QUEUEEDITOR_H
#include <vector>
#include "DownloadInfo.h"
class QueueEditor
{
public:
// NOTE: changes to this enum must be synced with "eRemoteEditAction" in unit "MessageBase.h"
enum EEditAction
{
eaFileMoveOffset = 1, // move to m_iOffset relative to the current position in queue
eaFileMoveTop,
eaFileMoveBottom,
eaFilePause,
eaFileResume,
eaFileDelete,
eaFilePauseAllPars,
eaFilePauseExtraPars,
eaFileSetPriority,
eaFileReorder,
eaFileSplit,
eaGroupMoveOffset, // move to m_iOffset relative to the current position in queue
eaGroupMoveTop,
eaGroupMoveBottom,
eaGroupPause,
eaGroupResume,
eaGroupDelete,
eaGroupDupeDelete,
eaGroupFinalDelete,
eaGroupPauseAllPars,
eaGroupPauseExtraPars,
eaGroupSetPriority,
eaGroupSetCategory,
eaGroupMerge,
eaGroupSetParameter,
eaGroupSetName,
eaGroupSetDupeKey,
eaGroupSetDupeScore,
eaGroupSetDupeMode
};
enum EMatchMode
{
mmID = 1,
mmName,
mmRegEx
};
private:
class EditItem
{
public:
int m_iOffset;
FileInfo* m_pFileInfo;
EditItem(FileInfo* pFileInfo, int iOffset);
};
typedef std::vector<EditItem*> ItemList;
typedef std::vector<FileInfo*> FileList;
private:
FileInfo* FindFileInfo(DownloadQueue* pDownloadQueue, int iID);
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);
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 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);
bool MergeGroups(DownloadQueue* pDownloadQueue, ItemList* pItemList);
bool SplitGroup(DownloadQueue* pDownloadQueue, ItemList* pItemList, const char* szName);
void ReorderFiles(DownloadQueue* pDownloadQueue, ItemList* pItemList);
void SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString);
void SetNZBDupeParam(NZBInfo* pNZBInfo, EEditAction eAction, const char* szText);
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 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);
};
#endif

97
README
View File

@@ -4,7 +4,7 @@
This is a short documentation. For more information please
visit NZBGet home page at
http://nzbget.net
http://nzbget.sourceforge.net
Contents
--------
@@ -87,14 +87,13 @@ And the following libraries are optional:
- libncurses (http://invisible-island.net/ncurses)
- for par-check and -repair (enabled by default):
- libpar2 (http://launchpad.net/libpar2,
http://parchive.sourceforge.net)
- libpar2 (http://parchive.sourceforge.net)
- libsigc++ (http://libsigc.sourceforge.net)
- for encrypted connections (TLS/SSL):
- OpenSSL (http://www.openssl.org)
or
- GnuTLS (http://www.gnu.org/software/gnutls)
or
- OpenSSL (http://www.openssl.org)
- for gzip support in web-server and web-client (enabled by default):
- zlib (http://www.zlib.net)
@@ -154,11 +153,11 @@ You may run configure with additional arguments:
--disable-parcheck - to make without parcheck-support. Use this option
if you can not use libpar2 or libsigc++.
--with-tlslib=(OpenSSL, GnuTLS) - to select which TLS/SSL library
--with-tlslib=(GnuTLS, OpenSSL) - to select which TLS/SSL library
should be used for encrypted server connections.
--disable-tls - to make without TLS/SSL support. Use this option if
you can not neither OpenSSL nor GnuTLS.
you can not neither GnuTLS nor OpenSSL.
--disable-gzip - to make without gzip support. Use this option
if you can not use zlib.
@@ -183,17 +182,20 @@ Following configure-parameters may be usefull:
The library libsigc++ must be installed first, since libpar2 requires it.
Official project libpar2 (http://parchive.sourceforge.net) has not been
updated for many years. The last official version of libpar 0.2 contains
known bugs which may crash the program during par-check. These bugs
have been fixed in the semi-official fork maintained by Debian/Ubuntu
team (http://launchpad.net/libpar2). It is highly recommended to use this
version of libpar2 (version 0.4 or newer) instead of the last official
version 0.2. Recent releases of Debian/Ubuntu include this libpar2 version.
If you use nzbget on a very slow computer like NAS-device, it may be good to
limit the time allowed for par-repair (option "ParTimeLimit" in nzbget
configuration file). This feature requires a patched version of libpar2.
To compile that version download the original source code of libpar2
(version 0.2) and apply patches "libpar2-0.2-bugfixes.patch" and
"libpar2-0.2-cancel.patch", provided with nzbget:
NZBGets configure script checks the installed version of libpar2 and prints
an error if it is older than 0.4. The check can be suppressed if the update
of libpar2 is not possible.
cd libpar2-0.2
cp ~/nzbget/libpar2-0.2-*.patch .
patch < libpar2-0.2-bugfixes.patch
patch < libpar2-0.2-cancel.patch
./configure
make
make install
If you are not able to use libpar2 or libsigc++ or do not want them you can
make nzbget without support for par-check using option "--disable-parcheck":
@@ -217,14 +219,14 @@ make the program without support for curses using option "--disable-curses":
Optional package: TLS
-------------------------
To enable encrypted server connections (TLS/SSL) you need to build the program
with TLS/SSL support. NZBGet can use two libraries: OpenSSL or GnuTLS.
with TLS/SSL support. NZBGet can use two libraries: GnuTLS or OpenSSL.
Configure-script checks which library is installed and use it. If both are
available it gives the precedence to OpenSSL. You may override that with
the option --with-tlslib=(OpenSSL, GnuTLS). For example to build with GnuTLS:
avialable it gives the precedence to GnuTLS. You may override that with
the option --with-tlslib=(GnuTLS, OpenSSL). For example to build whith OpenSSL:
./configure --with-tlslib= GnuTLS
./configure --with-tlslib=OpenSSL
Following configure-parameters may be useful:
Following configure-parameters may be usefull:
--with-libtls-includes
--with-libtls-libraries
@@ -249,8 +251,7 @@ To compile the program with par-check-support you also need the following
libraries:
- libsigc++ (http://libsigc.sourceforge.net)
- libpar2 (http://launchpad.net/libpar2,
http://parchive.sourceforge.net)
- libpar2 (http://parchive.sourceforge.net)
Download these libaries, then use patch-files provided with NZBGet to create
preconfigured project files and solutions for each library.
@@ -259,10 +260,16 @@ to use patch-files, if you do not familiar with this technique.
To compile the program with TLS/SSL support you also need the library:
- OpenSSL (http://www.openssl.org)
or
- GnuTLS (http://www.gnu.org/software/gnutls)
Download a precompiled version of GnuTLS from http://josefsson.org/gnutls4win
and create lib-file as described there in section "Using the GnuTLS DLL from
your Visual Studio program".
After libsigc++ and libpar2 are compiled in static libraries (.lib), the
library for GnuTLS is created and include- and libraries-paths are configured
in MS Visual C++ 2005 you should be able to compile NZBGet.
=====================================
6. Configuration
=====================================
@@ -380,18 +387,9 @@ It prints something like:
[1] nzbname\filename1.rar (50.00 MB)
[2] nzbname\filename1.r01 (50.00 MB)
[3] another-nzb\filename3.r01 (100.00 MB)
[4] another-nzb\filename3.r02 (100.00 MB)
This is the list of individual files listed within nzb-file. To print
the list of nzb-files (without content) add G-modifier to the list command:
[1] nzbname (4.56 GB)
[2] another-nzb (4.20 GB)
The numbers in square braces are ID's of files or groups in queue.
They can be used in edit-command. For example to move file with
ID 2 to the top of queue:
The numbers in square braces are ID's of files in queue. They can be used
in edit-command. For example to move file with ID 2 to the top of queue:
nzbget -E T 2
@@ -404,8 +402,8 @@ or to delete files from queue:
nzbget -E D 3 10-15 20-21 16
The edit-command has also a group-mode which affects all files from the
same nzb-file. You need to pass an ID of the group. For example to delete
the whole group 1:
same nzb-request. You need to pass one ID of any file in the group. For
example to delete all files from the first nzb-request:
nzbget -E G D 1
@@ -446,10 +444,10 @@ Post processing scripts
After the download of nzb-file is completed nzbget can call post-processing
scripts, defined in configuration file.
Example post-processing scripts are provided in directory "scripts".
Example post-processing scripts are provided in directory "ppscripts".
To use the scripts copy them into your local directory and set options
<ScriptDir>, <PostScript> and <ScriptOrder>.
<ScriptDir>, <DefScript> and <ScriptOrder>.
For information on writing your own post-processing scripts please
visit NZBGet web site.
@@ -471,14 +469,13 @@ and port defined in NZBGet configuration file in options "ControlIP" and
http://localhost:6789/
For login credentials type username and the password defined by
options "ControlUsername" (default "nzbget") and "ControlPassword"
(default "tegbzn6789").
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/username:password/
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
@@ -510,13 +507,21 @@ The complete content of license is provided in file COPYING.
Additional exemption: compiling, linking, and/or using OpenSSL is allowed.
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)
libpar2 is distributed under GPL; libsigc++ and GnuTLS - under LGPL.
=====================================
10. Contact
=====================================
If you encounter any problem, feel free to use the forum
nzbget.net/forum
nzbget.sourceforge.net/forum
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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -236,21 +236,16 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) + ntohl(pListAnswer->m_iCategoryLen);
MatchedNZBInfo* pNZBInfo = new MatchedNZBInfo();
pNZBInfo->SetID(ntohl(pListAnswer->m_iID));
pNZBInfo->SetKind((NZBInfo::EKind)ntohl(pListAnswer->m_iKind));
pNZBInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo)));
pNZBInfo->SetRemainingSize(Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
pNZBInfo->SetPausedSize(Util::JoinInt64(ntohl(pListAnswer->m_iPausedSizeHi), ntohl(pListAnswer->m_iPausedSizeLo)));
pNZBInfo->SetPausedFileCount(ntohl(pListAnswer->m_iPausedCount));
pNZBInfo->SetFilename(szFileName);
pNZBInfo->SetName(szName);
pNZBInfo->SetDestDir(szDestDir);
pNZBInfo->SetCategory(szCategory);
pNZBInfo->SetQueuedFilename(m_szQueuedFilename);
pNZBInfo->SetPriority(ntohl(pListAnswer->m_iPriority));
pNZBInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
pDownloadQueue->GetQueue()->push_back(pNZBInfo);
pNZBInfo->Retain();
pDownloadQueue->GetNZBInfoList()->Add(pNZBInfo);
pBufPtr += sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
ntohl(pListAnswer->m_iNameLen) + ntohl(pListAnswer->m_iDestDirLen) +
@@ -265,7 +260,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
const char* szName = pBufPtr + sizeof(SNZBListResponsePPPEntry);
const char* szValue = pBufPtr + sizeof(SNZBListResponsePPPEntry) + ntohl(pListAnswer->m_iNameLen);
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
pNZBInfo->GetParameters()->SetParameter(szName, szValue);
pBufPtr += sizeof(SNZBListResponsePPPEntry) + ntohl(pListAnswer->m_iNameLen) +
@@ -289,16 +284,21 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
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->GetQueue()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
pFileInfo->SetNZBInfo(pNZBInfo);
pNZBInfo->GetFileList()->push_back(pFileInfo);
pDownloadQueue->GetFileQueue()->push_back(pFileInfo);
pBufPtr += sizeof(SNZBListResponseFileEntry) + ntohl(pListAnswer->m_iSubjectLen) +
ntohl(pListAnswer->m_iFilenameLen);
}
}
pDownloadQueue->GetNZBInfoList()->ReleaseAll();
}
bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPattern)
@@ -367,61 +367,61 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
printf("Queue List\n");
printf("-----------------------------------\n");
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
BuildFileList(&ListResponse, pBuf, pDownloadQueue);
DownloadQueue cRemoteQueue;
BuildFileList(&ListResponse, pBuf, &cRemoteQueue);
long long lRemaining = 0;
long long lPaused = 0;
int iMatches = 0;
int iNrFileEntries = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (FileQueue::iterator it = cRemoteQueue.GetFileQueue()->begin(); it != cRemoteQueue.GetFileQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
FileInfo* pFileInfo = *it;
char szPriority[100];
szPriority[0] = '\0';
if (pFileInfo->GetPriority() != 0)
{
FileInfo* pFileInfo = *it2;
iNrFileEntries++;
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())
{
sprintf(szStatus, " (paused)");
lPaused += pFileInfo->GetRemainingSize();
}
else
{
szStatus[0] = '\0';
lRemaining += pFileInfo->GetRemainingSize();
}
if (!szPattern || ((MatchedFileInfo*)pFileInfo)->m_bMatch)
{
printf("[%i] %s/%s (%.2f MB%s%s)%s\n", pFileInfo->GetID(), pFileInfo->GetNZBInfo()->GetName(),
pFileInfo->GetFilename(),
(float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
szCompleted, szThreads, szStatus);
iMatches++;
}
sprintf(szPriority, "[%+i] ", pFileInfo->GetPriority());
}
}
DownloadQueue::Unlock();
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())
{
sprintf(szStatus, " (paused)");
lPaused += pFileInfo->GetRemainingSize();
}
else
{
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++;
}
delete pFileInfo;
}
if (iMatches == 0)
{
@@ -429,7 +429,7 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
}
printf("-----------------------------------\n");
printf("Files: %i\n", iNrFileEntries);
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
if (szPattern)
{
printf("Matches: %i\n", iMatches);
@@ -457,21 +457,21 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
printf("Queue List\n");
printf("-----------------------------------\n");
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
BuildFileList(&ListResponse, pBuf, pDownloadQueue);
DownloadQueue cRemoteQueue;
BuildFileList(&ListResponse, pBuf, &cRemoteQueue);
GroupQueue cGroupQueue;
cRemoteQueue.BuildGroups(&cGroupQueue);
long long lRemaining = 0;
long long lPaused = 0;
int iMatches = 0;
int iNrFileEntries = 0;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (GroupQueue::iterator it = cGroupQueue.begin(); it != cGroupQueue.end(); it++)
{
NZBInfo* pNZBInfo = *it;
GroupInfo* pGroupInfo = *it;
iNrFileEntries += pNZBInfo->GetFileList()->size();
long long lUnpausedRemainingSize = pNZBInfo->GetRemainingSize() - pNZBInfo->GetPausedSize();
long long lUnpausedRemainingSize = pGroupInfo->GetRemainingSize() - pGroupInfo->GetPausedSize();
lRemaining += lUnpausedRemainingSize;
char szRemaining[20];
@@ -479,38 +479,45 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
char szPriority[100];
szPriority[0] = '\0';
if (pNZBInfo->GetPriority() != 0)
if (pGroupInfo->GetMinPriority() != 0 || pGroupInfo->GetMaxPriority() != 0)
{
sprintf(szPriority, "[%+i] ", pNZBInfo->GetPriority());
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 (pNZBInfo->GetPausedSize() > 0)
if (pGroupInfo->GetPausedSize() > 0)
{
char szPausedSize[20];
Util::FormatFileSize(szPausedSize, sizeof(szPausedSize), pNZBInfo->GetPausedSize());
Util::FormatFileSize(szPausedSize, sizeof(szPausedSize), pGroupInfo->GetPausedSize());
sprintf(szPaused, " + %s paused", szPausedSize);
lPaused += pNZBInfo->GetPausedSize();
lPaused += pGroupInfo->GetPausedSize();
}
char szCategory[1024];
szCategory[0] = '\0';
if (pNZBInfo->GetCategory() && strlen(pNZBInfo->GetCategory()) > 0)
if (pGroupInfo->GetNZBInfo()->GetCategory() && strlen(pGroupInfo->GetNZBInfo()->GetCategory()) > 0)
{
sprintf(szCategory, " (%s)", pNZBInfo->GetCategory());
sprintf(szCategory, " (%s)", pGroupInfo->GetNZBInfo()->GetCategory());
}
char szThreads[100];
szThreads[0] = '\0';
if (pNZBInfo->GetActiveDownloads() > 0)
if (pGroupInfo->GetActiveDownloads() > 0)
{
sprintf(szThreads, ", %i thread%s", pNZBInfo->GetActiveDownloads(), (pNZBInfo->GetActiveDownloads() > 1 ? "s" : ""));
sprintf(szThreads, ", %i thread%s", pGroupInfo->GetActiveDownloads(), (pGroupInfo->GetActiveDownloads() > 1 ? "s" : ""));
}
char szParameters[1024];
szParameters[0] = '\0';
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
for (NZBParameterList::iterator it = pGroupInfo->GetNZBInfo()->GetParameters()->begin(); it != pGroupInfo->GetNZBInfo()->GetParameters()->end(); it++)
{
if (szParameters[0] == '\0')
{
@@ -530,39 +537,33 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
strncat(szParameters, ")", sizeof(szParameters) - strlen(szParameters) - 1);
}
char szUrlOrFile[100];
if (pNZBInfo->GetKind() == NZBInfo::nkUrl)
if (!szPattern || ((MatchedNZBInfo*)pGroupInfo->GetNZBInfo())->m_bMatch)
{
strncpy(szUrlOrFile, "URL", sizeof(szUrlOrFile));
}
else
{
snprintf(szUrlOrFile, sizeof(szUrlOrFile), "%i file%s", (int)pNZBInfo->GetFileList()->size(),
pNZBInfo->GetFileList()->size() > 1 ? "s" : "");
szUrlOrFile[100-1] = '\0';
}
if (!szPattern || ((MatchedNZBInfo*)pNZBInfo)->m_bMatch)
{
printf("[%i] %s%s (%s, %s%s%s)%s%s\n", pNZBInfo->GetID(), szPriority,
pNZBInfo->GetName(), szUrlOrFile, szRemaining,
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++;
}
}
for (FileQueue::iterator it = cRemoteQueue.GetFileQueue()->begin(); it != cRemoteQueue.GetFileQueue()->end(); it++)
{
delete *it;
}
if (iMatches == 0)
{
printf("No matches founds\n");
}
printf("-----------------------------------\n");
printf("Groups: %i\n", pDownloadQueue->GetQueue()->size());
printf("Groups: %i\n", cGroupQueue.size());
if (szPattern)
{
printf("Matches: %i\n", iMatches);
}
printf("Files: %i\n", iNrFileEntries);
printf("Files: %i\n", cRemoteQueue.GetFileQueue()->size());
if (lPaused > 0)
{
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0),
@@ -572,8 +573,6 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
{
printf("Remaining size: %.2f MB\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0));
}
DownloadQueue::Unlock();
}
}
@@ -817,8 +816,8 @@ bool RemoteClient::RequestServerDumpDebug()
return OK;
}
bool RemoteClient::RequestServerEditQueue(DownloadQueue::EEditAction eAction, int iOffset, const char* szText,
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode)
bool RemoteClient::RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder)
{
if ((iIDCount <= 0 || pIDList == NULL) && (pNameList == NULL || pNameList->size() == 0))
{
@@ -852,9 +851,10 @@ bool RemoteClient::RequestServerEditQueue(DownloadQueue::EEditAction eAction, in
SNZBEditQueueRequest EditQueueRequest;
InitMessageBase(&EditQueueRequest.m_MessageBase, eRemoteRequestEditQueue, sizeof(EditQueueRequest));
EditQueueRequest.m_iAction = htonl(eAction);
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);
@@ -1149,7 +1149,7 @@ bool RemoteClient::RequestHistory()
HistoryInfo::EKind eKind = (HistoryInfo::EKind)ntohl(pListAnswer->m_iKind);
const char* szNicename = pBufPtr + sizeof(SNZBHistoryResponseEntry);
if (eKind == HistoryInfo::hkNzb)
if (eKind == HistoryInfo::hkNZBInfo)
{
long long lSize = Util::JoinInt64(ntohl(pListAnswer->m_iSizeHi), ntohl(pListAnswer->m_iSizeLo));
@@ -1164,7 +1164,7 @@ bool RemoteClient::RequestHistory()
szParStatusText[ntohl(pListAnswer->m_iParStatus)],
szScriptStatusText[ntohl(pListAnswer->m_iScriptStatus)]);
}
else if (eKind == HistoryInfo::hkUrl)
else if (eKind == HistoryInfo::hkUrlInfo)
{
const char* szUrlStatusText[] = { "", "", "Url download successful", "Url download failed", "" };
@@ -1224,3 +1224,76 @@ bool RemoteClient::RequestServerDownloadUrl(const char* szURL, const char* szNZB
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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,8 +65,8 @@ public:
bool RequestServerPauseUnpause(bool bPause, eRemotePauseUnpauseAction iAction);
bool RequestServerSetDownloadRate(int iRate);
bool RequestServerDumpDebug();
bool RequestServerEditQueue(DownloadQueue::EEditAction eAction, int iOffset, const char* szText,
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode);
bool RequestServerEditQueue(eRemoteEditAction iAction, int iOffset, const char* szText,
int* pIDList, int iIDCount, NameList* pNameList, eRemoteMatchMode iMatchMode, bool bSmartOrder);
bool RequestServerLog(int iLines);
bool RequestServerShutdown();
bool RequestServerReload();
@@ -76,6 +76,7 @@ public:
bool RequestScan(bool bSyncMode);
bool RequestHistory();
bool RequestServerDownloadUrl(const char* szURL, const char* szNZBFilename, const char* szCategory, bool bAddFirst, bool bAddPaused, int iPriority);
bool RequestUrlQueue();
void BuildFileList(SNZBListResponse* pListResponse, const char* pTrailingData, DownloadQueue* pDownloadQueue);
};

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -46,11 +46,13 @@
#include "Options.h"
#include "Log.h"
#include "QueueCoordinator.h"
#include "QueueScript.h"
#include "ScriptController.h"
#include "DiskState.h"
#include "Util.h"
extern QueueCoordinator* g_pQueueCoordinator;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
Scanner::FileData::FileData(const char* szFilename)
{
@@ -67,8 +69,7 @@ Scanner::FileData::~FileData()
Scanner::QueueData::QueueData(const char* szFilename, const char* szNZBName, const char* szCategory,
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
EAddStatus* pAddStatus, int* pNZBID)
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, EAddStatus* pAddStatus)
{
m_szFilename = strdup(szFilename);
m_szNZBName = strdup(szNZBName);
@@ -79,9 +80,7 @@ Scanner::QueueData::QueueData(const char* szFilename, const char* szNZBName, con
m_eDupeMode = eDupeMode;
m_bAddTop = bAddTop;
m_bAddPaused = bAddPaused;
m_pUrlInfo = pUrlInfo;
m_pAddStatus = pAddStatus;
m_pNZBID = pNZBID;
if (pParameters)
{
@@ -105,14 +104,6 @@ void Scanner::QueueData::SetAddStatus(EAddStatus eAddStatus)
}
}
void Scanner::QueueData::SetNZBID(int iNZBID)
{
if (m_pNZBID)
{
*m_pNZBID = iNZBID;
}
}
Scanner::Scanner()
{
@@ -120,9 +111,11 @@ Scanner::Scanner()
m_bRequestedNZBDirScan = false;
m_bScanning = false;
m_iNZBDirInterval = 0;
m_iNZBDirInterval = g_pOptions->GetNzbDirInterval() * 1000;
m_iPass = 0;
m_bScanScript = false;
const char* szNZBScript = g_pOptions->GetNZBProcess();
m_bNZBScript = szNZBScript && strlen(szNZBScript) > 0;
}
Scanner::~Scanner()
@@ -138,13 +131,6 @@ Scanner::~Scanner()
ClearQueueList();
}
void Scanner::InitOptions()
{
m_iNZBDirInterval = g_pOptions->GetNzbDirInterval() * 1000;
const char* szScanScript = g_pOptions->GetScanScript();
m_bScanScript = szScanScript && strlen(szScanScript) > 0;
}
void Scanner::ClearQueueList()
{
for (QueueList::iterator it = m_QueueList.begin(); it != m_QueueList.end(); it++)
@@ -167,7 +153,7 @@ void Scanner::Check()
m_bRequestedNZBDirScan = false;
m_bScanning = true;
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
if (!bCheckStat && m_bScanScript)
if (!bCheckStat && m_bNZBScript)
{
// if immediate scan requested, we need second scan to process files extracted by NzbProcess-script
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
@@ -182,7 +168,7 @@ void Scanner::Check()
// - third scan is needed to check sizes of extracted files.
if (g_pOptions->GetNzbDirInterval() > 0 && g_pOptions->GetNzbDirFileAge() < g_pOptions->GetNzbDirInterval())
{
int iMaxPass = m_bScanScript ? 3 : 1;
int iMaxPass = m_bNZBScript ? 3 : 1;
if (m_iPass < iMaxPass)
{
// scheduling another scan of incoming directory in NzbDirFileAge seconds.
@@ -212,28 +198,31 @@ void Scanner::CheckIncomingNZBs(const char* szDirectory, const char* szCategory,
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
struct stat buffer;
char fullfilename[1023 + 1]; // one char reserved for the trailing slash (if needed)
snprintf(fullfilename, 1023, "%s%s", szDirectory, filename);
fullfilename[1023 - 1] = '\0';
bool bIsDirectory = Util::DirectoryExists(fullfilename);
// check subfolders
if (bIsDirectory && strcmp(filename, ".") && strcmp(filename, ".."))
if (!stat(fullfilename, &buffer))
{
fullfilename[strlen(fullfilename) + 1] = '\0';
fullfilename[strlen(fullfilename)] = PATH_SEPARATOR;
const char* szUseCategory = filename;
char szSubCategory[1024];
if (strlen(szCategory) > 0)
// check subfolders
if ((buffer.st_mode & S_IFDIR) != 0 && strcmp(filename, ".") && strcmp(filename, ".."))
{
snprintf(szSubCategory, 1023, "%s%c%s", szCategory, PATH_SEPARATOR, filename);
szSubCategory[1024 - 1] = '\0';
szUseCategory = szSubCategory;
fullfilename[strlen(fullfilename) + 1] = '\0';
fullfilename[strlen(fullfilename)] = PATH_SEPARATOR;
const char* szUseCategory = filename;
char szSubCategory[1024];
if (strlen(szCategory) > 0)
{
snprintf(szSubCategory, 1023, "%s%c%s", szCategory, PATH_SEPARATOR, filename);
szSubCategory[1024 - 1] = '\0';
szUseCategory = szSubCategory;
}
CheckIncomingNZBs(fullfilename, szUseCategory, bCheckStat);
}
else if ((buffer.st_mode & S_IFDIR) == 0 && CanProcessFile(fullfilename, bCheckStat))
{
ProcessIncomingFile(szDirectory, filename, fullfilename, szCategory);
}
CheckIncomingNZBs(fullfilename, szUseCategory, bCheckStat);
}
else if (!bIsDirectory && CanProcessFile(fullfilename, bCheckStat))
{
ProcessIncomingFile(szDirectory, filename, fullfilename, szCategory);
}
}
}
@@ -355,8 +344,6 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
EAddStatus eAddStatus = asSkipped;
bool bAdded = false;
QueueData* pQueueData = NULL;
NZBInfo* pUrlInfo = NULL;
int iNZBID = 0;
for (QueueList::iterator it = m_QueueList.begin(); it != m_QueueList.end(); it++)
{
@@ -375,7 +362,6 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
bAddTop = pQueueData->GetAddTop();
bAddPaused = pQueueData->GetAddPaused();
pParameters->CopyFrom(pQueueData->GetParameters());
pUrlInfo = pQueueData->GetUrlInfo();
}
}
@@ -383,10 +369,9 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
bool bExists = true;
if (m_bScanScript && strcasecmp(szExtension, ".nzb_processed"))
if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed"))
{
ScanScriptController::ExecuteScripts(szFullFilename,
pUrlInfo ? pUrlInfo->GetURL() : "", szDirectory,
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory,
&szNZBName, &szNZBCategory, &iPriority, pParameters, &bAddTop, &bAddPaused);
bExists = Util::FileExists(szFullFilename);
if (bExists && strcasecmp(szExtension, ".nzb"))
@@ -408,7 +393,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
if (bRenameOK)
{
bAdded = AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority,
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, pUrlInfo, &iNZBID);
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused);
}
else
{
@@ -420,7 +405,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
else if (bExists && !strcasecmp(szExtension, ".nzb"))
{
bAdded = AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority,
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, pUrlInfo, &iNZBID);
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused);
}
delete pParameters;
@@ -431,14 +416,13 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
if (pQueueData)
{
pQueueData->SetAddStatus(eAddStatus == asFailed ? asFailed : bAdded ? asSuccess : asSkipped);
pQueueData->SetNZBID(iNZBID);
}
}
void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParameters)
{
bool bUnpack = g_pOptions->GetUnpack();
const char* szPostScript = g_pOptions->GetPostScript();
const char* szDefScript = g_pOptions->GetDefScript();
if (szCategory && *szCategory)
{
@@ -446,36 +430,44 @@ void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParame
if (pCategory)
{
bUnpack = pCategory->GetUnpack();
if (pCategory->GetPostScript() && *pCategory->GetPostScript())
if (pCategory->GetDefScript() && *pCategory->GetDefScript())
{
szPostScript = pCategory->GetPostScript();
szDefScript = pCategory->GetDefScript();
}
}
}
pParameters->SetParameter("*Unpack:", bUnpack ? "yes" : "no");
if (szPostScript && *szPostScript)
if (szDefScript && *szDefScript)
{
// split szPostScript into tokens and create pp-parameter for each token
Tokenizer tok(szPostScript, ",;");
while (const char* szScriptName = tok.Next())
// split szDefScript into tokens and create pp-parameter for each token
char* szDefScript2 = strdup(szDefScript);
char* saveptr;
char* szScriptName = strtok_r(szDefScript2, ",;", &saveptr);
while (szScriptName)
{
char szParam[1024];
snprintf(szParam, 1024, "%s:", szScriptName);
szParam[1024-1] = '\0';
pParameters->SetParameter(szParam, "yes");
szScriptName = Util::Trim(szScriptName);
if (szScriptName[0] != '\0')
{
char szParam[1024];
snprintf(szParam, 1024, "%s:", szScriptName);
szParam[1024-1] = '\0';
pParameters->SetParameter(szParam, "yes");
}
szScriptName = strtok_r(NULL, ",;", &saveptr);
}
free(szDefScript2);
}
}
bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory,
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo, int* pNZBID)
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused)
{
const char* szBasename = Util::BaseFileName(szFilename);
info("Adding collection %s to queue", szBasename);
info("Collection %s found", szBasename);
NZBFile* pNZBFile = NZBFile::Create(szFilename, szCategory);
bool bOK = pNZBFile != NULL;
@@ -494,52 +486,41 @@ bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, cons
if (bOK)
{
NZBInfo* pNZBInfo = pNZBFile->GetNZBInfo();
pNZBInfo->SetQueuedFilename(bakname2);
pNZBFile->GetNZBInfo()->SetQueuedFilename(bakname2);
if (szNZBName && strlen(szNZBName) > 0)
{
pNZBInfo->SetName(NULL);
pNZBFile->GetNZBInfo()->SetName(NULL);
#ifdef WIN32
char* szAnsiFilename = strdup(szNZBName);
WebUtil::Utf8ToAnsi(szAnsiFilename, strlen(szAnsiFilename) + 1);
pNZBInfo->SetFilename(szAnsiFilename);
pNZBFile->GetNZBInfo()->SetFilename(szAnsiFilename);
free(szAnsiFilename);
#else
pNZBInfo->SetFilename(szNZBName);
pNZBFile->GetNZBInfo()->SetFilename(szNZBName);
#endif
pNZBInfo->BuildDestDirName();
pNZBFile->GetNZBInfo()->BuildDestDirName();
}
pNZBInfo->SetDupeKey(szDupeKey);
pNZBInfo->SetDupeScore(iDupeScore);
pNZBInfo->SetDupeMode(eDupeMode);
pNZBInfo->SetPriority(iPriority);
if (pUrlInfo)
{
pNZBInfo->SetURL(pUrlInfo->GetURL());
pNZBInfo->SetUrlStatus(pUrlInfo->GetUrlStatus());
}
pNZBFile->GetNZBInfo()->SetDupeKey(szDupeKey);
pNZBFile->GetNZBInfo()->SetDupeScore(iDupeScore);
pNZBFile->GetNZBInfo()->SetDupeMode(eDupeMode);
if (pNZBFile->GetPassword())
{
pNZBInfo->GetParameters()->SetParameter("*Unpack:Password", pNZBFile->GetPassword());
pNZBFile->GetNZBInfo()->GetParameters()->SetParameter("*Unpack:Password", pNZBFile->GetPassword());
}
pNZBInfo->GetParameters()->CopyFrom(pParameters);
pNZBFile->GetNZBInfo()->GetParameters()->CopyFrom(pParameters);
for (::FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
{
FileInfo* pFileInfo = *it;
pFileInfo->SetPriority(iPriority);
pFileInfo->SetPaused(bAddPaused);
}
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, pUrlInfo, bAddTop);
if (pNZBID)
{
*pNZBID = pNZBInfo->GetID();
}
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, bAddTop);
}
delete pNZBFile;
@@ -562,8 +543,8 @@ void Scanner::ScanNZBDir(bool bSyncMode)
Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char* szCategory,
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
const char* szFileName, const char* szBuffer, int iBufSize, int* pNZBID)
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused,
const char* szFileName, const char* szBuffer, int iBufSize)
{
bool bNZB = false;
char szTempFileName[1024];
@@ -657,9 +638,8 @@ Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char*
}
EAddStatus eAddStatus = asSkipped;
QueueData* pQueueData = new QueueData(szScanFileName, szNZBName, szUseCategory, iPriority,
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, pUrlInfo,
&eAddStatus, pNZBID);
QueueData* pQueueData = new QueueData(szScanFileName, szNZBName, szUseCategory,
iPriority, szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, &eAddStatus);
free(szUseCategory);
m_QueueList.push_back(pQueueData);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -74,15 +74,12 @@ private:
NZBParameterList m_Parameters;
bool m_bAddTop;
bool m_bAddPaused;
NZBInfo* m_pUrlInfo;
EAddStatus* m_pAddStatus;
int* m_pNZBID;
public:
QueueData(const char* szFilename, const char* szNZBName, const char* szCategory,
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
EAddStatus* pAddStatus, int* pNZBID);
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, EAddStatus* pAddStatus);
~QueueData();
const char* GetFilename() { return m_szFilename; }
const char* GetNZBName() { return m_szNZBName; }
@@ -94,16 +91,14 @@ private:
NZBParameterList* GetParameters() { return &m_Parameters; }
bool GetAddTop() { return m_bAddTop; }
bool GetAddPaused() { return m_bAddPaused; }
NZBInfo* GetUrlInfo() { return m_pUrlInfo; }
void SetAddStatus(EAddStatus eAddStatus);
void SetNZBID(int iNZBID);
};
typedef std::deque<QueueData*> QueueList;
bool m_bRequestedNZBDirScan;
int m_iNZBDirInterval;
bool m_bScanScript;
bool m_bNZBScript;
int m_iPass;
FileList m_FileList;
QueueList m_QueueList;
@@ -113,24 +108,23 @@ private:
void CheckIncomingNZBs(const char* szDirectory, const char* szCategory, bool bCheckStat);
bool AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory,
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo, int* pNZBID);
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused);
void ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename,
const char* szFullFilename, const char* szCategory);
bool CanProcessFile(const char* szFullFilename, bool bCheckStat);
void InitPPParameters(const char* szCategory, NZBParameterList* pParameters);
void DropOldFiles();
void ClearQueueList();
public:
Scanner();
~Scanner();
void InitOptions();
void ScanNZBDir(bool bSyncMode);
void Check();
EAddStatus AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
const char* szFileName, const char* szBuffer, int iBufSize, int* pNZBID);
void InitPPParameters(const char* szCategory, NZBParameterList* pParameters);
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused,
const char* szFileName, const char* szBuffer, int iBufSize);
};
#endif

352
Scheduler.cpp Normal file
View File

@@ -0,0 +1,352 @@
/*
* This file is 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.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#else
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "nzbget.h"
#include "Scheduler.h"
#include "ScriptController.h"
#include "Options.h"
#include "Log.h"
#include "NewsServer.h"
#include "ServerPool.h"
#include "FeedInfo.h"
#include "FeedCoordinator.h"
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern FeedCoordinator* g_pFeedCoordinator;
Scheduler::Task::Task(int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand, const char* szParam)
{
m_iHours = iHours;
m_iMinutes = iMinutes;
m_iWeekDaysBits = iWeekDaysBits;
m_eCommand = eCommand;
m_szParam = szParam ? strdup(szParam) : NULL;
m_tLastExecuted = 0;
}
Scheduler::Task::~Task()
{
free(m_szParam);
}
Scheduler::Scheduler()
{
debug("Creating Scheduler");
m_tLastCheck = 0;
m_TaskList.clear();
}
Scheduler::~Scheduler()
{
debug("Destroying Scheduler");
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
delete *it;
}
}
void Scheduler::AddTask(Task* pTask)
{
m_mutexTaskList.Lock();
m_TaskList.push_back(pTask);
m_mutexTaskList.Unlock();
}
bool Scheduler::CompareTasks(Scheduler::Task* pTask1, Scheduler::Task* pTask2)
{
return (pTask1->m_iHours < pTask2->m_iHours) ||
((pTask1->m_iHours == pTask2->m_iHours) && (pTask1->m_iMinutes < pTask2->m_iMinutes));
}
void Scheduler::FirstCheck()
{
m_mutexTaskList.Lock();
m_TaskList.sort(CompareTasks);
m_mutexTaskList.Unlock();
// check all tasks for the last week
time_t tCurrent = time(NULL);
m_tLastCheck = tCurrent - 60*60*24*7;
m_bDetectClockChanges = false;
m_bExecuteProcess = false;
CheckTasks();
}
void Scheduler::IntervalCheck()
{
m_bDetectClockChanges = true;
m_bExecuteProcess = true;
CheckTasks();
}
void Scheduler::CheckTasks()
{
PrepareLog();
m_mutexTaskList.Lock();
time_t tCurrent = time(NULL);
if (m_bDetectClockChanges)
{
// Detect large step changes of system time
time_t tDiff = tCurrent - m_tLastCheck;
if (tDiff > 60*90 || tDiff < -60*90)
{
debug("Reset scheduled tasks (detected clock adjustment greater than 90 minutes)");
m_bExecuteProcess = false;
m_tLastCheck = tCurrent;
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
Task* pTask = *it;
pTask->m_tLastExecuted = 0;
}
}
}
tm tmCurrent;
localtime_r(&tCurrent, &tmCurrent);
tm tmLastCheck;
localtime_r(&m_tLastCheck, &tmLastCheck);
tm tmLoop;
memcpy(&tmLoop, &tmLastCheck, sizeof(tmLastCheck));
tmLoop.tm_hour = tmCurrent.tm_hour;
tmLoop.tm_min = tmCurrent.tm_min;
tmLoop.tm_sec = tmCurrent.tm_sec;
time_t tLoop = mktime(&tmLoop);
while (tLoop <= tCurrent)
{
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
Task* pTask = *it;
if (pTask->m_tLastExecuted != tLoop)
{
tm tmAppoint;
memcpy(&tmAppoint, &tmLoop, sizeof(tmLoop));
tmAppoint.tm_hour = pTask->m_iHours;
tmAppoint.tm_min = pTask->m_iMinutes;
tmAppoint.tm_sec = 0;
time_t tAppoint = mktime(&tmAppoint);
tAppoint -= g_pOptions->GetTimeCorrection();
int iWeekDay = tmAppoint.tm_wday;
if (iWeekDay == 0)
{
iWeekDay = 7;
}
bool bWeekDayOK = pTask->m_iWeekDaysBits == 0 || (pTask->m_iWeekDaysBits & (1 << (iWeekDay - 1)));
bool bDoTask = bWeekDayOK && m_tLastCheck < tAppoint && tAppoint <= tCurrent;
//debug("TEMP: 1) m_tLastCheck=%i, tCurrent=%i, tLoop=%i, tAppoint=%i, bWeekDayOK=%i, bDoTask=%i", m_tLastCheck, tCurrent, tLoop, tAppoint, (int)bWeekDayOK, (int)bDoTask);
if (bDoTask)
{
ExecuteTask(pTask);
pTask->m_tLastExecuted = tLoop;
}
}
}
tLoop += 60*60*24; // inc day
localtime_r(&tLoop, &tmLoop);
}
m_tLastCheck = tCurrent;
m_mutexTaskList.Unlock();
PrintLog();
}
void Scheduler::ExecuteTask(Task* pTask)
{
const char* szCommandName[] = { "Pause", "Unpause", "Set download rate", "Execute program", "Pause Scan", "Unpause Scan",
"Enable Server", "Disable Server", "Fetch Feed" };
debug("Executing scheduled command: %s", szCommandName[pTask->m_eCommand]);
switch (pTask->m_eCommand)
{
case scDownloadRate:
if (!Util::EmptyStr(pTask->m_szParam))
{
g_pOptions->SetDownloadRate(atoi(pTask->m_szParam) * 1024);
m_bDownloadRateChanged = true;
}
break;
case scPauseDownload:
case scUnpauseDownload:
m_bPauseDownload = pTask->m_eCommand == scPauseDownload;
m_bPauseDownloadChanged = true;
break;
case scProcess:
if (m_bExecuteProcess)
{
SchedulerScriptController::StartScript(pTask->m_szParam);
}
break;
case scPauseScan:
case scUnpauseScan:
g_pOptions->SetPauseScan(pTask->m_eCommand == scPauseScan);
m_bPauseScanChanged = true;
break;
case scActivateServer:
case scDeactivateServer:
EditServer(pTask->m_eCommand == scActivateServer, pTask->m_szParam);
break;
case scFetchFeed:
if (m_bExecuteProcess)
{
FetchFeed(pTask->m_szParam);
break;
}
}
}
void Scheduler::PrepareLog()
{
m_bDownloadRateChanged = false;
m_bPauseDownloadChanged = false;
m_bPauseScanChanged = false;
m_bServerChanged = false;
}
void Scheduler::PrintLog()
{
if (m_bDownloadRateChanged)
{
info("Scheduler: setting download rate to %i KB/s", g_pOptions->GetDownloadRate() / 1024);
}
if (m_bPauseScanChanged)
{
info("Scheduler: %s scan", g_pOptions->GetPauseScan() ? "pausing" : "unpausing");
}
if (m_bServerChanged)
{
int index = 0;
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++, index++)
{
NewsServer* pServer = *it;
if (pServer->GetActive() != m_ServerStatusList[index])
{
info("Scheduler: %s %s", pServer->GetActive() ? "activating" : "deactivating", pServer->GetName());
}
}
g_pServerPool->Changed();
}
}
void Scheduler::EditServer(bool bActive, const char* szServerList)
{
char* szServerList2 = strdup(szServerList);
char* saveptr;
char* szServer = strtok_r(szServerList2, ",;", &saveptr);
while (szServer)
{
szServer = Util::Trim(szServer);
if (!Util::EmptyStr(szServer))
{
int iID = atoi(szServer);
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
{
NewsServer* pServer = *it;
if ((iID > 0 && pServer->GetID() == iID) ||
!strcasecmp(pServer->GetName(), szServer))
{
if (!m_bServerChanged)
{
// store old server status for logging
m_ServerStatusList.clear();
m_ServerStatusList.reserve(g_pServerPool->GetServers()->size());
for (Servers::iterator it2 = g_pServerPool->GetServers()->begin(); it2 != g_pServerPool->GetServers()->end(); it2++)
{
NewsServer* pServer2 = *it2;
m_ServerStatusList.push_back(pServer2->GetActive());
}
}
m_bServerChanged = true;
pServer->SetActive(bActive);
break;
}
}
}
szServer = strtok_r(NULL, ",;", &saveptr);
}
free(szServerList2);
}
void Scheduler::FetchFeed(const char* szFeedList)
{
char* szFeedList2 = strdup(szFeedList);
char* saveptr;
char* szFeed = strtok_r(szFeedList2, ",;", &saveptr);
while (szFeed)
{
szFeed = Util::Trim(szFeed);
if (!Util::EmptyStr(szFeed))
{
int iID = atoi(szFeed);
for (Feeds::iterator it = g_pFeedCoordinator->GetFeeds()->begin(); it != g_pFeedCoordinator->GetFeeds()->end(); it++)
{
FeedInfo* pFeed = *it;
if (pFeed->GetID() == iID ||
!strcasecmp(pFeed->GetName(), szFeed) ||
!strcasecmp("0", szFeed))
{
g_pFeedCoordinator->FetchFeed(pFeed->GetID());
break;
}
}
}
szFeed = strtok_r(NULL, ",;", &saveptr);
}
free(szFeedList2);
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-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
@@ -40,7 +40,6 @@ public:
scPauseDownload,
scUnpauseDownload,
scDownloadRate,
scScript,
scProcess,
scPauseScan,
scUnpauseScan,
@@ -52,7 +51,6 @@ public:
class Task
{
private:
int m_iID;
int m_iHours;
int m_iMinutes;
int m_iWeekDaysBits;
@@ -61,7 +59,7 @@ public:
time_t m_tLastExecuted;
public:
Task(int iID, int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand,
Task(int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand,
const char* szParam);
~Task();
friend class Scheduler;
@@ -79,6 +77,7 @@ private:
bool m_bDownloadRateChanged;
bool m_bExecuteProcess;
bool m_bPauseDownloadChanged;
bool m_bPauseDownload;
bool m_bPauseScanChanged;
bool m_bServerChanged;
ServerStatusList m_ServerStatusList;
@@ -89,7 +88,6 @@ private:
void PrintLog();
void EditServer(bool bActive, const char* szServerList);
void FetchFeed(const char* szFeedList);
void CheckScheduledResume();
public:
Scheduler();
@@ -97,6 +95,8 @@ public:
void AddTask(Task* pTask);
void FirstCheck();
void IntervalCheck();
bool GetPauseDownloadChanged() { return m_bPauseDownloadChanged; }
bool GetPauseDownload() { return m_bPauseDownload; }
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -46,16 +46,21 @@
#include <stdarg.h>
#include "nzbget.h"
#include "Script.h"
#include "ScriptController.h"
#include "Log.h"
#include "Util.h"
#include "Options.h"
// System global variable holding environments variables
extern char** environ;
extern Options* g_pOptions;
extern char* (*g_szEnvironmentVariables)[];
extern DownloadQueueHolder* g_pDownloadQueueHolder;
static const int POSTPROCESS_PARCHECK = 92;
static const int POSTPROCESS_SUCCESS = 93;
static const int POSTPROCESS_ERROR = 94;
static const int POSTPROCESS_NONE = 95;
#ifndef WIN32
#define CHILD_WATCHDOG 1
@@ -260,6 +265,41 @@ void ScriptController::PrepareEnvOptions(const char* szStripPrefix)
g_pOptions->UnlockOptEntries();
}
/**
* If szStripPrefix is not NULL, only pp-parameters, whose names start with the prefix
* are processed. The prefix is then stripped from the names.
* If szStripPrefix is NULL, all pp-parameters are processed; without stripping.
*/
void ScriptController::PrepareEnvParameters(NZBInfo* pNZBInfo, const char* szStripPrefix)
{
int iPrefixLen = szStripPrefix ? strlen(szStripPrefix) : 0;
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szValue = pParameter->GetValue();
#ifdef WIN32
char* szAnsiValue = strdup(szValue);
WebUtil::Utf8ToAnsi(szAnsiValue, strlen(szAnsiValue) + 1);
szValue = szAnsiValue;
#endif
if (szStripPrefix && !strncmp(pParameter->GetName(), szStripPrefix, iPrefixLen) && (int)strlen(pParameter->GetName()) > iPrefixLen)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName() + iPrefixLen, szValue);
}
else if (!szStripPrefix)
{
SetEnvVarSpecial("NZBPR", pParameter->GetName(), szValue);
}
#ifdef WIN32
free(szAnsiValue);
#endif
}
}
void ScriptController::SetEnvVarSpecial(const char* szPrefix, const char* szName, const char* szValue)
{
char szVarname[1024];
@@ -557,7 +597,7 @@ int ScriptController::Execute()
}
while (pWatchDog->IsRunning())
{
usleep(5 * 1000);
usleep(1 * 1000);
}
delete pWatchDog;
#endif
@@ -738,3 +778,465 @@ void ScriptController::PrintMessage(Message::EKind eKind, const char* szFormat,
AddMessage(eKind, tmp3);
}
void PostScriptController::StartJob(PostInfo* pPostInfo)
{
PostScriptController* pScriptController = new PostScriptController();
pScriptController->m_pPostInfo = pPostInfo;
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
pScriptController->SetAutoDestroy(false);
pScriptController->m_iPrefixLen = 0;
pPostInfo->SetPostThread(pScriptController);
pScriptController->Start();
}
void PostScriptController::Run()
{
FileList activeList;
// the locking is needed for accessing the members of NZBInfo
g_pDownloadQueueHolder->LockQueue();
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szVarname = pParameter->GetName();
if (strlen(szVarname) > 0 && szVarname[0] != '*' && szVarname[strlen(szVarname)-1] == ':' &&
(!strcasecmp(pParameter->GetValue(), "yes") || !strcasecmp(pParameter->GetValue(), "on") || !strcasecmp(pParameter->GetValue(), "1")))
{
char* szScriptName = strdup(szVarname);
szScriptName[strlen(szScriptName)-1] = '\0'; // remove trailing ':'
activeList.push_back(szScriptName);
}
}
m_pPostInfo->GetNZBInfo()->GetScriptStatuses()->Clear();
g_pDownloadQueueHolder->UnlockQueue();
Options::ScriptList scriptList;
g_pOptions->LoadScriptList(&scriptList);
for (Options::ScriptList::iterator it = scriptList.begin(); it != scriptList.end(); it++)
{
Options::Script* pScript = *it;
for (FileList::iterator it2 = activeList.begin(); it2 != activeList.end(); it2++)
{
char* szActiveName = *it2;
// if any script has requested par-check, do not execute other scripts
if (Util::SameFilename(pScript->GetName(), szActiveName) && !m_pPostInfo->GetRequestParCheck())
{
ExecuteScript(pScript->GetName(), pScript->GetDisplayName(), pScript->GetLocation());
}
}
}
for (FileList::iterator it = activeList.begin(); it != activeList.end(); it++)
{
free(*it);
}
m_pPostInfo->SetStage(PostInfo::ptFinished);
m_pPostInfo->SetWorking(false);
}
void PostScriptController::ExecuteScript(const char* szScriptName, const char* szDisplayName, const char* szLocation)
{
PrintMessage(Message::mkInfo, "Executing post-process-script %s for %s", szScriptName, m_pPostInfo->GetInfoName());
SetScript(szLocation);
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "post-process-script %s for %s", szScriptName, m_pPostInfo->GetInfoName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(szDisplayName);
m_iPrefixLen = strlen(szDisplayName) + 2; // 2 = strlen(": ");
PrepareParams(szScriptName);
int iExitCode = Execute();
szInfoName[0] = 'P'; // uppercase
SetLogPrefix(NULL);
ScriptStatus::EStatus eStatus = AnalyseExitCode(iExitCode);
// the locking is needed for accessing the members of NZBInfo
g_pDownloadQueueHolder->LockQueue();
m_pPostInfo->GetNZBInfo()->GetScriptStatuses()->Add(szScriptName, eStatus);
g_pDownloadQueueHolder->UnlockQueue();
}
void PostScriptController::PrepareParams(const char* szScriptName)
{
// the locking is needed for accessing the members of NZBInfo
g_pDownloadQueueHolder->LockQueue();
// Reset
ResetEnv();
SetEnvVar("NZBPP_NZBNAME", m_pPostInfo->GetNZBInfo()->GetName());
SetEnvVar("NZBPP_DIRECTORY", m_pPostInfo->GetNZBInfo()->GetDestDir());
SetEnvVar("NZBPP_NZBFILENAME", m_pPostInfo->GetNZBInfo()->GetFilename());
SetEnvVar("NZBPP_FINALDIR", m_pPostInfo->GetNZBInfo()->GetFinalDir());
SetEnvVar("NZBPP_CATEGORY", m_pPostInfo->GetNZBInfo()->GetCategory());
SetIntEnvVar("NZBPP_HEALTH", m_pPostInfo->GetNZBInfo()->CalcHealth());
SetIntEnvVar("NZBPP_CRITICALHEALTH", m_pPostInfo->GetNZBInfo()->CalcCriticalHealth());
int iParStatus[] = { 0, 0, 1, 2, 3, 4 };
SetIntEnvVar("NZBPP_PARSTATUS", iParStatus[m_pPostInfo->GetNZBInfo()->GetParStatus()]);
int iUnpackStatus[] = { 0, 0, 1, 2, 3, 4 };
SetIntEnvVar("NZBPP_UNPACKSTATUS", iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
SetIntEnvVar("NZBPP_NZBID", m_pPostInfo->GetNZBInfo()->GetID());
SetIntEnvVar("NZBPP_HEALTHDELETED", (int)m_pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsHealth);
SetIntEnvVar("NZBPP_TOTALARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetTotalArticles());
SetIntEnvVar("NZBPP_SUCCESSARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetSuccessArticles());
SetIntEnvVar("NZBPP_FAILEDARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetFailedArticles());
for (ServerStatList::iterator it = m_pPostInfo->GetNZBInfo()->GetServerStats()->begin(); it != m_pPostInfo->GetNZBInfo()->GetServerStats()->end(); it++)
{
ServerStat* pServerStat = *it;
char szName[50];
snprintf(szName, 50, "NZBPP_SERVER%i_SUCCESSARTICLES", pServerStat->GetServerID());
szName[50-1] = '\0';
SetIntEnvVar(szName, pServerStat->GetSuccessArticles());
snprintf(szName, 50, "NZBPP_SERVER%i_FAILEDARTICLES", pServerStat->GetServerID());
szName[50-1] = '\0';
SetIntEnvVar(szName, pServerStat->GetFailedArticles());
}
PrepareEnvParameters(m_pPostInfo->GetNZBInfo(), NULL);
char szParamPrefix[1024];
snprintf(szParamPrefix, 1024, "%s:", szScriptName);
szParamPrefix[1024-1] = '\0';
PrepareEnvParameters(m_pPostInfo->GetNZBInfo(), szParamPrefix);
PrepareEnvOptions(szParamPrefix);
g_pDownloadQueueHolder->UnlockQueue();
}
ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int iExitCode)
{
// The ScriptStatus is accumulated for all scripts:
// If any script has failed the status is "failure", etc.
switch (iExitCode)
{
case POSTPROCESS_SUCCESS:
PrintMessage(Message::mkInfo, "%s successful", GetInfoName());
return ScriptStatus::srSuccess;
case POSTPROCESS_ERROR:
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
PrintMessage(Message::mkError, "%s failed", GetInfoName());
return ScriptStatus::srFailure;
case POSTPROCESS_NONE:
PrintMessage(Message::mkInfo, "%s skipped", GetInfoName());
return ScriptStatus::srNone;
#ifndef DISABLE_PARCHECK
case POSTPROCESS_PARCHECK:
if (m_pPostInfo->GetNZBInfo()->GetParStatus() > NZBInfo::psSkipped)
{
PrintMessage(Message::mkError, "%s requested par-check/repair, but the collection was already checked", GetInfoName());
return ScriptStatus::srFailure;
}
else
{
PrintMessage(Message::mkInfo, "%s requested par-check/repair", GetInfoName());
m_pPostInfo->SetRequestParCheck(true);
return ScriptStatus::srSuccess;
}
break;
#endif
default:
PrintMessage(Message::mkError, "%s failed (terminated with unknown status)", GetInfoName());
return ScriptStatus::srFailure;
}
}
void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "FINALDIR=", 9))
{
g_pDownloadQueueHolder->LockQueue();
m_pPostInfo->GetNZBInfo()->SetFinalDir(szMsgText + 6 + 9);
g_pDownloadQueueHolder->UnlockQueue();
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
g_pDownloadQueueHolder->LockQueue();
m_pPostInfo->GetNZBInfo()->GetParameters()->SetParameter(szParam, szValue + 1);
g_pDownloadQueueHolder->UnlockQueue();
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else if (!strncmp(szMsgText, "[HISTORY] ", 10))
{
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szMsgText);
}
else
{
ScriptController::AddMessage(eKind, szText);
m_pPostInfo->AppendMessage(eKind, szText);
}
if (g_pOptions->GetPausePostProcess())
{
time_t tStageTime = m_pPostInfo->GetStageTime();
time_t tStartTime = m_pPostInfo->GetStartTime();
time_t tWaitTime = time(NULL);
// wait until Post-processor is unpaused
while (g_pOptions->GetPausePostProcess() && !IsStopped())
{
usleep(100 * 1000);
// update time stamps
time_t tDelta = time(NULL) - tWaitTime;
if (tStageTime > 0)
{
m_pPostInfo->SetStageTime(tStageTime + tDelta);
}
if (tStartTime > 0)
{
m_pPostInfo->SetStartTime(tStartTime + tDelta);
}
}
}
}
void PostScriptController::Stop()
{
debug("Stopping post-process-script");
Thread::Stop();
Terminate();
}
void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory,
char** pNZBName, char** pCategory, int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused)
{
info("Executing nzb-process-script for %s", Util::BaseFileName(szNZBFilename));
NZBScriptController* pScriptController = new NZBScriptController();
pScriptController->SetScript(szScript);
pScriptController->m_pNZBName = pNZBName;
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameters = pParameters;
pScriptController->m_iPriority = iPriority;
pScriptController->m_bAddTop = bAddTop;
pScriptController->m_bAddPaused = bAddPaused;
char szInfoName[1024];
snprintf(szInfoName, 1024, "nzb-process-script for %s", Util::BaseFileName(szNZBFilename));
szInfoName[1024-1] = '\0';
pScriptController->SetInfoName(szInfoName);
pScriptController->SetEnvVar("NZBNP_FILENAME", szNZBFilename);
pScriptController->SetEnvVar("NZBNP_NZBNAME", strlen(*pNZBName) > 0 ? *pNZBName : Util::BaseFileName(szNZBFilename));
pScriptController->SetEnvVar("NZBNP_CATEGORY", *pCategory);
pScriptController->SetIntEnvVar("NZBNP_PRIORITY", *iPriority);
pScriptController->SetIntEnvVar("NZBNP_TOP", *bAddTop ? 1 : 0);
pScriptController->SetIntEnvVar("NZBNP_PAUSED", *bAddPaused ? 1 : 0);
// remove trailing slash
char szDir[1024];
strncpy(szDir, szDirectory, 1024);
szDir[1024-1] = '\0';
int iLen = strlen(szDir);
if (szDir[iLen-1] == PATH_SEPARATOR)
{
szDir[iLen-1] = '\0';
}
pScriptController->SetEnvVar("NZBNP_DIRECTORY", szDir);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(szScript), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
pScriptController->SetLogPrefix(szLogPrefix);
pScriptController->m_iPrefixLen = strlen(szLogPrefix) + 2; // 2 = strlen(": ");
pScriptController->Execute();
delete pScriptController;
}
void NZBScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
szText = szText + m_iPrefixLen;
if (!strncmp(szText, "[NZB] ", 6))
{
debug("Command %s detected", szText + 6);
if (!strncmp(szText + 6, "NZBNAME=", 8))
{
free(*m_pNZBName);
*m_pNZBName = strdup(szText + 6 + 8);
}
else if (!strncmp(szText + 6, "CATEGORY=", 9))
{
free(*m_pCategory);
*m_pCategory = strdup(szText + 6 + 9);
}
else if (!strncmp(szText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
m_pParameters->SetParameter(szParam, szValue + 1);
}
else
{
error("Invalid command \"%s\" received from %s", szText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szText + 6 + 9);
}
else if (!strncmp(szText + 6, "TOP=", 4))
{
*m_bAddTop = atoi(szText + 6 + 4) != 0;
}
else if (!strncmp(szText + 6, "PAUSED=", 7))
{
*m_bAddPaused = atoi(szText + 6 + 7) != 0;
}
else
{
error("Invalid command \"%s\" received from %s", szText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, 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_NZBNAME", pNZBInfo->GetName());
// "NZBNA_NAME" is not correct but kept for compatibility with older versions where this name was used by mistake
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();
}
}
pScriptController->SetIntEnvVar("NZBNA_LASTID", iLastID);
pScriptController->SetIntEnvVar("NZBNA_PRIORITY", iMaxPriority);
pScriptController->PrepareEnvParameters(pNZBInfo, NULL);
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);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
SetLogPrefix(szLogPrefix);
Execute();
free(m_szNZBName);
}
void SchedulerScriptController::StartScript(const char* szCommandLine)
{
char** argv = NULL;
if (!Util::SplitCommandLine(szCommandLine, &argv))
{
error("Could not execute scheduled process-script, failed to parse command line: %s", szCommandLine);
return;
}
info("Executing scheduled process-script %s", Util::BaseFileName(argv[0]));
SchedulerScriptController* pScriptController = new SchedulerScriptController();
pScriptController->SetScript(argv[0]);
pScriptController->SetArgs((const char**)argv, true);
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
}
void SchedulerScriptController::Run()
{
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduled process-script %s", Util::BaseFileName(GetScript()));
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
SetLogPrefix(szLogPrefix);
Execute();
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,12 +23,15 @@
*/
#ifndef SCRIPT_H
#define SCRIPT_H
#ifndef SCRIPTCONTROLLER_H
#define SCRIPTCONTROLLER_H
#include <vector>
#include <list>
#include "Log.h"
#include "Thread.h"
#include "DownloadInfo.h"
#include "Options.h"
class EnvironmentStrings
{
@@ -79,6 +82,7 @@ protected:
bool GetTerminated() { return m_bTerminated; }
void ResetEnv();
void PrepareEnvOptions(const char* szStripPrefix);
void PrepareEnvParameters(NZBInfo* pNZBInfo, const char* szStripPrefix);
void PrepareArgs();
public:
@@ -100,4 +104,64 @@ public:
void SetIntEnvVar(const char* szName, int iValue);
};
class PostScriptController : public Thread, public ScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szNZBName[1024];
int m_iPrefixLen;
void ExecuteScript(const char* szScriptName, const char* szDisplayName, const char* szLocation);
void PrepareParams(const char* szScriptName);
ScriptStatus::EStatus AnalyseExitCode(int iExitCode);
typedef std::deque<char*> FileList;
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
virtual void Stop();
static void StartJob(PostInfo* pPostInfo);
static void InitParamsForNewNZB(NZBInfo* pNZBInfo);
};
class NZBScriptController : public ScriptController
{
private:
char** m_pNZBName;
char** m_pCategory;
int* m_iPriority;
NZBParameterList* m_pParameters;
bool* m_bAddTop;
bool* m_bAddPaused;
int m_iPrefixLen;
protected:
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory,
char** pNZBName, char** pCategory, int* iPriority, NZBParameterList* pParameters,
bool* bAddTop, bool* bAddPaused);
};
class NZBAddedScriptController : public Thread, public ScriptController
{
private:
char* m_szNZBName;
public:
virtual void Run();
static void StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript);
};
class SchedulerScriptController : public Thread, public ScriptController
{
public:
virtual void Run();
static void StartScript(const char* szCommandLine);
};
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -42,6 +42,7 @@
#include "nzbget.h"
#include "ServerPool.h"
#include "Log.h"
static const int CONNECTION_HOLD_SECODNS = 5;
@@ -58,16 +59,12 @@ ServerPool::ServerPool()
m_iMaxNormLevel = 0;
m_iTimeout = 60;
m_iGeneration = 0;
g_pLog->RegisterDebuggable(this);
}
ServerPool::~ ServerPool()
{
debug("Destroying ServerPool");
g_pLog->UnregisterDebuggable(this);
m_Levels.clear();
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
@@ -330,33 +327,34 @@ void ServerPool::Changed()
void ServerPool::LogDebugInfo()
{
info(" ---------- ServerPool");
debug(" ServerPool");
debug(" ----------------");
info(" Max-Level: %i", m_iMaxNormLevel);
debug(" Max-Level: %i", m_iMaxNormLevel);
m_mutexConnections.Lock();
info(" Servers: %i", m_Servers.size());
debug(" Servers: %i", m_Servers.size());
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
{
NewsServer* pNewsServer = *it;
info(" %i) %s (%s): Level=%i, NormLevel=%i", pNewsServer->GetID(), pNewsServer->GetName(),
debug(" %i) %s (%s): Level=%i, NormLevel=%i", pNewsServer->GetID(), pNewsServer->GetName(),
pNewsServer->GetHost(), pNewsServer->GetLevel(), pNewsServer->GetNormLevel());
}
info(" Levels: %i", m_Levels.size());
debug(" Levels: %i", m_Levels.size());
int index = 0;
for (Levels::iterator it = m_Levels.begin(); it != m_Levels.end(); it++, index++)
{
int iSize = *it;
info(" %i: Free connections=%i", index, iSize);
debug(" %i: Size=%i", index, iSize);
}
info(" Connections: %i", m_Connections.size());
debug(" Connections: %i", m_Connections.size());
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
{
PooledConnection* pConnection = *it;
info(" %i) %s (%s): Level=%i, NormLevel=%i, InUse:%i", pConnection->GetNewsServer()->GetID(),
debug(" %i) %s (%s): Level=%i, NormLevel=%i, InUse:%i", pConnection->GetNewsServer()->GetID(),
pConnection->GetNewsServer()->GetName(), pConnection->GetNewsServer()->GetHost(),
pConnection->GetNewsServer()->GetLevel(), pConnection->GetNewsServer()->GetNormLevel(),
(int)pConnection->GetInUse());

View File

@@ -30,12 +30,11 @@
#include <vector>
#include <time.h>
#include "Log.h"
#include "Thread.h"
#include "NewsServer.h"
#include "NNTPConnection.h"
class ServerPool : public Debuggable
class ServerPool
{
private:
class PooledConnection : public NNTPConnection
@@ -66,9 +65,6 @@ private:
void NormalizeLevels();
static bool CompareServers(NewsServer* pServer1, NewsServer* pServer2);
protected:
virtual void LogDebugInfo();
public:
ServerPool();
~ServerPool();
@@ -82,6 +78,8 @@ public:
void CloseUnusedConnections();
void Changed();
int GetGeneration() { return m_iGeneration; }
void LogDebugInfo();
};
#endif

View File

View File

View File

View File

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,9 +45,9 @@
#include "Log.h"
#include "Util.h"
#include "ParCoordinator.h"
#include "Options.h"
extern Options* g_pOptions;
extern DownloadQueueHolder* g_pDownloadQueueHolder;
void UnpackController::FileList::Clear()
{
@@ -86,7 +86,7 @@ void UnpackController::StartJob(PostInfo* pPostInfo)
void UnpackController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
m_szDestDir[1024-1] = '\0';
@@ -109,7 +109,7 @@ void UnpackController::Run()
m_szPassword[1024-1] = '\0';
}
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
snprintf(m_szInfoName, 1024, "unpack for %s", m_szName);
m_szInfoName[1024-1] = '\0';
@@ -206,7 +206,7 @@ void UnpackController::ExecuteUnrar()
m_bAllOKMessageReceived = false;
m_eUnpacker = upUnrar;
SetProgressLabel("");
int iExitCode = Execute();
SetLogPrefix(NULL);
@@ -397,7 +397,7 @@ bool UnpackController::FileHasRarSignature(const char* szFilename)
int cnt = 0;
FILE* infile;
infile = fopen(szFilename, FOPEN_RB);
infile = fopen(szFilename, "rb");
if (infile)
{
cnt = (int)fread(fileSignature, 1, sizeof(fileSignature), infile);
@@ -444,8 +444,7 @@ bool UnpackController::Cleanup()
if (!Util::MoveFile(szSrcFile, szDstFile))
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not move file %s to %s: %s", szSrcFile, szDstFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
PrintMessage(Message::mkError, "Could not move file %s to %s", szSrcFile, szDstFile);
bOK = false;
}
@@ -454,10 +453,9 @@ bool UnpackController::Cleanup()
}
}
char szErrBuf[256];
if (bOK && !Util::DeleteDirectoryWithContent(m_szUnpackDir, szErrBuf, sizeof(szErrBuf)))
if (bOK && !Util::DeleteDirectoryWithContent(m_szUnpackDir))
{
PrintMessage(Message::mkError, "Could not delete temporary directory %s: %s", m_szUnpackDir, szErrBuf);
PrintMessage(Message::mkError, "Could not remove temporary directory %s", m_szUnpackDir);
}
if (!m_bUnpackOK && m_bFinalDirCreated)
@@ -492,8 +490,7 @@ bool UnpackController::Cleanup()
if (remove(szFullFilename) != 0)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not delete file %s: %s", szFullFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
}
}
}
@@ -623,9 +620,9 @@ void UnpackController::Stop()
void UnpackController::SetProgressLabel(const char* szProgressLabel)
{
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
m_pPostInfo->SetProgressLabel(szProgressLabel);
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
}
@@ -643,7 +640,7 @@ void MoveController::StartJob(PostInfo* pPostInfo)
void MoveController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
@@ -660,7 +657,7 @@ void MoveController::Run()
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szDestDir, 1024);
m_szDestDir[1024-1] = '\0';
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
info("Moving completed files for %s", szNZBName);
@@ -672,10 +669,10 @@ void MoveController::Run()
{
info("%s successful", szInfoName);
// save new dest dir
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir);
m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msSuccess);
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
}
else
{
@@ -713,15 +710,15 @@ bool MoveController::MoveFiles()
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: %s", szSrcFile, szDstFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
PrintMessage(Message::mkError, "Could not move file %s to %s! Errcode: %i", szSrcFile, szDstFile, errno);
bOK = false;
}
}
}
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir, szErrBuf, sizeof(szErrBuf)))
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir))
{
PrintMessage(Message::mkError, "Could not delete intermediate directory %s: %s", m_szInterDir, szErrBuf);
PrintMessage(Message::mkError, "Could not remove intermediate directory %s", m_szInterDir);
}
return bOK;
@@ -742,7 +739,7 @@ void CleanupController::StartJob(PostInfo* pPostInfo)
void CleanupController::Run()
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
g_pDownloadQueueHolder->LockQueue();
char szNZBName[1024];
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
@@ -768,7 +765,7 @@ void CleanupController::Run()
m_szFinalDir[0] = '\0';
}
DownloadQueue::Unlock();
g_pDownloadQueueHolder->UnlockQueue();
info("Cleaning up %s", szNZBName);
@@ -809,11 +806,36 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
*bDeleted = false;
bool bOK = true;
ExtList extList;
// split ExtCleanupDisk into tokens and create a list
char* szExtCleanupDisk = strdup(g_pOptions->GetExtCleanupDisk());
char* saveptr;
char* szExt = strtok_r(szExtCleanupDisk, ",; ", &saveptr);
while (szExt)
{
extList.push_back(szExt);
szExt = strtok_r(NULL, ",; ", &saveptr);
}
DirBrowser dir(szDestDir);
while (const char* filename = dir.Next())
{
// check file extension
bool bDeleteIt = Util::MatchFileExt(filename, g_pOptions->GetExtCleanupDisk(), ",;");
int iFilenameLen = strlen(filename);
bool bDeleteIt = false;
for (ExtList::iterator it = extList.begin(); it != extList.end(); it++)
{
const char* szExt = *it;
int iExtLen = strlen(szExt);
if (iFilenameLen >= iExtLen && !strcasecmp(szExt, filename + iFilenameLen - iExtLen))
{
bDeleteIt = true;
break;
}
}
if (bDeleteIt)
{
@@ -824,8 +846,7 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
if (remove(szFullFilename) != 0)
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not delete file %s: %s", szFullFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
PrintMessage(Message::mkError, "Could not delete file %s! Errcode: %i", szFullFilename, errno);
bOK = false;
}
@@ -833,5 +854,7 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted)
}
}
free(szExtCleanupDisk);
return bOK;
}

View File

@@ -31,7 +31,7 @@
#include "Log.h"
#include "Thread.h"
#include "DownloadInfo.h"
#include "Script.h"
#include "ScriptController.h"
class UnpackController : public Thread, public ScriptController
{
@@ -119,6 +119,8 @@ private:
bool Cleanup(const char* szDestDir, bool *bDeleted);
typedef std::deque<char*> ExtList;
public:
virtual void Run();
static void StartJob(PostInfo* pPostInfo);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-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
@@ -44,13 +44,19 @@
#include "UrlCoordinator.h"
#include "Options.h"
#include "WebDownloader.h"
#include "DiskState.h"
#include "Log.h"
#include "Util.h"
#include "NZBFile.h"
#include "QueueCoordinator.h"
#include "Scanner.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
extern QueueCoordinator* g_pQueueCoordinator;
extern Scanner* g_pScanner;
UrlDownloader::UrlDownloader() : WebDownloader()
{
m_szCategory = NULL;
@@ -93,7 +99,7 @@ void UrlDownloader::ProcessHeader(const char* szLine)
szParamName[100-1] = '\0';
char* szVal = WebUtil::Latin1ToUtf8(szValue);
m_pNZBInfo->GetParameters()->SetParameter(szParamName, szVal);
m_ppParameters.SetParameter(szParamName, szVal);
free(szVal);
}
free(szModLine);
@@ -105,8 +111,7 @@ UrlCoordinator::UrlCoordinator()
debug("Creating UrlCoordinator");
m_bHasMoreJobs = true;
g_pLog->RegisterDebuggable(this);
m_bForce = false;
}
UrlCoordinator::~UrlCoordinator()
@@ -114,8 +119,6 @@ UrlCoordinator::~UrlCoordinator()
debug("Destroying UrlCoordinator");
// Cleanup
g_pLog->UnregisterDebuggable(this);
debug("Deleting UrlDownloaders");
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
@@ -123,6 +126,14 @@ UrlCoordinator::~UrlCoordinator()
}
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");
}
@@ -130,36 +141,34 @@ void UrlCoordinator::Run()
{
debug("Entering UrlCoordinator-loop");
while (!DownloadQueue::IsLoaded())
{
usleep(20 * 1000);
}
int iResetCounter = 0;
while (!IsStopped())
{
bool bDownloadStarted = false;
if (!g_pOptions->GetPauseDownload() || g_pOptions->GetUrlForce())
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()) || m_bForce || g_pOptions->GetUrlForce())
{
// start download for next URL
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
if ((int)m_ActiveDownloads.size() < g_pOptions->GetUrlConnections())
{
NZBInfo* pNZBInfo = GetNextUrl(pDownloadQueue);
bool bHasMoreUrls = pNZBInfo != NULL;
UrlInfo* pUrlInfo;
bool bHasMoreUrls = GetNextUrl(pDownloadQueue, pUrlInfo);
bool bUrlDownloadsRunning = !m_ActiveDownloads.empty();
m_bHasMoreJobs = bHasMoreUrls || bUrlDownloadsRunning;
if (bHasMoreUrls && !IsStopped())
{
StartUrlDownload(pNZBInfo);
bDownloadStarted = true;
StartUrlDownload(pUrlInfo);
}
if (!bHasMoreUrls)
{
m_bForce = false;
}
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
}
int iSleepInterval = bDownloadStarted ? 0 : 100;
int iSleepInterval = 100;
usleep(iSleepInterval * 1000);
iResetCounter += iSleepInterval;
@@ -176,9 +185,9 @@ void UrlCoordinator::Run()
bool completed = false;
while (!completed)
{
DownloadQueue::Lock();
g_pQueueCoordinator->LockQueue();
completed = m_ActiveDownloads.size() == 0;
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
usleep(100 * 1000);
ResetHangingDownloads();
}
@@ -192,12 +201,12 @@ void UrlCoordinator::Stop()
Thread::Stop();
debug("Stopping UrlDownloads");
DownloadQueue::Lock();
g_pQueueCoordinator->LockQueue();
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
(*it)->Stop();
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
debug("UrlDownloads are notified");
}
@@ -209,8 +218,8 @@ void UrlCoordinator::ResetHangingDownloads()
return;
}
DownloadQueue::Lock();
time_t tm = time(NULL);
g_pQueueCoordinator->LockQueue();
time_t tm = ::time(NULL);
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
{
@@ -218,12 +227,12 @@ void UrlCoordinator::ResetHangingDownloads()
if (tm - pUrlDownloader->GetLastUpdateTime() > TimeOut &&
pUrlDownloader->GetStatus() == UrlDownloader::adRunning)
{
NZBInfo* pNZBInfo = pUrlDownloader->GetNZBInfo();
UrlInfo* pUrlInfo = pUrlDownloader->GetUrlInfo();
debug("Terminating hanging download %s", pUrlDownloader->GetInfoName());
if (pUrlDownloader->Terminate())
{
error("Terminated hanging download %s", pUrlDownloader->GetInfoName());
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
pUrlInfo->SetStatus(UrlInfo::aiUndefined);
}
else
{
@@ -238,87 +247,86 @@ void UrlCoordinator::ResetHangingDownloads()
it++;
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
}
void UrlCoordinator::LogDebugInfo()
{
info(" ---------- UrlCoordinator");
debug(" UrlCoordinator");
debug(" ----------------");
DownloadQueue::Lock();
info(" Active Downloads: %i", m_ActiveDownloads.size());
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();
}
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
}
void UrlCoordinator::AddUrlToQueue(NZBInfo* pNZBInfo, bool bAddTop)
void UrlCoordinator::AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst)
{
debug("Adding NZB-URL to queue");
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
if (bAddTop)
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
pDownloadQueue->GetUrlQueue()->push_back(pUrlInfo);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
pDownloadQueue->GetQueue()->push_front(pNZBInfo);
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
}
else
if (pUrlInfo->GetForce())
{
pDownloadQueue->GetQueue()->push_back(pNZBInfo);
m_bForce = true;
}
pDownloadQueue->Save();
DownloadQueue::Unlock();
g_pQueueCoordinator->UnlockQueue();
}
/*
* Returns next URL for download.
*/
NZBInfo* UrlCoordinator::GetNextUrl(DownloadQueue* pDownloadQueue)
bool UrlCoordinator::GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo)
{
bool bPauseDownload = g_pOptions->GetPauseDownload();
bool bPauseDownload = g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2();
NZBInfo* pNZBInfo = NULL;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
for (UrlQueue::iterator at = pDownloadQueue->GetUrlQueue()->begin(); at != pDownloadQueue->GetUrlQueue()->end(); at++)
{
NZBInfo* pNZBInfo1 = *it;
if (pNZBInfo1->GetKind() == NZBInfo::nkUrl &&
pNZBInfo1->GetUrlStatus() == NZBInfo::lsNone &&
pNZBInfo1->GetDeleteStatus() == NZBInfo::dsNone &&
(!bPauseDownload || g_pOptions->GetUrlForce()) &&
(!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()))
pUrlInfo = *at;
if (pUrlInfo->GetStatus() == 0 && (!bPauseDownload || pUrlInfo->GetForce() || g_pOptions->GetUrlForce()))
{
pNZBInfo = pNZBInfo1;
return true;
break;
}
}
return pNZBInfo;
return false;
}
void UrlCoordinator::StartUrlDownload(NZBInfo* pNZBInfo)
void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
{
debug("Starting new UrlDownloader");
UrlDownloader* pUrlDownloader = new UrlDownloader();
pUrlDownloader->SetAutoDestroy(true);
pUrlDownloader->Attach(this);
pUrlDownloader->SetNZBInfo(pNZBInfo);
pUrlDownloader->SetURL(pNZBInfo->GetURL());
pUrlDownloader->SetForce(g_pOptions->GetUrlForce());
pNZBInfo->SetActiveDownloads(1);
pUrlDownloader->SetUrlInfo(pUrlInfo);
pUrlDownloader->SetURL(pUrlInfo->GetURL());
pUrlDownloader->SetForce(pUrlInfo->GetForce() || g_pOptions->GetUrlForce());
char tmp[1024];
pNZBInfo->MakeNiceUrlName(pNZBInfo->GetURL(), pNZBInfo->GetFilename(), tmp, 1024);
pUrlInfo->GetName(tmp, 1024);
pUrlDownloader->SetInfoName(tmp);
snprintf(tmp, 1024, "%surl-%i.tmp", g_pOptions->GetTempDir(), pNZBInfo->GetID());
snprintf(tmp, 1024, "%surl-%i.tmp", g_pOptions->GetTempDir(), pUrlInfo->GetID());
tmp[1024-1] = '\0';
pUrlDownloader->SetOutputFilename(tmp);
pNZBInfo->SetUrlStatus(NZBInfo::lsRunning);
pUrlInfo->SetStatus(UrlInfo::aiRunning);
m_ActiveDownloads.push_back(pUrlDownloader);
pUrlDownloader->Start();
@@ -341,8 +349,20 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
{
debug("URL downloaded");
bool bRetry = pUrlDownloader->GetStatus() == WebDownloader::adRetry;
NZBInfo* pNZBInfo = pUrlDownloader->GetNZBInfo();
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())
@@ -352,7 +372,7 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
}
else
{
strncpy(filename, Util::BaseFileName(pNZBInfo->GetURL()), 1024);
strncpy(filename, Util::BaseFileName(pUrlInfo->GetURL()), 1024);
filename[1024-1] = '\0';
// TODO: decode URL escaping
@@ -362,9 +382,8 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
debug("Filename: [%s]", filename);
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
// delete Download from active jobs
g_pQueueCoordinator->LockQueue();
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
UrlDownloader* pa = *it;
@@ -374,124 +393,62 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
break;
}
}
pNZBInfo->SetActiveDownloads(0);
g_pQueueCoordinator->UnlockQueue();
if (pNZBInfo->GetDeleting())
{
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
pNZBInfo->SetDeleting(false);
}
else if (pUrlDownloader->GetStatus() == WebDownloader::adFinished)
{
pNZBInfo->SetUrlStatus(NZBInfo::lsFinished);
}
else if (pUrlDownloader->GetStatus() == WebDownloader::adFailed)
{
pNZBInfo->SetUrlStatus(NZBInfo::lsFailed);
}
else if (pUrlDownloader->GetStatus() == WebDownloader::adRetry)
{
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
}
Aspect aspect = { eaUrlCompleted, pUrlInfo };
Notify(&aspect);
if (!bRetry)
{
DownloadQueue::Aspect aspect = { DownloadQueue::eaUrlCompleted, pDownloadQueue, pNZBInfo, NULL };
pDownloadQueue->Notify(&aspect);
}
DownloadQueue::Unlock();
if (bRetry)
{
return;
}
if (pNZBInfo->GetUrlStatus() == NZBInfo::lsFinished)
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished)
{
// add nzb-file to download queue
Scanner::EAddStatus eAddStatus = g_pScanner->AddExternalFile(
!Util::EmptyStr(pNZBInfo->GetFilename()) ? pNZBInfo->GetFilename() : filename,
!Util::EmptyStr(pNZBInfo->GetCategory()) ? pNZBInfo->GetCategory() : pUrlDownloader->GetCategory(),
pNZBInfo->GetPriority(), pNZBInfo->GetDupeKey(), pNZBInfo->GetDupeScore(), pNZBInfo->GetDupeMode(),
pNZBInfo->GetParameters(), false, pNZBInfo->GetAddUrlPaused(), pNZBInfo,
pUrlDownloader->GetOutputFilename(), NULL, 0, NULL);
pUrlInfo->GetNZBFilename() && strlen(pUrlInfo->GetNZBFilename()) > 0 ? pUrlInfo->GetNZBFilename() : filename,
strlen(pUrlInfo->GetCategory()) > 0 ? pUrlInfo->GetCategory() : pUrlDownloader->GetCategory(),
pUrlInfo->GetPriority(), pUrlInfo->GetDupeKey(), pUrlInfo->GetDupeScore(), pUrlInfo->GetDupeMode(),
pUrlDownloader->GetParameters(), pUrlInfo->GetAddTop(), pUrlInfo->GetAddPaused(),
pUrlDownloader->GetOutputFilename(), NULL, 0);
if (eAddStatus == Scanner::asSuccess)
if (eAddStatus != Scanner::asSuccess)
{
// if scanner has successfully added nzb-file to queue, our pNZBInfo is
// already removed from queue and destroyed
return;
pUrlInfo->SetStatus(eAddStatus == Scanner::asFailed ? UrlInfo::aiScanFailed : UrlInfo::aiScanSkipped);
}
}
// delete Download from Url Queue
if (pUrlInfo->GetStatus() != UrlInfo::aiRetry)
{
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
{
UrlInfo* pa = *it;
if (pa == pUrlInfo)
{
pDownloadQueue->GetUrlQueue()->erase(it);
break;
}
}
pNZBInfo->SetUrlStatus(eAddStatus == Scanner::asFailed ? NZBInfo::lsScanFailed : NZBInfo::lsScanSkipped);
}
bool bDeleteObj = true;
// the rest of function is only for failed URLs or for failed scans
pDownloadQueue = DownloadQueue::Lock();
// delete URL from queue
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
bool bDeleteObj = true;
// add failed URL to history
if (g_pOptions->GetKeepHistory() > 0 &&
pNZBInfo->GetUrlStatus() != NZBInfo::lsFinished &&
!pNZBInfo->GetAvoidHistory())
{
HistoryInfo* pHistoryInfo = new HistoryInfo(pNZBInfo);
pHistoryInfo->SetTime(time(NULL));
pDownloadQueue->GetHistory()->push_front(pHistoryInfo);
bDeleteObj = false;
}
pDownloadQueue->Save();
DownloadQueue::Unlock();
if (bDeleteObj)
{
delete pNZBInfo;
}
}
bool UrlCoordinator::DeleteQueueEntry(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bAvoidHistory)
{
if (pNZBInfo->GetActiveDownloads() > 0)
{
info("Deleting active URL %s", pNZBInfo->GetName());
pNZBInfo->SetDeleting(true);
pNZBInfo->SetAvoidHistory(bAvoidHistory);
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
if (g_pOptions->GetKeepHistory() > 0 && pUrlInfo->GetStatus() != UrlInfo::aiFinished)
{
UrlDownloader* pUrlDownloader = *it;
if (pUrlDownloader->GetNZBInfo() == pNZBInfo)
{
pUrlDownloader->Stop();
return true;
}
}
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 (bDeleteObj)
{
delete pUrlInfo;
}
}
info("Deleting URL %s", pNZBInfo->GetName());
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
if (g_pOptions->GetKeepHistory() > 0 && !bAvoidHistory)
{
HistoryInfo* pHistoryInfo = new HistoryInfo(pNZBInfo);
pHistoryInfo->SetTime(time(NULL));
pDownloadQueue->GetHistory()->push_front(pHistoryInfo);
}
else
{
delete pNZBInfo;
}
return true;
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-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
@@ -30,7 +30,6 @@
#include <list>
#include <time.h>
#include "Log.h"
#include "Thread.h"
#include "WebDownloader.h"
#include "DownloadInfo.h"
@@ -38,24 +37,31 @@
class UrlDownloader;
class UrlCoordinator : public Thread, public Observer, public Debuggable
class UrlCoordinator : public Thread, public Observer, public Subject
{
private:
public:
typedef std::list<UrlDownloader*> ActiveDownloads;
enum EAspectAction
{
eaUrlAdded,
eaUrlCompleted
};
struct Aspect
{
EAspectAction eAction;
UrlInfo* pUrlInfo;
};
private:
ActiveDownloads m_ActiveDownloads;
bool m_bHasMoreJobs;
bool m_bForce;
NZBInfo* GetNextUrl(DownloadQueue* pDownloadQueue);
void StartUrlDownload(NZBInfo* pNZBInfo);
bool GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo);
void StartUrlDownload(UrlInfo* pUrlInfo);
void UrlCompleted(UrlDownloader* pUrlDownloader);
void ResetHangingDownloads();
protected:
virtual void LogDebugInfo();
public:
UrlCoordinator();
virtual ~UrlCoordinator();
@@ -64,16 +70,18 @@ public:
void Update(Subject* pCaller, void* pAspect);
// Editing the queue
void AddUrlToQueue(NZBInfo* pNZBInfo, bool bAddTop);
void AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst);
bool HasMoreJobs() { return m_bHasMoreJobs; }
bool DeleteQueueEntry(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bAvoidHistory);
void LogDebugInfo();
};
class UrlDownloader : public WebDownloader
{
private:
NZBInfo* m_pNZBInfo;
UrlInfo* m_pUrlInfo;
char* m_szCategory;
NZBParameterList m_ppParameters;
protected:
virtual void ProcessHeader(const char* szLine);
@@ -81,9 +89,10 @@ protected:
public:
UrlDownloader();
~UrlDownloader();
void SetNZBInfo(NZBInfo* pNZBInfo) { m_pNZBInfo = pNZBInfo; }
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
void SetUrlInfo(UrlInfo* pUrlInfo) { m_pUrlInfo = pUrlInfo; }
UrlInfo* GetUrlInfo() { return m_pUrlInfo; }
const char* GetCategory() { return m_szCategory; }
NZBParameterList* GetParameters() { return &m_ppParameters; }
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -144,15 +144,15 @@ DirBrowser::DirBrowser(const char* szPath)
char szMask[MAX_PATH + 1];
snprintf(szMask, MAX_PATH + 1, "%s%c*.*", szPath, (int)PATH_SEPARATOR);
szMask[MAX_PATH] = '\0';
m_hFile = FindFirstFile(szMask, &m_FindData);
m_hFile = _findfirst(szMask, &m_FindData);
m_bFirst = true;
}
DirBrowser::~DirBrowser()
{
if (m_hFile != INVALID_HANDLE_VALUE)
if (m_hFile != -1L)
{
FindClose(m_hFile);
_findclose(m_hFile);
}
}
@@ -161,16 +161,16 @@ const char* DirBrowser::Next()
bool bOK = false;
if (m_bFirst)
{
bOK = m_hFile != INVALID_HANDLE_VALUE;
bOK = m_hFile != -1L;
m_bFirst = false;
}
else
{
bOK = FindNextFile(m_hFile, &m_FindData) != 0;
bOK = _findnext(m_hFile, &m_FindData) == 0;
}
if (bOK)
{
return m_FindData.cFileName;
return m_FindData.name;
}
return NULL;
}
@@ -386,7 +386,7 @@ bool Util::DirEmpty(const char* szDirFilename)
bool Util::LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength)
{
FILE* pFile = fopen(szFileName, FOPEN_RB);
FILE* pFile = fopen(szFileName, "rb");
if (!pFile)
{
return false;
@@ -418,7 +418,7 @@ bool Util::LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBuff
bool Util::SaveBufferIntoFile(const char* szFileName, const char* szBuffer, int iBufLen)
{
FILE* pFile = fopen(szFileName, FOPEN_WB);
FILE* pFile = fopen(szFileName, "wb");
if (!pFile)
{
return false;
@@ -449,7 +449,7 @@ bool Util::CreateSparseFile(const char* szFilename, int iSize)
}
#else
// create file
FILE* pFile = fopen(szFilename, FOPEN_AB);
FILE* pFile = fopen(szFilename, "ab");
if (pFile)
{
fclose(pFile);
@@ -459,7 +459,7 @@ bool Util::CreateSparseFile(const char* szFilename, int iSize)
// 1) set file size using function "truncate" (it is fast, if works)
truncate(szFilename, iSize);
// check if it worked
pFile = fopen(szFilename, FOPEN_AB);
pFile = fopen(szFilename, "ab");
if (pFile)
{
fseek(pFile, 0, SEEK_END);
@@ -469,7 +469,7 @@ bool Util::CreateSparseFile(const char* szFilename, int iSize)
// 2) truncate did not work, expanding the file by writing in it (it is slow)
fclose(pFile);
truncate(szFilename, 0);
pFile = fopen(szFilename, FOPEN_AB);
pFile = fopen(szFilename, "ab");
char c = '0';
fwrite(&c, 1, iSize, pFile);
bOK = ftell(pFile) == iSize;
@@ -484,7 +484,7 @@ bool Util::TruncateFile(const char* szFilename, int iSize)
{
bool bOK = false;
#ifdef WIN32
FILE *file = fopen(szFilename, FOPEN_RBP);
FILE *file = fopen(szFilename, "r+b");
fseek(file, iSize, SEEK_SET);
bOK = SetEndOfFile((HANDLE)_get_osfhandle(_fileno(file))) != 0;
fclose(file);
@@ -497,7 +497,7 @@ bool Util::TruncateFile(const char* szFilename, int iSize)
//replace bad chars in filename
void Util::MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSlashes)
{
const char* szReplaceChars = bAllowSlashes ? ":*?\"><\n\r\t" : "\\/:*?\"><\n\r\t";
const char* szReplaceChars = bAllowSlashes ? ":*?\"><'\n\r\t" : "\\/:*?\"><'\n\r\t";
char* p = szFilename;
while (*p)
{
@@ -654,15 +654,15 @@ bool Util::MoveFile(const char* szSrcFilename, const char* szDstFilename)
bool bOK = rename(szSrcFilename, szDstFilename) == 0;
#ifndef WIN32
if (!bOK && errno == EXDEV)
if (!bOK && (errno == EXDEV))
{
FILE* infile = fopen(szSrcFilename, FOPEN_RB);
FILE* infile = fopen(szSrcFilename, "rb");
if (!infile)
{
return false;
}
FILE* outfile = fopen(szDstFilename, FOPEN_WBP);
FILE* outfile = fopen(szDstFilename, "wb+");
if (!outfile)
{
fclose(infile);
@@ -692,22 +692,9 @@ bool Util::MoveFile(const char* szSrcFilename, const char* szDstFilename)
bool Util::FileExists(const char* szFilename)
{
#ifdef WIN32
// we use a native windows call because c-lib function "stat" fails on windows if file date is invalid
WIN32_FIND_DATA findData;
HANDLE handle = FindFirstFile(szFilename, &findData);
if (handle != INVALID_HANDLE_VALUE)
{
bool bExists = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
FindClose(handle);
return bExists;
}
return false;
#else
struct stat buffer;
bool bExists = !stat(szFilename, &buffer) && S_ISREG(buffer.st_mode);
return bExists;
#endif
}
bool Util::FileExists(const char* szPath, const char* szFilenameWithoutPath)
@@ -721,22 +708,9 @@ bool Util::FileExists(const char* szPath, const char* szFilenameWithoutPath)
bool Util::DirectoryExists(const char* szDirFilename)
{
#ifdef WIN32
// we use a native windows call because c-lib function "stat" fails on windows if file date is invalid
WIN32_FIND_DATA findData;
HANDLE handle = FindFirstFile(szDirFilename, &findData);
if (handle != INVALID_HANDLE_VALUE)
{
bool bExists = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
FindClose(handle);
return bExists;
}
return false;
#else
struct stat buffer;
bool bExists = !stat(szDirFilename, &buffer) && S_ISDIR(buffer.st_mode);
return bExists;
#endif
}
bool Util::CreateDirectory(const char* szDirFilename)
@@ -748,18 +722,14 @@ bool Util::CreateDirectory(const char* szDirFilename)
bool Util::RemoveDirectory(const char* szDirFilename)
{
#ifdef WIN32
return _rmdir(szDirFilename) == 0;
return ::RemoveDirectory(szDirFilename);
#else
return remove(szDirFilename) == 0;
#endif
}
bool Util::DeleteDirectoryWithContent(const char* szDirFilename, char* szErrBuf, int iBufSize)
bool Util::DeleteDirectoryWithContent(const char* szDirFilename)
{
*szErrBuf = '\0';
char szSysErrStr[256];
bool bDel = false;
bool bOK = true;
DirBrowser dir(szDirFilename);
@@ -773,27 +743,16 @@ bool Util::DeleteDirectoryWithContent(const char* szDirFilename, char* szErrBuf,
{
if (Util::DirectoryExists(szFullFilename))
{
bDel = DeleteDirectoryWithContent(szFullFilename, szSysErrStr, sizeof(szSysErrStr));
bOK &= DeleteDirectoryWithContent(szFullFilename);
}
else
{
bDel = remove(szFullFilename) == 0;
}
bOK &= bDel;
if (!bDel && !*szErrBuf)
{
snprintf(szErrBuf, iBufSize, "could not delete %s: %s", szFullFilename, GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
bOK &= remove(szFullFilename) == 0;
}
}
}
bDel = RemoveDirectory(szDirFilename);
bOK &= bDel;
if (!bDel && !*szErrBuf)
{
GetLastErrorMessage(szErrBuf, iBufSize);
}
return bOK;
return bOK && RemoveDirectory(szDirFilename);
}
long long Util::FileSize(const char* szFilename)
@@ -958,23 +917,6 @@ bool Util::SameFilename(const char* szFilename1, const char* szFilename2)
#endif
}
bool Util::MatchFileExt(const char* szFilename, const char* szExtensionList, const char* szListSeparator)
{
int iFilenameLen = strlen(szFilename);
Tokenizer tok(szExtensionList, szListSeparator);
while (const char* szExt = tok.Next())
{
int iExtLen = strlen(szExt);
if (iFilenameLen >= iExtLen && !strcasecmp(szExt, szFilename + iFilenameLen - iExtLen))
{
return true;
}
}
return false;
}
#ifndef WIN32
void Util::FixExecPermission(const char* szFilename)
{
@@ -1216,76 +1158,6 @@ bool Util::RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName,
}
#endif
/* From boost */
inline int32_t is_leap(int32_t year)
{
if(year % 400 == 0)
return 1;
if(year % 100 == 0)
return 0;
if(year % 4 == 0)
return 1;
return 0;
}
inline int32_t days_from_0(int32_t year)
{
year--;
return 365 * year + (year / 400) - (year/100) + (year / 4);
}
inline int32_t days_from_1970(int32_t year)
{
static const int days_from_0_to_1970 = days_from_0(1970);
return days_from_0(year) - days_from_0_to_1970;
}
inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day)
{
static const int32_t days[2][12] =
{
{ 0,31,59,90,120,151,181,212,243,273,304,334},
{ 0,31,60,91,121,152,182,213,244,274,305,335}
};
return days[is_leap(year)][month-1] + day - 1;
}
inline time_t internal_timegm(tm const *t)
{
int year = t->tm_year + 1900;
int month = t->tm_mon;
if(month > 11)
{
year += month/12;
month %= 12;
}
else if(month < 0)
{
int years_diff = (-month + 11)/12;
year -= years_diff;
month+=12 * years_diff;
}
month++;
int day = t->tm_mday;
int day_of_year = days_from_1jan(year,month,day);
int days_since_epoch = days_from_1970(year) + day_of_year;
time_t seconds_in_day = 3600 * 24;
time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec;
return result;
}
// prevent PC from going to sleep
void Util::SetStandByMode(bool bStandBy)
{
#ifdef WIN32
SetThreadExecutionState((bStandBy ? 0 : ES_SYSTEM_REQUIRED) | ES_CONTINUOUS);
#endif
}
time_t Util::Timegm(tm const *t)
{
return internal_timegm(t);
}
unsigned int WebUtil::DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer)
{
@@ -1911,8 +1783,9 @@ time_t WebUtil::ParseRfc822DateTime(const char* szDateTimeStr)
rawtime.tm_min = minutes;
rawtime.tm_sec = seconds;
time_t enctime = Util::Timegm(&rawtime);
enctime -= (zonehours * 60 + (zonehours > 0 ? zoneminutes : -zoneminutes)) * 60;
time_t enctime = mktime(&rawtime);
enctime = enctime - (zonehours * 60 + (zonehours > 0 ? zoneminutes : -zoneminutes)) * 60;
return enctime;
}
@@ -2369,59 +2242,4 @@ GUnzipStream::EStatus GUnzipStream::Read(const void **pOutputBuffer, int *iOutpu
return zlError;
}
Tokenizer::Tokenizer(const char* szDataString, const char* szSeparators)
{
// an optimization to avoid memory allocation for short data string (shorten than 1024 chars)
int iLen = strlen(szDataString);
if (iLen < sizeof(m_szDefaultBuf) - 1)
{
strncpy(m_szDefaultBuf, szDataString, sizeof(m_szDefaultBuf));
m_szDefaultBuf[1024- 1] = '\0';
m_szDataString = m_szDefaultBuf;
m_bInplaceBuf = true;
}
else
{
m_szDataString = strdup(szDataString);
m_bInplaceBuf = false;
}
m_szSeparators = szSeparators;
m_szSavePtr = NULL;
m_bWorking = false;
}
Tokenizer::Tokenizer(char* szDataString, const char* szSeparators, bool bInplaceBuf)
{
m_szDataString = bInplaceBuf ? szDataString : strdup(szDataString);
m_szSeparators = szSeparators;
m_szSavePtr = NULL;
m_bWorking = false;
m_bInplaceBuf = bInplaceBuf;
}
Tokenizer::~Tokenizer()
{
if (!m_bInplaceBuf)
{
free(m_szDataString);
}
}
char* Tokenizer::Next()
{
char* szToken = NULL;
while (!szToken || !*szToken)
{
szToken = strtok_r(m_bWorking ? NULL : m_szDataString, m_szSeparators, &m_szSavePtr);
m_bWorking = true;
if (!szToken)
{
return NULL;
}
szToken = Util::Trim(szToken);
}
return szToken;
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-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
@@ -33,8 +33,6 @@
#include <dirent.h>
#endif
#include <time.h>
#ifdef WIN32
extern int optind, opterr;
extern char *optarg;
@@ -45,8 +43,8 @@ class DirBrowser
{
private:
#ifdef WIN32
WIN32_FIND_DATA m_FindData;
HANDLE m_hFile;
struct _finddata_t m_FindData;
intptr_t m_hFile;
bool m_bFirst;
#else
DIR* m_pDir;
@@ -72,7 +70,7 @@ public:
const char* GetBuffer() { return m_szBuffer; }
};
class Util
class Util
{
public:
@@ -90,7 +88,7 @@ public:
static bool DirectoryExists(const char* szDirFilename);
static bool CreateDirectory(const char* szDirFilename);
static bool RemoveDirectory(const char* szDirFilename);
static bool DeleteDirectoryWithContent(const char* szDirFilename, char* szErrBuf, int iBufSize);
static bool DeleteDirectoryWithContent(const char* szDirFilename);
static bool ForceDirectories(const char* szPath, char* szErrBuf, int iBufSize);
static bool GetCurrentDirectory(char* szBuffer, int iBufSize);
static bool SetCurrentDirectory(const char* szDirFilename);
@@ -105,7 +103,6 @@ public:
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
static void FormatFileSize(char* szBuffer, int iBufLen, long long lFileSize);
static bool SameFilename(const char* szFilename1, const char* szFilename2);
static bool MatchFileExt(const char* szFilename, const char* szExtensionList, const char* szListSeparator);
static char* GetLastErrorMessage(char* szBuffer, int iBufLen);
/*
@@ -146,11 +143,6 @@ public:
static bool RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName, char* szBuffer, int* iBufLen);
#endif
static void SetStandByMode(bool bStandBy);
/* cross platform version of GNU timegm, which is similar to mktime but takes an UTC time as parameter */
static time_t Timegm(tm const *t);
/*
* 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").
@@ -353,21 +345,4 @@ public:
};
#endif
class Tokenizer
{
private:
char m_szDefaultBuf[2014];
char* m_szDataString;
bool m_bInplaceBuf;
const char* m_szSeparators;
char* m_szSavePtr;
bool m_bWorking;
public:
Tokenizer(const char* szDataString, const char* szSeparators);
Tokenizer(char* szDataString, const char* szSeparators, bool bInplaceBuf);
~Tokenizer();
char* Next();
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2012-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-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
@@ -124,19 +124,19 @@ void WebDownloader::Run()
if ((((Status == adFailed) && (iRemainedDownloadRetries > 1)) ||
((Status == adConnectError) && (iRemainedConnectRetries > 1)))
&& !IsStopped() && !(!m_bForce && g_pOptions->GetPauseDownload()))
&& !IsStopped() && !(!m_bForce && (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) &&
!(!m_bForce && g_pOptions->GetPauseDownload()))
!(!m_bForce && (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())))
{
usleep(100 * 1000);
msec += 100;
}
}
if (IsStopped() || (!m_bForce && g_pOptions->GetPauseDownload()))
if (IsStopped() || (!m_bForce && (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())))
{
Status = adRetry;
break;
@@ -298,15 +298,7 @@ void WebDownloader::SendHeaders(URL *pUrl)
tmp[1024-1] = '\0';
m_pConnection->WriteLine(tmp);
if ((!strcasecmp(pUrl->GetProtocol(), "http") && (pUrl->GetPort() == 80 || pUrl->GetPort() == 0)) ||
(!strcasecmp(pUrl->GetProtocol(), "https") && (pUrl->GetPort() == 443 || pUrl->GetPort() == 0)))
{
snprintf(tmp, 1024, "Host: %s\r\n", pUrl->GetHost());
}
else
{
snprintf(tmp, 1024, "Host: %s:%i\r\n", pUrl->GetHost(), pUrl->GetPort());
}
snprintf(tmp, 1024, "Host: %s\r\n", pUrl->GetHost());
tmp[1024-1] = '\0';
m_pConnection->WriteLine(tmp);
@@ -658,7 +650,7 @@ bool WebDownloader::PrepareFile()
// prepare file for writing
const char* szFilename = m_szOutputFilename;
m_pOutFile = fopen(szFilename, FOPEN_WB);
m_pOutFile = fopen(szFilename, "wb");
if (!m_pOutFile)
{
error("Could not %s file %s", "create", szFilename);
@@ -681,7 +673,7 @@ void WebDownloader::LogDebugInfo()
ctime_r(&m_tLastUpdateTime, szTime);
#endif
info(" Web-Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(m_szOutputFilename));
debug(" Web-Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(m_szOutputFilename));
}
void WebDownloader::Stop()

View File

@@ -88,7 +88,7 @@ protected:
public:
WebDownloader();
virtual ~WebDownloader();
~WebDownloader();
EStatus GetStatus() { return m_eStatus; }
virtual void Run();
virtual void Stop();

View File

@@ -223,15 +223,20 @@ bool WebProcessor::IsAuthorizedIP(const char* szRemoteAddr)
// split option AuthorizedIP into tokens and check each token
bool bAuthorized = false;
Tokenizer tok(g_pOptions->GetAuthorizedIP(), ",;");
while (const char* szIP = tok.Next())
char* szAuthorizedIP = strdup(g_pOptions->GetAuthorizedIP());
char* saveptr;
char* szIP = strtok_r(szAuthorizedIP, ",;", &saveptr);
while (szIP)
{
if (!strcmp(szIP, szRemoteIP))
szIP = Util::Trim(szIP);
if (szIP[0] != '\0' && !strcmp(szIP, szRemoteIP))
{
bAuthorized = true;
break;
}
szIP = strtok_r(NULL, ",;", &saveptr);
}
free(szAuthorizedIP);
return bAuthorized;
}

View File

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-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -86,14 +86,12 @@ protected:
void BuildErrorResponse(int iErrCode, const char* szErrText, ...);
void BuildBoolResponse(bool bOK);
void BuildIntResponse(int iValue);
void AppendResponse(const char* szPart);
bool IsJson();
bool CheckSafeMethod();
bool NextParamAsInt(int* iValue);
bool NextParamAsBool(bool* bValue);
bool NextParamAsStr(char** szValueBuf);
char* XmlNextValue(char* szXml, const char* szTag, int* pValueLength);
const char* BoolToStr(bool bValue);
char* EncodeStr(const char* szStr);
void DecodeStr(char* szStr);

939
configure vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,10 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(nzbget, 13.0, hugbug@users.sourceforge.net)
AC_INIT(nzbget, 12.0, hugbug@users.sourceforge.net)
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(nzbget, 13.0)
AC_CONFIG_SRCDIR([daemon/main/nzbget.cpp])
AM_INIT_AUTOMAKE(nzbget, 12.0)
AC_CONFIG_SRCDIR([nzbget.cpp])
AC_CONFIG_HEADERS([config.h])
@@ -338,7 +338,7 @@ if test "$ENABLEPARCHECK" = "yes"; then
dnl
dnl check if libpar2 has recent bugfixes-patch
dnl
AC_MSG_CHECKING(whether libpar2 has recent bugfixes)
AC_MSG_CHECKING(whether libpar2 has recent bugfixes-patch (version 2))
AC_TRY_COMPILE(
[#include <libpar2/par2cmdline.h>]
[#include <libpar2/par2repairer.h>]
@@ -352,11 +352,11 @@ if test "$ENABLEPARCHECK" = "yes"; then
if test "$PAR2PATCHV2" = "no" ; then
AC_ARG_ENABLE(libpar2-bugfixes-check,
[AS_HELP_STRING([--disable-libpar2-bugfixes-check], [do not check libpar2 version])],
[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. Please update libpar2 to version 0.4 or newer (http://launchpad.net/libpar2). If you cannot install a newer version of 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 update is highly recommended!])
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
@@ -376,54 +376,12 @@ AC_ARG_ENABLE(tls,
AC_MSG_RESULT($USETLS)
if test "$USETLS" = "yes"; then
AC_ARG_WITH(tlslib,
[AS_HELP_STRING([--with-tlslib=(OpenSSL, GnuTLS)], [TLS/SSL library to use])],
[AS_HELP_STRING([--with-tlslib=(GnuTLS, OpenSSL)], [TLS/SSL library to use])],
[TLSLIB="$withval"])
if test "$TLSLIB" != "GnuTLS" -a "$TLSLIB" != "OpenSSL" -a "$TLSLIB" != ""; then
AC_MSG_ERROR([Invalid argument for option --with-tlslib])
fi
if test "$TLSLIB" = "OpenSSL" -o "$TLSLIB" = ""; then
AC_ARG_WITH(openssl_includes,
[AS_HELP_STRING([--with-openssl-includes=DIR], [OpenSSL include directory])],
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
[INCVAL="yes"],
[INCVAL="no"])
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"],
FOUND=yes
FOUND=no)
fi
AC_CHECK_HEADER(openssl/ssl.h,
FOUND=yes
TLSHEADERS=yes,
FOUND=no)
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; 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),
FOUND=no)
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; then
AC_MSG_ERROR([Couldn't find OpenSSL library])
fi
if test "$FOUND" = "yes"; then
TLSLIB="OpenSSL"
AC_DEFINE([HAVE_OPENSSL],1,[Define to 1 to use OpenSSL library for TLS/SSL-support.])
fi
fi
fi
if test "$TLSLIB" = "GnuTLS" -o "$TLSLIB" = ""; then
INCVAL="${LIBPREF}/include"
LIBVAL="${LIBPREF}/lib"
@@ -458,12 +416,52 @@ if test "$USETLS" = "yes"; then
fi
fi
fi
if test "$TLSLIB" = "OpenSSL" -o "$TLSLIB" = ""; then
AC_ARG_WITH(openssl_includes,
[AS_HELP_STRING([--with-openssl-includes=DIR], [OpenSSL include directory])],
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
[INCVAL="yes"],
[INCVAL="no"])
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
AC_CHECK_HEADER(openssl/ssl.h,
FOUND=yes
TLSHEADERS=yes,
FOUND=no)
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; 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),
FOUND=no)
if test "$FOUND" = "no" -a "$TLSLIB" = "OpenSSL"; then
AC_MSG_ERROR([Couldn't find OpenSSL library])
fi
if test "$FOUND" = "yes"; then
TLSLIB="OpenSSL"
AC_DEFINE([HAVE_OPENSSL],1,[Define to 1 to use OpenSSL library for TLS/SSL-support.])
fi
fi
fi
if test "$TLSLIB" = ""; then
if test "$TLSHEADERS" = ""; then
AC_MSG_ERROR([Couldn't find neither OpenSSL nor GnuTLS headers (ssl.h or gnutls.h)])
AC_MSG_ERROR([Couldn't find neither GnuTLS nor OpenSSL headers (gnutls.h or ssl.h)])
else
AC_MSG_ERROR([Couldn't find neither OpenSSL nor GnuTLS library])
AC_MSG_ERROR([Couldn't find neither GnuTLS nor OpenSSL library])
fi
fi
else

View File

@@ -1,477 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2008-2014 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"
#else
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "nzbget.h"
#include "Scheduler.h"
#include "Options.h"
#include "Log.h"
#include "NewsServer.h"
#include "ServerPool.h"
#include "FeedInfo.h"
#include "FeedCoordinator.h"
#include "QueueScript.h"
extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern FeedCoordinator* g_pFeedCoordinator;
class SchedulerScriptController : public Thread, public NZBScriptController
{
private:
char* m_szScript;
bool m_bExternalProcess;
int m_iTaskID;
void PrepareParams(const char* szScriptName);
void ExecuteExternalProcess();
protected:
virtual void ExecuteScript(Options::Script* pScript);
public:
virtual ~SchedulerScriptController();
virtual void Run();
static void StartScript(const char* szParam, bool bExternalProcess, int iTaskID);
};
Scheduler::Task::Task(int iID, int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand, const char* szParam)
{
m_iID = iID;
m_iHours = iHours;
m_iMinutes = iMinutes;
m_iWeekDaysBits = iWeekDaysBits;
m_eCommand = eCommand;
m_szParam = szParam ? strdup(szParam) : NULL;
m_tLastExecuted = 0;
}
Scheduler::Task::~Task()
{
free(m_szParam);
}
Scheduler::Scheduler()
{
debug("Creating Scheduler");
m_tLastCheck = 0;
m_TaskList.clear();
}
Scheduler::~Scheduler()
{
debug("Destroying Scheduler");
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
delete *it;
}
}
void Scheduler::AddTask(Task* pTask)
{
m_mutexTaskList.Lock();
m_TaskList.push_back(pTask);
m_mutexTaskList.Unlock();
}
bool Scheduler::CompareTasks(Scheduler::Task* pTask1, Scheduler::Task* pTask2)
{
return (pTask1->m_iHours < pTask2->m_iHours) ||
((pTask1->m_iHours == pTask2->m_iHours) && (pTask1->m_iMinutes < pTask2->m_iMinutes));
}
void Scheduler::FirstCheck()
{
m_mutexTaskList.Lock();
m_TaskList.sort(CompareTasks);
m_mutexTaskList.Unlock();
// check all tasks for the last week
time_t tCurrent = time(NULL);
m_tLastCheck = tCurrent - 60*60*24*7;
m_bDetectClockChanges = false;
m_bExecuteProcess = false;
CheckTasks();
}
void Scheduler::IntervalCheck()
{
m_bDetectClockChanges = true;
m_bExecuteProcess = true;
CheckTasks();
CheckScheduledResume();
}
void Scheduler::CheckTasks()
{
PrepareLog();
m_mutexTaskList.Lock();
time_t tCurrent = time(NULL);
if (!m_TaskList.empty())
{
if (m_bDetectClockChanges)
{
// Detect large step changes of system time
time_t tDiff = tCurrent - m_tLastCheck;
if (tDiff > 60*90 || tDiff < -60*90)
{
debug("Reset scheduled tasks (detected clock adjustment greater than 90 minutes)");
m_bExecuteProcess = false;
m_tLastCheck = tCurrent;
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
Task* pTask = *it;
pTask->m_tLastExecuted = 0;
}
}
}
time_t tLocalCurrent = tCurrent + g_pOptions->GetLocalTimeOffset();
time_t tLocalLastCheck = m_tLastCheck + g_pOptions->GetLocalTimeOffset();
tm tmCurrent;
gmtime_r(&tLocalCurrent, &tmCurrent);
tm tmLastCheck;
gmtime_r(&tLocalLastCheck, &tmLastCheck);
tm tmLoop;
memcpy(&tmLoop, &tmLastCheck, sizeof(tmLastCheck));
tmLoop.tm_hour = tmCurrent.tm_hour;
tmLoop.tm_min = tmCurrent.tm_min;
tmLoop.tm_sec = tmCurrent.tm_sec;
time_t tLoop = Util::Timegm(&tmLoop);
while (tLoop <= tLocalCurrent)
{
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
Task* pTask = *it;
if (pTask->m_tLastExecuted != tLoop)
{
tm tmAppoint;
memcpy(&tmAppoint, &tmLoop, sizeof(tmLoop));
tmAppoint.tm_hour = pTask->m_iHours;
tmAppoint.tm_min = pTask->m_iMinutes;
tmAppoint.tm_sec = 0;
time_t tAppoint = Util::Timegm(&tmAppoint);
int iWeekDay = tmAppoint.tm_wday;
if (iWeekDay == 0)
{
iWeekDay = 7;
}
bool bWeekDayOK = pTask->m_iWeekDaysBits == 0 || (pTask->m_iWeekDaysBits & (1 << (iWeekDay - 1)));
bool bDoTask = bWeekDayOK && tLocalLastCheck < tAppoint && tAppoint <= tLocalCurrent;
//debug("TEMP: 1) m_tLastCheck=%i, tLocalCurrent=%i, tLoop=%i, tAppoint=%i, bWeekDayOK=%i, bDoTask=%i", m_tLastCheck, tLocalCurrent, tLoop, tAppoint, (int)bWeekDayOK, (int)bDoTask);
if (bDoTask)
{
ExecuteTask(pTask);
pTask->m_tLastExecuted = tLoop;
}
}
}
tLoop += 60*60*24; // inc day
gmtime_r(&tLoop, &tmLoop);
}
}
m_tLastCheck = tCurrent;
m_mutexTaskList.Unlock();
PrintLog();
}
void Scheduler::ExecuteTask(Task* pTask)
{
const char* szCommandName[] = { "Pause", "Unpause", "Set download rate", "Execute process", "Execute script",
"Pause Scan", "Unpause Scan", "Enable Server", "Disable Server", "Fetch Feed" };
debug("Executing scheduled command: %s", szCommandName[pTask->m_eCommand]);
switch (pTask->m_eCommand)
{
case scDownloadRate:
if (!Util::EmptyStr(pTask->m_szParam))
{
g_pOptions->SetDownloadRate(atoi(pTask->m_szParam) * 1024);
m_bDownloadRateChanged = true;
}
break;
case scPauseDownload:
case scUnpauseDownload:
g_pOptions->SetPauseDownload(pTask->m_eCommand == scPauseDownload);
m_bPauseDownloadChanged = true;
break;
case scScript:
case scProcess:
if (m_bExecuteProcess)
{
SchedulerScriptController::StartScript(pTask->m_szParam, pTask->m_eCommand == scProcess, pTask->m_iID);
}
break;
case scPauseScan:
case scUnpauseScan:
g_pOptions->SetPauseScan(pTask->m_eCommand == scPauseScan);
m_bPauseScanChanged = true;
break;
case scActivateServer:
case scDeactivateServer:
EditServer(pTask->m_eCommand == scActivateServer, pTask->m_szParam);
break;
case scFetchFeed:
if (m_bExecuteProcess)
{
FetchFeed(pTask->m_szParam);
break;
}
}
}
void Scheduler::PrepareLog()
{
m_bDownloadRateChanged = false;
m_bPauseDownloadChanged = false;
m_bPauseScanChanged = false;
m_bServerChanged = false;
}
void Scheduler::PrintLog()
{
if (m_bDownloadRateChanged)
{
info("Scheduler: setting download rate to %i KB/s", g_pOptions->GetDownloadRate() / 1024);
}
if (m_bPauseDownloadChanged)
{
info("Scheduler: %s download", g_pOptions->GetPauseDownload() ? "pausing" : "unpausing");
}
if (m_bPauseScanChanged)
{
info("Scheduler: %s scan", g_pOptions->GetPauseScan() ? "pausing" : "unpausing");
}
if (m_bServerChanged)
{
int index = 0;
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++, index++)
{
NewsServer* pServer = *it;
if (pServer->GetActive() != m_ServerStatusList[index])
{
info("Scheduler: %s %s", pServer->GetActive() ? "activating" : "deactivating", pServer->GetName());
}
}
g_pServerPool->Changed();
}
}
void Scheduler::EditServer(bool bActive, const char* szServerList)
{
Tokenizer tok(szServerList, ",;");
while (const char* szServer = tok.Next())
{
int iID = atoi(szServer);
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
{
NewsServer* pServer = *it;
if ((iID > 0 && pServer->GetID() == iID) ||
!strcasecmp(pServer->GetName(), szServer))
{
if (!m_bServerChanged)
{
// store old server status for logging
m_ServerStatusList.clear();
m_ServerStatusList.reserve(g_pServerPool->GetServers()->size());
for (Servers::iterator it2 = g_pServerPool->GetServers()->begin(); it2 != g_pServerPool->GetServers()->end(); it2++)
{
NewsServer* pServer2 = *it2;
m_ServerStatusList.push_back(pServer2->GetActive());
}
}
m_bServerChanged = true;
pServer->SetActive(bActive);
break;
}
}
}
}
void Scheduler::FetchFeed(const char* szFeedList)
{
Tokenizer tok(szFeedList, ",;");
while (const char* szFeed = tok.Next())
{
int iID = atoi(szFeed);
for (Feeds::iterator it = g_pFeedCoordinator->GetFeeds()->begin(); it != g_pFeedCoordinator->GetFeeds()->end(); it++)
{
FeedInfo* pFeed = *it;
if (pFeed->GetID() == iID ||
!strcasecmp(pFeed->GetName(), szFeed) ||
!strcasecmp("0", szFeed))
{
g_pFeedCoordinator->FetchFeed(!strcasecmp("0", szFeed) ? 0 : pFeed->GetID());
break;
}
}
}
}
void Scheduler::CheckScheduledResume()
{
time_t tResumeTime = g_pOptions->GetResumeTime();
time_t tCurrentTime = time(NULL);
if (tResumeTime > 0 && tCurrentTime >= tResumeTime)
{
info("Autoresume");
g_pOptions->SetResumeTime(0);
g_pOptions->SetPauseDownload(false);
g_pOptions->SetPausePostProcess(false);
g_pOptions->SetPauseScan(false);
}
}
SchedulerScriptController::~SchedulerScriptController()
{
free(m_szScript);
}
void SchedulerScriptController::StartScript(const char* szParam, bool bExternalProcess, int iTaskID)
{
char** argv = NULL;
if (bExternalProcess && !Util::SplitCommandLine(szParam, &argv))
{
error("Could not execute scheduled process-script, failed to parse command line: %s", szParam);
return;
}
SchedulerScriptController* pScriptController = new SchedulerScriptController();
pScriptController->m_bExternalProcess = bExternalProcess;
pScriptController->m_szScript = strdup(szParam);
pScriptController->m_iTaskID = iTaskID;
if (bExternalProcess)
{
pScriptController->SetScript(argv[0]);
pScriptController->SetArgs((const char**)argv, true);
}
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
}
void SchedulerScriptController::Run()
{
if (m_bExternalProcess)
{
ExecuteExternalProcess();
}
else
{
ExecuteScriptList(m_szScript);
}
}
void SchedulerScriptController::ExecuteScript(Options::Script* pScript)
{
if (!pScript->GetSchedulerScript())
{
return;
}
PrintMessage(Message::mkInfo, "Executing scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduler-script %s for Task%i", pScript->GetName(), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void SchedulerScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetIntEnvVar("NZBSP_TASKID", m_iTaskID);
PrepareEnvScript(NULL, szScriptName);
}
void SchedulerScriptController::ExecuteExternalProcess()
{
info("Executing scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scheduled process-script %s for Task%i", Util::BaseFileName(GetScript()), m_iTaskID);
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
char szLogPrefix[1024];
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 1024);
szLogPrefix[1024-1] = '\0';
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
SetLogPrefix(szLogPrefix);
Execute();
}

View File

@@ -1,546 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "nzbget.h"
#include "StatMeter.h"
#include "Options.h"
#include "ServerPool.h"
#include "DiskState.h"
extern ServerPool* g_pServerPool;
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
static const int DAYS_UP_TO_2013_JAN_1 = 15706;
static const int DAYS_IN_TWENTY_YEARS = 366*20;
ServerVolume::ServerVolume()
{
m_BytesPerSeconds.resize(60);
m_BytesPerMinutes.resize(60);
m_BytesPerHours.resize(24);
m_BytesPerDays.resize(0);
m_iFirstDay = 0;
m_tDataTime = 0;
m_lTotalBytes = 0;
m_lCustomBytes = 0;
m_tCustomTime = time(NULL);
m_iSecSlot = 0;
m_iMinSlot = 0;
m_iHourSlot = 0;
m_iDaySlot = 0;
}
void ServerVolume::CalcSlots(time_t tLocCurTime)
{
m_iSecSlot = (int)tLocCurTime % 60;
m_iMinSlot = ((int)tLocCurTime / 60) % 60;
m_iHourSlot = ((int)tLocCurTime % 86400) / 3600;
int iDaysSince1970 = (int)tLocCurTime / 86400;
m_iDaySlot = iDaysSince1970 - DAYS_UP_TO_2013_JAN_1 + 1;
if (0 <= m_iDaySlot && m_iDaySlot < DAYS_IN_TWENTY_YEARS)
{
int iCurDay = iDaysSince1970;
if (m_iFirstDay == 0 || m_iFirstDay > iCurDay)
{
m_iFirstDay = iCurDay;
}
m_iDaySlot = iCurDay - m_iFirstDay;
if (m_iDaySlot + 1 > (int)m_BytesPerDays.size())
{
m_BytesPerDays.resize(m_iDaySlot + 1);
}
}
else
{
m_iDaySlot = -1;
}
}
void ServerVolume::AddData(int iBytes)
{
time_t tCurTime = time(NULL);
time_t tLocCurTime = tCurTime + g_pOptions->GetLocalTimeOffset();
time_t tLocDataTime = m_tDataTime + g_pOptions->GetLocalTimeOffset();
int iLastMinSlot = m_iMinSlot;
int iLastHourSlot = m_iHourSlot;
CalcSlots(tLocCurTime);
if (tLocCurTime != tLocDataTime)
{
// clear seconds/minutes/hours slots if necessary
// also handle the backwards changes of system clock
int iTotalDelta = (int)(tLocCurTime - tLocDataTime);
int iDeltaSign = iTotalDelta >= 0 ? 1 : -1;
iTotalDelta = abs(iTotalDelta);
int iSecDelta = iTotalDelta;
if (iDeltaSign < 0) iSecDelta++;
if (iSecDelta >= 60) iSecDelta = 60;
for (int i = 0; i < iSecDelta; i++)
{
int iNulSlot = m_iSecSlot - i * iDeltaSign;
if (iNulSlot < 0) iNulSlot += 60;
if (iNulSlot >= 60) iNulSlot -= 60;
m_BytesPerSeconds[iNulSlot] = 0;
}
int iMinDelta = iTotalDelta / 60;
if (iDeltaSign < 0) iMinDelta++;
if (abs(iMinDelta) >= 60) iMinDelta = 60;
if (iMinDelta == 0 && m_iMinSlot != iLastMinSlot) iMinDelta = 1;
for (int i = 0; i < iMinDelta; i++)
{
int iNulSlot = m_iMinSlot - i * iDeltaSign;
if (iNulSlot < 0) iNulSlot += 60;
if (iNulSlot >= 60) iNulSlot -= 60;
m_BytesPerMinutes[iNulSlot] = 0;
}
int iHourDelta = iTotalDelta / (60 * 60);
if (iDeltaSign < 0) iHourDelta++;
if (iHourDelta >= 24) iHourDelta = 24;
if (iHourDelta == 0 && m_iHourSlot != iLastHourSlot) iHourDelta = 1;
for (int i = 0; i < iHourDelta; i++)
{
int iNulSlot = m_iHourSlot - i * iDeltaSign;
if (iNulSlot < 0) iNulSlot += 24;
if (iNulSlot >= 24) iNulSlot -= 24;
m_BytesPerHours[iNulSlot] = 0;
}
}
// add bytes to every slot
m_BytesPerSeconds[m_iSecSlot] += iBytes;
m_BytesPerMinutes[m_iMinSlot] += iBytes;
m_BytesPerHours[m_iHourSlot] += iBytes;
if (m_iDaySlot >= 0)
{
m_BytesPerDays[m_iDaySlot] += iBytes;
}
m_lTotalBytes += iBytes;
m_lCustomBytes += iBytes;
m_tDataTime = tCurTime;
}
void ServerVolume::ResetCustom()
{
m_lCustomBytes = 0;
m_tCustomTime = time(NULL);
}
void ServerVolume::LogDebugInfo()
{
info(" ---------- ServerVolume");
char szSec[4000];
szSec[0] = '\0';
for (int i = 0; i < 60; i++)
{
char szNum[20];
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerSeconds[i]);
strncat(szSec, szNum, 4000);
}
info("Secs: %s", szSec);
szSec[0] = '\0';
for (int i = 0; i < 60; i++)
{
char szNum[20];
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerMinutes[i]);
strncat(szSec, szNum, 4000);
}
info("Mins: %s", szSec);
szSec[0] = '\0';
for (int i = 0; i < 24; i++)
{
char szNum[20];
snprintf(szNum, 20, "[%i]=%lli ", i, m_BytesPerHours[i]);
strncat(szSec, szNum, 4000);
}
info("Hours: %s", szSec);
szSec[0] = '\0';
for (int i = 0; i < (int)m_BytesPerDays.size(); i++)
{
char szNum[20];
snprintf(szNum, 20, "[%i]=%lli ", m_iFirstDay + i, m_BytesPerDays[i]);
strncat(szSec, szNum, 4000);
}
info("Days: %s", szSec);
}
StatMeter::StatMeter()
{
debug("Creating StatMeter");
ResetSpeedStat();
m_iAllBytes = 0;
m_tStartDownload = 0;
m_tPausedFrom = 0;
m_bStandBy = true;
m_tStartServer = 0;
m_tLastCheck = 0;
m_tLastTimeOffset = 0;
m_bStatChanged = false;
g_pLog->RegisterDebuggable(this);
}
StatMeter::~StatMeter()
{
debug("Destroying StatMeter");
// Cleanup
g_pLog->UnregisterDebuggable(this);
for (ServerVolumes::iterator it = m_ServerVolumes.begin(); it != m_ServerVolumes.end(); it++)
{
delete *it;
}
debug("StatMeter destroyed");
}
void StatMeter::Init()
{
m_tStartServer = time(NULL);
m_tLastCheck = m_tStartServer;
AdjustTimeOffset();
m_ServerVolumes.resize(1 + g_pServerPool->GetServers()->size());
m_ServerVolumes[0] = new ServerVolume();
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
{
NewsServer* pServer = *it;
m_ServerVolumes[pServer->GetID()] = new ServerVolume();
}
}
void StatMeter::AdjustTimeOffset()
{
time_t tUtcTime = time(NULL);
tm tmSplittedTime;
gmtime_r(&tUtcTime, &tmSplittedTime);
tmSplittedTime.tm_isdst = -1;
time_t tLocTime = mktime(&tmSplittedTime);
time_t tLocalTimeDelta = tUtcTime - tLocTime;
g_pOptions->SetLocalTimeOffset((int)tLocalTimeDelta + g_pOptions->GetTimeCorrection());
m_tLastTimeOffset = tUtcTime;
debug("UTC delta: %i (%i+%i)", g_pOptions->GetLocalTimeOffset(), (int)tLocalTimeDelta, g_pOptions->GetTimeCorrection());
}
/*
* Called once per second.
* - detect large step changes of system time and adjust statistics;
* - save volume stats (if changed).
*/
void StatMeter::IntervalCheck()
{
time_t m_tCurTime = time(NULL);
time_t tDiff = m_tCurTime - m_tLastCheck;
if (tDiff > 60 || tDiff < 0)
{
m_tStartServer += tDiff + 1; // "1" because the method is called once per second
if (m_tStartDownload != 0 && !m_bStandBy)
{
m_tStartDownload += tDiff + 1;
}
AdjustTimeOffset();
}
else if (m_tLastTimeOffset > m_tCurTime ||
m_tCurTime - m_tLastTimeOffset > 60 * 60 * 3 ||
(m_tCurTime - m_tLastTimeOffset > 60 && !m_bStandBy))
{
// checking time zone settings may prevent the device from entering sleep/hibernate mode
// check every minute if not in standby
// check at least every 3 hours even in standby
AdjustTimeOffset();
}
m_tLastCheck = m_tCurTime;
if (m_bStatChanged)
{
Save();
}
}
void StatMeter::EnterLeaveStandBy(bool bEnter)
{
m_mutexStat.Lock();
m_bStandBy = bEnter;
if (bEnter)
{
m_tPausedFrom = time(NULL);
}
else
{
if (m_tStartDownload == 0)
{
m_tStartDownload = time(NULL);
}
else
{
m_tStartDownload += time(NULL) - m_tPausedFrom;
}
m_tPausedFrom = 0;
ResetSpeedStat();
}
m_mutexStat.Unlock();
}
void StatMeter::CalcTotalStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy)
{
m_mutexStat.Lock();
if (m_tStartServer > 0)
{
*iUpTimeSec = (int)(time(NULL) - m_tStartServer);
}
else
{
*iUpTimeSec = 0;
}
*bStandBy = m_bStandBy;
if (m_bStandBy)
{
*iDnTimeSec = (int)(m_tPausedFrom - m_tStartDownload);
}
else
{
*iDnTimeSec = (int)(time(NULL) - m_tStartDownload);
}
*iAllBytes = m_iAllBytes;
m_mutexStat.Unlock();
}
/*
* NOTE: see note to "AddSpeedReading"
*/
int StatMeter::CalcCurrentDownloadSpeed()
{
if (m_bStandBy)
{
return 0;
}
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
if (iTimeDiff == 0)
{
return 0;
}
return (int)(m_iSpeedTotalBytes / iTimeDiff);
}
void StatMeter::AddSpeedReading(int iBytes)
{
time_t tCurTime = time(NULL);
int iNowSlot = (int)tCurTime / SPEEDMETER_SLOTSIZE;
if (g_pOptions->GetAccurateRate())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Lock();
#else
m_mutexSpeed.Lock();
#endif
}
while (iNowSlot > m_iSpeedTime[m_iSpeedBytesIndex])
{
//record bytes in next slot
m_iSpeedBytesIndex++;
if (m_iSpeedBytesIndex >= SPEEDMETER_SLOTS)
{
m_iSpeedBytesIndex = 0;
}
//Adjust counters with outgoing information.
m_iSpeedTotalBytes = m_iSpeedTotalBytes - (long long)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];
//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)
{
long long iSpeedTotalBytes = 0;
for (int i = 0; i < SPEEDMETER_SLOTS; i++)
{
iSpeedTotalBytes += m_iSpeedBytes[i];
}
m_iSpeedTotalBytes = iSpeedTotalBytes;
m_tSpeedCorrection = tCurTime;
}
if (m_iSpeedTotalBytes == 0)
{
m_iSpeedStartTime = iNowSlot;
}
m_iSpeedBytes[m_iSpeedBytesIndex] += iBytes;
m_iSpeedTotalBytes += iBytes;
m_iAllBytes += iBytes;
if (g_pOptions->GetAccurateRate())
{
#ifdef HAVE_SPINLOCK
m_spinlockSpeed.Unlock();
#else
m_mutexSpeed.Unlock();
#endif
}
}
void StatMeter::ResetSpeedStat()
{
time_t tCurTime = time(NULL);
m_iSpeedStartTime = (int)tCurTime / SPEEDMETER_SLOTSIZE;
for (int i = 0; i < SPEEDMETER_SLOTS; i++)
{
m_iSpeedBytes[i] = 0;
m_iSpeedTime[i] = m_iSpeedStartTime;
}
m_iSpeedBytesIndex = 0;
m_iSpeedTotalBytes = 0;
m_tSpeedCorrection = tCurTime;
}
void StatMeter::LogDebugInfo()
{
info(" ---------- SpeedMeter");
float fSpeed = (float)(CalcCurrentDownloadSpeed() / 1024.0);
int iTimeDiff = (int)time(NULL) - m_iSpeedStartTime * SPEEDMETER_SLOTSIZE;
info(" Speed: %f", fSpeed);
info(" SpeedStartTime: %i", m_iSpeedStartTime);
info(" SpeedTotalBytes: %i", m_iSpeedTotalBytes);
info(" SpeedBytesIndex: %i", m_iSpeedBytesIndex);
info(" AllBytes: %i", m_iAllBytes);
info(" Time: %i", (int)time(NULL));
info(" TimeDiff: %i", iTimeDiff);
for (int i=0; i < SPEEDMETER_SLOTS; i++)
{
info(" Bytes[%i]: %i, Time[%i]: %i", i, m_iSpeedBytes[i], i, m_iSpeedTime[i]);
}
m_mutexVolume.Lock();
int index = 0;
for (ServerVolumes::iterator it = m_ServerVolumes.begin(); it != m_ServerVolumes.end(); it++, index++)
{
ServerVolume* pServerVolume = *it;
info(" ServerVolume %i", index);
pServerVolume->LogDebugInfo();
}
m_mutexVolume.Unlock();
}
void StatMeter::AddServerData(int iBytes, int iServerID)
{
if (iBytes == 0)
{
return;
}
m_mutexVolume.Lock();
m_ServerVolumes[0]->AddData(iBytes);
m_ServerVolumes[iServerID]->AddData(iBytes);
m_bStatChanged = true;
m_mutexVolume.Unlock();
}
ServerVolumes* StatMeter::LockServerVolumes()
{
m_mutexVolume.Lock();
// update slots
for (ServerVolumes::iterator it = m_ServerVolumes.begin(); it != m_ServerVolumes.end(); it++)
{
ServerVolume* pServerVolume = *it;
pServerVolume->AddData(0);
}
return &m_ServerVolumes;
}
void StatMeter::UnlockServerVolumes()
{
m_mutexVolume.Unlock();
}
void StatMeter::Save()
{
if (!g_pOptions->GetServerMode())
{
return;
}
m_mutexVolume.Lock();
g_pDiskState->SaveStats(g_pServerPool->GetServers(), &m_ServerVolumes);
m_bStatChanged = false;
m_mutexVolume.Unlock();
}
bool StatMeter::Load(bool* pPerfectServerMatch)
{
m_mutexVolume.Lock();
bool bOK = g_pDiskState->LoadStats(g_pServerPool->GetServers(), &m_ServerVolumes, pPerfectServerMatch);
for (ServerVolumes::iterator it = m_ServerVolumes.begin(); it != m_ServerVolumes.end(); it++)
{
ServerVolume* pServerVolume = *it;
pServerVolume->CalcSlots(pServerVolume->GetDataTime() + g_pOptions->GetLocalTimeOffset());
}
m_mutexVolume.Unlock();
return bOK;
}

View File

@@ -1,140 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2014 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 STATMETER_H
#define STATMETER_H
#include <vector>
#include <time.h>
#include "Log.h"
#include "Thread.h"
class ServerVolume
{
public:
typedef std::vector<long long> VolumeArray;
private:
VolumeArray m_BytesPerSeconds;
VolumeArray m_BytesPerMinutes;
VolumeArray m_BytesPerHours;
VolumeArray m_BytesPerDays;
int m_iFirstDay;
long long m_lTotalBytes;
long long m_lCustomBytes;
time_t m_tDataTime;
time_t m_tCustomTime;
int m_iSecSlot;
int m_iMinSlot;
int m_iHourSlot;
int m_iDaySlot;
public:
ServerVolume();
VolumeArray* BytesPerSeconds() { return &m_BytesPerSeconds; }
VolumeArray* BytesPerMinutes() { return &m_BytesPerMinutes; }
VolumeArray* BytesPerHours() { return &m_BytesPerHours; }
VolumeArray* BytesPerDays() { return &m_BytesPerDays; }
void SetFirstDay(int iFirstDay) { m_iFirstDay = iFirstDay; }
int GetFirstDay() { return m_iFirstDay; }
void SetTotalBytes(long long lTotalBytes) { m_lTotalBytes = lTotalBytes; }
long long GetTotalBytes() { return m_lTotalBytes; }
void SetCustomBytes(long long lCustomBytes) { m_lCustomBytes = lCustomBytes; }
long long GetCustomBytes() { return m_lCustomBytes; }
int GetSecSlot() { return m_iSecSlot; }
int GetMinSlot() { return m_iMinSlot; }
int GetHourSlot() { return m_iHourSlot; }
int GetDaySlot() { return m_iDaySlot; }
time_t GetDataTime() { return m_tDataTime; }
void SetDataTime(time_t tDataTime) { m_tDataTime = tDataTime; }
time_t GetCustomTime() { return m_tCustomTime; }
void SetCustomTime(time_t tCustomTime) { m_tCustomTime = tCustomTime; }
void AddData(int iBytes);
void CalcSlots(time_t tLocCurTime);
void ResetCustom();
void LogDebugInfo();
};
typedef std::vector<ServerVolume*> ServerVolumes;
class StatMeter : public Debuggable
{
private:
// speed meter
static const int SPEEDMETER_SLOTS = 30;
static const int SPEEDMETER_SLOTSIZE = 1; //Split elapsed time into this number of secs.
int m_iSpeedBytes[SPEEDMETER_SLOTS];
long long m_iSpeedTotalBytes;
int m_iSpeedTime[SPEEDMETER_SLOTS];
int m_iSpeedStartTime;
time_t m_tSpeedCorrection;
int m_iSpeedBytesIndex;
#ifdef HAVE_SPINLOCK
SpinLock m_spinlockSpeed;
#else
Mutex m_mutexSpeed;
#endif
// time
long long m_iAllBytes;
time_t m_tStartServer;
time_t m_tLastCheck;
time_t m_tLastTimeOffset;
time_t m_tStartDownload;
time_t m_tPausedFrom;
bool m_bStandBy;
Mutex m_mutexStat;
// data volume
bool m_bStatChanged;
ServerVolumes m_ServerVolumes;
Mutex m_mutexVolume;
void ResetSpeedStat();
void AdjustTimeOffset();
protected:
virtual void LogDebugInfo();
public:
StatMeter();
~StatMeter();
void Init();
int CalcCurrentDownloadSpeed();
void AddSpeedReading(int iBytes);
void AddServerData(int iBytes, int iServerID);
void CalcTotalStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAllBytes, bool* bStandBy);
bool GetStandBy() { return m_bStandBy; }
void IntervalCheck();
void EnterLeaveStandBy(bool bEnter);
ServerVolumes* LockServerVolumes();
void UnlockServerVolumes();
void Save();
bool Load(bool* pPerfectServerMatch);
};
#endif

View File

@@ -1,322 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdio.h>
#include "nzbget.h"
#include "PostScript.h"
#include "Log.h"
#include "Util.h"
#include "Options.h"
extern Options* g_pOptions;
static const int POSTPROCESS_PARCHECK = 92;
static const int POSTPROCESS_SUCCESS = 93;
static const int POSTPROCESS_ERROR = 94;
static const int POSTPROCESS_NONE = 95;
void PostScriptController::StartJob(PostInfo* pPostInfo)
{
PostScriptController* pScriptController = new PostScriptController();
pScriptController->m_pPostInfo = pPostInfo;
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
pScriptController->SetAutoDestroy(false);
pScriptController->m_iPrefixLen = 0;
pPostInfo->SetPostThread(pScriptController);
pScriptController->Start();
}
void PostScriptController::Run()
{
StringBuilder scriptCommaList;
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szVarname = pParameter->GetName();
if (strlen(szVarname) > 0 && szVarname[0] != '*' && szVarname[strlen(szVarname)-1] == ':' &&
(!strcasecmp(pParameter->GetValue(), "yes") || !strcasecmp(pParameter->GetValue(), "on") || !strcasecmp(pParameter->GetValue(), "1")))
{
char* szScriptName = strdup(szVarname);
szScriptName[strlen(szScriptName)-1] = '\0'; // remove trailing ':'
scriptCommaList.Append(szScriptName);
scriptCommaList.Append(",");
free(szScriptName);
}
}
m_pPostInfo->GetNZBInfo()->GetScriptStatuses()->Clear();
DownloadQueue::Unlock();
ExecuteScriptList(scriptCommaList.GetBuffer());
m_pPostInfo->SetStage(PostInfo::ptFinished);
m_pPostInfo->SetWorking(false);
}
void PostScriptController::ExecuteScript(Options::Script* pScript)
{
// if any script has requested par-check, do not execute other scripts
if (!pScript->GetPostScript() || m_pPostInfo->GetRequestParCheck())
{
return;
}
PrintMessage(Message::mkInfo, "Executing post-process-script %s for %s", pScript->GetName(), m_pPostInfo->GetNZBInfo()->GetName());
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "post-process-script %s for %s", pScript->GetName(), m_pPostInfo->GetNZBInfo()->GetName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
int iExitCode = Execute();
szInfoName[0] = 'P'; // uppercase
SetLogPrefix(NULL);
ScriptStatus::EStatus eStatus = AnalyseExitCode(iExitCode);
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->GetScriptStatuses()->Add(pScript->GetName(), eStatus);
DownloadQueue::Unlock();
}
void PostScriptController::PrepareParams(const char* szScriptName)
{
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
ResetEnv();
SetIntEnvVar("NZBPP_NZBID", m_pPostInfo->GetNZBInfo()->GetID());
SetEnvVar("NZBPP_NZBNAME", m_pPostInfo->GetNZBInfo()->GetName());
SetEnvVar("NZBPP_DIRECTORY", m_pPostInfo->GetNZBInfo()->GetDestDir());
SetEnvVar("NZBPP_NZBFILENAME", m_pPostInfo->GetNZBInfo()->GetFilename());
SetEnvVar("NZBPP_URL", m_pPostInfo->GetNZBInfo()->GetURL());
SetEnvVar("NZBPP_FINALDIR", m_pPostInfo->GetNZBInfo()->GetFinalDir());
SetEnvVar("NZBPP_CATEGORY", m_pPostInfo->GetNZBInfo()->GetCategory());
SetIntEnvVar("NZBPP_HEALTH", m_pPostInfo->GetNZBInfo()->CalcHealth());
SetIntEnvVar("NZBPP_CRITICALHEALTH", m_pPostInfo->GetNZBInfo()->CalcCriticalHealth(false));
char szStatus[256];
strncpy(szStatus, m_pPostInfo->GetNZBInfo()->MakeTextStatus(true), sizeof(szStatus));
szStatus[256-1] = '\0';
SetEnvVar("NZBPP_STATUS", szStatus);
char* szDetail = strchr(szStatus, '/');
if (szDetail) *szDetail = '\0';
SetEnvVar("NZBPP_TOTALSTATUS", szStatus);
const char* szScriptStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
SetEnvVar("NZBPP_SCRIPTSTATUS", szScriptStatusName[m_pPostInfo->GetNZBInfo()->GetScriptStatuses()->CalcTotalStatus()]);
// deprecated
int iParStatus[] = { 0, 0, 1, 2, 3, 4 };
SetIntEnvVar("NZBPP_PARSTATUS", iParStatus[m_pPostInfo->GetNZBInfo()->GetParStatus()]);
// deprecated
int iUnpackStatus[] = { 0, 0, 1, 2, 3, 4 };
SetIntEnvVar("NZBPP_UNPACKSTATUS", iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
// deprecated
SetIntEnvVar("NZBPP_HEALTHDELETED", (int)m_pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsHealth);
SetIntEnvVar("NZBPP_TOTALARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetTotalArticles());
SetIntEnvVar("NZBPP_SUCCESSARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetSuccessArticles());
SetIntEnvVar("NZBPP_FAILEDARTICLES", (int)m_pPostInfo->GetNZBInfo()->GetFailedArticles());
for (ServerStatList::iterator it = m_pPostInfo->GetNZBInfo()->GetServerStats()->begin(); it != m_pPostInfo->GetNZBInfo()->GetServerStats()->end(); it++)
{
ServerStat* pServerStat = *it;
char szName[50];
snprintf(szName, 50, "NZBPP_SERVER%i_SUCCESSARTICLES", pServerStat->GetServerID());
szName[50-1] = '\0';
SetIntEnvVar(szName, pServerStat->GetSuccessArticles());
snprintf(szName, 50, "NZBPP_SERVER%i_FAILEDARTICLES", pServerStat->GetServerID());
szName[50-1] = '\0';
SetIntEnvVar(szName, pServerStat->GetFailedArticles());
}
PrepareEnvScript(m_pPostInfo->GetNZBInfo()->GetParameters(), szScriptName);
DownloadQueue::Unlock();
}
ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int iExitCode)
{
// The ScriptStatus is accumulated for all scripts:
// If any script has failed the status is "failure", etc.
switch (iExitCode)
{
case POSTPROCESS_SUCCESS:
PrintMessage(Message::mkInfo, "%s successful", GetInfoName());
return ScriptStatus::srSuccess;
case POSTPROCESS_ERROR:
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
PrintMessage(Message::mkError, "%s failed", GetInfoName());
return ScriptStatus::srFailure;
case POSTPROCESS_NONE:
PrintMessage(Message::mkInfo, "%s skipped", GetInfoName());
return ScriptStatus::srNone;
#ifndef DISABLE_PARCHECK
case POSTPROCESS_PARCHECK:
if (m_pPostInfo->GetNZBInfo()->GetParStatus() > NZBInfo::psSkipped)
{
PrintMessage(Message::mkError, "%s requested par-check/repair, but the collection was already checked", GetInfoName());
return ScriptStatus::srFailure;
}
else
{
PrintMessage(Message::mkInfo, "%s requested par-check/repair", GetInfoName());
m_pPostInfo->SetRequestParCheck(true);
return ScriptStatus::srSuccess;
}
break;
#endif
default:
PrintMessage(Message::mkError, "%s failed (terminated with unknown status)", GetInfoName());
return ScriptStatus::srFailure;
}
}
void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "FINALDIR=", 9))
{
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->SetFinalDir(szMsgText + 6 + 9);
DownloadQueue::Unlock();
}
else if (!strncmp(szMsgText + 6, "DIRECTORY=", 10))
{
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->SetDestDir(szMsgText + 6 + 10);
DownloadQueue::Unlock();
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
DownloadQueue::Lock();
m_pPostInfo->GetNZBInfo()->GetParameters()->SetParameter(szParam, szValue + 1);
DownloadQueue::Unlock();
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else if (!strncmp(szMsgText, "[HISTORY] ", 10))
{
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szMsgText);
}
else
{
ScriptController::AddMessage(eKind, szText);
m_pPostInfo->AppendMessage(eKind, szText);
}
if (g_pOptions->GetPausePostProcess() && !m_pPostInfo->GetNZBInfo()->GetForcePriority())
{
time_t tStageTime = m_pPostInfo->GetStageTime();
time_t tStartTime = m_pPostInfo->GetStartTime();
time_t tWaitTime = time(NULL);
// wait until Post-processor is unpaused
while (g_pOptions->GetPausePostProcess() && !m_pPostInfo->GetNZBInfo()->GetForcePriority() && !IsStopped())
{
usleep(100 * 1000);
// update time stamps
time_t tDelta = time(NULL) - tWaitTime;
if (tStageTime > 0)
{
m_pPostInfo->SetStageTime(tStageTime + tDelta);
}
if (tStartTime > 0)
{
m_pPostInfo->SetStartTime(tStartTime + tDelta);
}
}
}
}
void PostScriptController::Stop()
{
debug("Stopping post-process-script");
Thread::Stop();
Terminate();
}

View File

@@ -1,55 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 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 POSTSCRIPT_H
#define POSTSCRIPT_H
#include "Thread.h"
#include "Log.h"
#include "QueueScript.h"
#include "DownloadInfo.h"
#include "Options.h"
class PostScriptController : public Thread, public NZBScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szNZBName[1024];
int m_iPrefixLen;
void PrepareParams(const char* szScriptName);
ScriptStatus::EStatus AnalyseExitCode(int iExitCode);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual void Run();
virtual void Stop();
static void StartJob(PostInfo* pPostInfo);
};
#endif

View File

@@ -1,800 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <set>
#include <algorithm>
#include "nzbget.h"
#include "PrePostProcessor.h"
#include "Options.h"
#include "Log.h"
#include "HistoryCoordinator.h"
#include "DupeCoordinator.h"
#include "PostScript.h"
#include "Util.h"
#include "Scheduler.h"
#include "Scanner.h"
#include "Unpack.h"
#include "NZBFile.h"
#include "StatMeter.h"
extern HistoryCoordinator* g_pHistoryCoordinator;
extern DupeCoordinator* g_pDupeCoordinator;
extern Options* g_pOptions;
extern Scheduler* g_pScheduler;
extern Scanner* g_pScanner;
extern StatMeter* g_pStatMeter;
PrePostProcessor::PrePostProcessor()
{
debug("Creating PrePostProcessor");
m_iJobCount = 0;
m_pCurJob = NULL;
m_szPauseReason = NULL;
m_DownloadQueueObserver.m_pOwner = this;
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
pDownloadQueue->Attach(&m_DownloadQueueObserver);
DownloadQueue::Unlock();
}
PrePostProcessor::~PrePostProcessor()
{
debug("Destroying PrePostProcessor");
}
void PrePostProcessor::Run()
{
debug("Entering PrePostProcessor-loop");
while (!DownloadQueue::IsLoaded())
{
usleep(20 * 1000);
}
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetReloadQueue())
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
SanitisePostQueue(pDownloadQueue);
DownloadQueue::Unlock();
}
g_pScheduler->FirstCheck();
int iDiskSpaceInterval = 1000;
int iSchedulerInterval = 1000;
int iHistoryInterval = 600000;
const int iStepMSec = 200;
while (!IsStopped())
{
// check incoming nzb directory
g_pScanner->Check();
if (!g_pOptions->GetPauseDownload() &&
g_pOptions->GetDiskSpace() > 0 && !g_pStatMeter->GetStandBy() &&
iDiskSpaceInterval >= 1000)
{
// check free disk space every 1 second
CheckDiskSpace();
iDiskSpaceInterval = 0;
}
iDiskSpaceInterval += iStepMSec;
// check post-queue every 200 msec
CheckPostQueue();
if (iSchedulerInterval >= 1000)
{
// check scheduler tasks every 1 second
g_pScheduler->IntervalCheck();
iSchedulerInterval = 0;
}
iSchedulerInterval += iStepMSec;
if (iHistoryInterval >= 600000)
{
// check history (remove old entries) every 10 minutes
g_pHistoryCoordinator->IntervalCheck();
iHistoryInterval = 0;
}
iHistoryInterval += iStepMSec;
Util::SetStandByMode(!m_pCurJob);
usleep(iStepMSec * 1000);
}
g_pHistoryCoordinator->Cleanup();
debug("Exiting PrePostProcessor-loop");
}
void PrePostProcessor::Stop()
{
Thread::Stop();
DownloadQueue::Lock();
#ifndef DISABLE_PARCHECK
m_ParCoordinator.Stop();
#endif
if (m_pCurJob && m_pCurJob->GetPostInfo() &&
(m_pCurJob->GetPostInfo()->GetStage() == PostInfo::ptUnpacking ||
m_pCurJob->GetPostInfo()->GetStage() == PostInfo::ptExecutingScript) &&
m_pCurJob->GetPostInfo()->GetPostThread())
{
Thread* pPostThread = m_pCurJob->GetPostInfo()->GetPostThread();
m_pCurJob->GetPostInfo()->SetPostThread(NULL);
pPostThread->SetAutoDestroy(true);
pPostThread->Stop();
}
DownloadQueue::Unlock();
}
void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
{
if (IsStopped())
{
return;
}
DownloadQueue::Aspect* pQueueAspect = (DownloadQueue::Aspect*)Aspect;
if (pQueueAspect->eAction == DownloadQueue::eaNzbFound)
{
NZBFound(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if (pQueueAspect->eAction == DownloadQueue::eaNzbAdded)
{
NZBAdded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
pQueueAspect->eAction == DownloadQueue::eaFileDeleted))
{
if (
#ifndef DISABLE_PARCHECK
!m_ParCoordinator.AddPar(pQueueAspect->pFileInfo, pQueueAspect->eAction == DownloadQueue::eaFileDeleted) &&
#endif
IsNZBFileCompleted(pQueueAspect->pNZBInfo, true, false) &&
!pQueueAspect->pNZBInfo->GetPostInfo() &&
(!pQueueAspect->pFileInfo->GetPaused() || IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, false)))
{
if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
(pQueueAspect->pFileInfo->GetAutoDeleted() &&
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))) &&
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth)
{
info("Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName());
NZBDownloaded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if ((pQueueAspect->eAction == DownloadQueue::eaFileDeleted ||
(pQueueAspect->eAction == DownloadQueue::eaFileCompleted &&
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() > NZBInfo::dsNone)) &&
!pQueueAspect->pNZBInfo->GetParCleanup() &&
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))
{
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
}
}
}
void PrePostProcessor::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce)
{
g_pDupeCoordinator->NZBFound(pDownloadQueue, pNZBInfo);
}
}
void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
if (g_pOptions->GetParCheck() != Options::pcForce)
{
m_ParCoordinator.PausePars(pDownloadQueue, pNZBInfo);
}
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
{
NZBCompleted(pDownloadQueue, pNZBInfo, false);
}
else if (!Util::EmptyStr(g_pOptions->GetQueueScript()))
{
QueueScriptController::StartScripts(pDownloadQueue, pNZBInfo);
}
}
void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
if (!pNZBInfo->GetPostInfo() && g_pOptions->GetDecode())
{
info("Queueing %s for post-processing", pNZBInfo->GetName());
pNZBInfo->EnterPostProcess();
m_iJobCount++;
if (pNZBInfo->GetParStatus() == NZBInfo::psNone &&
g_pOptions->GetParCheck() != Options::pcAlways &&
g_pOptions->GetParCheck() != Options::pcForce)
{
pNZBInfo->SetParStatus(NZBInfo::psSkipped);
}
if (pNZBInfo->GetRenameStatus() == NZBInfo::rsNone && !g_pOptions->GetParRename())
{
pNZBInfo->SetRenameStatus(NZBInfo::rsSkipped);
}
if (pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone)
{
pNZBInfo->SetParStatus(NZBInfo::psFailure);
pNZBInfo->SetUnpackStatus(NZBInfo::usFailure);
pNZBInfo->SetRenameStatus(NZBInfo::rsFailure);
pNZBInfo->SetMoveStatus(NZBInfo::msFailure);
}
pDownloadQueue->Save();
}
else
{
NZBCompleted(pDownloadQueue, pNZBInfo, true);
}
}
void PrePostProcessor::NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
{
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone)
{
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
}
pNZBInfo->SetDeleting(false);
if ((g_pOptions->GetDeleteCleanupDisk() && pNZBInfo->GetCleanupDisk()) ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
{
// download was cancelled, deleting already downloaded files from disk
for (NZBInfo::Files::reverse_iterator it = pNZBInfo->GetCompletedFiles()->rbegin(); it != pNZBInfo->GetCompletedFiles()->rend(); it++)
{
char* szFilename = *it;
if (Util::FileExists(szFilename))
{
detail("Deleting file %s", Util::BaseFileName(szFilename));
remove(szFilename);
}
}
// delete .out.tmp-files and _brokenlog.txt
DirBrowser dir(pNZBInfo->GetDestDir());
while (const char* szFilename = dir.Next())
{
int iLen = strlen(szFilename);
if ((iLen > 8 && !strcmp(szFilename + iLen - 8, ".out.tmp")) || !strcmp(szFilename, "_brokenlog.txt"))
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", pNZBInfo->GetDestDir(), PATH_SEPARATOR, szFilename);
szFullFilename[1024-1] = '\0';
detail("Deleting file %s", szFilename);
remove(szFullFilename);
}
}
// delete old directory (if empty)
if (Util::DirEmpty(pNZBInfo->GetDestDir()))
{
rmdir(pNZBInfo->GetDestDir());
}
}
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth)
{
NZBDownloaded(pDownloadQueue, pNZBInfo);
}
else
{
NZBCompleted(pDownloadQueue, pNZBInfo, true);
}
}
void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue)
{
bool bAddToHistory = g_pOptions->GetKeepHistory() > 0 && !pNZBInfo->GetAvoidHistory();
if (bAddToHistory)
{
g_pHistoryCoordinator->AddToHistory(pDownloadQueue, pNZBInfo);
}
pNZBInfo->SetAvoidHistory(false);
bool bNeedSave = bAddToHistory;
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth))
{
g_pDupeCoordinator->NZBCompleted(pDownloadQueue, pNZBInfo);
bNeedSave = true;
}
if (!bAddToHistory)
{
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
delete pNZBInfo;
}
if (bSaveQueue && bNeedSave)
{
pDownloadQueue->Save();
}
}
void PrePostProcessor::CheckDiskSpace()
{
long long lFreeSpace = Util::FreeDiskSize(g_pOptions->GetDestDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetDestDir());
g_pOptions->SetPauseDownload(true);
}
if (!Util::EmptyStr(g_pOptions->GetInterDir()))
{
lFreeSpace = Util::FreeDiskSize(g_pOptions->GetInterDir());
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
{
warn("Low disk space on %s. Pausing download", g_pOptions->GetInterDir());
g_pOptions->SetPauseDownload(true);
}
}
}
void PrePostProcessor::CheckPostQueue()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
if (!m_pCurJob && m_iJobCount > 0)
{
m_pCurJob = GetNextJob(pDownloadQueue);
if (!m_pCurJob && !g_pOptions->GetPausePostProcess())
{
error("Internal error: no jobs found in queue");
m_iJobCount = 0;
}
}
if (m_pCurJob)
{
PostInfo* pPostInfo = m_pCurJob->GetPostInfo();
if (!pPostInfo->GetWorking() && !IsNZBFileDownloading(m_pCurJob))
{
#ifndef DISABLE_PARCHECK
if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
g_pOptions->GetParCheck() != Options::pcManual)
{
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psNone);
pPostInfo->SetRequestParCheck(false);
pPostInfo->SetStage(PostInfo::ptQueued);
pPostInfo->GetNZBInfo()->GetScriptStatuses()->Clear();
DeletePostThread(pPostInfo);
}
else if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
g_pOptions->GetParCheck() == Options::pcManual)
{
pPostInfo->SetRequestParCheck(false);
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psManual);
DeletePostThread(pPostInfo);
if (!pPostInfo->GetNZBInfo()->GetFileList()->empty())
{
info("Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName());
pDownloadQueue->EditEntry(pPostInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupResume, 0, NULL);
pPostInfo->SetStage(PostInfo::ptFinished);
}
else
{
info("There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName());
pPostInfo->SetStage(PostInfo::ptQueued);
}
}
#endif
if (pPostInfo->GetDeleted())
{
pPostInfo->SetStage(PostInfo::ptFinished);
}
if (pPostInfo->GetStage() == PostInfo::ptQueued &&
(!g_pOptions->GetPausePostProcess() || pPostInfo->GetNZBInfo()->GetForcePriority()))
{
DeletePostThread(pPostInfo);
StartJob(pDownloadQueue, pPostInfo);
}
else if (pPostInfo->GetStage() == PostInfo::ptFinished)
{
UpdatePauseState(false, NULL);
JobCompleted(pDownloadQueue, pPostInfo);
}
else if (!g_pOptions->GetPausePostProcess())
{
error("Internal error: invalid state in post-processor");
// TODO: cancel (delete) current job
}
}
}
DownloadQueue::Unlock();
}
NZBInfo* PrePostProcessor::GetNextJob(DownloadQueue* pDownloadQueue)
{
NZBInfo* pNZBInfo = NULL;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo1 = *it;
if (pNZBInfo1->GetPostInfo() && (!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()) &&
(!g_pOptions->GetPausePostProcess() || pNZBInfo1->GetForcePriority()))
{
pNZBInfo = pNZBInfo1;
}
}
return pNZBInfo;
}
/**
* Reset the state of items after reloading from disk and
* delete items which could not be resumed.
* Also count the number of post-jobs.
*/
void PrePostProcessor::SanitisePostQueue(DownloadQueue* pDownloadQueue)
{
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
if (pPostInfo)
{
m_iJobCount++;
if (pPostInfo->GetStage() == PostInfo::ptExecutingScript ||
!Util::DirectoryExists(pNZBInfo->GetDestDir()))
{
pPostInfo->SetStage(PostInfo::ptFinished);
}
else
{
pPostInfo->SetStage(PostInfo::ptQueued);
}
}
}
}
void PrePostProcessor::DeletePostThread(PostInfo* pPostInfo)
{
delete pPostInfo->GetPostThread();
pPostInfo->SetPostThread(NULL);
}
void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
{
#ifndef DISABLE_PARCHECK
if (pPostInfo->GetNZBInfo()->GetRenameStatus() == NZBInfo::rsNone)
{
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-rename");
m_ParCoordinator.StartParRenameJob(pPostInfo);
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone)
{
if (m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-check");
m_ParCoordinator.StartParCheckJob(pPostInfo);
}
else
{
info("Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName());
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSkipped);
pPostInfo->SetWorking(false);
pPostInfo->SetStage(PostInfo::ptQueued);
}
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
pPostInfo->GetNZBInfo()->CalcHealth() < pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) &&
pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000 &&
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
warn("Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(),
pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) / 10.0);
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
pPostInfo->GetNZBInfo()->GetFailedSize() - pPostInfo->GetNZBInfo()->GetParFailedSize() > 0 &&
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
info("Collection %s with health %.1f%% needs par-check",
pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->CalcHealth() / 10.0);
pPostInfo->SetRequestParCheck(true);
return;
}
#endif
NZBParameter* pUnpackParameter = pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
bool bUnpackParam = !(pUnpackParameter && !strcasecmp(pUnpackParameter->GetValue(), "no"));
bool bUnpack = bUnpackParam && (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone);
bool bParFailed = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible ||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual;
bool bCleanup = !bUnpack &&
pPostInfo->GetNZBInfo()->GetCleanupStatus() == NZBInfo::csNone &&
(pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess ||
(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)) &&
strlen(g_pOptions->GetExtCleanupDisk()) > 0;
bool bMoveInter = !bUnpack &&
pPostInfo->GetNZBInfo()->GetMoveStatus() == NZBInfo::msNone &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usSpace &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psManual &&
strlen(g_pOptions->GetInterDir()) > 0 &&
!strncmp(pPostInfo->GetNZBInfo()->GetDestDir(), g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
bool bPostScript = true;
if (bUnpack && bParFailed)
{
warn("Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(),
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure");
pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
bUnpack = false;
}
if (!bUnpack && !bMoveInter && !bPostScript)
{
pPostInfo->SetStage(PostInfo::ptFinished);
return;
}
pPostInfo->SetProgressLabel(bUnpack ? "Unpacking" : bMoveInter ? "Moving" : "Executing post-process-script");
pPostInfo->SetWorking(true);
pPostInfo->SetStage(bUnpack ? PostInfo::ptUnpacking : bMoveInter ? PostInfo::ptMoving : PostInfo::ptExecutingScript);
pPostInfo->SetFileProgress(0);
pPostInfo->SetStageProgress(0);
pDownloadQueue->Save();
if (!pPostInfo->GetStartTime())
{
pPostInfo->SetStartTime(time(NULL));
}
pPostInfo->SetStageTime(time(NULL));
if (bUnpack)
{
UpdatePauseState(g_pOptions->GetUnpackPauseQueue(), "unpack");
UnpackController::StartJob(pPostInfo);
}
else if (bCleanup)
{
UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "cleanup");
CleanupController::StartJob(pPostInfo);
}
else if (bMoveInter)
{
UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "move");
MoveController::StartJob(pPostInfo);
}
else
{
UpdatePauseState(g_pOptions->GetScriptPauseQueue(), "post-process-script");
PostScriptController::StartJob(pPostInfo);
}
}
void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
{
NZBInfo* pNZBInfo = pPostInfo->GetNZBInfo();
DeletePostThread(pPostInfo);
pNZBInfo->LeavePostProcess();
if (IsNZBFileCompleted(pNZBInfo, true, false))
{
// Cleaning up queue if par-check was successful or unpack was successful or
// script was successful (if unpack was not performed)
bool bCanCleanupQueue = pNZBInfo->GetParStatus() == NZBInfo::psSuccess ||
pNZBInfo->GetParStatus() == NZBInfo::psRepairPossible ||
pNZBInfo->GetUnpackStatus() == NZBInfo::usSuccess ||
(pNZBInfo->GetUnpackStatus() == NZBInfo::usNone &&
pNZBInfo->GetScriptStatuses()->CalcTotalStatus() == ScriptStatus::srSuccess);
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue)
{
if (!pNZBInfo->GetFileList()->empty())
{
info("Cleaning up download queue for %s", pNZBInfo->GetName());
pNZBInfo->ClearCompletedFiles();
pNZBInfo->SetParCleanup(true);
pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
}
}
NZBCompleted(pDownloadQueue, pNZBInfo, false);
}
if (pNZBInfo == m_pCurJob)
{
m_pCurJob = NULL;
}
m_iJobCount--;
pDownloadQueue->Save();
}
bool PrePostProcessor::IsNZBFileCompleted(NZBInfo* pNZBInfo, bool bIgnorePausedPars, bool bAllowOnlyOneDeleted)
{
int iDeleted = 0;
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (pFileInfo->GetDeleted())
{
iDeleted++;
}
if (((!pFileInfo->GetPaused() || !bIgnorePausedPars || !pFileInfo->GetParFile()) &&
!pFileInfo->GetDeleted()) ||
(bAllowOnlyOneDeleted && iDeleted > 1))
{
return false;
}
}
return true;
}
bool PrePostProcessor::IsNZBFileDownloading(NZBInfo* pNZBInfo)
{
if (pNZBInfo->GetActiveDownloads())
{
return true;
}
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
if (!pFileInfo->GetPaused())
{
return true;
}
}
return false;
}
void PrePostProcessor::UpdatePauseState(bool bNeedPause, const char* szReason)
{
if (bNeedPause && !g_pOptions->GetTempPauseDownload())
{
info("Pausing download before %s", szReason);
}
else if (!bNeedPause && g_pOptions->GetTempPauseDownload())
{
info("Unpausing download after %s", m_szPauseReason);
}
g_pOptions->SetTempPauseDownload(bNeedPause);
m_szPauseReason = szReason;
}
bool PrePostProcessor::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText)
{
debug("Edit-command for post-processor received");
switch (eAction)
{
case DownloadQueue::eaPostDelete:
return PostQueueDelete(pDownloadQueue, pIDList);
default:
return false;
}
}
bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pIDList)
{
bool bOK = false;
for (IDList::iterator itID = pIDList->begin(); itID != pIDList->end(); itID++)
{
int iID = *itID;
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
if (pPostInfo && pNZBInfo->GetID() == iID)
{
if (pPostInfo->GetWorking())
{
info("Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName());
pPostInfo->SetDeleted(true);
#ifndef DISABLE_PARCHECK
if (PostInfo::ptLoadingPars <= pPostInfo->GetStage() && pPostInfo->GetStage() <= PostInfo::ptRenaming)
{
if (m_ParCoordinator.Cancel())
{
bOK = true;
}
}
else
#endif
if (pPostInfo->GetPostThread())
{
debug("Terminating %s for %s", (pPostInfo->GetStage() == PostInfo::ptUnpacking ? "unpack" : "post-process-script"), pPostInfo->GetNZBInfo()->GetName());
pPostInfo->GetPostThread()->Stop();
bOK = true;
}
else
{
error("Internal error in PrePostProcessor::QueueDelete");
}
}
else
{
info("Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName());
JobCompleted(pDownloadQueue, pPostInfo);
bOK = true;
}
break;
}
}
}
return bOK;
}

View File

@@ -1,82 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 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 PREPOSTPROCESSOR_H
#define PREPOSTPROCESSOR_H
#include <deque>
#include "Thread.h"
#include "Observer.h"
#include "DownloadInfo.h"
#include "ParCoordinator.h"
class PrePostProcessor : public Thread
{
private:
class DownloadQueueObserver: public Observer
{
public:
PrePostProcessor* m_pOwner;
virtual void Update(Subject* Caller, void* Aspect) { m_pOwner->DownloadQueueUpdate(Caller, Aspect); }
};
private:
ParCoordinator m_ParCoordinator;
DownloadQueueObserver m_DownloadQueueObserver;
int m_iJobCount;
NZBInfo* m_pCurJob;
const char* m_szPauseReason;
bool IsNZBFileCompleted(NZBInfo* pNZBInfo, bool bIgnorePausedPars, bool bAllowOnlyOneDeleted);
bool IsNZBFileDownloading(NZBInfo* pNZBInfo);
void CheckPostQueue();
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
void StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
void SaveQueue(DownloadQueue* pDownloadQueue);
void SanitisePostQueue(DownloadQueue* pDownloadQueue);
void CheckDiskSpace();
void UpdatePauseState(bool bNeedPause, const char* szReason);
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue);
bool PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pIDList);
void DeletePostThread(PostInfo* pPostInfo);
NZBInfo* GetNextJob(DownloadQueue* pDownloadQueue);
void DownloadQueueUpdate(Subject* Caller, void* Aspect);
public:
PrePostProcessor();
virtual ~PrePostProcessor();
virtual void Run();
virtual void Stop();
bool HasMoreJobs() { return m_iJobCount > 0; }
int GetJobCount() { return m_iJobCount; }
bool EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText);
void NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
};
#endif

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