mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-06 21:18:25 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b87cf1b23 |
@@ -77,10 +77,22 @@ ArticleDownloader::~ArticleDownloader()
|
||||
{
|
||||
debug("Destroying ArticleDownloader");
|
||||
|
||||
free(m_szTempFilename);
|
||||
free(m_szArticleFilename);
|
||||
free(m_szInfoName);
|
||||
free(m_szOutputFilename);
|
||||
if (m_szTempFilename)
|
||||
{
|
||||
free(m_szTempFilename);
|
||||
}
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void ArticleDownloader::SetTempFilename(const char* v)
|
||||
@@ -146,19 +158,18 @@ void ArticleDownloader::Run()
|
||||
|
||||
int iRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
|
||||
int iRemainedRetries = iRetries;
|
||||
Servers failedServers;
|
||||
ServerPool::Servers failedServers;
|
||||
failedServers.reserve(g_pServerPool->GetServers()->size());
|
||||
NewsServer* pWantServer = NULL;
|
||||
NewsServer* pLastServer = NULL;
|
||||
int iLevel = 0;
|
||||
int iServerConfigGeneration = g_pServerPool->GetGeneration();
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
Status = adFailed;
|
||||
|
||||
SetStatus(adWaiting);
|
||||
while (!m_pConnection && !(IsStopped() || iServerConfigGeneration != g_pServerPool->GetGeneration()))
|
||||
while (!IsStopped() && !m_pConnection)
|
||||
{
|
||||
m_pConnection = g_pServerPool->GetConnection(iLevel, pWantServer, &failedServers);
|
||||
usleep(5 * 1000);
|
||||
@@ -166,8 +177,7 @@ void ArticleDownloader::Run()
|
||||
SetLastUpdateTimeNow();
|
||||
SetStatus(adRunning);
|
||||
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration())
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
@@ -181,15 +191,10 @@ void ArticleDownloader::Run()
|
||||
bool bConnected = m_pConnection && m_pConnection->Connect();
|
||||
if (bConnected && !IsStopped())
|
||||
{
|
||||
NewsServer* pNewsServer = m_pConnection->GetNewsServer();
|
||||
detail("Downloading %s @ %s (%s)", m_szInfoName, pNewsServer->GetName(), m_pConnection->GetHost());
|
||||
|
||||
// Okay, we got a Connection. Now start downloading.
|
||||
detail("Downloading %s @ server%i (%s)", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
Status = Download();
|
||||
|
||||
if (Status == adFinished || Status == adFailed || Status == adNotFound || Status == adCrcError)
|
||||
{
|
||||
m_ServerStats.SetStat(pNewsServer->GetID(), Status == adFinished ? 1 : 0, Status == adFinished ? 0 : 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (bConnected)
|
||||
@@ -229,16 +234,14 @@ void ArticleDownloader::Run()
|
||||
pWantServer = pLastServer;
|
||||
}
|
||||
|
||||
if (pWantServer &&
|
||||
!(IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration()))
|
||||
if (pWantServer && !IsStopped() &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
SetStatus(adWaiting);
|
||||
int msec = 0;
|
||||
while (!(IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration()) &&
|
||||
msec < g_pOptions->GetRetryInterval() * 1000)
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
@@ -247,8 +250,7 @@ void ArticleDownloader::Run()
|
||||
SetStatus(adRunning);
|
||||
}
|
||||
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2() ||
|
||||
iServerConfigGeneration != g_pServerPool->GetGeneration())
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
@@ -262,25 +264,22 @@ void ArticleDownloader::Run()
|
||||
// if all servers from all levels were tried, break the loop with failure status
|
||||
|
||||
bool bAllServersOnLevelFailed = true;
|
||||
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
NewsServer* pCandidateServer = *it;
|
||||
if (pCandidateServer->GetNormLevel() == iLevel)
|
||||
if (pCandidateServer->GetLevel() == iLevel)
|
||||
{
|
||||
bool bServerFailed = !pCandidateServer->GetActive() || pCandidateServer->GetMaxConnections() == 0;
|
||||
if (!bServerFailed)
|
||||
bool bServerFailed = false;
|
||||
for (ServerPool::Servers::iterator it = failedServers.begin(); it != failedServers.end(); it++)
|
||||
{
|
||||
for (Servers::iterator it = failedServers.begin(); it != failedServers.end(); it++)
|
||||
NewsServer* pIgnoreServer = *it;
|
||||
if (pIgnoreServer == pCandidateServer ||
|
||||
(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
|
||||
pIgnoreServer->GetLevel() == pCandidateServer->GetLevel()))
|
||||
{
|
||||
NewsServer* pIgnoreServer = *it;
|
||||
if (pIgnoreServer == pCandidateServer ||
|
||||
(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
|
||||
pIgnoreServer->GetNormLevel() == pCandidateServer->GetNormLevel()))
|
||||
{
|
||||
bServerFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bServerFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bServerFailed)
|
||||
{
|
||||
@@ -292,14 +291,14 @@ void ArticleDownloader::Run()
|
||||
|
||||
if (bAllServersOnLevelFailed)
|
||||
{
|
||||
if (iLevel < g_pServerPool->GetMaxNormLevel())
|
||||
if (iLevel < g_pServerPool->GetMaxLevel())
|
||||
{
|
||||
detail("Article %s @ all level %i servers failed, increasing level", m_szInfoName, iLevel);
|
||||
iLevel++;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("Article %s @ all servers failed", m_szInfoName);
|
||||
warn("Article %s @ all servers failed", m_szInfoName);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
@@ -329,7 +328,7 @@ void ArticleDownloader::Run()
|
||||
|
||||
if (Status == adFailed)
|
||||
{
|
||||
detail("Download %s failed", m_szInfoName);
|
||||
warn("Download %s failed", m_szInfoName);
|
||||
}
|
||||
|
||||
SetStatus(Status);
|
||||
@@ -421,8 +420,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
detail("Article %s @ %s (%s) failed: Unexpected end of article", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
|
||||
warn("Article %s @ server%i (%s) failed: Unexpected end of article", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
@@ -456,8 +455,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
if (strncmp(p, m_pArticleInfo->GetMessageID(), strlen(m_pArticleInfo->GetMessageID())))
|
||||
{
|
||||
if (char* e = strrchr(p, '\r')) *e = '\0'; // remove trailing CR-character
|
||||
detail("Article %s @ %s (%s) failed: Wrong message-id, expected %s, returned %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
warn("Article %s @ server%i (%s) failed: Wrong message-id, expected %s, returned %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
@@ -485,8 +484,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
|
||||
if (!bEnd && Status == adRunning && !IsStopped())
|
||||
{
|
||||
detail("Article %s @ %s (%s) failed: article incomplete", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
|
||||
warn("Article %s @ server%i (%s) failed: article incomplete", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost());
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
@@ -513,21 +512,21 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
detail("Article %s @ %s (%s) failed, %s: Connection closed by remote host", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment);
|
||||
warn("Article %s @ server%i (%s) failed, %s: Connection closed by remote host", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment);
|
||||
}
|
||||
return adConnectError;
|
||||
}
|
||||
else if (m_pConnection->GetAuthError() || !strncmp(szResponse, "400", 3) || !strncmp(szResponse, "499", 3))
|
||||
{
|
||||
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adConnectError;
|
||||
}
|
||||
else if (!strncmp(szResponse, "41", 2) || !strncmp(szResponse, "42", 2) || !strncmp(szResponse, "43", 2))
|
||||
{
|
||||
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szResponse, "2", 1))
|
||||
@@ -538,8 +537,8 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
|
||||
else
|
||||
{
|
||||
// unknown error, no special handling
|
||||
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
warn("Article %s @ server%i (%s) failed, %s: %s", m_szInfoName,
|
||||
m_pConnection->GetNewsServer()->GetID(), m_pConnection->GetHost(), szComment, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
@@ -564,13 +563,13 @@ bool ArticleDownloader::Write(char* szLine, int iLen)
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("Decoding %s failed: unsupported encoding", m_szInfoName);
|
||||
warn("Decoding %s failed: unsupported encoding", m_szInfoName);
|
||||
return false;
|
||||
}
|
||||
if (!bOK)
|
||||
{
|
||||
debug("Failed line: %s", szLine);
|
||||
detail("Decoding %s failed", m_szInfoName);
|
||||
warn("Decoding %s failed", m_szInfoName);
|
||||
}
|
||||
return bOK;
|
||||
}
|
||||
@@ -589,9 +588,7 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
{
|
||||
if (!strncmp(szLine, "=ybegin ", 8))
|
||||
{
|
||||
if (g_pOptions->GetDupeCheck() &&
|
||||
m_pFileInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
!m_pFileInfo->GetNZBInfo()->GetManyDupeFiles())
|
||||
if (g_pOptions->GetDupeCheck())
|
||||
{
|
||||
m_pFileInfo->LockOutputFile();
|
||||
bool bOutputInitialized = m_pFileInfo->GetOutputInitialized();
|
||||
@@ -616,8 +613,7 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
m_pFileInfo->SetOutputInitialized(true);
|
||||
}
|
||||
m_pFileInfo->UnlockOutputFile();
|
||||
if (!bOutputInitialized && m_szArticleFilename &&
|
||||
Util::FileExists(m_pFileInfo->GetNZBInfo()->GetDestDir(), m_szArticleFilename))
|
||||
if (!bOutputInitialized && m_szArticleFilename && m_pFileInfo->IsDupe(m_szArticleFilename))
|
||||
{
|
||||
m_bDuplicate = true;
|
||||
return false;
|
||||
@@ -663,9 +659,7 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
m_pOutFile = fopen(szFilename, bDirectWrite ? "rb+" : "wb");
|
||||
if (!m_pOutFile)
|
||||
{
|
||||
char szSysErrStr[256];
|
||||
error("Could not %s file %s! Errcode: %i, %s", bDirectWrite ? "open" : "create", szFilename,
|
||||
errno, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
error("Could not %s file %s", bDirectWrite ? "open" : "create", szFilename);
|
||||
return false;
|
||||
}
|
||||
if (g_pOptions->GetWriteBufferSize() == -1)
|
||||
@@ -772,7 +766,7 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("Decoding %s failed: no binary data or unsupported encoding format", m_szInfoName);
|
||||
warn("Decoding %s failed: no binary data or unsupported encoding format", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
|
||||
@@ -817,27 +811,27 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
remove(m_szResultFilename);
|
||||
if (eStatus == Decoder::eCrcError)
|
||||
{
|
||||
detail("Decoding %s failed: CRC-Error", m_szInfoName);
|
||||
warn("Decoding %s failed: CRC-Error", m_szInfoName);
|
||||
return adCrcError;
|
||||
}
|
||||
else if (eStatus == Decoder::eArticleIncomplete)
|
||||
{
|
||||
detail("Decoding %s failed: article incomplete", m_szInfoName);
|
||||
warn("Decoding %s failed: article incomplete", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else if (eStatus == Decoder::eInvalidSize)
|
||||
{
|
||||
detail("Decoding %s failed: size mismatch", m_szInfoName);
|
||||
warn("Decoding %s failed: size mismatch", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else if (eStatus == Decoder::eNoBinaryData)
|
||||
{
|
||||
detail("Decoding %s failed: no binary data found", m_szInfoName);
|
||||
warn("Decoding %s failed: no binary data found", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("Decoding %s failed", m_szInfoName);
|
||||
warn("Decoding %s failed", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
@@ -960,7 +954,17 @@ void ArticleDownloader::CompleteFileParts()
|
||||
}
|
||||
|
||||
char ofn[1024];
|
||||
Util::MakeUniqueFilename(ofn, 1024, szNZBDestDir, m_pFileInfo->GetFilename());
|
||||
snprintf(ofn, 1024, "%s%c%s", szNZBDestDir, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
ofn[1024-1] = '\0';
|
||||
|
||||
// prevent overwriting existing files
|
||||
int dupcount = 0;
|
||||
while (Util::FileExists(ofn))
|
||||
{
|
||||
dupcount++;
|
||||
snprintf(ofn, 1024, "%s%c%s_duplicate%d", szNZBDestDir, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename(), dupcount);
|
||||
ofn[1024-1] = '\0';
|
||||
}
|
||||
|
||||
FILE* outfile = NULL;
|
||||
char tmpdestfile[1024];
|
||||
@@ -1054,7 +1058,10 @@ void ArticleDownloader::CompleteFileParts()
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
if (buffer)
|
||||
{
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (outfile)
|
||||
{
|
||||
@@ -1106,9 +1113,7 @@ void ArticleDownloader::CompleteFileParts()
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("%i of %i article downloads failed for \"%s\"",
|
||||
iBrokenCount + m_pFileInfo->GetMissedArticles(),
|
||||
m_pFileInfo->GetTotalArticles(), InfoFilename);
|
||||
warn("%i of %i article downloads failed for \"%s\"", iBrokenCount, m_pFileInfo->GetArticles()->size(), InfoFilename);
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
{
|
||||
@@ -1116,14 +1121,12 @@ void ArticleDownloader::CompleteFileParts()
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", szNZBDestDir, (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
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);
|
||||
fprintf(file, "%s (%i/%i)%s", m_pFileInfo->GetFilename(), m_pFileInfo->GetArticles()->size() - iBrokenCount, m_pFileInfo->GetArticles()->size(), LINE_ENDING);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
// the locking is needed for accessing the members of NZBInfo
|
||||
// the locking is needed for accessing the memebers of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
m_pFileInfo->GetNZBInfo()->GetCompletedFiles()->push_back(strdup(ofn));
|
||||
if (strcmp(m_pFileInfo->GetNZBInfo()->GetDestDir(), szNZBDestDir))
|
||||
@@ -1163,7 +1166,13 @@ bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldD
|
||||
if (strcmp(szFileName, szNewFileName))
|
||||
{
|
||||
// prevent overwriting of existing files
|
||||
Util::MakeUniqueFilename(szNewFileName, 1024, pNZBInfo->GetDestDir(), Util::BaseFileName(szFileName));
|
||||
int dupcount = 0;
|
||||
while (Util::FileExists(szNewFileName))
|
||||
{
|
||||
dupcount++;
|
||||
snprintf(szNewFileName, 1024, "%s%c%s_duplicate%d", pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, Util::BaseFileName(szFileName), dupcount);
|
||||
szNewFileName[1024-1] = '\0';
|
||||
}
|
||||
|
||||
detail("Moving file %s to %s", szFileName, szNewFileName);
|
||||
if (Util::MoveFile(szFileName, szNewFileName))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -72,7 +72,6 @@ private:
|
||||
UDecoder m_UDecoder;
|
||||
FILE* m_pOutFile;
|
||||
bool m_bDuplicate;
|
||||
ServerStatList m_ServerStats;
|
||||
|
||||
EStatus Download();
|
||||
bool Write(char* szLine, int iLen);
|
||||
@@ -95,7 +94,6 @@ public:
|
||||
void SetArticleInfo(ArticleInfo* pArticleInfo) { m_pArticleInfo = pArticleInfo; }
|
||||
ArticleInfo* GetArticleInfo() { return m_pArticleInfo; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
ServerStatList* GetServerStats() { return &m_ServerStats; }
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
bool Terminate();
|
||||
|
||||
12
BinRpc.cpp
12
BinRpc.cpp
@@ -358,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, pRecvBuffer, iBufLen) != Scanner::asFailed;
|
||||
iPriority, NULL, bAddTop, bAddPaused, NULL, pRecvBuffer, iBufLen, true);
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, bOK ? "Collection %s added to queue" : "Download Request failed for %s",
|
||||
@@ -563,7 +563,10 @@ void ListBinCommand::Execute()
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
delete pRegEx;
|
||||
if (pRegEx)
|
||||
{
|
||||
delete pRegEx;
|
||||
}
|
||||
|
||||
ListResponse.m_iNrTrailingNZBEntries = htonl(iNrNZBEntries);
|
||||
ListResponse.m_iNrTrailingPPPEntries = htonl(iNrPPPEntries);
|
||||
@@ -609,7 +612,10 @@ void ListBinCommand::Execute()
|
||||
m_pConnection->Send(buf, bufsize);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
if (buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void LogBinCommand::Execute()
|
||||
|
||||
335
ChangeLog
335
ChangeLog
@@ -1,325 +1,3 @@
|
||||
nzbget-12.0:
|
||||
- added RSS feeds support:
|
||||
- new options "FeedX.Name", "FeedX.URL", "FeedX.Filter",
|
||||
"FeedX.Interval", "FeedX.PauseNzb", "FeedX.Category",
|
||||
"FeedX.Priority" (section "Rss Feeds");
|
||||
- new option "FeedHistory" (section "Download Queue");
|
||||
- button "Preview Feed" on settings tab near each feed definition;
|
||||
- new toolbar button "Feeds" on downloads tab with menu to
|
||||
view feeds or fetch new nzbs from all feeds (the button is
|
||||
visible only if there are feeds defined in settings);
|
||||
- new dialog to see feed content showing status of each item (new,
|
||||
fetched, backlog) with ability to manually fetch selected items;
|
||||
- powerful filters for RSS feeds;
|
||||
- new dialog to build filters in web-interface with instant preview;
|
||||
- added download health monitoring:
|
||||
- health indicates download status, whether the file is damaged
|
||||
and how much;
|
||||
- 100% health means no download errors occurred; 0% means all
|
||||
articles failed;
|
||||
- there is also a critical health which is calculated for each
|
||||
nzb-file based on number and size of par-files;
|
||||
- if during download the health goes down below 100% a health
|
||||
badge appears near download name indicating the necessity of
|
||||
par-repair; the indicator can be orange (repair may be possible)
|
||||
or red (unrepairable) if the health goes down below critical health;
|
||||
- new option "HealthCheck" to define what to do with unhealthy
|
||||
(unrepairable) downloads (pause, delete, none);
|
||||
- health and critical health are displayed in download-edit dialog;
|
||||
health is displayed in history dialog; if download was aborted
|
||||
(HealthCheck=delete) this is indicated in history dialog;
|
||||
- health allows to determine download status for downloads which
|
||||
have unpack and/or par-check disabled; for such downloads the
|
||||
status in history is shown based on health: success (health=100%),
|
||||
damaged (health > critical) or failure (health < critical);
|
||||
- par-check is now automatically started for downloads having
|
||||
health below 100%; this works independently of unpack (even if
|
||||
unpack is disabled);
|
||||
- for downloads having health less than critical health no par-check
|
||||
is performed (it would fail); Instead the par-check status is
|
||||
set to "failure" automatically saving time of actual par-check;
|
||||
- new fields "Health" and "CriticalHealth" are returned by
|
||||
RPC-Method "listgroups";
|
||||
- new fields "Health", "CriticalHealth", "Deleted" and "HealthDeleted"
|
||||
are returned by RPC-Method "history";
|
||||
- new parameters "NZBPP_HEALTH" and "NZBPP_CRITICALHEALTH" are passed
|
||||
to pp-scripts;
|
||||
- added collecting of server usage statistical data for each download:
|
||||
- number of successful and failed article downloads per news server;
|
||||
- new page in history dialog shows collected statistics;
|
||||
- new fields in RPC-method "history": ServerStats (array),
|
||||
TotalArticles, SuccessArticles, FailedArticles;
|
||||
- new env. vars passed to pp-scripts: NZBPP_TOTALARTICLES,
|
||||
NZBPP_SUCCESSARTICLES, NZBPP_FAILEDARTICLES and per used news
|
||||
server: NZBPP_SERVERX_SUCCESSARTICLES, NZBPP_SERVERX_FAILEDARTICLES;
|
||||
- also new env.var HEALTHDELETED;
|
||||
- added smart duplicates feature:
|
||||
- mostly for use with RSS feeds;
|
||||
- automatic detection of duplicate nzb-files to avoid download of
|
||||
duplicates;
|
||||
- nzb-files can be also manually marked as duplicates;
|
||||
- if download fails - automatically choose another release (duplicate);
|
||||
- if download succeeds all remaining duplicates are skipped (not downloaded);
|
||||
- download items have new properties to tune duplicate handling
|
||||
behavior: duplicate key, duplicate score and duplicate mode;
|
||||
- if download was deleted by duplicate check its status in the
|
||||
history is shown as "DUPE";
|
||||
- new actions "GroupSetDupeKey", "GroupSetDupeScore", "GroupSetDupeMode",
|
||||
"HistorySetDupeKey", "HistorySetDupeScore", "HistorySetDupeMode",
|
||||
"HistoryMarkBad" and "HistoryMarkGood" of RPC-command "editqueue";
|
||||
new actions "B" and "G" of command "--edit/-E" for history items
|
||||
(subcommand "H");
|
||||
- when deleting downloads from queue there are three options now:
|
||||
"move to history", "move to history as duplicate" and "delete
|
||||
without history tracking";
|
||||
- new actions "GroupDupeDelete", "GroupFinalDelete" and
|
||||
"HistorySetDupeBackup" in RPC-method "editqueue";
|
||||
- RPC-commands "listgroups", "postqueue" and "history" now return
|
||||
more info about nzb-item (many new fields);
|
||||
- removed option "MergeNzb" because it conflicts with duplicate
|
||||
handling, items can be merged manually if necessary;
|
||||
- automatic detection of exactly same nzb-files (same content)
|
||||
coming from different sources (different RSS feeds etc.);
|
||||
individual files (inside nzb-file) having extensions listed in
|
||||
option "ExtCleanupDisk" are excluded from content comparison
|
||||
(unless these are par2-files, which are never excluded);
|
||||
- when history item expires (as defined by option "KeepHistory")
|
||||
and the duplicate check is active (option "DupeCheck") the item
|
||||
is not completely deleted from history; instead the amount of
|
||||
stored data reduces to minimum required for duplicate check
|
||||
(about 200 bytes vs 2000 bytes for full history item);
|
||||
- such old history items are not shown in web-interface by default
|
||||
(to avoid transferring of large amount of history items);
|
||||
- new button "Hidden" in web-interface to show hidden history items;
|
||||
the items are marked with badge "hidden";
|
||||
- RPC-method "editqueue" has now two actions to delete history
|
||||
records: "HistoryDelete", "HistoryFinal"; action "HistoryDelete"
|
||||
which has existed before now hides records, already hidden records
|
||||
are ignored;
|
||||
- added functions "Mark as Bad" and "Mark as Good" for history
|
||||
items;
|
||||
- duplicate properties (dupekey, dupescore and dupemode) can now
|
||||
be viewed and changed in download-edit-dialog and
|
||||
history-edit-dialog via new button "Dupe";
|
||||
- for full documentation see http://nzbget.sourceforge.net/RSS#Duplicates;
|
||||
- created NZBGet.app - NZBGet is now a user friendly Mac OSX application
|
||||
with easy installation and seamless integration into OS UI:
|
||||
works in background, is controlled from a web-browser, few
|
||||
important functions are accessible via menubar icon;
|
||||
- better Windows package:
|
||||
- unrar is included;
|
||||
- several options are set to better defaults;
|
||||
- all paths are set as relative paths to program directory;
|
||||
the program can be started after installation without editing
|
||||
anything in config;
|
||||
- included two new batch-files:
|
||||
- nzbget-start.bat - starts program in normal mode (dos box);
|
||||
- nzbget-recovery-mode.bat - starts with empty password (dos box);
|
||||
- both batch files open browser window with correct address;
|
||||
- config-file template is stored in nzbget.conf.template;
|
||||
- nzbget.conf is not included in the package. When the program is
|
||||
started for the first time (using one of batch files) the template
|
||||
config file is copied into nzbget.conf;
|
||||
- updates will be easy in the future: to update the program all
|
||||
files from newer archive must be extracted over old files. Since
|
||||
the archive doesn't have nzbget.conf, the existing config is kept
|
||||
unmodified. The template config file will be updated;
|
||||
- added file README-WINDOWS.txt with small instructions;
|
||||
- version string now includes revision number (like "r789");
|
||||
- added automatic updates:
|
||||
- new button "Check for updates" on settings tab of web-interface,
|
||||
in section "SYSTEM", initiates check and shows dialog allowing to
|
||||
install new version;
|
||||
- it is possible to choose between stable, testing and development
|
||||
branches;
|
||||
- this feature is for end-users using binary packages created and
|
||||
updated by maintainers, who need to write an update script specific
|
||||
for platform;
|
||||
- the script is then called by NZBGet when user clicks on install-button;
|
||||
- the script must download and install new version;
|
||||
- for more info visit http://nzbget.sourceforge.net/Packaging;
|
||||
- news servers can now be temporarily disabled via speed limit dialog
|
||||
without reloading of the program:
|
||||
- new option "ServerX.Active" to disable servers via settings;
|
||||
- new option "ServerX.Name" to use for logging and in UI;
|
||||
- changed the way how option "Unpack" works:
|
||||
- instead of enabling/disabling the unpacker as a whole, it now
|
||||
defines the initial value of post-processing parameter "Unpack"
|
||||
for nzb-file when it is added to queue;
|
||||
- this makes it now possible to disable Unpack globally but still
|
||||
enable it for selected nzb-files;
|
||||
- new option "CategoryX.Unpack" to set unpack on a per category basis;
|
||||
- combined all footer buttons into one button "Actions" with menu:
|
||||
- in download-edit-dialog: "Pause/Resume", "Delete" and "Cancel
|
||||
Post-Processing";
|
||||
- in history-dialog: "Delete", "Post-Process Again" and "Download
|
||||
Remaining Files (Return to Queue)";
|
||||
- DirectNZB headers X-DNZB-MoreInfo and X-DNZB-Details are now processed
|
||||
when downloading URLs and the links "More Info" and "Details" are shown
|
||||
in download-edit-dialog and in history-dialog in Actions menu;
|
||||
- program can now be stopped via web-interface: new button "shutdown"
|
||||
in section "SYSTEM";
|
||||
- added menu "View" to settings page which allows to switch to "Compact Mode"
|
||||
when option descriptions are hidden;
|
||||
- added confirmation dialog by leaving settings page if there are unsaved
|
||||
changes;
|
||||
- downloads manually deleted from queue are shown with status "deleted"
|
||||
in the history (instead of "unknown");
|
||||
- all table columns except "Name" now have fixed widths to avoid annoying
|
||||
layout changes especially during post-processing when long status messages
|
||||
are displayed in the name-column;
|
||||
- added filter buttons to messages tab (info, warning, etc.);
|
||||
- added automatic par-renaming of extracted files if archive includes
|
||||
par-files;
|
||||
- added support for http redirects when fetching URLs;
|
||||
- added new command "Download again" for history items; new action
|
||||
"HistoryRedownload" of RPC-method "editqueue"; for controlling via command
|
||||
line: new action "A" of subcommand "H" of command "--edit/-E";
|
||||
- download queue is now saved in a more safe way to avoid potential loss
|
||||
of queue if the program crashes during saving of queue;
|
||||
- destination directory for option "CategoryX.DestDir" is not checked/created
|
||||
on program start anymore (only when a download starts for that category);
|
||||
this helps when certain categories are configured for external disks,
|
||||
which are not always connected;
|
||||
- added new option "CategoryX.Aliases" to configure category name matching
|
||||
with nzb-sites; especially useful with rss feeds;
|
||||
- in RPC-Method "appendurl" parameter "addtop" adds nzb to the top of
|
||||
the main download queue (not only to the top of the URL queue);
|
||||
- new logo (thanks to dogzipp for the logo);
|
||||
- added support for metatag "password" in nzb-files;
|
||||
- pp-scripts which move files can now inform the program about new
|
||||
location by printing text "[NZB] FINALDIR=/path/to/files"; the final
|
||||
path is then shown in history dialog instead of download path;
|
||||
- new env-var "NZBPP_FINALDIR" passed to pp-scripts;
|
||||
- pp-scripts can now set post-processing parameters by printing
|
||||
command "[NZB] NZBPR_varname=value"; this allows scripts which are
|
||||
executed sooner to pass data for scripts executed later;
|
||||
- added new option "AuthorizedIP" to set the list of IP-addresses which
|
||||
may connect without authorization;
|
||||
- new option "ParRename" to force par-renaming as a first post-processing
|
||||
step (active by default); this saves an unpack attempt and is even more
|
||||
useful if unpack is disabled;
|
||||
- post-processing progress label is now automatically trimmed if it
|
||||
doesn't fill into one line; this avoids layout breaking if the text
|
||||
is too long;
|
||||
- reversed the order of priorities in comboboxes in dialogs: the highest
|
||||
priority - at the top, the lowest - at the bottom;
|
||||
- small changes in button captions: edit dialogs called from settings
|
||||
page (choose script, choose order, build rss filter) now have buttons
|
||||
"Discard/Apply" instead of "Close/Save"; in all other dialogs button
|
||||
"Close" renamed to "Cancel" unless it was the only button in dialog;
|
||||
- small change in css: slightly reduced the max height of modal dialogs
|
||||
to better work on notebooks;
|
||||
- options "DeleteCleanupDisk" and "NzbCleanupDisk" are now active by
|
||||
default (in the example config file);
|
||||
- extended add-dialog with options "Add paused" and "Disable duplicate check";
|
||||
- source nzb-files are now deleted when download-item leaves queue and
|
||||
history (option "NzbCleanupDisk");
|
||||
- when deleting downloads from queue the messages about deleted
|
||||
individual files are now printed as "detail" instead of "info";
|
||||
- failed article downloads are now logged as "detail" instead of
|
||||
"warning" to reduce number of warnings for downloads removed from
|
||||
server (DMCA); one warning is printed for a file with a summary of
|
||||
number of failed downloads for the file;
|
||||
- tuned algorithm calculating maximum threads limit to allow more
|
||||
threads for backup server connections (related to option "TreadLimit"
|
||||
removed in v11); this may sometimes increase speed when backup servers
|
||||
were used;
|
||||
- by adding nzb-file to queue via RPC-methods "append" and "appendurl"
|
||||
the actual format of the file is checked and if nzb-format is detected
|
||||
the file is added even if it does not have .nzb extension;
|
||||
- added new option "UrlForce" to allow URL-downloads (including fetching
|
||||
of RSS feeds and nzb-files from feeds) even if download is paused;
|
||||
the option is active by default;
|
||||
- destination directory for option "DestDir" is not checked/created on
|
||||
program start anymore (only when a download starts); this helps when
|
||||
DestDir is mounted to a network drive which is not available on program start;
|
||||
- added special handling for files ".AppleDouble" and ".DS_Store" during
|
||||
unpack to avoid problems on NAS having support for AFP protocol (used
|
||||
on Mac OSX);
|
||||
- history records with failed script status are now shown as "PP-FAILURE"
|
||||
in history list (instead of just "FAILURE");
|
||||
- option "DiskSpace" now checks space on "InterDir" in addition to
|
||||
"DestDir";
|
||||
- support for rar-archives with non-standard extensions is now limited
|
||||
to file extensions consisting of digits; this is to avoid extracting
|
||||
of rar-archives having non-rar extensions on purpose (example: .cbr);
|
||||
- if option "ParRename" is disabled (not recommended) unpacker does
|
||||
not initiate par-rename anymore, instead the full par-verify is
|
||||
performed then;
|
||||
- for external script the exec-permissions are now added automatically;
|
||||
this makes the installation of pp-scripts and other scripts easier;
|
||||
- option "InterDir" is now active by default;
|
||||
- when option "InterDir" is used the intermediate destination directory
|
||||
names now include unique numbers to avoid several downloads with same
|
||||
name to use the same directory and interfere with each other;
|
||||
- when option "UnpackCleanupDisk" is active all archive files are now
|
||||
deleted from download directory without relying on output printed by
|
||||
unrar; this solves issues with non-ascii-characters in archive file
|
||||
names on some platforms and especially in combination with rar5;
|
||||
- improved handling of non-ascii characters in file names on windows;
|
||||
- added support for rar5-format when checking signatures of archives
|
||||
with non-standard file extensions;
|
||||
- small restructure in settings order:
|
||||
- combined sections "REMOTE CONTROL" and "PERMISSIONS" into one
|
||||
section with name "SECURITY";
|
||||
- moved sections "CATEGORIES" and "RSS FEEDS" higher in the
|
||||
section list;
|
||||
- improved par-check: if main par2-file is corrupted and can not be
|
||||
loaded other par2-files are downloaded and then used as replacement
|
||||
for main par2-file;
|
||||
- if unpack did not find archive files the par-check is not requested
|
||||
anymore if par-rename was already done;
|
||||
- better handling of obfuscated nzb-files containing multiple files
|
||||
with same names; removed option "StrictParName" which was not working
|
||||
good with obfuscated files; if more par-files are required for repair
|
||||
the files with strict names are tried first and then other par-files;
|
||||
- added new scheduler commands "ActivateServer", "DeactivateServer" and
|
||||
"FetchFeed"; combined options "TaskX.DownloadRate" and "TaskX.Process"
|
||||
into one option "TaskX.Param", also used by new commands;
|
||||
- added status filter buttons to history page;
|
||||
- if unpack fails with write error (usually because of not enough space
|
||||
on disk) this is shown as status "Unpack: space" in web-interface;
|
||||
this unpack-status is handled as "success" by duplicate handling
|
||||
(no download of other duplicate); also added new unpack-status "wrong
|
||||
password" (only for rar5-archives); env.var. NZBPP_UNPACKSTATUS has
|
||||
two new possible values: 3 (write error) and 4 (wrong password);
|
||||
updated pp-script "EMail.py" to support new unpack-statuses;
|
||||
- fixed a potential seg. fault in a commonly used function;
|
||||
- added new option "TimeCorrection" to adjust conversion from system
|
||||
time to local time (solves issues with scheduler when using a
|
||||
binary compiled for other platform);
|
||||
- NZBIDs are now generated with more care avoiding numbering holes
|
||||
possible in previous versions;
|
||||
- fixed: invalid "Offset" passed to RPC-method "editqueue" or command
|
||||
line action "-E/--edit" could crash the program;
|
||||
- fixed: crash after downloading of an URL (happen only on certain systems);
|
||||
- fixed: restoring of settings didn't work for multi-sections (servers,
|
||||
categories, etc.) if they were empty;
|
||||
- fixed: choosing local files didn't work in Opera;
|
||||
- fixed: certain characters printed by pp-scripts could crash the
|
||||
program;
|
||||
- fixed: malformed nzb-file could cause a memory leak;
|
||||
- fixed: when a duplicate file was detected in collection it was
|
||||
automatically deleted (if option DupeCheck is active) but the
|
||||
total size of collection was not updated;
|
||||
- when deleting individual files the total count of files in collection
|
||||
was not updated;
|
||||
- fixed: when multiple nzb-files were added via URL (rss including) at
|
||||
the same time the info about category and priority could get lost for
|
||||
some of files;
|
||||
- fixed: if unpack fails the created destination directory was not
|
||||
automatically removed (only if option "InterDir" was active);
|
||||
- fixed scrolling to the top of page happening by clicking on items in
|
||||
downloads/history lists and on action-buttons in edit-download and
|
||||
history dialogs;
|
||||
- fixed potential buffer overflow in remote client;
|
||||
- improved error reporting when creation of temporary output file fails;
|
||||
- fixed: when deleting download, if all remaining queued files are
|
||||
par2-files the disk cleanup should not be performed, but it was
|
||||
sometimes;
|
||||
- fixed a potential problem in incorrect using of one library function.
|
||||
|
||||
nzbget-11.0:
|
||||
- reworked concept of post-processing scripts:
|
||||
- multiple scripts can be assigned to each nzb-file;
|
||||
@@ -711,17 +389,6 @@ nzbget-10.0:
|
||||
and in configuration options were not displayed properly and could be
|
||||
discarded on saving;
|
||||
|
||||
nzbget-9.1:
|
||||
- added full par-scan feature needed to par-check/repair files which
|
||||
were renamed after creation of par-files:
|
||||
- new option <ParScan> to activate full par-scan (always or automatic);
|
||||
the automatic full par-scan activates if missing files are detected
|
||||
during par-check, this avoids unnecessary full scan for normal
|
||||
(not renamed) par sets;
|
||||
- improved the post-processing script to better handle renamed rar-files;
|
||||
- replaced a browser error message when trying to add local files in
|
||||
IE9 with a better message dialog;
|
||||
|
||||
nzbget-9.0:
|
||||
- changed version naming scheme by removing the leading zero: current
|
||||
version is now called 9.0 instead of 0.9.0 (it's really the 9th major
|
||||
@@ -1438,7 +1105,7 @@ nzbget-0.3.0:
|
||||
of completing and state (paused or not) for every file is printed.
|
||||
The header of queue shows number of total files, number of unpaused
|
||||
files and size for all and unpaused files. Better using of screen estate
|
||||
space - no more empty lines and separate header for status (total seven
|
||||
space <EFBFBD> no more empty lines and separate header for status (total seven
|
||||
lines gain). The messages are printed on several lines (if they not fill
|
||||
in one line) without trimming now;
|
||||
- configure.ac-file updated to work with recent versions of autoconf/automake.
|
||||
|
||||
@@ -164,11 +164,21 @@ Connection::~Connection()
|
||||
|
||||
Disconnect();
|
||||
|
||||
free(m_szHost);
|
||||
free(m_szCipher);
|
||||
if (m_szHost)
|
||||
{
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
|
||||
free(m_szReadBuf);
|
||||
#ifndef DISABLE_TLS
|
||||
delete m_pTLSSocket;
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
delete m_pTLSSocket;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -185,7 +195,10 @@ void Connection::SetSuppressErrors(bool bSuppressErrors)
|
||||
|
||||
void Connection::SetCipher(const char* szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
m_szCipher = szCipher ? strdup(szCipher) : NULL;
|
||||
}
|
||||
|
||||
@@ -731,7 +744,11 @@ bool Connection::StartTLS(bool bIsClient, const char* szCertFile, const char* sz
|
||||
{
|
||||
debug("Starting TLS");
|
||||
|
||||
delete m_pTLSSocket;
|
||||
if (m_pTLSSocket)
|
||||
{
|
||||
delete m_pTLSSocket;
|
||||
}
|
||||
|
||||
m_pTLSSocket = new TLSSocket(m_iSocket, bIsClient, szCertFile, szKeyFile, m_szCipher);
|
||||
m_pTLSSocket->SetSuppressErrors(m_bSuppressErrors);
|
||||
|
||||
|
||||
20
Decoder.cpp
20
Decoder.cpp
@@ -60,12 +60,18 @@ Decoder::~ Decoder()
|
||||
{
|
||||
debug("Destroying Decoder");
|
||||
|
||||
free(m_szArticleFilename);
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::Clear()
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = NULL;
|
||||
}
|
||||
|
||||
@@ -262,7 +268,10 @@ BreakLoop:
|
||||
pb += 6; //=strlen(" name=")
|
||||
char* pe;
|
||||
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
|
||||
free(m_szArticleFilename);
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = (char*)malloc(pe - pb + 1);
|
||||
strncpy(m_szArticleFilename, pb, pe - pb);
|
||||
m_szArticleFilename[pe - pb] = '\0';
|
||||
@@ -395,7 +404,10 @@ unsigned int UDecoder::DecodeBuffer(char* buffer, int len)
|
||||
// extracting filename
|
||||
char* pe;
|
||||
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
|
||||
free(m_szArticleFilename);
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = (char*)malloc(pe - pb + 1);
|
||||
strncpy(m_szArticleFilename, pb, pe - pb);
|
||||
m_szArticleFilename[pe - pb] = '\0';
|
||||
|
||||
1183
DiskState.cpp
1183
DiskState.cpp
File diff suppressed because it is too large
Load Diff
18
DiskState.h
18
DiskState.h
@@ -27,13 +27,10 @@
|
||||
#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);
|
||||
@@ -48,32 +45,19 @@ private:
|
||||
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 PostQueueExists(bool bCompleted);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
563
DownloadInfo.cpp
563
DownloadInfo.cpp
@@ -42,21 +42,16 @@
|
||||
#include "nzbget.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
int FileInfo::m_iIDGen = 0;
|
||||
int FileInfo::m_iIDMax = 0;
|
||||
int NZBInfo::m_iIDGen = 0;
|
||||
int NZBInfo::m_iIDMax = 0;
|
||||
int PostInfo::m_iIDGen = 0;
|
||||
int PostInfo::m_iIDMax = 0;
|
||||
int UrlInfo::m_iIDGen = 0;
|
||||
int UrlInfo::m_iIDMax = 0;
|
||||
int HistoryInfo::m_iIDGen = 0;
|
||||
int HistoryInfo::m_iIDMax = 0;
|
||||
|
||||
|
||||
NZBParameter::NZBParameter(const char* szName)
|
||||
{
|
||||
@@ -66,31 +61,26 @@ NZBParameter::NZBParameter(const char* szName)
|
||||
|
||||
NZBParameter::~NZBParameter()
|
||||
{
|
||||
free(m_szName);
|
||||
free(m_szValue);
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
if (m_szValue)
|
||||
{
|
||||
free(m_szValue);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBParameter::SetValue(const char* szValue)
|
||||
{
|
||||
free(m_szValue);
|
||||
if (m_szValue)
|
||||
{
|
||||
free(m_szValue);
|
||||
}
|
||||
m_szValue = strdup(szValue);
|
||||
}
|
||||
|
||||
|
||||
NZBParameterList::~NZBParameterList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void NZBParameterList::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
void NZBParameterList::SetParameter(const char* szName, const char* szValue)
|
||||
{
|
||||
NZBParameter* pParameter = NULL;
|
||||
@@ -126,30 +116,6 @@ void NZBParameterList::SetParameter(const char* szName, const char* szValue)
|
||||
pParameter->SetValue(szValue);
|
||||
}
|
||||
|
||||
NZBParameter* NZBParameterList::Find(const char* szName, bool bCaseSensitive)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
if ((bCaseSensitive && !strcmp(pParameter->GetName(), szName)) ||
|
||||
(!bCaseSensitive && !strcasecmp(pParameter->GetName(), szName)))
|
||||
{
|
||||
return pParameter;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NZBParameterList::CopyFrom(NZBParameterList* pSourceParameters)
|
||||
{
|
||||
for (iterator it = pSourceParameters->begin(); it != pSourceParameters->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
SetParameter(pParameter->GetName(), pParameter->GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScriptStatus::ScriptStatus(const char* szName, EStatus eStatus)
|
||||
{
|
||||
@@ -159,7 +125,10 @@ ScriptStatus::ScriptStatus(const char* szName, EStatus eStatus)
|
||||
|
||||
ScriptStatus::~ScriptStatus()
|
||||
{
|
||||
free(m_szName);
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,85 +170,17 @@ ScriptStatus::EStatus ScriptStatusList::CalcTotalStatus()
|
||||
}
|
||||
|
||||
|
||||
ServerStat::ServerStat(int iServerID)
|
||||
{
|
||||
m_iServerID = iServerID;
|
||||
m_iSuccessArticles = 0;
|
||||
m_iFailedArticles = 0;
|
||||
}
|
||||
|
||||
|
||||
ServerStatList::~ServerStatList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void ServerStatList::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
void ServerStatList::SetStat(int iServerID, int iSuccessArticles, int iFailedArticles, bool bAdd)
|
||||
{
|
||||
ServerStat* pServerStat = NULL;
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
ServerStat* pServerStat1 = *it;
|
||||
if (pServerStat1->GetServerID() == iServerID)
|
||||
{
|
||||
pServerStat = pServerStat1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pServerStat)
|
||||
{
|
||||
pServerStat = new ServerStat(iServerID);
|
||||
push_back(pServerStat);
|
||||
}
|
||||
|
||||
pServerStat->SetSuccessArticles((bAdd ? pServerStat->GetSuccessArticles() : 0) + iSuccessArticles);
|
||||
pServerStat->SetFailedArticles((bAdd ? pServerStat->GetFailedArticles() : 0) + iFailedArticles);
|
||||
}
|
||||
|
||||
void ServerStatList::Add(ServerStatList* pServerStats)
|
||||
{
|
||||
for (iterator it = pServerStats->begin(); it != pServerStats->end(); it++)
|
||||
{
|
||||
ServerStat* pServerStat = *it;
|
||||
SetStat(pServerStat->GetServerID(), pServerStat->GetSuccessArticles(), pServerStat->GetFailedArticles(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NZBInfo::NZBInfo(bool bPersistent)
|
||||
NZBInfo::NZBInfo()
|
||||
{
|
||||
debug("Creating NZBInfo");
|
||||
|
||||
m_szFilename = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_szFinalDir = strdup("");
|
||||
m_szCategory = strdup("");
|
||||
m_szName = NULL;
|
||||
m_iFileCount = 0;
|
||||
m_iParkedFileCount = 0;
|
||||
m_lSize = 0;
|
||||
m_lSuccessSize = 0;
|
||||
m_lFailedSize = 0;
|
||||
m_lCurrentSuccessSize = 0;
|
||||
m_lCurrentFailedSize = 0;
|
||||
m_lParSize = 0;
|
||||
m_lParSuccessSize = 0;
|
||||
m_lParFailedSize = 0;
|
||||
m_lParCurrentSuccessSize = 0;
|
||||
m_lParCurrentFailedSize = 0;
|
||||
m_iTotalArticles = 0;
|
||||
m_iSuccessArticles = 0;
|
||||
m_iFailedArticles = 0;
|
||||
m_iRefCount = 0;
|
||||
m_bPostProcess = false;
|
||||
m_eRenameStatus = rsNone;
|
||||
@@ -287,42 +188,51 @@ NZBInfo::NZBInfo(bool bPersistent)
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eCleanupStatus = csNone;
|
||||
m_eMoveStatus = msNone;
|
||||
m_eDeleteStatus = dsNone;
|
||||
m_eMarkStatus = ksNone;
|
||||
m_bDeleting = false;
|
||||
m_bDeletePaused = false;
|
||||
m_bManyDupeFiles = false;
|
||||
m_bAvoidHistory = false;
|
||||
m_bHealthPaused = false;
|
||||
m_bDeleted = false;
|
||||
m_bParCleanup = false;
|
||||
m_bCleanupDisk = false;
|
||||
m_bUnpackCleanedUpDisk = false;
|
||||
m_szQueuedFilename = strdup("");
|
||||
m_szDupeKey = strdup("");
|
||||
m_iDupeScore = 0;
|
||||
m_eDupeMode = dmScore;
|
||||
m_iFullContentHash = 0;
|
||||
m_iFilteredContentHash = 0;
|
||||
m_Owner = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDMessageGen = 0;
|
||||
m_iID = bPersistent ? ++m_iIDGen : 0;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
NZBInfo::~NZBInfo()
|
||||
{
|
||||
debug("Destroying NZBInfo");
|
||||
|
||||
free(m_szFilename);
|
||||
free(m_szDestDir);
|
||||
free(m_szFinalDir);
|
||||
free(m_szCategory);
|
||||
free(m_szName);
|
||||
free(m_szQueuedFilename);
|
||||
free(m_szDupeKey);
|
||||
if (m_szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
if (m_szQueuedFilename)
|
||||
{
|
||||
free(m_szQueuedFilename);
|
||||
}
|
||||
|
||||
ClearCompletedFiles();
|
||||
|
||||
for (NZBParameterList::iterator it = m_ppParameters.begin(); it != m_ppParameters.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_ppParameters.clear();
|
||||
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
@@ -335,7 +245,7 @@ NZBInfo::~NZBInfo()
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::Retain()
|
||||
void NZBInfo::AddReference()
|
||||
{
|
||||
m_iRefCount++;
|
||||
}
|
||||
@@ -352,22 +262,9 @@ void NZBInfo::Release()
|
||||
void NZBInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDMax < m_iID)
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDMax = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::ResetGenID(bool bMax)
|
||||
{
|
||||
if (bMax)
|
||||
{
|
||||
m_iIDGen = m_iIDMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iIDGen = 0;
|
||||
m_iIDMax = 0;
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,19 +279,19 @@ void NZBInfo::ClearCompletedFiles()
|
||||
|
||||
void NZBInfo::SetDestDir(const char* szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void NZBInfo::SetFinalDir(const char* szFinalDir)
|
||||
{
|
||||
free(m_szFinalDir);
|
||||
m_szFinalDir = strdup(szFinalDir);
|
||||
}
|
||||
|
||||
void NZBInfo::SetFilename(const char * szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
if (m_szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
m_szFilename = strdup(szFilename);
|
||||
|
||||
if (!m_szName)
|
||||
@@ -402,37 +299,37 @@ void NZBInfo::SetFilename(const char * szFilename)
|
||||
char szNZBNicename[1024];
|
||||
MakeNiceNZBName(m_szFilename, szNZBNicename, sizeof(szNZBNicename), true);
|
||||
szNZBNicename[1024-1] = '\0';
|
||||
#ifdef WIN32
|
||||
WebUtil::AnsiToUtf8(szNZBNicename, 1024);
|
||||
#endif
|
||||
SetName(szNZBNicename);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::SetName(const char* szName)
|
||||
{
|
||||
free(m_szName);
|
||||
if (m_szName)
|
||||
{
|
||||
free(m_szName);
|
||||
}
|
||||
m_szName = szName ? strdup(szName) : NULL;
|
||||
}
|
||||
|
||||
void NZBInfo::SetCategory(const char* szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
m_szCategory = strdup(szCategory);
|
||||
}
|
||||
|
||||
void NZBInfo::SetQueuedFilename(const char * szQueuedFilename)
|
||||
{
|
||||
free(m_szQueuedFilename);
|
||||
if (m_szQueuedFilename)
|
||||
{
|
||||
free(m_szQueuedFilename);
|
||||
}
|
||||
m_szQueuedFilename = strdup(szQueuedFilename);
|
||||
}
|
||||
|
||||
void NZBInfo::SetDupeKey(const char* szDupeKey)
|
||||
{
|
||||
free(m_szDupeKey);
|
||||
m_szDupeKey = strdup(szDupeKey ? szDupeKey : "");
|
||||
}
|
||||
|
||||
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize, bool bRemoveExt)
|
||||
{
|
||||
char postname[1024];
|
||||
@@ -458,20 +355,16 @@ void NZBInfo::BuildDestDirName()
|
||||
{
|
||||
char szDestDir[1024];
|
||||
|
||||
if (Util::EmptyStr(g_pOptions->GetInterDir()))
|
||||
if (strlen(g_pOptions->GetInterDir()) == 0)
|
||||
{
|
||||
BuildFinalDirName(szDestDir, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szDestDir, 1024, "%s%s.#%i", g_pOptions->GetInterDir(), GetName(), GetID());
|
||||
snprintf(szDestDir, 1024, "%s%s", g_pOptions->GetInterDir(), GetName());
|
||||
szDestDir[1024-1] = '\0';
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
WebUtil::Utf8ToAnsi(szDestDir, 1024);
|
||||
#endif
|
||||
|
||||
SetDestDir(szDestDir);
|
||||
}
|
||||
|
||||
@@ -485,7 +378,7 @@ void NZBInfo::BuildFinalDirName(char* szFinalDirBuf, int iBufSize)
|
||||
|
||||
if (bUseCategory)
|
||||
{
|
||||
Options::Category *pCategory = g_pOptions->FindCategory(m_szCategory, false);
|
||||
Options::Category *pCategory = g_pOptions->FindCategory(m_szCategory);
|
||||
if (pCategory && pCategory->GetDestDir() && pCategory->GetDestDir()[0] != '\0')
|
||||
{
|
||||
snprintf(szFinalDirBuf, iBufSize, "%s", pCategory->GetDestDir());
|
||||
@@ -509,47 +402,11 @@ void NZBInfo::BuildFinalDirName(char* szFinalDirBuf, int iBufSize)
|
||||
snprintf(szBuffer, 1024, "%s%s", szFinalDirBuf, GetName());
|
||||
szBuffer[1024-1] = '\0';
|
||||
strncpy(szFinalDirBuf, szBuffer, iBufSize);
|
||||
|
||||
#ifdef WIN32
|
||||
WebUtil::Utf8ToAnsi(szFinalDirBuf, iBufSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
int NZBInfo::CalcHealth()
|
||||
void NZBInfo::SetParameter(const char* szName, const char* szValue)
|
||||
{
|
||||
if (m_lCurrentFailedSize == 0 || m_lSize == m_lParSize)
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
int iHealth = (int)(Util::Int64ToFloat(m_lSize - m_lParSize -
|
||||
(m_lCurrentFailedSize - m_lParCurrentFailedSize)) * 1000.0 /
|
||||
Util::Int64ToFloat(m_lSize - m_lParSize));
|
||||
|
||||
if (iHealth == 1000 && m_lCurrentFailedSize - m_lParCurrentFailedSize > 0)
|
||||
{
|
||||
iHealth = 999;
|
||||
}
|
||||
|
||||
return iHealth;
|
||||
}
|
||||
|
||||
int NZBInfo::CalcCriticalHealth()
|
||||
{
|
||||
long long lGoodParSize = m_lParSize - m_lParCurrentFailedSize;
|
||||
int iCriticalHealth = (int)(Util::Int64ToFloat(m_lSize - lGoodParSize*2) * 1000.0 /
|
||||
Util::Int64ToFloat(m_lSize - lGoodParSize));
|
||||
|
||||
if (lGoodParSize*2 > m_lSize)
|
||||
{
|
||||
iCriticalHealth = 0;
|
||||
}
|
||||
else if (iCriticalHealth == 1000 && m_lParSize > 0)
|
||||
{
|
||||
iCriticalHealth = 999;
|
||||
}
|
||||
|
||||
return iCriticalHealth;
|
||||
m_ppParameters.SetParameter(szName, szValue);
|
||||
}
|
||||
|
||||
NZBInfo::Messages* NZBInfo::LockMessages()
|
||||
@@ -628,19 +485,27 @@ ArticleInfo::~ ArticleInfo()
|
||||
{
|
||||
//debug("Destroying ArticleInfo");
|
||||
|
||||
free(m_szMessageID);
|
||||
free(m_szResultFilename);
|
||||
if (m_szMessageID)
|
||||
{
|
||||
free(m_szMessageID);
|
||||
}
|
||||
if (m_szResultFilename)
|
||||
{
|
||||
free(m_szResultFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void ArticleInfo::SetMessageID(const char * szMessageID)
|
||||
{
|
||||
free(m_szMessageID);
|
||||
m_szMessageID = strdup(szMessageID);
|
||||
}
|
||||
|
||||
void ArticleInfo::SetResultFilename(const char * v)
|
||||
{
|
||||
free(m_szResultFilename);
|
||||
if (m_szResultFilename)
|
||||
{
|
||||
free(m_szResultFilename);
|
||||
}
|
||||
m_szResultFilename = strdup(v);
|
||||
}
|
||||
|
||||
@@ -658,35 +523,40 @@ FileInfo::FileInfo()
|
||||
m_bFilenameConfirmed = false;
|
||||
m_lSize = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_lMissedSize = 0;
|
||||
m_lSuccessSize = 0;
|
||||
m_lFailedSize = 0;
|
||||
m_iTotalArticles = 0;
|
||||
m_iMissedArticles = 0;
|
||||
m_iFailedArticles = 0;
|
||||
m_iSuccessArticles = 0;
|
||||
m_tTime = 0;
|
||||
m_bPaused = false;
|
||||
m_bDeleted = false;
|
||||
m_iCompleted = 0;
|
||||
m_bParFile = false;
|
||||
m_bOutputInitialized = false;
|
||||
m_pNZBInfo = NULL;
|
||||
m_iPriority = 0;
|
||||
m_bExtraPriority = false;
|
||||
m_iActiveDownloads = 0;
|
||||
m_bAutoDeleted = false;
|
||||
m_iID = ++m_iIDGen;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
FileInfo::~ FileInfo()
|
||||
{
|
||||
debug("Destroying FileInfo");
|
||||
|
||||
free(m_szSubject);
|
||||
free(m_szFilename);
|
||||
free(m_szOutputFilename);
|
||||
delete m_pMutexOutputFile;
|
||||
if (m_szSubject)
|
||||
{
|
||||
free(m_szSubject);
|
||||
}
|
||||
if (m_szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
if (m_pMutexOutputFile)
|
||||
{
|
||||
delete m_pMutexOutputFile;
|
||||
}
|
||||
|
||||
for (Groups::iterator it = m_Groups.begin(); it != m_Groups.end() ;it++)
|
||||
{
|
||||
@@ -714,22 +584,9 @@ void FileInfo::ClearArticles()
|
||||
void FileInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDMax < m_iID)
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDMax = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfo::ResetGenID(bool bMax)
|
||||
{
|
||||
if (bMax)
|
||||
{
|
||||
m_iIDGen = m_iIDMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iIDGen = 0;
|
||||
m_iIDMax = 0;
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,7 +597,7 @@ void FileInfo::SetNZBInfo(NZBInfo* pNZBInfo)
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
m_pNZBInfo = pNZBInfo;
|
||||
m_pNZBInfo->Retain();
|
||||
m_pNZBInfo->AddReference();
|
||||
}
|
||||
|
||||
void FileInfo::SetSubject(const char* szSubject)
|
||||
@@ -750,7 +607,10 @@ void FileInfo::SetSubject(const char* szSubject)
|
||||
|
||||
void FileInfo::SetFilename(const char* szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
if (m_szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
m_szFilename = strdup(szFilename);
|
||||
}
|
||||
|
||||
@@ -771,7 +631,10 @@ void FileInfo::UnlockOutputFile()
|
||||
|
||||
void FileInfo::SetOutputFilename(const char* szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
m_szOutputFilename = strdup(szOutputFilename);
|
||||
}
|
||||
|
||||
@@ -790,6 +653,24 @@ void FileInfo::SetActiveDownloads(int iActiveDownloads)
|
||||
}
|
||||
}
|
||||
|
||||
bool FileInfo::IsDupe(const char* szFilename)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%c%s", m_pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, szFilename);
|
||||
fileName[1024-1] = '\0';
|
||||
if (Util::FileExists(fileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
snprintf(fileName, 1024, "%s%c%s_broken", m_pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, szFilename);
|
||||
fileName[1024-1] = '\0';
|
||||
if (Util::FileExists(fileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GroupInfo::GroupInfo()
|
||||
{
|
||||
@@ -815,22 +696,6 @@ GroupInfo::~GroupInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GroupQueue::~GroupQueue()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void GroupQueue::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
PostInfo::PostInfo()
|
||||
{
|
||||
debug("Creating PostInfo");
|
||||
@@ -840,6 +705,7 @@ PostInfo::PostInfo()
|
||||
m_bWorking = false;
|
||||
m_bDeleted = false;
|
||||
m_bRequestParCheck = false;
|
||||
m_bRequestParRename = false;
|
||||
m_szProgressLabel = strdup("");
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
@@ -849,15 +715,22 @@ PostInfo::PostInfo()
|
||||
m_pPostThread = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDMessageGen = 0;
|
||||
m_iID = ++m_iIDGen;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
PostInfo::~ PostInfo()
|
||||
{
|
||||
debug("Destroying PostInfo");
|
||||
|
||||
free(m_szInfoName);
|
||||
free(m_szProgressLabel);
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szProgressLabel)
|
||||
{
|
||||
free(m_szProgressLabel);
|
||||
}
|
||||
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
@@ -878,7 +751,7 @@ void PostInfo::SetNZBInfo(NZBInfo* pNZBInfo)
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
m_pNZBInfo = pNZBInfo;
|
||||
m_pNZBInfo->Retain();
|
||||
m_pNZBInfo->AddReference();
|
||||
}
|
||||
|
||||
void PostInfo::SetInfoName(const char* szInfoName)
|
||||
@@ -888,7 +761,10 @@ void PostInfo::SetInfoName(const char* szInfoName)
|
||||
|
||||
void PostInfo::SetProgressLabel(const char* szProgressLabel)
|
||||
{
|
||||
free(m_szProgressLabel);
|
||||
if (m_szProgressLabel)
|
||||
{
|
||||
free(m_szProgressLabel);
|
||||
}
|
||||
m_szProgressLabel = strdup(szProgressLabel);
|
||||
}
|
||||
|
||||
@@ -918,7 +794,6 @@ void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
{
|
||||
std::map<int, GroupInfo*> groupMap;
|
||||
@@ -931,7 +806,7 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
{
|
||||
pGroupInfo = new GroupInfo();
|
||||
pGroupInfo->m_pNZBInfo = pFileInfo->GetNZBInfo();
|
||||
pGroupInfo->m_pNZBInfo->Retain();
|
||||
pGroupInfo->m_pNZBInfo->AddReference();
|
||||
pGroupInfo->m_iFirstID = pFileInfo->GetID();
|
||||
pGroupInfo->m_iLastID = pFileInfo->GetID();
|
||||
pGroupInfo->m_tMinTime = pFileInfo->GetTime();
|
||||
@@ -991,75 +866,70 @@ void DownloadQueue::BuildGroups(GroupQueue* pGroupQueue)
|
||||
|
||||
UrlInfo::UrlInfo()
|
||||
{
|
||||
//debug("Creating UrlInfo");
|
||||
//debug("Creating ArticleInfo");
|
||||
m_szURL = NULL;
|
||||
m_szNZBFilename = strdup("");
|
||||
m_szCategory = strdup("");
|
||||
m_iPriority = 0;
|
||||
m_iDupeScore = 0;
|
||||
m_szDupeKey = strdup("");
|
||||
m_eDupeMode = dmScore;
|
||||
m_bAddTop = false;
|
||||
m_bAddPaused = false;
|
||||
m_bForce = false;
|
||||
m_eStatus = aiUndefined;
|
||||
m_iID = ++m_iIDGen;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
UrlInfo::~ UrlInfo()
|
||||
{
|
||||
free(m_szURL);
|
||||
free(m_szNZBFilename);
|
||||
free(m_szCategory);
|
||||
free(m_szDupeKey);
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
}
|
||||
|
||||
void UrlInfo::SetURL(const char* szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
m_szURL = strdup(szURL);
|
||||
}
|
||||
|
||||
void UrlInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDMax < m_iID)
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDMax = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void UrlInfo::ResetGenID(bool bMax)
|
||||
{
|
||||
if (bMax)
|
||||
{
|
||||
m_iIDGen = m_iIDMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iIDGen = 0;
|
||||
m_iIDMax = 0;
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void UrlInfo::SetNZBFilename(const char* szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
m_szNZBFilename = strdup(szNZBFilename);
|
||||
}
|
||||
|
||||
void UrlInfo::SetCategory(const char* szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
m_szCategory = strdup(szCategory);
|
||||
}
|
||||
|
||||
void UrlInfo::SetDupeKey(const char* szDupeKey)
|
||||
{
|
||||
free(m_szDupeKey);
|
||||
m_szDupeKey = strdup(szDupeKey);
|
||||
}
|
||||
|
||||
void UrlInfo::GetName(char* szBuffer, int iSize)
|
||||
{
|
||||
MakeNiceName(m_szURL, m_szNZBFilename, szBuffer, iSize);
|
||||
@@ -1084,44 +954,14 @@ void UrlInfo::MakeNiceName(const char* szURL, const char* szNZBFilename, char* s
|
||||
}
|
||||
|
||||
|
||||
DupInfo::DupInfo()
|
||||
{
|
||||
m_szName = NULL;
|
||||
m_szDupeKey = NULL;
|
||||
m_iDupeScore = 0;
|
||||
m_eDupeMode = dmScore;
|
||||
m_lSize = 0;
|
||||
m_iFullContentHash = 0;
|
||||
m_iFilteredContentHash = 0;
|
||||
m_eStatus = dsUndefined;
|
||||
}
|
||||
|
||||
DupInfo::~DupInfo()
|
||||
{
|
||||
free(m_szName);
|
||||
free(m_szDupeKey);
|
||||
}
|
||||
|
||||
void DupInfo::SetName(const char* szName)
|
||||
{
|
||||
free(m_szName);
|
||||
m_szName = strdup(szName);
|
||||
}
|
||||
|
||||
void DupInfo::SetDupeKey(const char* szDupeKey)
|
||||
{
|
||||
free(m_szDupeKey);
|
||||
m_szDupeKey = strdup(szDupeKey);
|
||||
}
|
||||
|
||||
|
||||
HistoryInfo::HistoryInfo(NZBInfo* pNZBInfo)
|
||||
{
|
||||
m_eKind = hkNZBInfo;
|
||||
m_pInfo = pNZBInfo;
|
||||
pNZBInfo->Retain();
|
||||
pNZBInfo->AddReference();
|
||||
m_tTime = 0;
|
||||
m_iID = ++m_iIDGen;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
HistoryInfo::HistoryInfo(UrlInfo* pUrlInfo)
|
||||
@@ -1129,15 +969,8 @@ HistoryInfo::HistoryInfo(UrlInfo* pUrlInfo)
|
||||
m_eKind = hkUrlInfo;
|
||||
m_pInfo = pUrlInfo;
|
||||
m_tTime = 0;
|
||||
m_iID = ++m_iIDGen;
|
||||
}
|
||||
|
||||
HistoryInfo::HistoryInfo(DupInfo* pDupInfo)
|
||||
{
|
||||
m_eKind = hkDupInfo;
|
||||
m_pInfo = pDupInfo;
|
||||
m_tTime = 0;
|
||||
m_iID = ++m_iIDGen;
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
HistoryInfo::~HistoryInfo()
|
||||
@@ -1150,31 +983,14 @@ HistoryInfo::~HistoryInfo()
|
||||
{
|
||||
delete (UrlInfo*)m_pInfo;
|
||||
}
|
||||
else if (m_eKind == hkDupInfo && m_pInfo)
|
||||
{
|
||||
delete (DupInfo*)m_pInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInfo::SetID(int iID)
|
||||
{
|
||||
m_iID = iID;
|
||||
if (m_iIDMax < m_iID)
|
||||
if (m_iIDGen < m_iID)
|
||||
{
|
||||
m_iIDMax = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInfo::ResetGenID(bool bMax)
|
||||
{
|
||||
if (bMax)
|
||||
{
|
||||
m_iIDGen = m_iIDMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iIDGen = 0;
|
||||
m_iIDMax = 0;
|
||||
m_iIDGen = m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1189,11 +1005,6 @@ void HistoryInfo::GetName(char* szBuffer, int iSize)
|
||||
{
|
||||
GetUrlInfo()->GetName(szBuffer, iSize);
|
||||
}
|
||||
else if (m_eKind == hkDupInfo)
|
||||
{
|
||||
strncpy(szBuffer, GetDupInfo()->GetName(), iSize);
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(szBuffer, "<unknown>", iSize);
|
||||
|
||||
267
DownloadInfo.h
267
DownloadInfo.h
@@ -85,18 +85,10 @@ private:
|
||||
char* m_szFilename;
|
||||
long long m_lSize;
|
||||
long long m_lRemainingSize;
|
||||
long long m_lSuccessSize;
|
||||
long long m_lFailedSize;
|
||||
long long m_lMissedSize;
|
||||
int m_iTotalArticles;
|
||||
int m_iMissedArticles;
|
||||
int m_iFailedArticles;
|
||||
int m_iSuccessArticles;
|
||||
time_t m_tTime;
|
||||
bool m_bPaused;
|
||||
bool m_bDeleted;
|
||||
bool m_bFilenameConfirmed;
|
||||
bool m_bParFile;
|
||||
int m_iCompleted;
|
||||
bool m_bOutputInitialized;
|
||||
char* m_szOutputFilename;
|
||||
@@ -107,14 +99,12 @@ private:
|
||||
bool m_bAutoDeleted;
|
||||
|
||||
static int m_iIDGen;
|
||||
static int m_iIDMax;
|
||||
|
||||
public:
|
||||
FileInfo();
|
||||
~FileInfo();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int iID);
|
||||
static void ResetGenID(bool bMax);
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
void SetNZBInfo(NZBInfo* pNZBInfo);
|
||||
Articles* GetArticles() { return &m_Articles; }
|
||||
@@ -126,24 +116,10 @@ public:
|
||||
void MakeValidFilename();
|
||||
bool GetFilenameConfirmed() { return m_bFilenameConfirmed; }
|
||||
void SetFilenameConfirmed(bool bFilenameConfirmed) { m_bFilenameConfirmed = bFilenameConfirmed; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; m_lRemainingSize = lSize; }
|
||||
void SetSize(long long s) { m_lSize = s; m_lRemainingSize = s; }
|
||||
long long GetSize() { return m_lSize; }
|
||||
long long GetRemainingSize() { return m_lRemainingSize; }
|
||||
void SetRemainingSize(long long lRemainingSize) { m_lRemainingSize = lRemainingSize; }
|
||||
long long GetMissedSize() { return m_lMissedSize; }
|
||||
void SetMissedSize(long long lMissedSize) { m_lMissedSize = lMissedSize; }
|
||||
long long GetSuccessSize() { return m_lSuccessSize; }
|
||||
void SetSuccessSize(long long lSuccessSize) { m_lSuccessSize = lSuccessSize; }
|
||||
long long GetFailedSize() { return m_lFailedSize; }
|
||||
void SetFailedSize(long long lFailedSize) { m_lFailedSize = lFailedSize; }
|
||||
int GetTotalArticles() { return m_iTotalArticles; }
|
||||
void SetTotalArticles(int iTotalArticles) { m_iTotalArticles = iTotalArticles; }
|
||||
int GetMissedArticles() { return m_iMissedArticles; }
|
||||
void SetMissedArticles(int iMissedArticles) { m_iMissedArticles = iMissedArticles; }
|
||||
int GetFailedArticles() { return m_iFailedArticles; }
|
||||
void SetFailedArticles(int iFailedArticles) { m_iFailedArticles = iFailedArticles; }
|
||||
int GetSuccessArticles() { return m_iSuccessArticles; }
|
||||
void SetSuccessArticles(int iSuccessArticles) { m_iSuccessArticles = iSuccessArticles; }
|
||||
void SetRemainingSize(long long s) { m_lRemainingSize = s; }
|
||||
time_t GetTime() { return m_tTime; }
|
||||
void SetTime(time_t tTime) { m_tTime = tTime; }
|
||||
bool GetPaused() { return m_bPaused; }
|
||||
@@ -151,9 +127,7 @@ public:
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
void SetDeleted(bool Deleted) { m_bDeleted = Deleted; }
|
||||
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 SetCompleted(int s) { m_iCompleted = s; }
|
||||
void ClearArticles();
|
||||
void LockOutputFile();
|
||||
void UnlockOutputFile();
|
||||
@@ -161,6 +135,7 @@ public:
|
||||
void SetOutputFilename(const char* szOutputFilename);
|
||||
bool GetOutputInitialized() { return m_bOutputInitialized; }
|
||||
void SetOutputInitialized(bool bOutputInitialized) { m_bOutputInitialized = bOutputInitialized; }
|
||||
bool IsDupe(const char* szFilename);
|
||||
int GetPriority() { return m_iPriority; }
|
||||
void SetPriority(int iPriority) { m_iPriority = iPriority; }
|
||||
bool GetExtraPriority() { return m_bExtraPriority; }
|
||||
@@ -210,15 +185,7 @@ public:
|
||||
int GetActiveDownloads() { return m_iActiveDownloads; }
|
||||
};
|
||||
|
||||
typedef std::deque<GroupInfo*> GroupQueueBase;
|
||||
|
||||
class GroupQueue : public GroupQueueBase
|
||||
{
|
||||
public:
|
||||
~GroupQueue();
|
||||
void Clear();
|
||||
};
|
||||
|
||||
typedef std::deque<GroupInfo*> GroupQueue;
|
||||
|
||||
class NZBParameter
|
||||
{
|
||||
@@ -242,11 +209,7 @@ typedef std::deque<NZBParameter*> NZBParameterListBase;
|
||||
class NZBParameterList : public NZBParameterListBase
|
||||
{
|
||||
public:
|
||||
~NZBParameterList();
|
||||
void SetParameter(const char* szName, const char* szValue);
|
||||
NZBParameter* Find(const char* szName, bool bCaseSensitive);
|
||||
void Clear();
|
||||
void CopyFrom(NZBParameterList* pSourceParameters);
|
||||
};
|
||||
|
||||
class ScriptStatus
|
||||
@@ -283,40 +246,6 @@ 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,
|
||||
dmAll,
|
||||
dmForce
|
||||
};
|
||||
|
||||
class NZBInfoList;
|
||||
|
||||
class NZBInfo
|
||||
@@ -345,9 +274,7 @@ public:
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess,
|
||||
usSpace,
|
||||
usPassword
|
||||
usSuccess
|
||||
};
|
||||
|
||||
enum ECleanupStatus
|
||||
@@ -364,21 +291,6 @@ public:
|
||||
msSuccess
|
||||
};
|
||||
|
||||
enum EDeleteStatus
|
||||
{
|
||||
dsNone,
|
||||
dsManual,
|
||||
dsHealth,
|
||||
dsDupe
|
||||
};
|
||||
|
||||
enum EMarkStatus
|
||||
{
|
||||
ksNone,
|
||||
ksBad,
|
||||
ksGood
|
||||
};
|
||||
|
||||
typedef std::vector<char*> Files;
|
||||
typedef std::deque<Message*> Messages;
|
||||
|
||||
@@ -388,23 +300,10 @@ private:
|
||||
char* m_szFilename;
|
||||
char* m_szName;
|
||||
char* m_szDestDir;
|
||||
char* m_szFinalDir;
|
||||
char* m_szCategory;
|
||||
int m_iFileCount;
|
||||
int m_iParkedFileCount;
|
||||
long long m_lSize;
|
||||
long long m_lSuccessSize;
|
||||
long long m_lFailedSize;
|
||||
long long m_lCurrentSuccessSize;
|
||||
long long m_lCurrentFailedSize;
|
||||
long long m_lParSize;
|
||||
long long m_lParSuccessSize;
|
||||
long long m_lParFailedSize;
|
||||
long long m_lParCurrentSuccessSize;
|
||||
long long m_lParCurrentFailedSize;
|
||||
int m_iTotalArticles;
|
||||
int m_iSuccessArticles;
|
||||
int m_iFailedArticles;
|
||||
Files m_completedFiles;
|
||||
bool m_bPostProcess;
|
||||
ERenameStatus m_eRenameStatus;
|
||||
@@ -412,85 +311,45 @@ private:
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
ECleanupStatus m_eCleanupStatus;
|
||||
EMoveStatus m_eMoveStatus;
|
||||
EDeleteStatus m_eDeleteStatus;
|
||||
EMarkStatus m_eMarkStatus;
|
||||
bool m_bDeletePaused;
|
||||
bool m_bManyDupeFiles;
|
||||
char* m_szQueuedFilename;
|
||||
bool m_bDeleting;
|
||||
bool m_bAvoidHistory;
|
||||
bool m_bHealthPaused;
|
||||
bool m_bDeleted;
|
||||
bool m_bParCleanup;
|
||||
bool m_bParManual;
|
||||
bool m_bCleanupDisk;
|
||||
bool m_bUnpackCleanedUpDisk;
|
||||
char* m_szDupeKey;
|
||||
int m_iDupeScore;
|
||||
EDupeMode m_eDupeMode;
|
||||
unsigned int m_iFullContentHash;
|
||||
unsigned int m_iFilteredContentHash;
|
||||
NZBInfoList* m_Owner;
|
||||
NZBParameterList m_ppParameters;
|
||||
ScriptStatusList m_scriptStatuses;
|
||||
ServerStatList m_ServerStats;
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
int m_iIDMessageGen;
|
||||
|
||||
static int m_iIDGen;
|
||||
static int m_iIDMax;
|
||||
|
||||
friend class NZBInfoList;
|
||||
|
||||
public:
|
||||
NZBInfo(bool bPersistent = true);
|
||||
NZBInfo();
|
||||
~NZBInfo();
|
||||
void Retain();
|
||||
void AddReference();
|
||||
void Release();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int iID);
|
||||
static void ResetGenID(bool bMax);
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
void SetFilename(const char* szFilename);
|
||||
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize, bool bRemoveExt);
|
||||
const char* GetDestDir() { return m_szDestDir; } // needs locking (for shared objects)
|
||||
void SetDestDir(const char* szDestDir); // needs locking (for shared objects)
|
||||
const char* GetFinalDir() { return m_szFinalDir; } // needs locking (for shared objects)
|
||||
void SetFinalDir(const char* szFinalDir); // needs locking (for shared objects)
|
||||
const char* GetCategory() { return m_szCategory; } // needs locking (for shared objects)
|
||||
void SetCategory(const char* szCategory); // needs locking (for shared objects)
|
||||
const char* GetName() { return m_szName; } // needs locking (for shared objects)
|
||||
void SetName(const char* szName); // needs locking (for shared objects)
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; }
|
||||
int GetFileCount() { return m_iFileCount; }
|
||||
void SetFileCount(int iFileCount) { m_iFileCount = iFileCount; }
|
||||
int GetParkedFileCount() { return m_iParkedFileCount; }
|
||||
void SetParkedFileCount(int iParkedFileCount) { m_iParkedFileCount = iParkedFileCount; }
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; }
|
||||
long long GetSuccessSize() { return m_lSuccessSize; }
|
||||
void SetSuccessSize(long long lSuccessSize) { m_lSuccessSize = lSuccessSize; }
|
||||
long long GetFailedSize() { return m_lFailedSize; }
|
||||
void SetFailedSize(long long lFailedSize) { m_lFailedSize = lFailedSize; }
|
||||
long long GetCurrentSuccessSize() { return m_lCurrentSuccessSize; }
|
||||
void SetCurrentSuccessSize(long long lCurrentSuccessSize) { m_lCurrentSuccessSize = lCurrentSuccessSize; }
|
||||
long long GetCurrentFailedSize() { return m_lCurrentFailedSize; }
|
||||
void SetCurrentFailedSize(long long lCurrentFailedSize) { m_lCurrentFailedSize = lCurrentFailedSize; }
|
||||
long long GetParSize() { return m_lParSize; }
|
||||
void SetParSize(long long lParSize) { m_lParSize = lParSize; }
|
||||
long long GetParSuccessSize() { return m_lParSuccessSize; }
|
||||
void SetParSuccessSize(long long lParSuccessSize) { m_lParSuccessSize = lParSuccessSize; }
|
||||
long long GetParFailedSize() { return m_lParFailedSize; }
|
||||
void SetParFailedSize(long long lParFailedSize) { m_lParFailedSize = lParFailedSize; }
|
||||
long long GetParCurrentSuccessSize() { return m_lParCurrentSuccessSize; }
|
||||
void SetParCurrentSuccessSize(long long lParCurrentSuccessSize) { m_lParCurrentSuccessSize = lParCurrentSuccessSize; }
|
||||
long long GetParCurrentFailedSize() { return m_lParCurrentFailedSize; }
|
||||
void SetParCurrentFailedSize(long long lParCurrentFailedSize) { m_lParCurrentFailedSize = lParCurrentFailedSize; }
|
||||
int GetTotalArticles() { return m_iTotalArticles; }
|
||||
void SetTotalArticles(int iTotalArticles) { m_iTotalArticles = iTotalArticles; }
|
||||
int GetSuccessArticles() { return m_iSuccessArticles; }
|
||||
void SetSuccessArticles(int iSuccessArticles) { m_iSuccessArticles = iSuccessArticles; }
|
||||
int GetFailedArticles() { return m_iFailedArticles; }
|
||||
void SetFailedArticles(int iFailedArticles) { m_iFailedArticles = iFailedArticles; }
|
||||
void BuildDestDirName();
|
||||
void BuildFinalDirName(char* szFinalDirBuf, int iBufSize);
|
||||
Files* GetCompletedFiles() { return &m_completedFiles; } // needs locking (for shared objects)
|
||||
@@ -507,22 +366,10 @@ public:
|
||||
void SetCleanupStatus(ECleanupStatus eCleanupStatus) { m_eCleanupStatus = eCleanupStatus; }
|
||||
EMoveStatus GetMoveStatus() { return m_eMoveStatus; }
|
||||
void SetMoveStatus(EMoveStatus eMoveStatus) { m_eMoveStatus = eMoveStatus; }
|
||||
EDeleteStatus GetDeleteStatus() { return m_eDeleteStatus; }
|
||||
void SetDeleteStatus(EDeleteStatus eDeleteStatus) { m_eDeleteStatus = eDeleteStatus; }
|
||||
EMarkStatus GetMarkStatus() { return m_eMarkStatus; }
|
||||
void SetMarkStatus(EMarkStatus eMarkStatus) { m_eMarkStatus = eMarkStatus; }
|
||||
const char* GetQueuedFilename() { return m_szQueuedFilename; }
|
||||
void SetQueuedFilename(const char* szQueuedFilename);
|
||||
bool GetDeleting() { return m_bDeleting; }
|
||||
void SetDeleting(bool bDeleting) { m_bDeleting = bDeleting; }
|
||||
bool GetDeletePaused() { return m_bDeletePaused; }
|
||||
void SetDeletePaused(bool bDeletePaused) { m_bDeletePaused = bDeletePaused; }
|
||||
bool GetManyDupeFiles() { return m_bManyDupeFiles; }
|
||||
void SetManyDupeFiles(bool bManyDupeFiles) { m_bManyDupeFiles = bManyDupeFiles; }
|
||||
bool GetAvoidHistory() { return m_bAvoidHistory; }
|
||||
void SetAvoidHistory(bool bAvoidHistory) { m_bAvoidHistory = bAvoidHistory; }
|
||||
bool GetHealthPaused() { return m_bHealthPaused; }
|
||||
void SetHealthPaused(bool bHealthPaused) { m_bHealthPaused = bHealthPaused; }
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
|
||||
bool GetParCleanup() { return m_bParCleanup; }
|
||||
void SetParCleanup(bool bParCleanup) { m_bParCleanup = bParCleanup; }
|
||||
bool GetCleanupDisk() { return m_bCleanupDisk; }
|
||||
@@ -530,20 +377,8 @@ public:
|
||||
bool GetUnpackCleanedUpDisk() { return m_bUnpackCleanedUpDisk; }
|
||||
void SetUnpackCleanedUpDisk(bool bUnpackCleanedUpDisk) { m_bUnpackCleanedUpDisk = bUnpackCleanedUpDisk; }
|
||||
NZBParameterList* GetParameters() { return &m_ppParameters; } // needs locking (for shared objects)
|
||||
void SetParameter(const char* szName, const char* szValue); // needs locking (for shared objects)
|
||||
ScriptStatusList* GetScriptStatuses() { return &m_scriptStatuses; } // needs locking (for shared objects)
|
||||
ServerStatList* GetServerStats() { return &m_ServerStats; }
|
||||
int CalcHealth();
|
||||
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; }
|
||||
void SetDupeScore(int iDupeScore) { m_iDupeScore = iDupeScore; }
|
||||
EDupeMode GetDupeMode() { return m_eDupeMode; }
|
||||
void SetDupeMode(EDupeMode eDupeMode) { m_eDupeMode = eDupeMode; }
|
||||
unsigned int GetFullContentHash() { return m_iFullContentHash; }
|
||||
void SetFullContentHash(unsigned int iFullContentHash) { m_iFullContentHash = iFullContentHash; }
|
||||
unsigned int GetFilteredContentHash() { return m_iFilteredContentHash; }
|
||||
void SetFilteredContentHash(unsigned int iFilteredContentHash) { m_iFilteredContentHash = iFilteredContentHash; }
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
@@ -585,6 +420,7 @@ private:
|
||||
bool m_bWorking;
|
||||
bool m_bDeleted;
|
||||
bool m_bRequestParCheck;
|
||||
bool m_bRequestParRename;
|
||||
EStage m_eStage;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
@@ -598,7 +434,6 @@ private:
|
||||
int m_iIDMessageGen;
|
||||
|
||||
static int m_iIDGen;
|
||||
static int m_iIDMax;
|
||||
|
||||
public:
|
||||
PostInfo();
|
||||
@@ -626,6 +461,8 @@ public:
|
||||
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
|
||||
bool GetRequestParCheck() { return m_bRequestParCheck; }
|
||||
void SetRequestParCheck(bool bRequestParCheck) { m_bRequestParCheck = bRequestParCheck; }
|
||||
bool GetRequestParRename() { return m_bRequestParRename; }
|
||||
void SetRequestParRename(bool bRequestParRename) { m_bRequestParRename = bRequestParRename; }
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
Thread* GetPostThread() { return m_pPostThread; }
|
||||
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
|
||||
@@ -648,9 +485,7 @@ public:
|
||||
aiRunning,
|
||||
aiFinished,
|
||||
aiFailed,
|
||||
aiRetry,
|
||||
aiScanSkipped,
|
||||
aiScanFailed
|
||||
aiRetry
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -659,23 +494,17 @@ private:
|
||||
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)
|
||||
@@ -684,71 +513,18 @@ public:
|
||||
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:
|
||||
enum EStatus
|
||||
{
|
||||
dsUndefined,
|
||||
dsSuccess,
|
||||
dsFailed,
|
||||
dsDeleted,
|
||||
dsDupe,
|
||||
dsBad,
|
||||
dsGood
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szDupeKey;
|
||||
int m_iDupeScore;
|
||||
EDupeMode m_eDupeMode;
|
||||
long long m_lSize;
|
||||
unsigned int m_iFullContentHash;
|
||||
unsigned int m_iFilteredContentHash;
|
||||
EStatus m_eStatus;
|
||||
|
||||
public:
|
||||
DupInfo();
|
||||
~DupInfo();
|
||||
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)
|
||||
void SetDupeKey(const char* szDupeKey); // needs locking (for shared objects)
|
||||
int GetDupeScore() { return m_iDupeScore; }
|
||||
void SetDupeScore(int iDupeScore) { m_iDupeScore = iDupeScore; }
|
||||
EDupeMode GetDupeMode() { return m_eDupeMode; }
|
||||
void SetDupeMode(EDupeMode eDupeMode) { m_eDupeMode = eDupeMode; }
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; }
|
||||
unsigned int GetFullContentHash() { return m_iFullContentHash; }
|
||||
void SetFullContentHash(unsigned int iFullContentHash) { m_iFullContentHash = iFullContentHash; }
|
||||
unsigned int GetFilteredContentHash() { return m_iFilteredContentHash; }
|
||||
void SetFilteredContentHash(unsigned int iFilteredContentHash) { m_iFilteredContentHash = iFilteredContentHash; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetStatus(EStatus Status) { m_eStatus = Status; }
|
||||
};
|
||||
|
||||
class HistoryInfo
|
||||
{
|
||||
public:
|
||||
@@ -756,8 +532,7 @@ public:
|
||||
{
|
||||
hkUnknown,
|
||||
hkNZBInfo,
|
||||
hkUrlInfo,
|
||||
hkDupInfo
|
||||
hkUrlInfo
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -767,20 +542,16 @@ private:
|
||||
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; }
|
||||
NZBInfo* GetNZBInfo() { return (NZBInfo*)m_pInfo; }
|
||||
UrlInfo* GetUrlInfo() { return (UrlInfo*)m_pInfo; }
|
||||
DupInfo* GetDupInfo() { return (DupInfo*)m_pInfo; }
|
||||
void DiscardUrlInfo() { m_pInfo = NULL; }
|
||||
time_t GetTime() { return m_tTime; }
|
||||
void SetTime(time_t tTime) { m_tTime = tTime; }
|
||||
|
||||
@@ -1,583 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "DiskState.h"
|
||||
#include "NZBFile.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "DupeCoordinator.h"
|
||||
|
||||
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)
|
||||
{
|
||||
bool bHasDupeKeys = !Util::EmptyStr(szDupeKey1) && !Util::EmptyStr(szDupeKey2);
|
||||
return (bHasDupeKeys && !strcmp(szDupeKey1, szDupeKey2)) ||
|
||||
(!bHasDupeKeys && !strcmp(szName1, szName2));
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the title was already downloaded or is already queued:
|
||||
- if there is a duplicate with exactly same content (via hash-check)
|
||||
in queue or in history - the new item is skipped;
|
||||
- if there is a duplicate marked as good in history - the new item is skipped;
|
||||
- if there is a duplicate with success-status in dup-history but
|
||||
there are no duplicates in recent history - the new item is skipped;
|
||||
- if queue has a duplicate with the same or higher score - the new item
|
||||
is moved to history as dupe-backup;
|
||||
- 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;
|
||||
- if queue doesn't have duplicates - the new item is added to queue.
|
||||
*/
|
||||
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 (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
|
||||
{
|
||||
GroupInfo* pGroupInfo = *it;
|
||||
NZBInfo* pGroupNZBInfo = pGroupInfo->GetNZBInfo();
|
||||
bool bSameContent = (pNZBInfo->GetFullContentHash() > 0 &&
|
||||
pNZBInfo->GetFullContentHash() == pGroupNZBInfo->GetFullContentHash()) ||
|
||||
(pNZBInfo->GetFilteredContentHash() > 0 &&
|
||||
pNZBInfo->GetFilteredContentHash() == pGroupNZBInfo->GetFilteredContentHash());
|
||||
|
||||
// if there is a duplicate with exactly same content (via hash-check)
|
||||
// in queue - the new item is skipped
|
||||
if (pGroupNZBInfo != pNZBInfo && bSameContent)
|
||||
{
|
||||
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(), pGroupNZBInfo->GetName());
|
||||
}
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// find duplicates in history
|
||||
|
||||
bool bSkip = false;
|
||||
bool bGood = false;
|
||||
bool bSameContent = false;
|
||||
const char* szDupeName = NULL;
|
||||
|
||||
// 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->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
((pNZBInfo->GetFullContentHash() > 0 &&
|
||||
pNZBInfo->GetFullContentHash() == pHistoryInfo->GetNZBInfo()->GetFullContentHash()) ||
|
||||
(pNZBInfo->GetFilteredContentHash() > 0 &&
|
||||
pNZBInfo->GetFilteredContentHash() == pHistoryInfo->GetNZBInfo()->GetFilteredContentHash())))
|
||||
{
|
||||
bSkip = true;
|
||||
bSameContent = true;
|
||||
szDupeName = pHistoryInfo->GetNZBInfo()->GetName();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
|
||||
((pNZBInfo->GetFullContentHash() > 0 &&
|
||||
pNZBInfo->GetFullContentHash() == pHistoryInfo->GetDupInfo()->GetFullContentHash()) ||
|
||||
(pNZBInfo->GetFilteredContentHash() > 0 &&
|
||||
pNZBInfo->GetFilteredContentHash() == pHistoryInfo->GetDupInfo()->GetFilteredContentHash())))
|
||||
{
|
||||
bSkip = true;
|
||||
bSameContent = true;
|
||||
szDupeName = pHistoryInfo->GetDupInfo()->GetName();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood &&
|
||||
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(),
|
||||
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
|
||||
{
|
||||
bSkip = true;
|
||||
bGood = true;
|
||||
szDupeName = pHistoryInfo->GetNZBInfo()->GetName();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
|
||||
pHistoryInfo->GetDupInfo()->GetDupeMode() != dmForce &&
|
||||
(pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood ||
|
||||
(pNZBInfo->GetDupeMode() == dmScore &&
|
||||
pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess &&
|
||||
pNZBInfo->GetDupeScore() <= pHistoryInfo->GetDupInfo()->GetDupeScore())) &&
|
||||
SameNameOrKey(pHistoryInfo->GetDupInfo()->GetName(), pHistoryInfo->GetDupInfo()->GetDupeKey(),
|
||||
pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
|
||||
{
|
||||
bSkip = true;
|
||||
bGood = pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood;
|
||||
szDupeName = pHistoryInfo->GetDupInfo()->GetName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
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() &&
|
||||
IsDupeSuccess(pHistoryInfo->GetNZBInfo()))
|
||||
{
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
|
||||
info("Collection %s is duplicate to %s", pNZBInfo->GetName(), pHistoryInfo->GetNZBInfo()->GetName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bSkip)
|
||||
{
|
||||
if (!strcmp(pNZBInfo->GetName(), szDupeName))
|
||||
{
|
||||
warn("Skipping duplicate %s, found in history with %s", pNZBInfo->GetName(),
|
||||
bSameContent ? "exactly same content" : bGood ? "good status" : "success status");
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Skipping duplicate %s, found in history %s with %s",
|
||||
pNZBInfo->GetName(), szDupeName,
|
||||
bSameContent ? "exactly same content" : bGood ? "good status" : "success status");
|
||||
}
|
||||
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
|
||||
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
|
||||
return;
|
||||
}
|
||||
|
||||
// find duplicates in download queue and post-queue and handle both items according to their scores:
|
||||
// only one item remains in queue and another one is moved to history as dupe-backup
|
||||
if (pNZBInfo->GetDupeMode() == dmScore)
|
||||
{
|
||||
// find duplicates in download queue
|
||||
for (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
|
||||
{
|
||||
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() <= pGroupNZBInfo->GetDupeScore())
|
||||
{
|
||||
// Flag saying QueueCoordinator to skip nzb-file
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsDupe);
|
||||
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
|
||||
else
|
||||
{
|
||||
// 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 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 && !IsDupeSuccess(pNZBInfo))
|
||||
{
|
||||
ReturnBestDupe(pDownloadQueue, pNZBInfo, pNZBInfo->GetName(), pNZBInfo->GetDupeKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the best duplicate from history to download queue.
|
||||
*/
|
||||
void DupeCoordinator::ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szNZBName, const char* szDupeKey)
|
||||
{
|
||||
// check if history (recent or dup) has other success-duplicates or good-duplicates
|
||||
bool bHistoryDupe = false;
|
||||
int iHistoryScore = 0;
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
bool bGoodDupe = false;
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
(IsDupeSuccess(pHistoryInfo->GetNZBInfo()) ||
|
||||
pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood) &&
|
||||
SameNameOrKey(pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey(), szNZBName, szDupeKey))
|
||||
{
|
||||
if (!bHistoryDupe || pHistoryInfo->GetNZBInfo()->GetDupeScore() > iHistoryScore)
|
||||
{
|
||||
iHistoryScore = pHistoryInfo->GetNZBInfo()->GetDupeScore();
|
||||
}
|
||||
bHistoryDupe = true;
|
||||
bGoodDupe = pHistoryInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksGood;
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
|
||||
pHistoryInfo->GetDupInfo()->GetDupeMode() != dmForce &&
|
||||
(pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess ||
|
||||
pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood) &&
|
||||
SameNameOrKey(pHistoryInfo->GetDupInfo()->GetName(), pHistoryInfo->GetDupInfo()->GetDupeKey(), szNZBName, szDupeKey))
|
||||
{
|
||||
if (!bHistoryDupe || pHistoryInfo->GetDupInfo()->GetDupeScore() > iHistoryScore)
|
||||
{
|
||||
iHistoryScore = pHistoryInfo->GetDupInfo()->GetDupeScore();
|
||||
}
|
||||
bHistoryDupe = true;
|
||||
bGoodDupe = pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood;
|
||||
}
|
||||
|
||||
if (bGoodDupe)
|
||||
{
|
||||
// another duplicate with good-status exists - exit without moving other dupes to queue
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (GroupQueue::iterator it = groupQueue.begin(); it != groupQueue.end(); it++)
|
||||
{
|
||||
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 = pGroupNZBInfo->GetDupeScore();
|
||||
bQueueDupe = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsDupe &&
|
||||
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))
|
||||
{
|
||||
pHistoryDupe = pHistoryInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// move that dupe-backup from history to download queue
|
||||
if (pHistoryDupe)
|
||||
{
|
||||
info("Found duplicate %s for %s", pHistoryDupe->GetNZBInfo()->GetName(), szNZBName);
|
||||
HistoryRedownload(pDownloadQueue, pHistoryDupe);
|
||||
}
|
||||
}
|
||||
|
||||
void DupeCoordinator::HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, bool bGood)
|
||||
{
|
||||
char szNZBName[1024];
|
||||
pHistoryInfo->GetName(szNZBName, 1024);
|
||||
|
||||
info("Marking %s as %s", szNZBName, (bGood ? "good" : "bad"));
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
pHistoryInfo->GetNZBInfo()->SetMarkStatus(bGood ? NZBInfo::ksGood : NZBInfo::ksBad);
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo)
|
||||
{
|
||||
pHistoryInfo->GetDupInfo()->SetStatus(bGood ? DupInfo::dsGood : DupInfo::dsBad);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not mark %s as bad: history item has wrong type", szNZBName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pOptions->GetDupeCheck() ||
|
||||
(pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDupeMode() == dmForce) ||
|
||||
(pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo &&
|
||||
pHistoryInfo->GetDupInfo()->GetDupeMode() == dmForce))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bGood)
|
||||
{
|
||||
// mark as good
|
||||
// moving all duplicates from history to dup-history
|
||||
HistoryCleanup(pDownloadQueue, pHistoryInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mark as bad
|
||||
const char* szDupeKey = pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ? pHistoryInfo->GetNZBInfo()->GetDupeKey() :
|
||||
pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo ? pHistoryInfo->GetDupInfo()->GetDupeKey() :
|
||||
NULL;
|
||||
ReturnBestDupe(pDownloadQueue, NULL, szNZBName, szDupeKey);
|
||||
}
|
||||
}
|
||||
|
||||
void DupeCoordinator::HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo* pMarkHistoryInfo)
|
||||
{
|
||||
const char* szDupeKey = pMarkHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ? pMarkHistoryInfo->GetNZBInfo()->GetDupeKey() :
|
||||
pMarkHistoryInfo->GetKind() == HistoryInfo::hkDupInfo ? pMarkHistoryInfo->GetDupInfo()->GetDupeKey() :
|
||||
NULL;
|
||||
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->GetHistoryList()->rbegin(); it != pDownloadQueue->GetHistoryList()->rend(); )
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
|
||||
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))
|
||||
{
|
||||
HistoryTransformToDup(pDownloadQueue, pHistoryInfo, index);
|
||||
index++;
|
||||
it = pDownloadQueue->GetHistoryList()->rbegin() + index;
|
||||
bChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bChanged && g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef 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
|
||||
@@ -1,742 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#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)
|
||||
{
|
||||
m_szUrl = strdup(szUrl);
|
||||
m_iCacheTimeSec = iCacheTimeSec;
|
||||
m_szCacheId = strdup(szCacheId);
|
||||
m_tLastUsage = tLastUsage;
|
||||
m_pFeedItemInfos = pFeedItemInfos;
|
||||
m_pFeedItemInfos->Retain();
|
||||
}
|
||||
|
||||
FeedCoordinator::FeedCacheItem::~FeedCacheItem()
|
||||
{
|
||||
free(m_szUrl);
|
||||
free(m_szCacheId);
|
||||
m_pFeedItemInfos->Release();
|
||||
}
|
||||
|
||||
FeedCoordinator::FeedCoordinator()
|
||||
{
|
||||
debug("Creating FeedCoordinator");
|
||||
m_bForce = false;
|
||||
m_bSave = false;
|
||||
|
||||
m_UrlCoordinatorObserver.m_pOwner = this;
|
||||
g_pUrlCoordinator->Attach(&m_UrlCoordinatorObserver);
|
||||
}
|
||||
|
||||
FeedCoordinator::~FeedCoordinator()
|
||||
{
|
||||
debug("Destroying FeedCoordinator");
|
||||
// Cleanup
|
||||
|
||||
debug("Deleting FeedDownloaders");
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_ActiveDownloads.clear();
|
||||
|
||||
debug("Deleting Feeds");
|
||||
for (Feeds::iterator it = m_Feeds.begin(); it != m_Feeds.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Feeds.clear();
|
||||
|
||||
debug("Deleting FeedCache");
|
||||
for (FeedCache::iterator it = m_FeedCache.begin(); it != m_FeedCache.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_FeedCache.clear();
|
||||
|
||||
debug("FeedCoordinator destroyed");
|
||||
}
|
||||
|
||||
void FeedCoordinator::AddFeed(FeedInfo* pFeedInfo)
|
||||
{
|
||||
m_Feeds.push_back(pFeedInfo);
|
||||
}
|
||||
|
||||
void FeedCoordinator::Run()
|
||||
{
|
||||
debug("Entering FeedCoordinator-loop");
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetReloadQueue())
|
||||
{
|
||||
g_pDiskState->LoadFeeds(&m_Feeds, &m_FeedHistory);
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
|
||||
int iSleepInterval = 100;
|
||||
int iUpdateCounter = 0;
|
||||
int iCleanupCounter = 60000;
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
usleep(iSleepInterval * 1000);
|
||||
|
||||
iUpdateCounter += iSleepInterval;
|
||||
if (iUpdateCounter >= 1000)
|
||||
{
|
||||
// this code should not be called too often, once per second is OK
|
||||
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()) || m_bForce || g_pOptions->GetUrlForce())
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
time_t tCurrent = time(NULL);
|
||||
if ((int)m_ActiveDownloads.size() < g_pOptions->GetUrlConnections())
|
||||
{
|
||||
m_bForce = false;
|
||||
// check feed list and update feeds
|
||||
for (Feeds::iterator it = m_Feeds.begin(); it != m_Feeds.end(); it++)
|
||||
{
|
||||
FeedInfo* pFeedInfo = *it;
|
||||
if (((pFeedInfo->GetInterval() > 0 &&
|
||||
(tCurrent - pFeedInfo->GetLastUpdate() >= pFeedInfo->GetInterval() * 60 ||
|
||||
tCurrent < pFeedInfo->GetLastUpdate())) ||
|
||||
pFeedInfo->GetFetch()) &&
|
||||
pFeedInfo->GetStatus() != FeedInfo::fsRunning)
|
||||
{
|
||||
StartFeedDownload(pFeedInfo, pFeedInfo->GetFetch());
|
||||
}
|
||||
else if (pFeedInfo->GetFetch())
|
||||
{
|
||||
m_bForce = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
CheckSaveFeeds();
|
||||
ResetHangingDownloads();
|
||||
iUpdateCounter = 0;
|
||||
}
|
||||
|
||||
iCleanupCounter += iSleepInterval;
|
||||
if (iCleanupCounter >= 60000)
|
||||
{
|
||||
// clean up feed history once a minute
|
||||
CleanupHistory();
|
||||
CleanupCache();
|
||||
CheckSaveFeeds();
|
||||
iCleanupCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// waiting for downloads
|
||||
debug("FeedCoordinator: waiting for Downloads to complete");
|
||||
bool completed = false;
|
||||
while (!completed)
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
completed = m_ActiveDownloads.size() == 0;
|
||||
m_mutexDownloads.Unlock();
|
||||
CheckSaveFeeds();
|
||||
usleep(100 * 1000);
|
||||
ResetHangingDownloads();
|
||||
}
|
||||
debug("FeedCoordinator: Downloads are completed");
|
||||
|
||||
debug("Exiting FeedCoordinator-loop");
|
||||
}
|
||||
|
||||
void FeedCoordinator::Stop()
|
||||
{
|
||||
Thread::Stop();
|
||||
|
||||
debug("Stopping UrlDownloads");
|
||||
m_mutexDownloads.Lock();
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
(*it)->Stop();
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
debug("UrlDownloads are notified");
|
||||
}
|
||||
|
||||
void FeedCoordinator::ResetHangingDownloads()
|
||||
{
|
||||
const int TimeOut = g_pOptions->GetTerminateTimeout();
|
||||
if (TimeOut == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
time_t tm = ::time(NULL);
|
||||
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
|
||||
{
|
||||
FeedDownloader* pFeedDownloader = *it;
|
||||
if (tm - pFeedDownloader->GetLastUpdateTime() > TimeOut &&
|
||||
pFeedDownloader->GetStatus() == FeedDownloader::adRunning)
|
||||
{
|
||||
debug("Terminating hanging download %s", pFeedDownloader->GetInfoName());
|
||||
if (pFeedDownloader->Terminate())
|
||||
{
|
||||
error("Terminated hanging download %s", pFeedDownloader->GetInfoName());
|
||||
pFeedDownloader->GetFeedInfo()->SetStatus(FeedInfo::fsUndefined);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not terminate hanging download %s", pFeedDownloader->GetInfoName());
|
||||
}
|
||||
m_ActiveDownloads.erase(it);
|
||||
// it's not safe to destroy pFeedDownloader, because the state of object is unknown
|
||||
delete pFeedDownloader;
|
||||
it = m_ActiveDownloads.begin();
|
||||
continue;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
void FeedCoordinator::LogDebugInfo()
|
||||
{
|
||||
debug(" FeedCoordinator");
|
||||
debug(" ----------------");
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
debug(" Active Downloads: %i", m_ActiveDownloads.size());
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
FeedDownloader* pFeedDownloader = *it;
|
||||
pFeedDownloader->LogDebugInfo();
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
void FeedCoordinator::StartFeedDownload(FeedInfo* pFeedInfo, bool bForce)
|
||||
{
|
||||
debug("Starting new FeedDownloader for %", pFeedInfo->GetName());
|
||||
|
||||
FeedDownloader* pFeedDownloader = new FeedDownloader();
|
||||
pFeedDownloader->SetAutoDestroy(true);
|
||||
pFeedDownloader->Attach(this);
|
||||
pFeedDownloader->SetFeedInfo(pFeedInfo);
|
||||
pFeedDownloader->SetURL(pFeedInfo->GetUrl());
|
||||
if (strlen(pFeedInfo->GetName()) > 0)
|
||||
{
|
||||
pFeedDownloader->SetInfoName(pFeedInfo->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
char szUrlName[1024];
|
||||
UrlInfo::MakeNiceName(pFeedInfo->GetUrl(), "", szUrlName, sizeof(szUrlName));
|
||||
pFeedDownloader->SetInfoName(szUrlName);
|
||||
}
|
||||
pFeedDownloader->SetForce(bForce || g_pOptions->GetUrlForce());
|
||||
|
||||
char tmp[1024];
|
||||
|
||||
if (pFeedInfo->GetID() > 0)
|
||||
{
|
||||
snprintf(tmp, 1024, "%sfeed-%i.tmp", g_pOptions->GetTempDir(), pFeedInfo->GetID());
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(tmp, 1024, "%sfeed-%i-%i.tmp", g_pOptions->GetTempDir(), (int)time(NULL), rand());
|
||||
}
|
||||
|
||||
tmp[1024-1] = '\0';
|
||||
pFeedDownloader->SetOutputFilename(tmp);
|
||||
|
||||
pFeedInfo->SetStatus(FeedInfo::fsRunning);
|
||||
pFeedInfo->SetForce(bForce);
|
||||
pFeedInfo->SetFetch(false);
|
||||
|
||||
m_ActiveDownloads.push_back(pFeedDownloader);
|
||||
pFeedDownloader->Start();
|
||||
}
|
||||
|
||||
void FeedCoordinator::Update(Subject* pCaller, void* pAspect)
|
||||
{
|
||||
debug("Notification from FeedDownloader received");
|
||||
|
||||
FeedDownloader* pFeedDownloader = (FeedDownloader*) pCaller;
|
||||
if ((pFeedDownloader->GetStatus() == WebDownloader::adFinished) ||
|
||||
(pFeedDownloader->GetStatus() == WebDownloader::adFailed) ||
|
||||
(pFeedDownloader->GetStatus() == WebDownloader::adRetry))
|
||||
{
|
||||
FeedCompleted(pFeedDownloader);
|
||||
}
|
||||
}
|
||||
|
||||
void FeedCoordinator::FeedCompleted(FeedDownloader* pFeedDownloader)
|
||||
{
|
||||
debug("Feed downloaded");
|
||||
|
||||
FeedInfo* pFeedInfo = pFeedDownloader->GetFeedInfo();
|
||||
bool bStatusOK = pFeedDownloader->GetStatus() == WebDownloader::adFinished;
|
||||
if (bStatusOK)
|
||||
{
|
||||
pFeedInfo->SetOutputFilename(pFeedDownloader->GetOutputFilename());
|
||||
}
|
||||
|
||||
// delete Download from Queue
|
||||
m_mutexDownloads.Lock();
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
FeedDownloader* pa = *it;
|
||||
if (pa == pFeedDownloader)
|
||||
{
|
||||
m_ActiveDownloads.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
|
||||
if (bStatusOK)
|
||||
{
|
||||
if (!pFeedInfo->GetPreview())
|
||||
{
|
||||
FeedFile* pFeedFile = FeedFile::Create(pFeedInfo->GetOutputFilename());
|
||||
remove(pFeedInfo->GetOutputFilename());
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
|
||||
if (pFeedFile)
|
||||
{
|
||||
ProcessFeed(pFeedInfo, pFeedFile->GetFeedItemInfos());
|
||||
delete pFeedFile;
|
||||
}
|
||||
|
||||
pFeedInfo->SetLastUpdate(time(NULL));
|
||||
pFeedInfo->SetForce(false);
|
||||
|
||||
m_bSave = true;
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
pFeedInfo->SetStatus(FeedInfo::fsFinished);
|
||||
}
|
||||
else
|
||||
{
|
||||
pFeedInfo->SetStatus(FeedInfo::fsFailed);
|
||||
}
|
||||
}
|
||||
|
||||
void FeedCoordinator::FilterFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos)
|
||||
{
|
||||
debug("Filtering feed %s", pFeedInfo->GetName());
|
||||
|
||||
FeedFilter* pFeedFilter = NULL;
|
||||
if (pFeedInfo->GetFilter() && strlen(pFeedInfo->GetFilter()) > 0)
|
||||
{
|
||||
pFeedFilter = new FeedFilter(pFeedInfo->GetFilter());
|
||||
}
|
||||
|
||||
for (FeedItemInfos::iterator it = pFeedItemInfos->begin(); it != pFeedItemInfos->end(); it++)
|
||||
{
|
||||
FeedItemInfo* pFeedItemInfo = *it;
|
||||
pFeedItemInfo->SetMatchStatus(FeedItemInfo::msAccepted);
|
||||
pFeedItemInfo->SetMatchRule(0);
|
||||
pFeedItemInfo->SetPauseNzb(pFeedInfo->GetPauseNzb());
|
||||
pFeedItemInfo->SetPriority(pFeedInfo->GetPriority());
|
||||
pFeedItemInfo->SetAddCategory(pFeedInfo->GetCategory());
|
||||
pFeedItemInfo->SetDupeScore(0);
|
||||
pFeedItemInfo->SetDupeMode(dmScore);
|
||||
pFeedItemInfo->BuildDupeKey(NULL, NULL);
|
||||
if (pFeedFilter)
|
||||
{
|
||||
pFeedFilter->Match(pFeedItemInfo);
|
||||
}
|
||||
}
|
||||
|
||||
delete pFeedFilter;
|
||||
}
|
||||
|
||||
void FeedCoordinator::ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos)
|
||||
{
|
||||
debug("Process feed %s", pFeedInfo->GetName());
|
||||
|
||||
FilterFeed(pFeedInfo, pFeedItemInfos);
|
||||
|
||||
bool bFirstFetch = pFeedInfo->GetLastUpdate() == 0;
|
||||
int iAdded = 0;
|
||||
|
||||
for (FeedItemInfos::iterator it = pFeedItemInfos->begin(); it != pFeedItemInfos->end(); it++)
|
||||
{
|
||||
FeedItemInfo* pFeedItemInfo = *it;
|
||||
if (pFeedItemInfo->GetMatchStatus() == FeedItemInfo::msAccepted)
|
||||
{
|
||||
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pFeedItemInfo->GetUrl());
|
||||
FeedHistoryInfo::EStatus eStatus = FeedHistoryInfo::hsUnknown;
|
||||
if (bFirstFetch)
|
||||
{
|
||||
eStatus = FeedHistoryInfo::hsBacklog;
|
||||
}
|
||||
else if (!pFeedHistoryInfo)
|
||||
{
|
||||
DownloadItem(pFeedInfo, pFeedItemInfo);
|
||||
eStatus = FeedHistoryInfo::hsFetched;
|
||||
iAdded++;
|
||||
}
|
||||
|
||||
if (pFeedHistoryInfo)
|
||||
{
|
||||
pFeedHistoryInfo->SetLastSeen(time(NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FeedHistory.Add(pFeedItemInfo->GetUrl(), eStatus, time(NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iAdded)
|
||||
{
|
||||
info("%s has %i new item(s)", pFeedInfo->GetName(), iAdded);
|
||||
}
|
||||
else
|
||||
{
|
||||
detail("%s has no new items", pFeedInfo->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void FeedCoordinator::DownloadItem(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo)
|
||||
{
|
||||
debug("Download %s from %s", pFeedItemInfo->GetUrl(), pFeedInfo->GetName());
|
||||
|
||||
UrlInfo* pUrlInfo = new UrlInfo();
|
||||
pUrlInfo->SetURL(pFeedItemInfo->GetUrl());
|
||||
|
||||
// add .nzb-extension if not present
|
||||
char szNZBName[1024];
|
||||
strncpy(szNZBName, pFeedItemInfo->GetFilename(), 1024);
|
||||
szNZBName[1024-1] = '\0';
|
||||
char* ext = strrchr(szNZBName, '.');
|
||||
if (ext && !strcasecmp(ext, ".nzb"))
|
||||
{
|
||||
*ext = '\0';
|
||||
}
|
||||
char szNZBName2[1024];
|
||||
snprintf(szNZBName2, 1024, "%s.nzb", szNZBName);
|
||||
Util::MakeValidFilename(szNZBName2, '_', false);
|
||||
if (strlen(szNZBName) > 0)
|
||||
{
|
||||
pUrlInfo->SetNZBFilename(szNZBName2);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (iID < 1 || iID > (int)m_Feeds.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FeedInfo* pFeedInfo = m_Feeds.at(iID - 1);
|
||||
|
||||
return PreviewFeed(pFeedInfo->GetName(), pFeedInfo->GetUrl(), pFeedInfo->GetFilter(),
|
||||
pFeedInfo->GetPauseNzb(), pFeedInfo->GetCategory(), pFeedInfo->GetPriority(),
|
||||
0, NULL, ppFeedItemInfos);
|
||||
}
|
||||
|
||||
bool FeedCoordinator::PreviewFeed(const char* szName, const char* szUrl, const char* szFilter,
|
||||
bool bPauseNzb, const char* szCategory, int iPriority,
|
||||
int iCacheTimeSec, const char* szCacheId, FeedItemInfos** ppFeedItemInfos)
|
||||
{
|
||||
debug("Preview feed %s", szName);
|
||||
|
||||
FeedInfo* pFeedInfo = new FeedInfo(0, szName, szUrl, 0, szFilter, bPauseNzb, szCategory, iPriority);
|
||||
pFeedInfo->SetPreview(true);
|
||||
|
||||
FeedItemInfos* pFeedItemInfos = NULL;
|
||||
bool bHasCache = false;
|
||||
if (iCacheTimeSec > 0 && *szCacheId != '\0')
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
for (FeedCache::iterator it = m_FeedCache.begin(); it != m_FeedCache.end(); it++)
|
||||
{
|
||||
FeedCacheItem* pFeedCacheItem = *it;
|
||||
if (!strcmp(pFeedCacheItem->GetCacheId(), szCacheId))
|
||||
{
|
||||
pFeedCacheItem->SetLastUsage(time(NULL));
|
||||
pFeedItemInfos = pFeedCacheItem->GetFeedItemInfos();
|
||||
pFeedItemInfos->Retain();
|
||||
bHasCache = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
if (!bHasCache)
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
|
||||
bool bFirstFetch = true;
|
||||
for (Feeds::iterator it = m_Feeds.begin(); it != m_Feeds.end(); it++)
|
||||
{
|
||||
FeedInfo* pFeedInfo2 = *it;
|
||||
if (!strcmp(pFeedInfo2->GetUrl(), pFeedInfo->GetUrl()) &&
|
||||
!strcmp(pFeedInfo2->GetFilter(), pFeedInfo->GetFilter()) &&
|
||||
pFeedInfo2->GetLastUpdate() > 0)
|
||||
{
|
||||
bFirstFetch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StartFeedDownload(pFeedInfo, true);
|
||||
m_mutexDownloads.Unlock();
|
||||
|
||||
// wait until the download in a separate thread completes
|
||||
while (pFeedInfo->GetStatus() == FeedInfo::fsRunning)
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
|
||||
// now can process the feed
|
||||
|
||||
FeedFile* pFeedFile = NULL;
|
||||
|
||||
if (pFeedInfo->GetStatus() == FeedInfo::fsFinished)
|
||||
{
|
||||
pFeedFile = FeedFile::Create(pFeedInfo->GetOutputFilename());
|
||||
}
|
||||
|
||||
remove(pFeedInfo->GetOutputFilename());
|
||||
|
||||
if (!pFeedFile)
|
||||
{
|
||||
delete pFeedInfo;
|
||||
return false;
|
||||
}
|
||||
|
||||
pFeedItemInfos = pFeedFile->GetFeedItemInfos();
|
||||
pFeedItemInfos->Retain();
|
||||
delete pFeedFile;
|
||||
|
||||
for (FeedItemInfos::iterator it = pFeedItemInfos->begin(); it != pFeedItemInfos->end(); it++)
|
||||
{
|
||||
FeedItemInfo* pFeedItemInfo = *it;
|
||||
pFeedItemInfo->SetStatus(bFirstFetch ? FeedItemInfo::isBacklog : FeedItemInfo::isNew);
|
||||
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pFeedItemInfo->GetUrl());
|
||||
if (pFeedHistoryInfo)
|
||||
{
|
||||
pFeedItemInfo->SetStatus((FeedItemInfo::EStatus)pFeedHistoryInfo->GetStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilterFeed(pFeedInfo, pFeedItemInfos);
|
||||
delete pFeedInfo;
|
||||
|
||||
if (iCacheTimeSec > 0 && *szCacheId != '\0' && !bHasCache)
|
||||
{
|
||||
FeedCacheItem* pFeedCacheItem = new FeedCacheItem(szUrl, iCacheTimeSec, szCacheId, time(NULL), pFeedItemInfos);
|
||||
m_mutexDownloads.Lock();
|
||||
m_FeedCache.push_back(pFeedCacheItem);
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
*ppFeedItemInfos = pFeedItemInfos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FeedCoordinator::FetchFeed(int iID)
|
||||
{
|
||||
debug("FetchFeeds");
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
for (Feeds::iterator it = m_Feeds.begin(); it != m_Feeds.end(); it++)
|
||||
{
|
||||
FeedInfo* pFeedInfo = *it;
|
||||
if (pFeedInfo->GetID() == iID || iID == 0)
|
||||
{
|
||||
pFeedInfo->SetFetch(true);
|
||||
m_bForce = true;
|
||||
}
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
void FeedCoordinator::UrlCoordinatorUpdate(Subject* pCaller, void* pAspect)
|
||||
{
|
||||
debug("Notification from URL-Coordinator received");
|
||||
|
||||
UrlCoordinator::Aspect* pUrlAspect = (UrlCoordinator::Aspect*)pAspect;
|
||||
if (pUrlAspect->eAction == UrlCoordinator::eaUrlCompleted)
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
FeedHistoryInfo* pFeedHistoryInfo = m_FeedHistory.Find(pUrlAspect->pUrlInfo->GetURL());
|
||||
if (pFeedHistoryInfo)
|
||||
{
|
||||
pFeedHistoryInfo->SetStatus(FeedHistoryInfo::hsFetched);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FeedHistory.Add(pUrlAspect->pUrlInfo->GetURL(), FeedHistoryInfo::hsFetched, time(NULL));
|
||||
}
|
||||
m_bSave = true;
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool FeedCoordinator::HasActiveDownloads()
|
||||
{
|
||||
m_mutexDownloads.Lock();
|
||||
bool bActive = !m_ActiveDownloads.empty();
|
||||
m_mutexDownloads.Unlock();
|
||||
return bActive;
|
||||
}
|
||||
|
||||
void FeedCoordinator::CheckSaveFeeds()
|
||||
{
|
||||
debug("CheckSaveFeeds");
|
||||
m_mutexDownloads.Lock();
|
||||
if (m_bSave)
|
||||
{
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveFeeds(&m_Feeds, &m_FeedHistory);
|
||||
}
|
||||
m_bSave = false;
|
||||
}
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
void FeedCoordinator::CleanupHistory()
|
||||
{
|
||||
debug("CleanupHistory");
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
|
||||
time_t tOldestUpdate = time(NULL);
|
||||
|
||||
for (Feeds::iterator it = m_Feeds.begin(); it != m_Feeds.end(); it++)
|
||||
{
|
||||
FeedInfo* pFeedInfo = *it;
|
||||
if (pFeedInfo->GetLastUpdate() < tOldestUpdate)
|
||||
{
|
||||
tOldestUpdate = pFeedInfo->GetLastUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
time_t tBorderDate = tOldestUpdate - g_pOptions->GetFeedHistory();
|
||||
int i = 0;
|
||||
for (FeedHistory::iterator it = m_FeedHistory.begin(); it != m_FeedHistory.end(); )
|
||||
{
|
||||
FeedHistoryInfo* pFeedHistoryInfo = *it;
|
||||
if (pFeedHistoryInfo->GetLastSeen() < tBorderDate)
|
||||
{
|
||||
detail("Deleting %s from feed history", pFeedHistoryInfo->GetUrl());
|
||||
delete pFeedHistoryInfo;
|
||||
m_FeedHistory.erase(it);
|
||||
it = m_FeedHistory.begin() + i;
|
||||
m_bSave = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
|
||||
void FeedCoordinator::CleanupCache()
|
||||
{
|
||||
debug("CleanupCache");
|
||||
|
||||
m_mutexDownloads.Lock();
|
||||
|
||||
time_t tCurTime = time(NULL);
|
||||
int i = 0;
|
||||
for (FeedCache::iterator it = m_FeedCache.begin(); it != m_FeedCache.end(); )
|
||||
{
|
||||
FeedCacheItem* pFeedCacheItem = *it;
|
||||
if (pFeedCacheItem->GetLastUsage() + pFeedCacheItem->GetCacheTimeSec() < tCurTime ||
|
||||
pFeedCacheItem->GetLastUsage() > tCurTime)
|
||||
{
|
||||
debug("Deleting %s from feed cache", pFeedCacheItem->GetUrl());
|
||||
delete pFeedCacheItem;
|
||||
m_FeedCache.erase(it);
|
||||
it = m_FeedCache.begin() + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
m_mutexDownloads.Unlock();
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FEEDCOORDINATOR_H
|
||||
#define FEEDCOORDINATOR_H
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <time.h>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "WebDownloader.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "FeedInfo.h"
|
||||
#include "Observer.h"
|
||||
|
||||
|
||||
class FeedDownloader;
|
||||
|
||||
class FeedCoordinator : public Thread, public Observer, public Subject
|
||||
{
|
||||
public:
|
||||
typedef std::list<FeedDownloader*> ActiveDownloads;
|
||||
|
||||
private:
|
||||
class UrlCoordinatorObserver: public Observer
|
||||
{
|
||||
public:
|
||||
FeedCoordinator* m_pOwner;
|
||||
virtual void Update(Subject* pCaller, void* pAspect) { m_pOwner->UrlCoordinatorUpdate(pCaller, pAspect); }
|
||||
};
|
||||
|
||||
class FeedCacheItem
|
||||
{
|
||||
private:
|
||||
char* m_szUrl;
|
||||
int m_iCacheTimeSec;
|
||||
char* m_szCacheId;
|
||||
time_t m_tLastUsage;
|
||||
FeedItemInfos* m_pFeedItemInfos;
|
||||
|
||||
public:
|
||||
FeedCacheItem(const char* szUrl, int iCacheTimeSec,const char* szCacheId,
|
||||
time_t tLastUsage, FeedItemInfos* pFeedItemInfos);
|
||||
~FeedCacheItem();
|
||||
const char* GetUrl() { return m_szUrl; }
|
||||
int GetCacheTimeSec() { return m_iCacheTimeSec; }
|
||||
const char* GetCacheId() { return m_szCacheId; }
|
||||
time_t GetLastUsage() { return m_tLastUsage; }
|
||||
void SetLastUsage(time_t tLastUsage) { m_tLastUsage = tLastUsage; }
|
||||
FeedItemInfos* GetFeedItemInfos() { return m_pFeedItemInfos; }
|
||||
};
|
||||
|
||||
typedef std::deque<FeedCacheItem*> FeedCache;
|
||||
|
||||
private:
|
||||
Feeds m_Feeds;
|
||||
ActiveDownloads m_ActiveDownloads;
|
||||
FeedHistory m_FeedHistory;
|
||||
Mutex m_mutexDownloads;
|
||||
UrlCoordinatorObserver m_UrlCoordinatorObserver;
|
||||
bool m_bForce;
|
||||
bool m_bSave;
|
||||
FeedCache m_FeedCache;
|
||||
|
||||
void StartFeedDownload(FeedInfo* pFeedInfo, bool bForce);
|
||||
void FeedCompleted(FeedDownloader* pFeedDownloader);
|
||||
void FilterFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos);
|
||||
void ProcessFeed(FeedInfo* pFeedInfo, FeedItemInfos* pFeedItemInfos);
|
||||
void DownloadItem(FeedInfo* pFeedInfo, FeedItemInfo* pFeedItemInfo);
|
||||
void ResetHangingDownloads();
|
||||
void UrlCoordinatorUpdate(Subject* pCaller, void* pAspect);
|
||||
void CleanupHistory();
|
||||
void CleanupCache();
|
||||
void CheckSaveFeeds();
|
||||
|
||||
public:
|
||||
FeedCoordinator();
|
||||
virtual ~FeedCoordinator();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
void Update(Subject* pCaller, void* pAspect);
|
||||
void AddFeed(FeedInfo* pFeedInfo);
|
||||
bool PreviewFeed(const char* szName, const char* szUrl, const char* szFilter,
|
||||
bool bPauseNzb, const char* szCategory, int iPriority,
|
||||
int iCacheTimeSec, const char* szCacheId, FeedItemInfos** ppFeedItemInfos);
|
||||
bool ViewFeed(int iID, FeedItemInfos** ppFeedItemInfos);
|
||||
void FetchFeed(int iID);
|
||||
bool HasActiveDownloads();
|
||||
Feeds* GetFeeds() { return &m_Feeds; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
class FeedDownloader : public WebDownloader
|
||||
{
|
||||
private:
|
||||
FeedInfo* m_pFeedInfo;
|
||||
|
||||
public:
|
||||
void SetFeedInfo(FeedInfo* pFeedInfo) { m_pFeedInfo = pFeedInfo; }
|
||||
FeedInfo* GetFeedInfo() { return m_pFeedInfo; }
|
||||
};
|
||||
|
||||
#endif
|
||||
609
FeedFile.cpp
609
FeedFile.cpp
@@ -1,609 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
#ifdef WIN32
|
||||
#include <comutil.h>
|
||||
#import <msxml.tlb> named_guids
|
||||
using namespace MSXML;
|
||||
#else
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlerror.h>
|
||||
#include <libxml/entities.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "FeedFile.h"
|
||||
#include "Log.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
FeedFile::FeedFile(const char* szFileName)
|
||||
{
|
||||
debug("Creating FeedFile");
|
||||
|
||||
m_szFileName = strdup(szFileName);
|
||||
m_pFeedItemInfos = new FeedItemInfos();
|
||||
m_pFeedItemInfos->Retain();
|
||||
|
||||
#ifndef WIN32
|
||||
m_pFeedItemInfo = NULL;
|
||||
m_szTagContent = NULL;
|
||||
m_iTagContentLen = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
FeedFile::~FeedFile()
|
||||
{
|
||||
debug("Destroying FeedFile");
|
||||
|
||||
// Cleanup
|
||||
free(m_szFileName);
|
||||
m_pFeedItemInfos->Release();
|
||||
|
||||
#ifndef WIN32
|
||||
delete m_pFeedItemInfo;
|
||||
free(m_szTagContent);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FeedFile::LogDebugInfo()
|
||||
{
|
||||
debug(" FeedFile %s", m_szFileName);
|
||||
}
|
||||
|
||||
void FeedFile::AddItem(FeedItemInfo* pFeedItemInfo)
|
||||
{
|
||||
m_pFeedItemInfos->Add(pFeedItemInfo);
|
||||
}
|
||||
|
||||
void FeedFile::ParseSubject(FeedItemInfo* pFeedItemInfo)
|
||||
{
|
||||
// if title has quatation marks we use only part within quatation marks
|
||||
char* p = (char*)pFeedItemInfo->GetTitle();
|
||||
char* start = strchr(p, '\"');
|
||||
if (start)
|
||||
{
|
||||
start++;
|
||||
char* end = strchr(start + 1, '\"');
|
||||
if (end)
|
||||
{
|
||||
int len = (int)(end - start);
|
||||
char* point = strchr(start + 1, '.');
|
||||
if (point && point < end)
|
||||
{
|
||||
char* filename = (char*)malloc(len + 1);
|
||||
strncpy(filename, start, len);
|
||||
filename[len] = '\0';
|
||||
|
||||
char* ext = strrchr(filename, '.');
|
||||
if (ext && !strcasecmp(ext, ".par2"))
|
||||
{
|
||||
*ext = '\0';
|
||||
}
|
||||
|
||||
pFeedItemInfo->SetFilename(filename);
|
||||
free(filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pFeedItemInfo->SetFilename(pFeedItemInfo->GetTitle());
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
FeedFile* FeedFile::Create(const char* szFileName)
|
||||
{
|
||||
CoInitialize(NULL);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
MSXML::IXMLDOMDocumentPtr doc;
|
||||
hr = doc.CreateInstance(MSXML::CLSID_DOMDocument);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Load the XML document file...
|
||||
doc->put_resolveExternals(VARIANT_FALSE);
|
||||
doc->put_validateOnParse(VARIANT_FALSE);
|
||||
doc->put_async(VARIANT_FALSE);
|
||||
|
||||
// filename needs to be properly encoded
|
||||
char* szURL = (char*)malloc(strlen(szFileName)*3 + 1);
|
||||
EncodeURL(szFileName, szURL);
|
||||
debug("url=\"%s\"", szURL);
|
||||
_variant_t v(szURL);
|
||||
free(szURL);
|
||||
|
||||
VARIANT_BOOL success = doc->load(v);
|
||||
if (success == VARIANT_FALSE)
|
||||
{
|
||||
_bstr_t r(doc->GetparseError()->reason);
|
||||
const char* szErrMsg = r;
|
||||
error("Error parsing rss feed: %s", szErrMsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FeedFile* pFile = new FeedFile(szFileName);
|
||||
if (!pFile->ParseFeed(doc))
|
||||
{
|
||||
delete pFile;
|
||||
pFile = NULL;
|
||||
}
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
void FeedFile::EncodeURL(const char* szFilename, char* szURL)
|
||||
{
|
||||
while (char ch = *szFilename++)
|
||||
{
|
||||
if (('0' <= ch && ch <= '9') ||
|
||||
('a' <= ch && ch <= 'z') ||
|
||||
('A' <= ch && ch <= 'Z') )
|
||||
{
|
||||
*szURL++ = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
*szURL++ = '%';
|
||||
int a = ch >> 4;
|
||||
*szURL++ = a > 9 ? a - 10 + 'a' : a + '0';
|
||||
a = ch & 0xF;
|
||||
*szURL++ = a > 9 ? a - 10 + 'a' : a + '0';
|
||||
}
|
||||
}
|
||||
*szURL = NULL;
|
||||
}
|
||||
|
||||
bool FeedFile::ParseFeed(IUnknown* nzb)
|
||||
{
|
||||
MSXML::IXMLDOMDocumentPtr doc = nzb;
|
||||
MSXML::IXMLDOMNodePtr root = doc->documentElement;
|
||||
|
||||
MSXML::IXMLDOMNodeListPtr itemList = root->selectNodes("/rss/channel/item");
|
||||
for (int i = 0; i < itemList->Getlength(); i++)
|
||||
{
|
||||
MSXML::IXMLDOMNodePtr node = itemList->Getitem(i);
|
||||
|
||||
FeedItemInfo* pFeedItemInfo = new FeedItemInfo();
|
||||
AddItem(pFeedItemInfo);
|
||||
|
||||
MSXML::IXMLDOMNodePtr tag;
|
||||
MSXML::IXMLDOMNodePtr attr;
|
||||
|
||||
// <title>Debian 6</title>
|
||||
tag = node->selectSingleNode("title");
|
||||
if (!tag)
|
||||
{
|
||||
// bad rss feed
|
||||
return false;
|
||||
}
|
||||
_bstr_t title(tag->Gettext());
|
||||
pFeedItemInfo->SetTitle(title);
|
||||
ParseSubject(pFeedItemInfo);
|
||||
|
||||
// <pubDate>Wed, 26 Jun 2013 00:02:54 -0600</pubDate>
|
||||
tag = node->selectSingleNode("pubDate");
|
||||
if (tag)
|
||||
{
|
||||
_bstr_t time(tag->Gettext());
|
||||
time_t unixtime = WebUtil::ParseRfc822DateTime(time);
|
||||
if (unixtime > 0)
|
||||
{
|
||||
pFeedItemInfo->SetTime(unixtime);
|
||||
}
|
||||
}
|
||||
|
||||
// <category>Movies > HD</category>
|
||||
tag = node->selectSingleNode("category");
|
||||
if (tag)
|
||||
{
|
||||
_bstr_t category(tag->Gettext());
|
||||
pFeedItemInfo->SetCategory(category);
|
||||
}
|
||||
|
||||
// <description>long text</description>
|
||||
tag = node->selectSingleNode("description");
|
||||
if (tag)
|
||||
{
|
||||
_bstr_t description(tag->Gettext());
|
||||
pFeedItemInfo->SetDescription(description);
|
||||
}
|
||||
|
||||
//<enclosure url="http://myindexer.com/fetch/9eeb264aecce961a6e0d" length="150263340" type="application/x-nzb" />
|
||||
tag = node->selectSingleNode("enclosure");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("url");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t url(attr->Gettext());
|
||||
pFeedItemInfo->SetUrl(url);
|
||||
}
|
||||
|
||||
attr = tag->Getattributes()->getNamedItem("length");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t size(attr->Gettext());
|
||||
long long lSize = atoll(size);
|
||||
pFeedItemInfo->SetSize(lSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pFeedItemInfo->GetUrl())
|
||||
{
|
||||
// <link>https://nzb.org/fetch/334534ce/4364564564</link>
|
||||
tag = node->selectSingleNode("link");
|
||||
if (!tag)
|
||||
{
|
||||
// bad rss feed
|
||||
return false;
|
||||
}
|
||||
_bstr_t link(tag->Gettext());
|
||||
pFeedItemInfo->SetUrl(link);
|
||||
}
|
||||
|
||||
|
||||
// newznab special
|
||||
|
||||
//<newznab:attr name="size" value="5423523453534" />
|
||||
if (pFeedItemInfo->GetSize() == 0)
|
||||
{
|
||||
tag = node->selectSingleNode("newznab:attr[@name='size']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t size(attr->Gettext());
|
||||
long long lSize = atoll(size);
|
||||
pFeedItemInfo->SetSize(lSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//<newznab:attr name="imdb" value="1588173"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='imdb']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t val(attr->Gettext());
|
||||
int iVal = atoi(val);
|
||||
pFeedItemInfo->SetImdbId(iVal);
|
||||
}
|
||||
}
|
||||
|
||||
//<newznab:attr name="rageid" value="33877"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='rageid']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t val(attr->Gettext());
|
||||
int iVal = atoi(val);
|
||||
pFeedItemInfo->SetRageId(iVal);
|
||||
}
|
||||
}
|
||||
|
||||
//<newznab:attr name="episode" value="E09"/>
|
||||
//<newznab:attr name="episode" value="9"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='episode']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t val(attr->Gettext());
|
||||
pFeedItemInfo->SetEpisode(val);
|
||||
}
|
||||
}
|
||||
|
||||
//<newznab:attr name="season" value="S03"/>
|
||||
//<newznab:attr name="season" value="3"/>
|
||||
tag = node->selectSingleNode("newznab:attr[@name='season']");
|
||||
if (tag)
|
||||
{
|
||||
attr = tag->Getattributes()->getNamedItem("value");
|
||||
if (attr)
|
||||
{
|
||||
_bstr_t val(attr->Gettext());
|
||||
pFeedItemInfo->SetSeason(val);
|
||||
}
|
||||
}
|
||||
|
||||
MSXML::IXMLDOMNodeListPtr itemList = node->selectNodes("newznab:attr");
|
||||
for (int i = 0; i < itemList->Getlength(); i++)
|
||||
{
|
||||
MSXML::IXMLDOMNodePtr node = itemList->Getitem(i);
|
||||
MSXML::IXMLDOMNodePtr name = node->Getattributes()->getNamedItem("name");
|
||||
MSXML::IXMLDOMNodePtr value = node->Getattributes()->getNamedItem("value");
|
||||
if (name && value)
|
||||
{
|
||||
_bstr_t name(name->Gettext());
|
||||
_bstr_t val(value->Gettext());
|
||||
pFeedItemInfo->GetAttributes()->Add(name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
FeedFile* FeedFile::Create(const char* szFileName)
|
||||
{
|
||||
FeedFile* pFile = new FeedFile(szFileName);
|
||||
|
||||
xmlSAXHandler SAX_handler = {0};
|
||||
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
|
||||
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
|
||||
SAX_handler.characters = reinterpret_cast<charactersSAXFunc>(SAX_characters);
|
||||
SAX_handler.error = reinterpret_cast<errorSAXFunc>(SAX_error);
|
||||
SAX_handler.getEntity = reinterpret_cast<getEntitySAXFunc>(SAX_getEntity);
|
||||
|
||||
pFile->m_bIgnoreNextError = false;
|
||||
|
||||
int ret = xmlSAXUserParseFile(&SAX_handler, pFile, szFileName);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
error("Failed to parse rss feed");
|
||||
delete pFile;
|
||||
pFile = NULL;
|
||||
}
|
||||
|
||||
return pFile;
|
||||
}
|
||||
|
||||
void FeedFile::Parse_StartElement(const char *name, const char **atts)
|
||||
{
|
||||
ResetTagContent();
|
||||
|
||||
if (!strcmp("item", name))
|
||||
{
|
||||
delete m_pFeedItemInfo;
|
||||
m_pFeedItemInfo = new FeedItemInfo();
|
||||
}
|
||||
else if (!strcmp("enclosure", name) && m_pFeedItemInfo)
|
||||
{
|
||||
//<enclosure url="http://myindexer.com/fetch/9eeb264aecce961a6e0d" length="150263340" type="application/x-nzb" />
|
||||
for (; *atts; atts+=2)
|
||||
{
|
||||
if (!strcmp("url", atts[0]))
|
||||
{
|
||||
char* szUrl = strdup(atts[1]);
|
||||
WebUtil::XmlDecode(szUrl);
|
||||
m_pFeedItemInfo->SetUrl(szUrl);
|
||||
free(szUrl);
|
||||
}
|
||||
else if (!strcmp("length", atts[0]))
|
||||
{
|
||||
long long lSize = atoll(atts[1]);
|
||||
m_pFeedItemInfo->SetSize(lSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_pFeedItemInfo && !strcmp("newznab:attr", name) &&
|
||||
atts[0] && atts[1] && atts[2] && atts[3] &&
|
||||
!strcmp("name", atts[0]) && !strcmp("value", atts[2]))
|
||||
{
|
||||
m_pFeedItemInfo->GetAttributes()->Add(atts[1], atts[3]);
|
||||
|
||||
//<newznab:attr name="size" value="5423523453534" />
|
||||
if (m_pFeedItemInfo->GetSize() == 0 &&
|
||||
!strcmp("size", atts[1]))
|
||||
{
|
||||
long long lSize = atoll(atts[3]);
|
||||
m_pFeedItemInfo->SetSize(lSize);
|
||||
}
|
||||
|
||||
//<newznab:attr name="imdb" value="1588173"/>
|
||||
else if (!strcmp("imdb", atts[1]))
|
||||
{
|
||||
m_pFeedItemInfo->SetImdbId(atoi(atts[3]));
|
||||
}
|
||||
|
||||
//<newznab:attr name="rageid" value="33877"/>
|
||||
else if (!strcmp("rageid", atts[1]))
|
||||
{
|
||||
m_pFeedItemInfo->SetRageId(atoi(atts[3]));
|
||||
}
|
||||
|
||||
//<newznab:attr name="episode" value="E09"/>
|
||||
//<newznab:attr name="episode" value="9"/>
|
||||
else if (!strcmp("episode", atts[1]))
|
||||
{
|
||||
m_pFeedItemInfo->SetEpisode(atts[3]);
|
||||
}
|
||||
|
||||
//<newznab:attr name="season" value="S03"/>
|
||||
//<newznab:attr name="season" value="3"/>
|
||||
else if (!strcmp("season", atts[1]))
|
||||
{
|
||||
m_pFeedItemInfo->SetSeason(atts[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FeedFile::Parse_EndElement(const char *name)
|
||||
{
|
||||
if (!strcmp("item", name))
|
||||
{
|
||||
// Close the file element, add the new file to file-list
|
||||
AddItem(m_pFeedItemInfo);
|
||||
m_pFeedItemInfo = NULL;
|
||||
}
|
||||
else if (!strcmp("title", name) && m_pFeedItemInfo)
|
||||
{
|
||||
m_pFeedItemInfo->SetTitle(m_szTagContent);
|
||||
ResetTagContent();
|
||||
ParseSubject(m_pFeedItemInfo);
|
||||
}
|
||||
else if (!strcmp("link", name) && m_pFeedItemInfo &&
|
||||
(!m_pFeedItemInfo->GetUrl() || strlen(m_pFeedItemInfo->GetUrl()) == 0))
|
||||
{
|
||||
m_pFeedItemInfo->SetUrl(m_szTagContent);
|
||||
ResetTagContent();
|
||||
}
|
||||
else if (!strcmp("category", name) && m_pFeedItemInfo)
|
||||
{
|
||||
m_pFeedItemInfo->SetCategory(m_szTagContent);
|
||||
ResetTagContent();
|
||||
}
|
||||
else if (!strcmp("description", name) && m_pFeedItemInfo)
|
||||
{
|
||||
m_pFeedItemInfo->SetDescription(m_szTagContent);
|
||||
ResetTagContent();
|
||||
}
|
||||
else if (!strcmp("pubDate", name) && m_pFeedItemInfo)
|
||||
{
|
||||
time_t unixtime = WebUtil::ParseRfc822DateTime(m_szTagContent);
|
||||
if (unixtime > 0)
|
||||
{
|
||||
m_pFeedItemInfo->SetTime(unixtime);
|
||||
}
|
||||
ResetTagContent();
|
||||
}
|
||||
}
|
||||
|
||||
void FeedFile::Parse_Content(const char *buf, int len)
|
||||
{
|
||||
m_szTagContent = (char*)realloc(m_szTagContent, m_iTagContentLen + len + 1);
|
||||
strncpy(m_szTagContent + m_iTagContentLen, buf, len);
|
||||
m_iTagContentLen += len;
|
||||
m_szTagContent[m_iTagContentLen] = '\0';
|
||||
}
|
||||
|
||||
void FeedFile::ResetTagContent()
|
||||
{
|
||||
free(m_szTagContent);
|
||||
m_szTagContent = NULL;
|
||||
m_iTagContentLen = 0;
|
||||
}
|
||||
|
||||
void FeedFile::SAX_StartElement(FeedFile* pFile, const char *name, const char **atts)
|
||||
{
|
||||
pFile->Parse_StartElement(name, atts);
|
||||
}
|
||||
|
||||
void FeedFile::SAX_EndElement(FeedFile* pFile, const char *name)
|
||||
{
|
||||
pFile->Parse_EndElement(name);
|
||||
}
|
||||
|
||||
void FeedFile::SAX_characters(FeedFile* pFile, const char * xmlstr, int len)
|
||||
{
|
||||
char* str = (char*)xmlstr;
|
||||
|
||||
// trim starting blanks
|
||||
int off = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char ch = str[i];
|
||||
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
|
||||
{
|
||||
off++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int newlen = len - off;
|
||||
|
||||
// trim ending blanks
|
||||
for (int i = len - 1; i >= off; i--)
|
||||
{
|
||||
char ch = str[i];
|
||||
if (ch == ' ' || ch == 10 || ch == 13 || ch == 9)
|
||||
{
|
||||
newlen--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlen > 0)
|
||||
{
|
||||
// interpret tag content
|
||||
pFile->Parse_Content(str + off, newlen);
|
||||
}
|
||||
}
|
||||
|
||||
void* FeedFile::SAX_getEntity(FeedFile* pFile, const char * name)
|
||||
{
|
||||
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
|
||||
if (!e)
|
||||
{
|
||||
warn("entity not found");
|
||||
pFile->m_bIgnoreNextError = true;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void FeedFile::SAX_error(FeedFile* pFile, const char *msg, ...)
|
||||
{
|
||||
if (pFile->m_bIgnoreNextError)
|
||||
{
|
||||
pFile->m_bIgnoreNextError = false;
|
||||
return;
|
||||
}
|
||||
|
||||
va_list argp;
|
||||
va_start(argp, msg);
|
||||
char szErrMsg[1024];
|
||||
vsnprintf(szErrMsg, sizeof(szErrMsg), msg, argp);
|
||||
szErrMsg[1024-1] = '\0';
|
||||
va_end(argp);
|
||||
|
||||
// remove trailing CRLF
|
||||
for (char* pend = szErrMsg + strlen(szErrMsg) - 1; pend >= szErrMsg && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
|
||||
error("Error parsing rss feed: %s", szErrMsg);
|
||||
}
|
||||
#endif
|
||||
70
FeedFile.h
70
FeedFile.h
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FEEDFILE_H
|
||||
#define FEEDFILE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "FeedInfo.h"
|
||||
|
||||
class FeedFile
|
||||
{
|
||||
private:
|
||||
FeedItemInfos* m_pFeedItemInfos;
|
||||
char* m_szFileName;
|
||||
|
||||
FeedFile(const char* szFileName);
|
||||
void AddItem(FeedItemInfo* pFeedItemInfo);
|
||||
void ParseSubject(FeedItemInfo* pFeedItemInfo);
|
||||
#ifdef WIN32
|
||||
bool ParseFeed(IUnknown* nzb);
|
||||
static void EncodeURL(const char* szFilename, char* szURL);
|
||||
#else
|
||||
FeedItemInfo* m_pFeedItemInfo;
|
||||
char* m_szTagContent;
|
||||
int m_iTagContentLen;
|
||||
bool m_bIgnoreNextError;
|
||||
|
||||
static void SAX_StartElement(FeedFile* pFile, const char *name, const char **atts);
|
||||
static void SAX_EndElement(FeedFile* pFile, const char *name);
|
||||
static void SAX_characters(FeedFile* pFile, const char * xmlstr, int len);
|
||||
static void* SAX_getEntity(FeedFile* pFile, const char * name);
|
||||
static void SAX_error(FeedFile* pFile, const char *msg, ...);
|
||||
void Parse_StartElement(const char *name, const char **atts);
|
||||
void Parse_EndElement(const char *name);
|
||||
void Parse_Content(const char *buf, int len);
|
||||
void ResetTagContent();
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual ~FeedFile();
|
||||
static FeedFile* Create(const char* szFileName);
|
||||
FeedItemInfos* GetFeedItemInfos() { return m_pFeedItemInfos; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
#endif
|
||||
1192
FeedFilter.cpp
1192
FeedFilter.cpp
File diff suppressed because it is too large
Load Diff
186
FeedFilter.h
186
FeedFilter.h
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FEEDFILTER_H
|
||||
#define FEEDFILTER_H
|
||||
|
||||
#include "DownloadInfo.h"
|
||||
#include "FeedInfo.h"
|
||||
#include "Util.h"
|
||||
|
||||
class FeedFilter
|
||||
{
|
||||
private:
|
||||
typedef std::deque<char*> RefValues;
|
||||
|
||||
enum ETermCommand
|
||||
{
|
||||
fcText,
|
||||
fcRegex,
|
||||
fcEqual,
|
||||
fcLess,
|
||||
fcLessEqual,
|
||||
fcGreater,
|
||||
fcGreaterEqual,
|
||||
fcOpeningBrace,
|
||||
fcClosingBrace,
|
||||
fcOrOperator
|
||||
};
|
||||
|
||||
class Term
|
||||
{
|
||||
private:
|
||||
bool m_bPositive;
|
||||
char* m_szField;
|
||||
ETermCommand m_eCommand;
|
||||
char* m_szParam;
|
||||
long long m_iIntParam;
|
||||
double m_fFloatParam;
|
||||
bool m_bFloat;
|
||||
RegEx* m_pRegEx;
|
||||
RefValues* m_pRefValues;
|
||||
|
||||
bool GetFieldData(const char* szField, FeedItemInfo* pFeedItemInfo,
|
||||
const char** StrValue, long long* IntValue);
|
||||
bool ParseParam(const char* szField, const char* szParam);
|
||||
bool ParseSizeParam(const char* szParam);
|
||||
bool ParseAgeParam(const char* szParam);
|
||||
bool ParseNumericParam(const char* szParam);
|
||||
bool MatchValue(const char* szStrValue, long long iIntValue);
|
||||
bool MatchText(const char* szStrValue);
|
||||
bool MatchRegex(const char* szStrValue);
|
||||
void FillWildMaskRefValues(const char* szStrValue, WildMask* pMask, int iRefOffset);
|
||||
void FillRegExRefValues(const char* szStrValue, RegEx* pRegEx);
|
||||
|
||||
public:
|
||||
Term();
|
||||
~Term();
|
||||
void SetRefValues(RefValues* pRefValues) { m_pRefValues = pRefValues; }
|
||||
bool Compile(char* szToken);
|
||||
bool Match(FeedItemInfo* pFeedItemInfo);
|
||||
ETermCommand GetCommand() { return m_eCommand; }
|
||||
};
|
||||
|
||||
typedef std::deque<Term*> TermList;
|
||||
|
||||
enum ERuleCommand
|
||||
{
|
||||
frAccept,
|
||||
frReject,
|
||||
frRequire,
|
||||
frOptions,
|
||||
frComment
|
||||
};
|
||||
|
||||
class Rule
|
||||
{
|
||||
private:
|
||||
bool m_bIsValid;
|
||||
ERuleCommand m_eCommand;
|
||||
char* m_szCategory;
|
||||
int m_iPriority;
|
||||
int m_iAddPriority;
|
||||
bool m_bPause;
|
||||
int m_iDupeScore;
|
||||
int m_iAddDupeScore;
|
||||
char* m_szDupeKey;
|
||||
char* m_szAddDupeKey;
|
||||
EDupeMode m_eDupeMode;
|
||||
char* m_szSeries;
|
||||
char* m_szRageId;
|
||||
bool m_bHasCategory;
|
||||
bool m_bHasPriority;
|
||||
bool m_bHasAddPriority;
|
||||
bool m_bHasPause;
|
||||
bool m_bHasDupeScore;
|
||||
bool m_bHasAddDupeScore;
|
||||
bool m_bHasDupeKey;
|
||||
bool m_bHasAddDupeKey;
|
||||
bool m_bHasDupeMode;
|
||||
bool m_bPatCategory;
|
||||
bool m_bPatDupeKey;
|
||||
bool m_bPatAddDupeKey;
|
||||
bool m_bHasSeries;
|
||||
bool m_bHasRageId;
|
||||
char* m_szPatCategory;
|
||||
char* m_szPatDupeKey;
|
||||
char* m_szPatAddDupeKey;
|
||||
TermList m_Terms;
|
||||
RefValues m_RefValues;
|
||||
|
||||
char* CompileCommand(char* szRule);
|
||||
char* CompileOptions(char* szRule);
|
||||
bool CompileTerm(char* szTerm);
|
||||
bool MatchExpression(FeedItemInfo* pFeedItemInfo);
|
||||
|
||||
public:
|
||||
Rule();
|
||||
~Rule();
|
||||
void Compile(char* szRule);
|
||||
bool IsValid() { return m_bIsValid; }
|
||||
ERuleCommand GetCommand() { return m_eCommand; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
int GetPriority() { return m_iPriority; }
|
||||
int GetAddPriority() { return m_iAddPriority; }
|
||||
bool GetPause() { return m_bPause; }
|
||||
const char* GetDupeKey() { return m_szDupeKey; }
|
||||
const char* GetAddDupeKey() { return m_szAddDupeKey; }
|
||||
int GetDupeScore() { return m_iDupeScore; }
|
||||
int GetAddDupeScore() { return m_iAddDupeScore; }
|
||||
EDupeMode GetDupeMode() { return m_eDupeMode; }
|
||||
const char* GetRageId() { return m_szRageId; }
|
||||
const char* GetSeries() { return m_szSeries; }
|
||||
bool HasCategory() { return m_bHasCategory; }
|
||||
bool HasPriority() { return m_bHasPriority; }
|
||||
bool HasAddPriority() { return m_bHasAddPriority; }
|
||||
bool HasPause() { return m_bHasPause; }
|
||||
bool HasDupeScore() { return m_bHasDupeScore; }
|
||||
bool HasAddDupeScore() { return m_bHasAddDupeScore; }
|
||||
bool HasDupeKey() { return m_bHasDupeKey; }
|
||||
bool HasAddDupeKey() { return m_bHasAddDupeKey; }
|
||||
bool HasDupeMode() { return m_bHasDupeMode; }
|
||||
bool HasRageId() { return m_bHasRageId; }
|
||||
bool HasSeries() { return m_bHasSeries; }
|
||||
bool Match(FeedItemInfo* pFeedItemInfo);
|
||||
void ExpandRefValues(FeedItemInfo* pFeedItemInfo, char** pDestStr, char* pPatStr);
|
||||
const char* GetRefValue(FeedItemInfo* pFeedItemInfo, const char* szVarName);
|
||||
};
|
||||
|
||||
typedef std::deque<Rule*> RuleList;
|
||||
|
||||
private:
|
||||
RuleList m_Rules;
|
||||
|
||||
void Compile(const char* szFilter);
|
||||
void CompileRule(char* szRule);
|
||||
void ApplyOptions(Rule* pRule, FeedItemInfo* pFeedItemInfo);
|
||||
|
||||
public:
|
||||
FeedFilter(const char* szFilter);
|
||||
~FeedFilter();
|
||||
void Match(FeedItemInfo* pFeedItemInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
440
FeedInfo.cpp
440
FeedInfo.cpp
@@ -1,440 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision: 0 $
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "FeedInfo.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
FeedInfo::FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval,
|
||||
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority)
|
||||
{
|
||||
m_iID = iID;
|
||||
m_szName = strdup(szName ? szName : "");
|
||||
m_szUrl = strdup(szUrl ? szUrl : "");
|
||||
m_szFilter = strdup(szFilter ? szFilter : "");
|
||||
m_iFilterHash = Util::HashBJ96(szFilter, strlen(szFilter), 0);
|
||||
m_szCategory = strdup(szCategory ? szCategory : "");
|
||||
m_iInterval = iInterval;
|
||||
m_bPauseNzb = bPauseNzb;
|
||||
m_iPriority = iPriority;
|
||||
m_tLastUpdate = 0;
|
||||
m_bPreview = false;
|
||||
m_eStatus = fsUndefined;
|
||||
m_szOutputFilename = NULL;
|
||||
m_bFetch = false;
|
||||
m_bForce = false;
|
||||
}
|
||||
|
||||
FeedInfo::~FeedInfo()
|
||||
{
|
||||
free(m_szName);
|
||||
free(m_szUrl);
|
||||
free(m_szFilter);
|
||||
free(m_szCategory);
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
|
||||
void FeedInfo::SetOutputFilename(const char* szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
m_szOutputFilename = strdup(szOutputFilename);
|
||||
}
|
||||
|
||||
|
||||
FeedItemInfo::Attr::Attr(const char* szName, const char* szValue)
|
||||
{
|
||||
m_szName = strdup(szName ? szName : "");
|
||||
m_szValue = strdup(szValue ? szValue : "");
|
||||
}
|
||||
|
||||
FeedItemInfo::Attr::~Attr()
|
||||
{
|
||||
free(m_szName);
|
||||
free(m_szValue);
|
||||
}
|
||||
|
||||
|
||||
FeedItemInfo::Attributes::~Attributes()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedItemInfo::Attributes::Add(const char* szName, const char* szValue)
|
||||
{
|
||||
push_back(new Attr(szName, szValue));
|
||||
}
|
||||
|
||||
FeedItemInfo::Attr* FeedItemInfo::Attributes::Find(const char* szName)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
Attr* pAttr = *it;
|
||||
if (!strcasecmp(pAttr->GetName(), szName))
|
||||
{
|
||||
return pAttr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
FeedItemInfo::FeedItemInfo()
|
||||
{
|
||||
m_pSharedFeedData = NULL;
|
||||
m_szTitle = NULL;
|
||||
m_szFilename = NULL;
|
||||
m_szUrl = NULL;
|
||||
m_szCategory = strdup("");
|
||||
m_lSize = 0;
|
||||
m_tTime = 0;
|
||||
m_iImdbId = 0;
|
||||
m_iRageId = 0;
|
||||
m_szDescription = strdup("");
|
||||
m_szSeason = NULL;
|
||||
m_szEpisode = NULL;
|
||||
m_iSeasonNum = 0;
|
||||
m_iEpisodeNum = 0;
|
||||
m_bSeasonEpisodeParsed = false;
|
||||
m_szAddCategory = strdup("");
|
||||
m_bPauseNzb = false;
|
||||
m_iPriority = 0;
|
||||
m_eStatus = isUnknown;
|
||||
m_eMatchStatus = msIgnored;
|
||||
m_iMatchRule = 0;
|
||||
m_szDupeKey = NULL;
|
||||
m_iDupeScore = 0;
|
||||
m_eDupeMode = dmScore;
|
||||
}
|
||||
|
||||
FeedItemInfo::~FeedItemInfo()
|
||||
{
|
||||
free(m_szTitle);
|
||||
free(m_szFilename);
|
||||
free(m_szUrl);
|
||||
free(m_szCategory);
|
||||
free(m_szDescription);
|
||||
free(m_szSeason);
|
||||
free(m_szEpisode);
|
||||
free(m_szAddCategory);
|
||||
free(m_szDupeKey);
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetTitle(const char* szTitle)
|
||||
{
|
||||
free(m_szTitle);
|
||||
m_szTitle = szTitle ? strdup(szTitle) : NULL;
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetFilename(const char* szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
m_szFilename = szFilename ? strdup(szFilename) : NULL;
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetUrl(const char* szUrl)
|
||||
{
|
||||
free(m_szUrl);
|
||||
m_szUrl = szUrl ? strdup(szUrl) : NULL;
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetCategory(const char* szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
m_szCategory = strdup(szCategory ? szCategory: "");
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetDescription(const char* szDescription)
|
||||
{
|
||||
free(m_szDescription);
|
||||
m_szDescription = strdup(szDescription ? szDescription: "");
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetSeason(const char* szSeason)
|
||||
{
|
||||
free(m_szSeason);
|
||||
m_szSeason = szSeason ? strdup(szSeason) : NULL;
|
||||
m_iSeasonNum = szSeason ? ParsePrefixedInt(szSeason) : 0;
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetEpisode(const char* szEpisode)
|
||||
{
|
||||
free(m_szEpisode);
|
||||
m_szEpisode = szEpisode ? strdup(szEpisode) : NULL;
|
||||
m_iEpisodeNum = szEpisode ? ParsePrefixedInt(szEpisode) : 0;
|
||||
}
|
||||
|
||||
int FeedItemInfo::ParsePrefixedInt(const char *szValue)
|
||||
{
|
||||
const char* szVal = szValue;
|
||||
if (!strchr("0123456789", *szVal))
|
||||
{
|
||||
szVal++;
|
||||
}
|
||||
return atoi(szVal);
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetAddCategory(const char* szAddCategory)
|
||||
{
|
||||
free(m_szAddCategory);
|
||||
m_szAddCategory = strdup(szAddCategory ? szAddCategory : "");
|
||||
}
|
||||
|
||||
void FeedItemInfo::SetDupeKey(const char* szDupeKey)
|
||||
{
|
||||
free(m_szDupeKey);
|
||||
m_szDupeKey = strdup(szDupeKey ? szDupeKey : "");
|
||||
}
|
||||
|
||||
void FeedItemInfo::AppendDupeKey(const char* szExtraDupeKey)
|
||||
{
|
||||
if (!m_szDupeKey || *m_szDupeKey == '\0' || !szExtraDupeKey || *szExtraDupeKey == '\0')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iLen = (m_szDupeKey ? strlen(m_szDupeKey) : 0) + 1 + strlen(szExtraDupeKey) + 1;
|
||||
char* szNewKey = (char*)malloc(iLen);
|
||||
snprintf(szNewKey, iLen, "%s-%s", m_szDupeKey, szExtraDupeKey);
|
||||
szNewKey[iLen - 1] = '\0';
|
||||
|
||||
free(m_szDupeKey);
|
||||
m_szDupeKey = szNewKey;
|
||||
}
|
||||
|
||||
void FeedItemInfo::BuildDupeKey(const char* szRageId, const char* szSeries)
|
||||
{
|
||||
int iRageId = szRageId && *szRageId ? atoi(szRageId) : m_iRageId;
|
||||
|
||||
free(m_szDupeKey);
|
||||
|
||||
if (m_iImdbId != 0)
|
||||
{
|
||||
m_szDupeKey = (char*)malloc(20);
|
||||
snprintf(m_szDupeKey, 20, "imdb=%i", m_iImdbId);
|
||||
}
|
||||
else if (szSeries && *szSeries && GetSeasonNum() != 0 && GetEpisodeNum() != 0)
|
||||
{
|
||||
int iLen = strlen(szSeries) + 50;
|
||||
m_szDupeKey = (char*)malloc(iLen);
|
||||
snprintf(m_szDupeKey, iLen, "series=%s-%s-%s", szSeries, m_szSeason, m_szEpisode);
|
||||
m_szDupeKey[iLen-1] = '\0';
|
||||
}
|
||||
else if (iRageId != 0 && GetSeasonNum() != 0 && GetEpisodeNum() != 0)
|
||||
{
|
||||
m_szDupeKey = (char*)malloc(100);
|
||||
snprintf(m_szDupeKey, 100, "rageid=%i-%s-%s", iRageId, m_szSeason, m_szEpisode);
|
||||
m_szDupeKey[100-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
m_szDupeKey = strdup("");
|
||||
}
|
||||
}
|
||||
|
||||
int FeedItemInfo::GetSeasonNum()
|
||||
{
|
||||
if (!m_szSeason && !m_bSeasonEpisodeParsed)
|
||||
{
|
||||
ParseSeasonEpisode();
|
||||
}
|
||||
|
||||
return m_iSeasonNum;
|
||||
}
|
||||
|
||||
int FeedItemInfo::GetEpisodeNum()
|
||||
{
|
||||
if (!m_szEpisode && !m_bSeasonEpisodeParsed)
|
||||
{
|
||||
ParseSeasonEpisode();
|
||||
}
|
||||
|
||||
return m_iEpisodeNum;
|
||||
}
|
||||
|
||||
void FeedItemInfo::ParseSeasonEpisode()
|
||||
{
|
||||
m_bSeasonEpisodeParsed = true;
|
||||
|
||||
RegEx* pRegEx = m_pSharedFeedData->GetSeasonEpisodeRegEx();
|
||||
|
||||
if (pRegEx->Match(m_szTitle))
|
||||
{
|
||||
char szRegValue[100];
|
||||
char szValue[100];
|
||||
|
||||
snprintf(szValue, 100, "S%02d", atoi(m_szTitle + pRegEx->GetMatchStart(1)));
|
||||
szValue[100-1] = '\0';
|
||||
SetSeason(szValue);
|
||||
|
||||
int iLen = pRegEx->GetMatchLen(2);
|
||||
iLen = iLen < 99 ? iLen : 99;
|
||||
strncpy(szRegValue, m_szTitle + pRegEx->GetMatchStart(2), pRegEx->GetMatchLen(2));
|
||||
szRegValue[iLen] = '\0';
|
||||
snprintf(szValue, 100, "E%s", szRegValue);
|
||||
szValue[100-1] = '\0';
|
||||
Util::ReduceStr(szValue, "-", "");
|
||||
for (char* p = szValue; *p; p++) *p = toupper(*p); // convert string to uppercase e02 -> E02
|
||||
SetEpisode(szValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FeedHistoryInfo::FeedHistoryInfo(const char* szUrl, FeedHistoryInfo::EStatus eStatus, time_t tLastSeen)
|
||||
{
|
||||
m_szUrl = szUrl ? strdup(szUrl) : NULL;
|
||||
m_eStatus = eStatus;
|
||||
m_tLastSeen = tLastSeen;
|
||||
}
|
||||
|
||||
FeedHistoryInfo::~FeedHistoryInfo()
|
||||
{
|
||||
free(m_szUrl);
|
||||
}
|
||||
|
||||
|
||||
FeedHistory::~FeedHistory()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void FeedHistory::Clear()
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
void FeedHistory::Add(const char* szUrl, FeedHistoryInfo::EStatus eStatus, time_t tLastSeen)
|
||||
{
|
||||
push_back(new FeedHistoryInfo(szUrl, eStatus, tLastSeen));
|
||||
}
|
||||
|
||||
void FeedHistory::Remove(const char* szUrl)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
FeedHistoryInfo* pFeedHistoryInfo = *it;
|
||||
if (!strcmp(pFeedHistoryInfo->GetUrl(), szUrl))
|
||||
{
|
||||
delete pFeedHistoryInfo;
|
||||
erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FeedHistoryInfo* FeedHistory::Find(const char* szUrl)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
FeedHistoryInfo* pFeedHistoryInfo = *it;
|
||||
if (!strcmp(pFeedHistoryInfo->GetUrl(), szUrl))
|
||||
{
|
||||
return pFeedHistoryInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
FeedItemInfos::FeedItemInfos()
|
||||
{
|
||||
debug("Creating FeedItemInfos");
|
||||
|
||||
m_iRefCount = 0;
|
||||
}
|
||||
|
||||
FeedItemInfos::~FeedItemInfos()
|
||||
{
|
||||
debug("Destroing FeedItemInfos");
|
||||
|
||||
for (iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedItemInfos::Retain()
|
||||
{
|
||||
m_iRefCount++;
|
||||
}
|
||||
|
||||
void FeedItemInfos::Release()
|
||||
{
|
||||
m_iRefCount--;
|
||||
if (m_iRefCount <= 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedItemInfos::Add(FeedItemInfo* pFeedItemInfo)
|
||||
{
|
||||
push_back(pFeedItemInfo);
|
||||
pFeedItemInfo->SetSharedFeedData(&m_SharedFeedData);
|
||||
}
|
||||
|
||||
|
||||
SharedFeedData::SharedFeedData()
|
||||
{
|
||||
m_pSeasonEpisodeRegEx = NULL;
|
||||
}
|
||||
|
||||
SharedFeedData::~SharedFeedData()
|
||||
{
|
||||
delete m_pSeasonEpisodeRegEx;
|
||||
}
|
||||
|
||||
RegEx* SharedFeedData::GetSeasonEpisodeRegEx()
|
||||
{
|
||||
if (!m_pSeasonEpisodeRegEx)
|
||||
{
|
||||
m_pSeasonEpisodeRegEx = new RegEx("[^[:alnum:]]s?([0-9]+)[ex]([0-9]+(-?e[0-9]+)?)[^[:alnum:]]", 10);
|
||||
}
|
||||
|
||||
return m_pSeasonEpisodeRegEx;
|
||||
}
|
||||
278
FeedInfo.h
278
FeedInfo.h
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision: 0 $
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FEEDINFO_H
|
||||
#define FEEDINFO_H
|
||||
|
||||
#include <deque>
|
||||
#include <time.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "DownloadInfo.h"
|
||||
|
||||
|
||||
class FeedInfo
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
fsUndefined,
|
||||
fsRunning,
|
||||
fsFinished,
|
||||
fsFailed
|
||||
};
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
char* m_szName;
|
||||
char* m_szUrl;
|
||||
int m_iInterval;
|
||||
char* m_szFilter;
|
||||
unsigned int m_iFilterHash;
|
||||
bool m_bPauseNzb;
|
||||
char* m_szCategory;
|
||||
int m_iPriority;
|
||||
time_t m_tLastUpdate;
|
||||
bool m_bPreview;
|
||||
EStatus m_eStatus;
|
||||
char* m_szOutputFilename;
|
||||
bool m_bFetch;
|
||||
bool m_bForce;
|
||||
|
||||
public:
|
||||
FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval,
|
||||
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority);
|
||||
~FeedInfo();
|
||||
int GetID() { return m_iID; }
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetUrl() { return m_szUrl; }
|
||||
int GetInterval() { return m_iInterval; }
|
||||
const char* GetFilter() { return m_szFilter; }
|
||||
unsigned int GetFilterHash() { return m_iFilterHash; }
|
||||
bool GetPauseNzb() { return m_bPauseNzb; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
int GetPriority() { return m_iPriority; }
|
||||
time_t GetLastUpdate() { return m_tLastUpdate; }
|
||||
void SetLastUpdate(time_t tLastUpdate) { m_tLastUpdate = tLastUpdate; }
|
||||
bool GetPreview() { return m_bPreview; }
|
||||
void SetPreview(bool bPreview) { m_bPreview = bPreview; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetStatus(EStatus Status) { m_eStatus = Status; }
|
||||
const char* GetOutputFilename() { return m_szOutputFilename; }
|
||||
void SetOutputFilename(const char* szOutputFilename);
|
||||
bool GetFetch() { return m_bFetch; }
|
||||
void SetFetch(bool bFetch) { m_bFetch = bFetch; }
|
||||
bool GetForce() { return m_bForce; }
|
||||
void SetForce(bool bForce) { m_bForce = bForce; }
|
||||
};
|
||||
|
||||
typedef std::deque<FeedInfo*> Feeds;
|
||||
|
||||
class SharedFeedData
|
||||
{
|
||||
private:
|
||||
RegEx* m_pSeasonEpisodeRegEx;
|
||||
|
||||
public:
|
||||
SharedFeedData();
|
||||
~SharedFeedData();
|
||||
RegEx* GetSeasonEpisodeRegEx();
|
||||
};
|
||||
|
||||
class FeedItemInfo
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
isUnknown,
|
||||
isBacklog,
|
||||
isFetched,
|
||||
isNew
|
||||
};
|
||||
|
||||
enum EMatchStatus
|
||||
{
|
||||
msIgnored,
|
||||
msAccepted,
|
||||
msRejected
|
||||
};
|
||||
|
||||
class Attr
|
||||
{
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szValue;
|
||||
public:
|
||||
Attr(const char* szName, const char* szValue);
|
||||
~Attr();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetValue() { return m_szValue; }
|
||||
};
|
||||
|
||||
typedef std::deque<Attr*> AttributesBase;
|
||||
|
||||
class Attributes: public AttributesBase
|
||||
{
|
||||
public:
|
||||
~Attributes();
|
||||
void Add(const char* szName, const char* szValue);
|
||||
Attr* Find(const char* szName);
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szTitle;
|
||||
char* m_szFilename;
|
||||
char* m_szUrl;
|
||||
time_t m_tTime;
|
||||
long long m_lSize;
|
||||
char* m_szCategory;
|
||||
int m_iImdbId;
|
||||
int m_iRageId;
|
||||
char* m_szDescription;
|
||||
char* m_szSeason;
|
||||
char* m_szEpisode;
|
||||
int m_iSeasonNum;
|
||||
int m_iEpisodeNum;
|
||||
bool m_bSeasonEpisodeParsed;
|
||||
char* m_szAddCategory;
|
||||
bool m_bPauseNzb;
|
||||
int m_iPriority;
|
||||
EStatus m_eStatus;
|
||||
EMatchStatus m_eMatchStatus;
|
||||
int m_iMatchRule;
|
||||
char* m_szDupeKey;
|
||||
int m_iDupeScore;
|
||||
EDupeMode m_eDupeMode;
|
||||
SharedFeedData* m_pSharedFeedData;
|
||||
Attributes m_Attributes;
|
||||
|
||||
int ParsePrefixedInt(const char *szValue);
|
||||
void ParseSeasonEpisode();
|
||||
|
||||
public:
|
||||
FeedItemInfo();
|
||||
~FeedItemInfo();
|
||||
void SetSharedFeedData(SharedFeedData* pSharedFeedData) { m_pSharedFeedData = pSharedFeedData; }
|
||||
const char* GetTitle() { return m_szTitle; }
|
||||
void SetTitle(const char* szTitle);
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
void SetFilename(const char* szFilename);
|
||||
const char* GetUrl() { return m_szUrl; }
|
||||
void SetUrl(const char* szUrl);
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long lSize) { m_lSize = lSize; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
void SetCategory(const char* szCategory);
|
||||
int GetImdbId() { return m_iImdbId; }
|
||||
void SetImdbId(int iImdbId) { m_iImdbId = iImdbId; }
|
||||
int GetRageId() { return m_iRageId; }
|
||||
void SetRageId(int iRageId) { m_iRageId = iRageId; }
|
||||
const char* GetDescription() { return m_szDescription; }
|
||||
void SetDescription(const char* szDescription);
|
||||
const char* GetSeason() { return m_szSeason; }
|
||||
void SetSeason(const char* szSeason);
|
||||
const char* GetEpisode() { return m_szEpisode; }
|
||||
void SetEpisode(const char* szEpisode);
|
||||
int GetSeasonNum();
|
||||
int GetEpisodeNum();
|
||||
const char* GetAddCategory() { return m_szAddCategory; }
|
||||
void SetAddCategory(const char* szAddCategory);
|
||||
bool GetPauseNzb() { return m_bPauseNzb; }
|
||||
void SetPauseNzb(bool bPauseNzb) { m_bPauseNzb = bPauseNzb; }
|
||||
int GetPriority() { return m_iPriority; }
|
||||
void SetPriority(int iPriority) { m_iPriority = iPriority; }
|
||||
time_t GetTime() { return m_tTime; }
|
||||
void SetTime(time_t tTime) { m_tTime = tTime; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetStatus(EStatus eStatus) { m_eStatus = eStatus; }
|
||||
EMatchStatus GetMatchStatus() { return m_eMatchStatus; }
|
||||
void SetMatchStatus(EMatchStatus eMatchStatus) { m_eMatchStatus = eMatchStatus; }
|
||||
int GetMatchRule() { return m_iMatchRule; }
|
||||
void SetMatchRule(int iMatchRule) { m_iMatchRule = iMatchRule; }
|
||||
const char* GetDupeKey() { return m_szDupeKey; }
|
||||
void SetDupeKey(const char* szDupeKey);
|
||||
void AppendDupeKey(const char* szExtraDupeKey);
|
||||
void BuildDupeKey(const char* szRageId, const char* szSeries);
|
||||
int GetDupeScore() { return m_iDupeScore; }
|
||||
void SetDupeScore(int iDupeScore) { m_iDupeScore = iDupeScore; }
|
||||
EDupeMode GetDupeMode() { return m_eDupeMode; }
|
||||
void SetDupeMode(EDupeMode eDupeMode) { m_eDupeMode = eDupeMode; }
|
||||
Attributes* GetAttributes() { return &m_Attributes; }
|
||||
};
|
||||
|
||||
typedef std::deque<FeedItemInfo*> FeedItemInfosBase;
|
||||
|
||||
class FeedItemInfos : public FeedItemInfosBase
|
||||
{
|
||||
private:
|
||||
int m_iRefCount;
|
||||
SharedFeedData m_SharedFeedData;
|
||||
|
||||
public:
|
||||
FeedItemInfos();
|
||||
~FeedItemInfos();
|
||||
void Retain();
|
||||
void Release();
|
||||
void Add(FeedItemInfo* pFeedItemInfo);
|
||||
};
|
||||
|
||||
class FeedHistoryInfo
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
hsUnknown,
|
||||
hsBacklog,
|
||||
hsFetched
|
||||
};
|
||||
|
||||
private:
|
||||
char* m_szUrl;
|
||||
EStatus m_eStatus;
|
||||
time_t m_tLastSeen;
|
||||
|
||||
public:
|
||||
FeedHistoryInfo(const char* szUrl, EStatus eStatus, time_t tLastSeen);
|
||||
~FeedHistoryInfo();
|
||||
const char* GetUrl() { return m_szUrl; }
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
void SetStatus(EStatus Status) { m_eStatus = Status; }
|
||||
time_t GetLastSeen() { return m_tLastSeen; }
|
||||
void SetLastSeen(time_t tLastSeen) { m_tLastSeen = tLastSeen; }
|
||||
};
|
||||
|
||||
typedef std::deque<FeedHistoryInfo*> FeedHistoryBase;
|
||||
|
||||
class FeedHistory : public FeedHistoryBase
|
||||
{
|
||||
public:
|
||||
~FeedHistory();
|
||||
void Clear();
|
||||
void Add(const char* szUrl, FeedHistoryInfo::EStatus eStatus, time_t tLastSeen);
|
||||
void Remove(const char* szUrl);
|
||||
FeedHistoryInfo* Find(const char* szUrl);
|
||||
};
|
||||
|
||||
#endif
|
||||
14
Log.cpp
14
Log.cpp
@@ -60,7 +60,10 @@ Log::Log()
|
||||
Log::~Log()
|
||||
{
|
||||
Clear();
|
||||
free(m_szLogFilename);
|
||||
if (m_szLogFilename)
|
||||
{
|
||||
free(m_szLogFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Filelog(const char* msg, ...)
|
||||
@@ -77,7 +80,6 @@ void Log::Filelog(const char* msg, ...)
|
||||
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
rawtime += g_pOptions->GetTimeCorrection();
|
||||
|
||||
char szTime[50];
|
||||
#ifdef HAVE_CTIME_R_3
|
||||
@@ -303,7 +305,10 @@ Message::Message(unsigned int iID, EKind eKind, time_t tTime, const char* szText
|
||||
|
||||
Message::~ Message()
|
||||
{
|
||||
free(m_szText);
|
||||
if (m_szText)
|
||||
{
|
||||
free(m_szText);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Clear()
|
||||
@@ -365,9 +370,6 @@ void Log::InitOptions()
|
||||
if (g_pOptions->GetCreateLog() && g_pOptions->GetLogFile())
|
||||
{
|
||||
m_szLogFilename = strdup(g_pOptions->GetLogFile());
|
||||
#ifdef WIN32
|
||||
WebUtil::Utf8ToAnsi(m_szLogFilename, strlen(m_szLogFilename) + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_iIDGen = 0;
|
||||
|
||||
325
Maintenance.cpp
325
Maintenance.cpp
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "Maintenance.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern Maintenance* g_pMaintenance;
|
||||
|
||||
|
||||
Maintenance::Maintenance()
|
||||
{
|
||||
m_iIDMessageGen = 0;
|
||||
m_UpdateScriptController = NULL;
|
||||
m_szUpdateScript = NULL;
|
||||
}
|
||||
|
||||
Maintenance::~Maintenance()
|
||||
{
|
||||
m_mutexController.Lock();
|
||||
if (m_UpdateScriptController)
|
||||
{
|
||||
m_UpdateScriptController->Detach();
|
||||
m_mutexController.Unlock();
|
||||
while (m_UpdateScriptController)
|
||||
{
|
||||
usleep(20*1000);
|
||||
}
|
||||
}
|
||||
|
||||
ClearMessages();
|
||||
|
||||
free(m_szUpdateScript);
|
||||
}
|
||||
|
||||
void Maintenance::ResetUpdateController()
|
||||
{
|
||||
m_mutexController.Lock();
|
||||
m_UpdateScriptController = NULL;
|
||||
m_mutexController.Unlock();
|
||||
}
|
||||
|
||||
void Maintenance::ClearMessages()
|
||||
{
|
||||
for (Log::Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
}
|
||||
|
||||
Log::Messages* Maintenance::LockMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
}
|
||||
|
||||
void Maintenance::UnlockMessages()
|
||||
{
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void Maintenance::AppendMessage(Message::EKind eKind, time_t tTime, const char * szText)
|
||||
{
|
||||
if (tTime == 0)
|
||||
{
|
||||
tTime = time(NULL);
|
||||
}
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
bool Maintenance::StartUpdate(EBranch eBranch)
|
||||
{
|
||||
m_mutexController.Lock();
|
||||
bool bAlreadyUpdating = m_UpdateScriptController != NULL;
|
||||
m_mutexController.Unlock();
|
||||
|
||||
if (bAlreadyUpdating)
|
||||
{
|
||||
error("Could not start update-script: update-script is already running");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_szUpdateScript)
|
||||
{
|
||||
free(m_szUpdateScript);
|
||||
m_szUpdateScript = NULL;
|
||||
}
|
||||
|
||||
if (!ReadPackageInfoStr("install-script", &m_szUpdateScript))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearMessages();
|
||||
|
||||
m_UpdateScriptController = new UpdateScriptController();
|
||||
m_UpdateScriptController->SetScript(m_szUpdateScript);
|
||||
m_UpdateScriptController->SetBranch(eBranch);
|
||||
m_UpdateScriptController->SetAutoDestroy(true);
|
||||
|
||||
m_UpdateScriptController->Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Maintenance::CheckUpdates(char** pUpdateInfo)
|
||||
{
|
||||
char* szUpdateInfoScript;
|
||||
if (!ReadPackageInfoStr("update-info-script", &szUpdateInfoScript))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*pUpdateInfo = NULL;
|
||||
UpdateInfoScriptController::ExecuteScript(szUpdateInfoScript, pUpdateInfo);
|
||||
|
||||
free(szUpdateInfoScript);
|
||||
|
||||
return *pUpdateInfo;
|
||||
}
|
||||
|
||||
bool Maintenance::ReadPackageInfoStr(const char* szKey, char** pValue)
|
||||
{
|
||||
char szFileName[1024];
|
||||
snprintf(szFileName, 1024, "%s%cpackage-info.json", g_pOptions->GetWebDir(), PATH_SEPARATOR);
|
||||
szFileName[1024-1] = '\0';
|
||||
|
||||
char* szPackageInfo;
|
||||
int iPackageInfoLen;
|
||||
if (!Util::LoadFileIntoBuffer(szFileName, &szPackageInfo, &iPackageInfoLen))
|
||||
{
|
||||
error("Could not load file %s", szFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
char szKeyStr[100];
|
||||
snprintf(szKeyStr, 100, "\"%s\"", szKey);
|
||||
szKeyStr[100-1] = '\0';
|
||||
|
||||
char* p = strstr(szPackageInfo, szKeyStr);
|
||||
if (!p)
|
||||
{
|
||||
error("Could not parse file %s", szFileName);
|
||||
free(szPackageInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
p = strchr(p + strlen(szKeyStr), '"');
|
||||
if (!p)
|
||||
{
|
||||
error("Could not parse file %s", szFileName);
|
||||
free(szPackageInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
p++;
|
||||
char* pend = strchr(p, '"');
|
||||
if (!pend)
|
||||
{
|
||||
error("Could not parse file %s", szFileName);
|
||||
free(szPackageInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
int iLen = pend - p;
|
||||
if (iLen >= sizeof(szFileName))
|
||||
{
|
||||
error("Could not parse file %s", szFileName);
|
||||
free(szPackageInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
*pValue = (char*)malloc(iLen+1);
|
||||
strncpy(*pValue, p, iLen);
|
||||
(*pValue)[iLen] = '\0';
|
||||
|
||||
WebUtil::JsonDecode(*pValue);
|
||||
|
||||
free(szPackageInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateScriptController::Run()
|
||||
{
|
||||
m_iPrefixLen = 0;
|
||||
PrintMessage(Message::mkInfo, "Executing update-script %s", GetScript());
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "update-script %s", Util::BaseFileName(GetScript()));
|
||||
szInfoName[1024-1] = '\0';
|
||||
SetInfoName(szInfoName);
|
||||
|
||||
const char* szBranchName[] = { "STABLE", "TESTING", "DEVEL" };
|
||||
SetEnvVar("NZBUP_BRANCH", szBranchName[m_eBranch]);
|
||||
|
||||
char szProcessID[20];
|
||||
#ifdef WIN32
|
||||
int pid = (int)GetCurrentProcessId();
|
||||
#else
|
||||
int pid = (int)getppid();
|
||||
#endif
|
||||
snprintf(szProcessID, 20, "%i", pid);
|
||||
szProcessID[20-1] = '\0';
|
||||
SetEnvVar("NZBUP_PROCESSID", szProcessID);
|
||||
|
||||
char szLogPrefix[100];
|
||||
strncpy(szLogPrefix, Util::BaseFileName(GetScript()), 100);
|
||||
szLogPrefix[100-1] = '\0';
|
||||
if (char* ext = strrchr(szLogPrefix, '.')) *ext = '\0'; // strip file extension
|
||||
SetLogPrefix(szLogPrefix);
|
||||
m_iPrefixLen = strlen(szLogPrefix) + 2; // 2 = strlen(": ");
|
||||
|
||||
Execute();
|
||||
|
||||
g_pMaintenance->ResetUpdateController();
|
||||
}
|
||||
|
||||
void UpdateScriptController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
szText = szText + m_iPrefixLen;
|
||||
|
||||
g_pMaintenance->AppendMessage(eKind, time(NULL), szText);
|
||||
ScriptController::AddMessage(eKind, szText);
|
||||
}
|
||||
|
||||
void UpdateInfoScriptController::ExecuteScript(const char* szScript, char** pUpdateInfo)
|
||||
{
|
||||
detail("Executing update-info-script %s", Util::BaseFileName(szScript));
|
||||
|
||||
UpdateInfoScriptController* pScriptController = new UpdateInfoScriptController();
|
||||
pScriptController->SetScript(szScript);
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "update-info-script %s", Util::BaseFileName(szScript));
|
||||
szInfoName[1024-1] = '\0';
|
||||
pScriptController->SetInfoName(szInfoName);
|
||||
|
||||
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();
|
||||
|
||||
if (pScriptController->m_UpdateInfo.GetBuffer())
|
||||
{
|
||||
int iLen = strlen(pScriptController->m_UpdateInfo.GetBuffer());
|
||||
*pUpdateInfo = (char*)malloc(iLen + 1);
|
||||
strncpy(*pUpdateInfo, pScriptController->m_UpdateInfo.GetBuffer(), iLen);
|
||||
(*pUpdateInfo)[iLen] = '\0';
|
||||
}
|
||||
|
||||
delete pScriptController;
|
||||
}
|
||||
|
||||
void UpdateInfoScriptController::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, "[UPDATEINFO]", 12))
|
||||
{
|
||||
m_UpdateInfo.Append(szText + 6 + 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Invalid command \"%s\" received from %s", szText, GetInfoName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, szText);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINTENANCE_H
|
||||
#define MAINTENANCE_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "ScriptController.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
class UpdateScriptController;
|
||||
|
||||
class Maintenance
|
||||
{
|
||||
private:
|
||||
Log::Messages m_Messages;
|
||||
Mutex m_mutexLog;
|
||||
Mutex m_mutexController;
|
||||
int m_iIDMessageGen;
|
||||
UpdateScriptController* m_UpdateScriptController;
|
||||
char* m_szUpdateScript;
|
||||
|
||||
bool ReadPackageInfoStr(const char* szKey, char** pValue);
|
||||
|
||||
public:
|
||||
enum EBranch
|
||||
{
|
||||
brStable,
|
||||
brTesting,
|
||||
brDevel
|
||||
};
|
||||
|
||||
Maintenance();
|
||||
~Maintenance();
|
||||
void ClearMessages();
|
||||
void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText);
|
||||
Log::Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
bool StartUpdate(EBranch eBranch);
|
||||
void ResetUpdateController();
|
||||
bool CheckUpdates(char** pUpdateInfo);
|
||||
};
|
||||
|
||||
class UpdateScriptController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
Maintenance::EBranch m_eBranch;
|
||||
int m_iPrefixLen;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
void SetBranch(Maintenance::EBranch eBranch) { m_eBranch = eBranch; }
|
||||
};
|
||||
|
||||
class UpdateInfoScriptController : public ScriptController
|
||||
{
|
||||
private:
|
||||
int m_iPrefixLen;
|
||||
StringBuilder m_UpdateInfo;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, const char* szText);
|
||||
|
||||
public:
|
||||
static void ExecuteScript(const char* szScript, char** pUpdateInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
29
Makefile.am
29
Makefile.am
@@ -24,12 +24,10 @@ bin_PROGRAMS = nzbget
|
||||
nzbget_SOURCES = \
|
||||
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h 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 \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
|
||||
NZBFile.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h ParRenamer.cpp ParRenamer.h \
|
||||
ParCoordinator.cpp ParCoordinator.h PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp RemoteClient.h \
|
||||
@@ -40,7 +38,7 @@ nzbget_SOURCES = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd \
|
||||
$(patches_FILES) $(windows_FILES) $(osx_FILES)
|
||||
$(patches_FILES) $(windows_FILES)
|
||||
|
||||
patches_FILES = \
|
||||
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
|
||||
@@ -49,21 +47,6 @@ patches_FILES = \
|
||||
windows_FILES = \
|
||||
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/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
|
||||
|
||||
doc_FILES = \
|
||||
README ChangeLog COPYING
|
||||
|
||||
@@ -73,7 +56,7 @@ exampleconf_FILES = \
|
||||
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/util.js webui/config.js \
|
||||
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
|
||||
webui/lib/jquery.js webui/lib/jquery.min.js \
|
||||
webui/img/icons.png webui/img/icons-2x.png \
|
||||
|
||||
42
Makefile.in
42
Makefile.in
@@ -85,10 +85,7 @@ PROGRAMS = $(bin_PROGRAMS)
|
||||
am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
ColoredFrontend.$(OBJEXT) Connection.$(OBJEXT) \
|
||||
Decoder.$(OBJEXT) DiskState.$(OBJEXT) DownloadInfo.$(OBJEXT) \
|
||||
DupeCoordinator.$(OBJEXT) Frontend.$(OBJEXT) \
|
||||
FeedCoordinator.$(OBJEXT) FeedFile.$(OBJEXT) \
|
||||
FeedFilter.$(OBJEXT) FeedInfo.$(OBJEXT) Log.$(OBJEXT) \
|
||||
LoggableFrontend.$(OBJEXT) Maintenance.$(OBJEXT) \
|
||||
Frontend.$(OBJEXT) Log.$(OBJEXT) LoggableFrontend.$(OBJEXT) \
|
||||
NCursesFrontend.$(OBJEXT) NNTPConnection.$(OBJEXT) \
|
||||
NZBFile.$(OBJEXT) NewsServer.$(OBJEXT) Observer.$(OBJEXT) \
|
||||
Options.$(OBJEXT) ParChecker.$(OBJEXT) ParRenamer.$(OBJEXT) \
|
||||
@@ -245,12 +242,10 @@ target_vendor = @target_vendor@
|
||||
nzbget_SOURCES = \
|
||||
ArticleDownloader.cpp ArticleDownloader.h BinRpc.cpp BinRpc.h \
|
||||
ColoredFrontend.cpp ColoredFrontend.h Connection.cpp Connection.h Decoder.cpp Decoder.h \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h 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 \
|
||||
DiskState.cpp DiskState.h DownloadInfo.cpp DownloadInfo.h Frontend.cpp Frontend.h \
|
||||
Log.cpp Log.h LoggableFrontend.cpp LoggableFrontend.h MessageBase.h \
|
||||
NCursesFrontend.cpp NCursesFrontend.h NNTPConnection.cpp NNTPConnection.h NZBFile.cpp \
|
||||
NZBFile.h NewsServer.cpp NewsServer.h Observer.cpp \
|
||||
Observer.h Options.cpp Options.h ParChecker.cpp ParChecker.h ParRenamer.cpp ParRenamer.h \
|
||||
ParCoordinator.cpp ParCoordinator.h PrePostProcessor.cpp PrePostProcessor.h QueueCoordinator.cpp \
|
||||
QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp RemoteClient.h \
|
||||
@@ -261,7 +256,7 @@ nzbget_SOURCES = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd \
|
||||
$(patches_FILES) $(windows_FILES) $(osx_FILES)
|
||||
$(patches_FILES) $(windows_FILES)
|
||||
|
||||
patches_FILES = \
|
||||
libpar2-0.2-bugfixes.patch libpar2-0.2-cancel.patch \
|
||||
@@ -270,21 +265,6 @@ patches_FILES = \
|
||||
windows_FILES = \
|
||||
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/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
|
||||
|
||||
doc_FILES = \
|
||||
README ChangeLog COPYING
|
||||
|
||||
@@ -294,7 +274,7 @@ exampleconf_FILES = \
|
||||
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/util.js webui/config.js \
|
||||
webui/lib/bootstrap.js webui/lib/bootstrap.min.js webui/lib/bootstrap.css \
|
||||
webui/lib/jquery.js webui/lib/jquery.min.js \
|
||||
webui/img/icons.png webui/img/icons-2x.png \
|
||||
@@ -460,15 +440,9 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Decoder.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DiskState.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadInfo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DupeCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedFile.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedFilter.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeedInfo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Frontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Log.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoggableFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Maintenance.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NCursesFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NNTPConnection.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NZBFile.Po@am__quote@
|
||||
@@ -617,7 +591,7 @@ distclean-tags:
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
mkdir $(distdir)
|
||||
$(mkdir_p) $(distdir)/osx $(distdir)/osx/NZBGet.xcodeproj $(distdir)/osx/Resources $(distdir)/osx/Resources/Images $(distdir)/osx/Resources/licenses $(distdir)/ppscripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
|
||||
$(mkdir_p) $(distdir)/ppscripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(DISTFILES)'; for file in $$list; do \
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef MESSAGEBASE_H
|
||||
#define MESSAGEBASE_H
|
||||
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A621B; // = "nzb-XX" (protocol version)
|
||||
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6217; // = "nzb-XX" (protocol version)
|
||||
static const int NZBREQUESTFILENAMESIZE = 512;
|
||||
static const int NZBREQUESTPASSWORDSIZE = 32;
|
||||
|
||||
@@ -88,8 +88,6 @@ enum eRemoteEditAction
|
||||
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
|
||||
@@ -97,25 +95,14 @@ enum eRemoteEditAction
|
||||
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
|
||||
eRemoteEditActionHistoryDelete, // 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)
|
||||
eRemoteEditActionHistorySetParameter // set post-process parameter for history-item
|
||||
};
|
||||
|
||||
// Possible values for field "m_iAction" of struct "SNZBPauseUnpauseRequest":
|
||||
|
||||
@@ -202,9 +202,14 @@ NCursesFrontend::NCursesFrontend()
|
||||
NCursesFrontend::~NCursesFrontend()
|
||||
{
|
||||
#ifdef WIN32
|
||||
free(m_pScreenBuffer);
|
||||
free(m_pOldScreenBuffer);
|
||||
|
||||
if (m_pScreenBuffer)
|
||||
{
|
||||
free(m_pScreenBuffer);
|
||||
}
|
||||
if (m_pOldScreenBuffer)
|
||||
{
|
||||
free(m_pOldScreenBuffer);
|
||||
}
|
||||
m_ColorAttr.clear();
|
||||
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
@@ -545,8 +550,6 @@ int NCursesFrontend::PrintMessage(Message* Msg, int iRow, int iMaxLines)
|
||||
szText = (char*)malloc(iLen);
|
||||
|
||||
time_t rawtime = Msg->GetTime();
|
||||
rawtime += g_pOptions->GetTimeCorrection();
|
||||
|
||||
char szTime[50];
|
||||
#ifdef HAVE_CTIME_R_3
|
||||
ctime_r(&rawtime, szTime, 50);
|
||||
@@ -720,8 +723,11 @@ void NCursesFrontend::PrintKeyInputBar()
|
||||
|
||||
void NCursesFrontend::SetHint(const char* szHint)
|
||||
{
|
||||
free(m_szHint);
|
||||
m_szHint = NULL;
|
||||
if (m_szHint)
|
||||
{
|
||||
free(m_szHint);
|
||||
m_szHint = NULL;
|
||||
}
|
||||
if (szHint)
|
||||
{
|
||||
m_szHint = strdup(szHint);
|
||||
@@ -786,8 +792,8 @@ void NCursesFrontend::PrintFileQueue()
|
||||
|
||||
char szBuffer[MAX_SCREEN_WIDTH];
|
||||
snprintf(szBuffer, sizeof(szBuffer), " %sFiles for downloading - %i / %i files in queue - %s / %s",
|
||||
m_bUseColor ? "" : "*** ", (int)pDownloadQueue->GetFileQueue()->size(),
|
||||
(int)pDownloadQueue->GetFileQueue()->size() - iPausedFiles, szRemaining, szUnpaused);
|
||||
m_bUseColor ? "" : "*** ", pDownloadQueue->GetFileQueue()->size(),
|
||||
pDownloadQueue->GetFileQueue()->size() - iPausedFiles, szRemaining, szUnpaused);
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
PrintTopHeader(szBuffer, m_iQueueWinTop, true);
|
||||
}
|
||||
@@ -971,7 +977,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)pGroupQueue->size(), szRemaining, szUnpaused);
|
||||
m_bUseColor ? "" : "*** ", pGroupQueue->size(), szRemaining, szUnpaused);
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
PrintTopHeader(szBuffer, m_iQueueWinTop, false);
|
||||
}
|
||||
@@ -1122,7 +1128,11 @@ void NCursesFrontend::PrepareGroupQueue()
|
||||
|
||||
void NCursesFrontend::ClearGroupQueue()
|
||||
{
|
||||
m_groupQueue.Clear();
|
||||
for (GroupQueue::iterator it = m_groupQueue.begin(); it != m_groupQueue.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_groupQueue.clear();
|
||||
}
|
||||
|
||||
bool NCursesFrontend::EditQueue(QueueEditor::EEditAction eAction, int iOffset)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Log.h"
|
||||
@@ -56,7 +55,11 @@ NNTPConnection::NNTPConnection(NewsServer* pNewsServer) : Connection(pNewsServer
|
||||
|
||||
NNTPConnection::~NNTPConnection()
|
||||
{
|
||||
free(m_szActiveGroup);
|
||||
if (m_szActiveGroup)
|
||||
{
|
||||
free(m_szActiveGroup);
|
||||
m_szActiveGroup = NULL;
|
||||
}
|
||||
free(m_szLineBuf);
|
||||
}
|
||||
|
||||
@@ -97,10 +100,10 @@ const char* NNTPConnection::Request(const char* req)
|
||||
|
||||
bool NNTPConnection::Authenticate()
|
||||
{
|
||||
if (strlen(m_pNewsServer->GetUser()) == 0 || strlen(m_pNewsServer->GetPassword()) == 0)
|
||||
if (!m_pNewsServer->GetUser() || strlen(m_pNewsServer->GetUser()) == 0 ||
|
||||
!m_pNewsServer->GetPassword() || strlen(m_pNewsServer->GetPassword()) == 0)
|
||||
{
|
||||
error("%c%s (%s) requested authorization but username/password are not set in settings",
|
||||
toupper(m_pNewsServer->GetName()[0]), m_pNewsServer->GetName() + 1, m_pNewsServer->GetHost());
|
||||
error("Server%i (%s) requested authorization but username/password are not set in settings", m_pNewsServer->GetID(), m_pNewsServer->GetHost());
|
||||
m_bAuthError = true;
|
||||
return false;
|
||||
}
|
||||
@@ -208,7 +211,11 @@ const char* NNTPConnection::JoinGroup(const char* grp)
|
||||
if (answer && !strncmp(answer, "2", 1))
|
||||
{
|
||||
debug("Changed group to %s on %s", grp, GetHost());
|
||||
free(m_szActiveGroup);
|
||||
|
||||
if (m_szActiveGroup)
|
||||
{
|
||||
free(m_szActiveGroup);
|
||||
}
|
||||
m_szActiveGroup = strdup(grp);
|
||||
}
|
||||
else
|
||||
@@ -249,7 +256,8 @@ bool NNTPConnection::Connect()
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((strlen(m_pNewsServer->GetUser()) > 0 && strlen(m_pNewsServer->GetPassword()) > 0) &&
|
||||
if ((m_pNewsServer->GetUser() && strlen(m_pNewsServer->GetUser()) > 0 &&
|
||||
m_pNewsServer->GetPassword() && strlen(m_pNewsServer->GetPassword()) > 0) &&
|
||||
!Authenticate())
|
||||
{
|
||||
return false;
|
||||
@@ -265,8 +273,11 @@ bool NNTPConnection::Disconnect()
|
||||
if (m_eStatus == csConnected)
|
||||
{
|
||||
Request("quit\r\n");
|
||||
free(m_szActiveGroup);
|
||||
m_szActiveGroup = NULL;
|
||||
if (m_szActiveGroup)
|
||||
{
|
||||
free(m_szActiveGroup);
|
||||
m_szActiveGroup = NULL;
|
||||
}
|
||||
}
|
||||
return Connection::Disconnect();
|
||||
}
|
||||
|
||||
281
NZBFile.cpp
281
NZBFile.cpp
@@ -34,7 +34,6 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <comutil.h>
|
||||
#import <msxml.tlb> named_guids
|
||||
@@ -62,15 +61,13 @@ NZBFile::NZBFile(const char* szFileName, const char* szCategory)
|
||||
debug("Creating NZBFile");
|
||||
|
||||
m_szFileName = strdup(szFileName);
|
||||
m_szPassword = NULL;
|
||||
m_pNZBInfo = new NZBInfo();
|
||||
m_pNZBInfo->Retain();
|
||||
m_pNZBInfo->AddReference();
|
||||
m_pNZBInfo->SetFilename(szFileName);
|
||||
m_pNZBInfo->SetCategory(szCategory);
|
||||
m_pNZBInfo->BuildDestDirName();
|
||||
|
||||
#ifndef WIN32
|
||||
m_bPassword = false;
|
||||
m_pFileInfo = NULL;
|
||||
m_pArticle = NULL;
|
||||
m_szTagContent = NULL;
|
||||
@@ -85,8 +82,10 @@ NZBFile::~NZBFile()
|
||||
debug("Destroying NZBFile");
|
||||
|
||||
// Cleanup
|
||||
free(m_szFileName);
|
||||
free(m_szPassword);
|
||||
if (m_szFileName)
|
||||
{
|
||||
free(m_szFileName);
|
||||
}
|
||||
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
@@ -100,8 +99,15 @@ NZBFile::~NZBFile()
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
delete m_pFileInfo;
|
||||
free(m_szTagContent);
|
||||
if (m_pFileInfo)
|
||||
{
|
||||
delete m_pFileInfo;
|
||||
}
|
||||
|
||||
if (m_szTagContent)
|
||||
{
|
||||
free(m_szTagContent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -121,70 +127,39 @@ void NZBFile::AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo)
|
||||
while ((int)pFileInfo->GetArticles()->size() < pArticleInfo->GetPartNumber())
|
||||
pFileInfo->GetArticles()->push_back(NULL);
|
||||
|
||||
int index = pArticleInfo->GetPartNumber() - 1;
|
||||
if ((*pFileInfo->GetArticles())[index])
|
||||
{
|
||||
delete (*pFileInfo->GetArticles())[index];
|
||||
}
|
||||
(*pFileInfo->GetArticles())[index] = pArticleInfo;
|
||||
(*pFileInfo->GetArticles())[pArticleInfo->GetPartNumber() - 1] = pArticleInfo;
|
||||
}
|
||||
|
||||
void NZBFile::AddFileInfo(FileInfo* pFileInfo)
|
||||
{
|
||||
// calculate file size and delete empty articles
|
||||
|
||||
long long lSize = 0;
|
||||
long long lMissedSize = 0;
|
||||
long long lOneSize = 0;
|
||||
int iUncountedArticles = 0;
|
||||
int iMissedArticles = 0;
|
||||
// deleting empty articles
|
||||
FileInfo::Articles* pArticles = pFileInfo->GetArticles();
|
||||
int iTotalArticles = (int)pArticles->size();
|
||||
int i = 0;
|
||||
for (FileInfo::Articles::iterator it = pArticles->begin(); it != pArticles->end(); )
|
||||
for (FileInfo::Articles::iterator it = pArticles->begin(); it != pArticles->end();)
|
||||
{
|
||||
ArticleInfo* pArticle = *it;
|
||||
if (!pArticle)
|
||||
if (*it == NULL)
|
||||
{
|
||||
pArticles->erase(it);
|
||||
it = pArticles->begin() + i;
|
||||
iMissedArticles++;
|
||||
if (lOneSize > 0)
|
||||
{
|
||||
lMissedSize += lOneSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
iUncountedArticles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lSize += pArticle->GetSize();
|
||||
if (lOneSize == 0)
|
||||
{
|
||||
lOneSize = pArticle->GetSize();
|
||||
}
|
||||
it++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pArticles->empty())
|
||||
if (!pArticles->empty())
|
||||
{
|
||||
delete pFileInfo;
|
||||
return;
|
||||
m_FileInfos.push_back(pFileInfo);
|
||||
pFileInfo->SetNZBInfo(m_pNZBInfo);
|
||||
m_pNZBInfo->SetSize(m_pNZBInfo->GetSize() + pFileInfo->GetSize());
|
||||
m_pNZBInfo->SetFileCount(m_pNZBInfo->GetFileCount() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pFileInfo;
|
||||
}
|
||||
|
||||
lMissedSize += iUncountedArticles * lOneSize;
|
||||
lSize += lMissedSize;
|
||||
m_FileInfos.push_back(pFileInfo);
|
||||
pFileInfo->SetNZBInfo(m_pNZBInfo);
|
||||
pFileInfo->SetSize(lSize);
|
||||
pFileInfo->SetRemainingSize(lSize - lMissedSize);
|
||||
pFileInfo->SetMissedSize(lMissedSize);
|
||||
pFileInfo->SetTotalArticles(iTotalArticles);
|
||||
pFileInfo->SetMissedArticles(iMissedArticles);
|
||||
}
|
||||
|
||||
void NZBFile::ParseSubject(FileInfo* pFileInfo, bool TryQuotes)
|
||||
@@ -333,7 +308,7 @@ bool NZBFile::HasDuplicateFilenames()
|
||||
/**
|
||||
* Generate filenames from subjects and check if the parsing of subject was correct
|
||||
*/
|
||||
void NZBFile::BuildFilenames()
|
||||
void NZBFile::ProcessFilenames()
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
@@ -352,185 +327,23 @@ void NZBFile::BuildFilenames()
|
||||
|
||||
if (HasDuplicateFilenames())
|
||||
{
|
||||
m_pNZBInfo->SetManyDupeFiles(true);
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->SetFilename(pFileInfo->GetSubject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CompareFileInfo(FileInfo* pFirst, FileInfo* pSecond)
|
||||
{
|
||||
return strcmp(pFirst->GetFilename(), pSecond->GetFilename()) > 0;
|
||||
}
|
||||
|
||||
void NZBFile::CalcHashes()
|
||||
{
|
||||
FileInfoList fileList;
|
||||
|
||||
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 (FileInfoList::iterator it = fileList.begin(); it != fileList.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
|
||||
// check file extension
|
||||
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++)
|
||||
{
|
||||
ArticleInfo* pArticle = *it;
|
||||
int iLen = strlen(pArticle->GetMessageID());
|
||||
iFullContentHash = Util::HashBJ96(pArticle->GetMessageID(), iLen, iFullContentHash);
|
||||
if (!bSkip)
|
||||
{
|
||||
iFilteredContentHash = Util::HashBJ96(pArticle->GetMessageID(), iLen, iFilteredContentHash);
|
||||
iUseForFilteredCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
iFilteredContentHash = 0;
|
||||
}
|
||||
|
||||
m_pNZBInfo->SetFullContentHash(iFullContentHash);
|
||||
m_pNZBInfo->SetFilteredContentHash(iFilteredContentHash);
|
||||
}
|
||||
|
||||
void NZBFile::ProcessFiles()
|
||||
{
|
||||
BuildFilenames();
|
||||
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->MakeValidFilename();
|
||||
|
||||
char szLoFileName[1024];
|
||||
strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
|
||||
szLoFileName[1024-1] = '\0';
|
||||
for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
bool bParFile = strstr(szLoFileName, ".par2");
|
||||
|
||||
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->SetFailedSize(m_pNZBInfo->GetFailedSize() + pFileInfo->GetMissedSize());
|
||||
m_pNZBInfo->SetCurrentFailedSize(m_pNZBInfo->GetFailedSize());
|
||||
|
||||
pFileInfo->SetParFile(bParFile);
|
||||
if (bParFile)
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
m_pNZBInfo->SetParSize(m_pNZBInfo->GetParSize() + pFileInfo->GetSize());
|
||||
m_pNZBInfo->SetParFailedSize(m_pNZBInfo->GetParFailedSize() + pFileInfo->GetMissedSize());
|
||||
m_pNZBInfo->SetParCurrentFailedSize(m_pNZBInfo->GetParFailedSize());
|
||||
}
|
||||
}
|
||||
|
||||
CalcHashes();
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
for (FileInfos::iterator it = m_FileInfos.begin(); it != m_FileInfos.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
g_pDiskState->SaveFile(pFileInfo);
|
||||
pFileInfo->ClearArticles();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_szPassword)
|
||||
{
|
||||
ReadPassword();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Password read using XML-parser may have special characters (such as TAB) stripped.
|
||||
* This function rereads password directly from file to keep all characters intact.
|
||||
*/
|
||||
void NZBFile::ReadPassword()
|
||||
{
|
||||
FILE* pFile = fopen(m_szFileName, "rb");
|
||||
if (!pFile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// obtain file size.
|
||||
fseek(pFile , 0 , SEEK_END);
|
||||
int iSize = ftell(pFile);
|
||||
rewind(pFile);
|
||||
|
||||
// reading first 4KB of the file
|
||||
|
||||
// allocate memory to contain the whole file.
|
||||
char* buf = (char*)malloc(4096);
|
||||
|
||||
iSize = iSize < 4096 ? iSize : 4096;
|
||||
|
||||
// copy the file into the buffer.
|
||||
fread(buf, 1, iSize, pFile);
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
buf[iSize-1] = '\0';
|
||||
|
||||
char* szMetaPassword = strstr(buf, "<meta type=\"password\">");
|
||||
if (szMetaPassword)
|
||||
{
|
||||
szMetaPassword += 22; // length of '<meta type="password">'
|
||||
char* szEnd = strstr(szMetaPassword, "</meta>");
|
||||
if (szEnd)
|
||||
{
|
||||
*szEnd = '\0';
|
||||
WebUtil::XmlDecode(szMetaPassword);
|
||||
free(m_szPassword);
|
||||
m_szPassword = strdup(szMetaPassword);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -571,7 +384,7 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
NZBFile* pFile = new NZBFile(szFileName, szCategory);
|
||||
if (pFile->ParseNZB(doc))
|
||||
{
|
||||
pFile->ProcessFiles();
|
||||
pFile->ProcessFilenames();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -595,7 +408,7 @@ void NZBFile::EncodeURL(const char* szFilename, char* szURL)
|
||||
else
|
||||
{
|
||||
*szURL++ = '%';
|
||||
int a = (unsigned char)ch >> 4;
|
||||
int a = ch >> 4;
|
||||
*szURL++ = a > 9 ? a - 10 + 'a' : a + '0';
|
||||
a = ch & 0xF;
|
||||
*szURL++ = a > 9 ? a - 10 + 'a' : a + '0';
|
||||
@@ -609,17 +422,10 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
|
||||
MSXML::IXMLDOMDocumentPtr doc = nzb;
|
||||
MSXML::IXMLDOMNodePtr root = doc->documentElement;
|
||||
|
||||
MSXML::IXMLDOMNodePtr node = root->selectSingleNode("/nzb/head/meta[@type='password']");
|
||||
if (node)
|
||||
{
|
||||
_bstr_t password(node->Gettext());
|
||||
m_szPassword = strdup(password);
|
||||
}
|
||||
|
||||
MSXML::IXMLDOMNodeListPtr fileList = root->selectNodes("/nzb/file");
|
||||
for (int i = 0; i < fileList->Getlength(); i++)
|
||||
{
|
||||
node = fileList->Getitem(i);
|
||||
MSXML::IXMLDOMNodePtr node = fileList->Getitem(i);
|
||||
MSXML::IXMLDOMNodePtr attribute = node->Getattributes()->getNamedItem("subject");
|
||||
if (!attribute) return false;
|
||||
_bstr_t subject(attribute->Gettext());
|
||||
@@ -668,6 +474,11 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
|
||||
pArticle->SetSize(lsize);
|
||||
AddArticle(pFileInfo, pArticle);
|
||||
}
|
||||
|
||||
if (lsize > 0)
|
||||
{
|
||||
pFileInfo->SetSize(pFileInfo->GetSize() + lsize);
|
||||
}
|
||||
}
|
||||
|
||||
AddFileInfo(pFileInfo);
|
||||
@@ -694,7 +505,7 @@ NZBFile* NZBFile::Create(const char* szFileName, const char* szCategory)
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
pFile->ProcessFiles();
|
||||
pFile->ProcessFilenames();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -758,6 +569,10 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
|
||||
partNumber = atol(attrvalue);
|
||||
}
|
||||
}
|
||||
if (lsize > 0)
|
||||
{
|
||||
m_pFileInfo->SetSize(m_pFileInfo->GetSize() + lsize);
|
||||
}
|
||||
|
||||
if (partNumber > 0)
|
||||
{
|
||||
@@ -768,10 +583,6 @@ void NZBFile::Parse_StartElement(const char *name, const char **atts)
|
||||
AddArticle(m_pFileInfo, m_pArticle);
|
||||
}
|
||||
}
|
||||
else if (!strcmp("meta", name))
|
||||
{
|
||||
m_bPassword = atts[0] && atts[1] && !strcmp("type", atts[0]) && !strcmp("password", atts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBFile::Parse_EndElement(const char *name)
|
||||
@@ -809,10 +620,6 @@ void NZBFile::Parse_EndElement(const char *name)
|
||||
m_pArticle->SetMessageID(ID);
|
||||
m_pArticle = NULL;
|
||||
}
|
||||
else if (!strcmp("meta", name) && m_bPassword)
|
||||
{
|
||||
m_szPassword = strdup(m_szTagContent);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBFile::Parse_Content(const char *buf, int len)
|
||||
|
||||
11
NZBFile.h
11
NZBFile.h
@@ -28,7 +28,6 @@
|
||||
#define NZBFILE_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "DownloadInfo.h"
|
||||
|
||||
@@ -36,24 +35,18 @@ class NZBFile
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
NZBFile(const char* szFileName, const char* szCategory);
|
||||
void AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
|
||||
void AddFileInfo(FileInfo* pFileInfo);
|
||||
void ParseSubject(FileInfo* pFileInfo, bool TryQuotes);
|
||||
void BuildFilenames();
|
||||
void ProcessFiles();
|
||||
void CalcHashes();
|
||||
void ProcessFilenames();
|
||||
bool HasDuplicateFilenames();
|
||||
void ReadPassword();
|
||||
#ifdef WIN32
|
||||
bool ParseNZB(IUnknown* nzb);
|
||||
static void EncodeURL(const char* szFilename, char* szURL);
|
||||
@@ -63,7 +56,6 @@ private:
|
||||
char* m_szTagContent;
|
||||
int m_iTagContentLen;
|
||||
bool m_bIgnoreNextError;
|
||||
bool m_bPassword;
|
||||
|
||||
static void SAX_StartElement(NZBFile* pFile, const char *name, const char **atts);
|
||||
static void SAX_EndElement(NZBFile* pFile, const char *name);
|
||||
@@ -81,7 +73,6 @@ public:
|
||||
const char* GetFileName() const { return m_szFileName; }
|
||||
FileInfos* GetFileInfos() { return &m_FileInfos; }
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
const char* GetPassword() { return m_szPassword; }
|
||||
void DetachFileInfos();
|
||||
|
||||
void LogDebugInfo();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -34,47 +34,45 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "NewsServer.h"
|
||||
|
||||
NewsServer::NewsServer(int iID, bool bActive, const char* szName, const char* szHost, int iPort,
|
||||
const char* szUser, const char* szPass, bool bJoinGroup, bool bTLS,
|
||||
const char* szCipher, int iMaxConnections, int iLevel, int iGroup)
|
||||
NewsServer::NewsServer(int iID, const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup)
|
||||
{
|
||||
m_iID = iID;
|
||||
m_iStateID = 0;
|
||||
m_bActive = bActive;
|
||||
m_szHost = NULL;
|
||||
m_iPort = iPort;
|
||||
m_szUser = NULL;
|
||||
m_szPassword = NULL;
|
||||
m_iLevel = iLevel;
|
||||
m_iNormLevel = iLevel;
|
||||
m_iGroup = iGroup;
|
||||
m_iMaxConnections = iMaxConnections;
|
||||
m_bJoinGroup = bJoinGroup;
|
||||
m_bTLS = bTLS;
|
||||
m_szHost = strdup(szHost ? szHost : "");
|
||||
m_szUser = strdup(szUser ? szUser : "");
|
||||
m_szPassword = strdup(szPass ? szPass : "");
|
||||
m_szCipher = strdup(szCipher ? szCipher : "");
|
||||
|
||||
if (szName && strlen(szName) > 0)
|
||||
{
|
||||
m_szName = strdup(szName);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_szName = (char*)malloc(20);
|
||||
snprintf(m_szName, 20, "server%i", iID);
|
||||
m_szName[20-1] = '\0';
|
||||
}
|
||||
m_szHost = szHost ? strdup(szHost) : NULL;
|
||||
m_szUser = szUser ? strdup(szUser) : NULL;
|
||||
m_szPassword = szPass ? strdup(szPass) : NULL;
|
||||
m_szCipher = szCipher ? strdup(szCipher) : NULL;
|
||||
}
|
||||
|
||||
NewsServer::~NewsServer()
|
||||
{
|
||||
free(m_szName);
|
||||
free(m_szHost);
|
||||
free(m_szUser);
|
||||
free(m_szPassword);
|
||||
free(m_szCipher);
|
||||
if (m_szHost)
|
||||
{
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szUser)
|
||||
{
|
||||
free(m_szUser);
|
||||
}
|
||||
if (m_szPassword)
|
||||
{
|
||||
free(m_szPassword);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
}
|
||||
|
||||
21
NewsServer.h
21
NewsServer.h
@@ -2,7 +2,7 @@
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2008 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,15 +27,10 @@
|
||||
#ifndef NEWSSERVER_H
|
||||
#define NEWSSERVER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NewsServer
|
||||
{
|
||||
private:
|
||||
int m_iID;
|
||||
int m_iStateID;
|
||||
bool m_bActive;
|
||||
char* m_szName;
|
||||
int m_iGroup;
|
||||
char* m_szHost;
|
||||
int m_iPort;
|
||||
@@ -43,22 +38,15 @@ private:
|
||||
char* m_szPassword;
|
||||
int m_iMaxConnections;
|
||||
int m_iLevel;
|
||||
int m_iNormLevel;
|
||||
bool m_bJoinGroup;
|
||||
bool m_bTLS;
|
||||
char* m_szCipher;
|
||||
|
||||
public:
|
||||
NewsServer(int iID, bool bActive, const char* szName, const char* szHost, int iPort,
|
||||
const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
NewsServer(int iID, const char* szHost, int iPort, const char* szUser, const char* szPass, bool bJoinGroup,
|
||||
bool bTLS, const char* szCipher, int iMaxConnections, int iLevel, int iGroup);
|
||||
~NewsServer();
|
||||
int GetID() { return m_iID; }
|
||||
int GetStateID() { return m_iStateID; }
|
||||
void SetStateID(int iStateID) { m_iStateID = iStateID; }
|
||||
bool GetActive() { return m_bActive; }
|
||||
void SetActive(bool bActive) { m_bActive = bActive; }
|
||||
const char* GetName() { return m_szName; }
|
||||
int GetGroup() { return m_iGroup; }
|
||||
const char* GetHost() { return m_szHost; }
|
||||
int GetPort() { return m_iPort; }
|
||||
@@ -66,13 +54,10 @@ public:
|
||||
const char* GetPassword() { return m_szPassword; }
|
||||
int GetMaxConnections() { return m_iMaxConnections; }
|
||||
int GetLevel() { return m_iLevel; }
|
||||
int GetNormLevel() { return m_iNormLevel; }
|
||||
void SetNormLevel(int iLevel) { m_iNormLevel = iLevel; }
|
||||
void SetLevel(int iLevel) { m_iLevel = iLevel; }
|
||||
int GetJoinGroup() { return m_bJoinGroup; }
|
||||
bool GetTLS() { return m_bTLS; }
|
||||
const char* GetCipher() { return m_szCipher; }
|
||||
};
|
||||
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
|
||||
#endif
|
||||
|
||||
831
Options.cpp
831
Options.cpp
File diff suppressed because it is too large
Load Diff
35
Options.h
35
Options.h
@@ -92,12 +92,6 @@ public:
|
||||
psFull,
|
||||
psAuto
|
||||
};
|
||||
enum EHealthCheck
|
||||
{
|
||||
hcPause,
|
||||
hcDelete,
|
||||
hcNone
|
||||
};
|
||||
enum EScriptLogKind
|
||||
{
|
||||
slNone,
|
||||
@@ -107,6 +101,7 @@ public:
|
||||
slError,
|
||||
slDebug
|
||||
};
|
||||
|
||||
enum EMatchMode
|
||||
{
|
||||
mmID = 1,
|
||||
@@ -179,18 +174,14 @@ public:
|
||||
private:
|
||||
char* m_szName;
|
||||
char* m_szDestDir;
|
||||
bool m_bUnpack;
|
||||
char* m_szDefScript;
|
||||
NameList m_Aliases;
|
||||
|
||||
public:
|
||||
Category(const char* szName, const char* szDestDir, bool bUnpack, const char* szDefScript);
|
||||
Category(const char* szName, const char* szDestDir, const char* szDefScript);
|
||||
~Category();
|
||||
const char* GetName() { return m_szName; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
bool GetUnpack() { return m_bUnpack; }
|
||||
const char* GetDefScript() { return m_szDefScript; }
|
||||
NameList* GetAliases() { return &m_Aliases; }
|
||||
};
|
||||
|
||||
typedef std::vector<Category*> CategoriesBase;
|
||||
@@ -199,7 +190,7 @@ public:
|
||||
{
|
||||
public:
|
||||
~Categories();
|
||||
Category* FindCategory(const char* szName, bool bSearchAliases);
|
||||
Category* FindCategory(const char* szName);
|
||||
};
|
||||
|
||||
class Script
|
||||
@@ -269,7 +260,6 @@ private:
|
||||
int m_iSecurePort;
|
||||
char* m_szSecureCert;
|
||||
char* m_szSecureKey;
|
||||
char* m_szAuthorizedIP;
|
||||
char* m_szLockFile;
|
||||
char* m_szDaemonUsername;
|
||||
EOutputMode m_eOutputMode;
|
||||
@@ -283,12 +273,11 @@ private:
|
||||
EParCheck m_eParCheck;
|
||||
bool m_bParRepair;
|
||||
EParScan m_eParScan;
|
||||
bool m_bParRename;
|
||||
EHealthCheck m_eHealthCheck;
|
||||
char* m_szDefScript;
|
||||
char* m_szScriptOrder;
|
||||
char* m_szNZBProcess;
|
||||
char* m_szNZBAddedProcess;
|
||||
bool m_bStrictParName;
|
||||
bool m_bNoConfig;
|
||||
int m_iUMask;
|
||||
int m_iUpdateInterval;
|
||||
@@ -308,6 +297,7 @@ private:
|
||||
bool m_bScriptPauseQueue;
|
||||
bool m_bNzbCleanupDisk;
|
||||
bool m_bDeleteCleanupDisk;
|
||||
bool m_bMergeNzb;
|
||||
int m_iParTimeLimit;
|
||||
int m_iKeepHistory;
|
||||
bool m_bAccurateRate;
|
||||
@@ -317,9 +307,6 @@ private:
|
||||
char* m_szSevenZipCmd;
|
||||
bool m_bUnpackPauseQueue;
|
||||
char* m_szExtCleanupDisk;
|
||||
int m_iFeedHistory;
|
||||
bool m_bUrlForce;
|
||||
int m_iTimeCorrection;
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool m_bServerMode;
|
||||
@@ -362,7 +349,6 @@ private:
|
||||
void InitServers();
|
||||
void InitCategories();
|
||||
void InitScheduler();
|
||||
void InitFeeds();
|
||||
void CheckOptions();
|
||||
void PrintUsage(char* com);
|
||||
void Dump();
|
||||
@@ -373,7 +359,6 @@ private:
|
||||
const char* GetOption(const char* optname);
|
||||
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);
|
||||
void LoadConfigFile();
|
||||
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate);
|
||||
@@ -434,7 +419,6 @@ public:
|
||||
int GetSecurePort() { return m_iSecurePort; }
|
||||
const char* GetSecureCert() { return m_szSecureCert; }
|
||||
const char* GetSecureKey() { return m_szSecureKey; }
|
||||
const char* GetAuthorizedIP() { return m_szAuthorizedIP; }
|
||||
const char* GetLockFile() { return m_szLockFile; }
|
||||
const char* GetDaemonUsername() { return m_szDaemonUsername; }
|
||||
EOutputMode GetOutputMode() { return m_eOutputMode; }
|
||||
@@ -448,12 +432,11 @@ public:
|
||||
EParCheck GetParCheck() { return m_eParCheck; }
|
||||
bool GetParRepair() { return m_bParRepair; }
|
||||
EParScan GetParScan() { return m_eParScan; }
|
||||
bool GetParRename() { return m_bParRename; }
|
||||
EHealthCheck GetHealthCheck() { return m_eHealthCheck; }
|
||||
const char* GetScriptOrder() { return m_szScriptOrder; }
|
||||
const char* GetDefScript() { return m_szDefScript; }
|
||||
const char* GetNZBProcess() { return m_szNZBProcess; }
|
||||
const char* GetNZBAddedProcess() { return m_szNZBAddedProcess; }
|
||||
bool GetStrictParName() { return m_bStrictParName; }
|
||||
int GetUMask() { return m_iUMask; }
|
||||
int GetUpdateInterval() {return m_iUpdateInterval; }
|
||||
bool GetCursesNZBName() { return m_bCursesNZBName; }
|
||||
@@ -472,6 +455,7 @@ public:
|
||||
bool GetScriptPauseQueue() { return m_bScriptPauseQueue; }
|
||||
bool GetNzbCleanupDisk() { return m_bNzbCleanupDisk; }
|
||||
bool GetDeleteCleanupDisk() { return m_bDeleteCleanupDisk; }
|
||||
bool GetMergeNzb() { return m_bMergeNzb; }
|
||||
int GetParTimeLimit() { return m_iParTimeLimit; }
|
||||
int GetKeepHistory() { return m_iKeepHistory; }
|
||||
bool GetAccurateRate() { return m_bAccurateRate; }
|
||||
@@ -481,11 +465,8 @@ public:
|
||||
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
|
||||
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
|
||||
const char* GetExtCleanupDisk() { return m_szExtCleanupDisk; }
|
||||
int GetFeedHistory() { return m_iFeedHistory; }
|
||||
bool GetUrlForce() { return m_bUrlForce; }
|
||||
int GetTimeCorrection() { return m_iTimeCorrection; }
|
||||
|
||||
Category* FindCategory(const char* szName, bool bSearchAliases) { return m_Categories.FindCategory(szName, bSearchAliases); }
|
||||
Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); }
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool GetServerMode() { return m_bServerMode; }
|
||||
|
||||
413
ParChecker.cpp
413
ParChecker.cpp
@@ -163,7 +163,6 @@ ParChecker::ParChecker()
|
||||
m_szInfoName = NULL;
|
||||
m_szErrMsg = NULL;
|
||||
m_szProgressLabel = (char*)malloc(1024);
|
||||
m_pRepairer = NULL;
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_iExtraFiles = 0;
|
||||
@@ -176,9 +175,22 @@ ParChecker::~ParChecker()
|
||||
{
|
||||
debug("Destroying ParChecker");
|
||||
|
||||
free(m_szDestDir);
|
||||
free(m_szNZBName);
|
||||
free(m_szInfoName);
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szNZBName)
|
||||
{
|
||||
free(m_szNZBName);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szErrMsg)
|
||||
{
|
||||
free(m_szErrMsg);
|
||||
}
|
||||
free(m_szProgressLabel);
|
||||
|
||||
Cleanup();
|
||||
@@ -186,9 +198,6 @@ ParChecker::~ParChecker()
|
||||
|
||||
void ParChecker::Cleanup()
|
||||
{
|
||||
delete (Repairer*)m_pRepairer;
|
||||
m_pRepairer = NULL;
|
||||
|
||||
for (FileList::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
|
||||
{
|
||||
free(*it);
|
||||
@@ -202,26 +211,32 @@ void ParChecker::Cleanup()
|
||||
m_ProcessedFiles.clear();
|
||||
|
||||
m_sourceFiles.clear();
|
||||
|
||||
free(m_szErrMsg);
|
||||
m_szErrMsg = NULL;
|
||||
}
|
||||
|
||||
void ParChecker::SetDestDir(const char * szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void ParChecker::SetNZBName(const char * szNZBName)
|
||||
{
|
||||
free(m_szNZBName);
|
||||
if (m_szNZBName)
|
||||
{
|
||||
free(m_szNZBName);
|
||||
}
|
||||
m_szNZBName = strdup(szNZBName);
|
||||
}
|
||||
|
||||
void ParChecker::SetInfoName(const char * szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
}
|
||||
|
||||
@@ -283,6 +298,49 @@ void ParChecker::Run()
|
||||
Completed();
|
||||
}
|
||||
|
||||
void ParChecker::WriteBrokenLog(EStatus eStatus)
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", m_szDestDir, (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
|
||||
if (eStatus != psRepairNotNeeded || Util::FileExists(szBrokenLogName))
|
||||
{
|
||||
FILE* file = fopen(szBrokenLogName, "ab");
|
||||
if (file)
|
||||
{
|
||||
if (eStatus == psFailed)
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
fprintf(file, "Repair cancelled for %s\n", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "Repair failed for %s: %s\n", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
}
|
||||
}
|
||||
else if (eStatus == psRepairPossible)
|
||||
{
|
||||
fprintf(file, "Repair possible for %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepaired)
|
||||
{
|
||||
fprintf(file, "Successfully repaired %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepairNotNeeded)
|
||||
{
|
||||
fprintf(file, "Repair not needed for %s\n", m_szInfoName);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open file %s", szBrokenLogName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
{
|
||||
Cleanup();
|
||||
@@ -297,22 +355,51 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
|
||||
debug("par: %s", m_szParFilename);
|
||||
|
||||
Result res;
|
||||
|
||||
Repairer* pRepairer = new Repairer();
|
||||
m_pRepairer = pRepairer;
|
||||
|
||||
pRepairer->sig_filename.connect(sigc::mem_fun(*this, &ParChecker::signal_filename));
|
||||
pRepairer->sig_progress.connect(sigc::mem_fun(*this, &ParChecker::signal_progress));
|
||||
pRepairer->sig_done.connect(sigc::mem_fun(*this, &ParChecker::signal_done));
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "Verifying %s", m_szInfoName);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
Result res = (Result)PreProcessPar();
|
||||
if (IsStopped() || res != eSuccess)
|
||||
res = pRepairer->PreProcess(m_szParFilename);
|
||||
debug("ParChecker: PreProcess-result=%i", res);
|
||||
|
||||
if (res != eSuccess || IsStopped())
|
||||
{
|
||||
if (res == eInvalidCommandLineArguments)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
|
||||
m_szErrMsg = strdup("Command line could not be parsed");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
|
||||
m_szErrMsg = strdup("par2-file could not be processed");
|
||||
}
|
||||
delete pRepairer;
|
||||
Cleanup();
|
||||
return psFailed;
|
||||
}
|
||||
|
||||
char BufReason[1024];
|
||||
BufReason[0] = '\0';
|
||||
if (m_szErrMsg)
|
||||
{
|
||||
free(m_szErrMsg);
|
||||
}
|
||||
m_szErrMsg = NULL;
|
||||
|
||||
m_eStage = ptVerifyingSources;
|
||||
Repairer* pRepairer = (Repairer*)m_pRepairer;
|
||||
res = pRepairer->Process(false);
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
|
||||
if (!IsStopped() && pRepairer->missingfilecount > 0 && g_pOptions->GetParScan() == Options::psAuto && AddMissingFiles())
|
||||
@@ -328,13 +415,75 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
|
||||
if (!IsStopped() && res == eRepairNotPossible)
|
||||
bool bMoreFilesLoaded = true;
|
||||
while (!IsStopped() && res == eRepairNotPossible)
|
||||
{
|
||||
res = (Result)ProcessMorePars();
|
||||
int missingblockcount = pRepairer->missingblockcount - pRepairer->recoverypacketmap.size();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bool hasMorePars = !m_QueuedParFiles.empty();
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (!hasMorePars)
|
||||
{
|
||||
int iBlockFound = 0;
|
||||
bool requested = RequestMorePars(missingblockcount, &iBlockFound);
|
||||
if (requested)
|
||||
{
|
||||
strncpy(m_szProgressLabel, "Awaiting additional par-files", 1024);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
hasMorePars = !m_QueuedParFiles.empty();
|
||||
m_bQueuedParFilesChanged = false;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (!requested && !hasMorePars)
|
||||
{
|
||||
snprintf(BufReason, 1024, "not enough par-blocks, %i block(s) needed, but %i block(s) available", missingblockcount, iBlockFound);
|
||||
BufReason[1024-1] = '\0';
|
||||
m_szErrMsg = strdup(BufReason);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasMorePars)
|
||||
{
|
||||
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
|
||||
bool bQueuedParFilesChanged = false;
|
||||
while (!bQueuedParFilesChanged && !IsStopped())
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bQueuedParFilesChanged = m_bQueuedParFilesChanged;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bMoreFilesLoaded = LoadMorePars();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
delete pRepairer;
|
||||
Cleanup();
|
||||
return psFailed;
|
||||
}
|
||||
@@ -402,192 +551,11 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
|
||||
PrintMessage(Message::mkError, "Repair failed for %s: %s", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
}
|
||||
|
||||
delete pRepairer;
|
||||
Cleanup();
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
int ParChecker::PreProcessPar()
|
||||
{
|
||||
Result res = eRepairFailed;
|
||||
while (!IsStopped() && res != eSuccess)
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
Repairer* pRepairer = new Repairer();
|
||||
m_pRepairer = pRepairer;
|
||||
pRepairer->sig_filename.connect(sigc::mem_fun(*this, &ParChecker::signal_filename));
|
||||
pRepairer->sig_progress.connect(sigc::mem_fun(*this, &ParChecker::signal_progress));
|
||||
pRepairer->sig_done.connect(sigc::mem_fun(*this, &ParChecker::signal_done));
|
||||
|
||||
res = pRepairer->PreProcess(m_szParFilename);
|
||||
debug("ParChecker: PreProcess-result=%i", res);
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not verify %s: stopping", m_szInfoName);
|
||||
m_szErrMsg = strdup("par-check was stopped");
|
||||
return eRepairFailed;
|
||||
}
|
||||
|
||||
if (res == eInvalidCommandLineArguments)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
|
||||
m_szErrMsg = strdup("Command line could not be parsed");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res != eSuccess)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "Could not verify %s: par2-file could not be processed", m_szInfoName);
|
||||
PrintMessage(Message::mkInfo, "Requesting more par2-files for %s", m_szInfoName);
|
||||
bool bHasMorePars = LoadMainParBak();
|
||||
if (!bHasMorePars)
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "No more par2-files found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res != eSuccess)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not verify %s: par2-file could not be processed", m_szInfoName);
|
||||
m_szErrMsg = strdup("par2-file could not be processed");
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ParChecker::LoadMainParBak()
|
||||
{
|
||||
while (!IsStopped())
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bool hasMorePars = !m_QueuedParFiles.empty();
|
||||
for (FileList::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_QueuedParFiles.clear();
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (hasMorePars)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int iBlockFound = 0;
|
||||
bool requested = RequestMorePars(1, &iBlockFound);
|
||||
if (requested)
|
||||
{
|
||||
strncpy(m_szProgressLabel, "Awaiting additional par-files", 1024);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
hasMorePars = !m_QueuedParFiles.empty();
|
||||
m_bQueuedParFilesChanged = false;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (!requested && !hasMorePars)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasMorePars)
|
||||
{
|
||||
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
|
||||
bool bQueuedParFilesChanged = false;
|
||||
while (!bQueuedParFilesChanged && !IsStopped())
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bQueuedParFilesChanged = m_bQueuedParFilesChanged;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ParChecker::ProcessMorePars()
|
||||
{
|
||||
Result res = eRepairNotPossible;
|
||||
Repairer* pRepairer = (Repairer*)m_pRepairer;
|
||||
|
||||
bool bMoreFilesLoaded = true;
|
||||
while (!IsStopped() && res == eRepairNotPossible)
|
||||
{
|
||||
int missingblockcount = pRepairer->missingblockcount - pRepairer->recoverypacketmap.size();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bool hasMorePars = !m_QueuedParFiles.empty();
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (!hasMorePars)
|
||||
{
|
||||
int iBlockFound = 0;
|
||||
bool requested = RequestMorePars(missingblockcount, &iBlockFound);
|
||||
if (requested)
|
||||
{
|
||||
strncpy(m_szProgressLabel, "Awaiting additional par-files", 1024);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
hasMorePars = !m_QueuedParFiles.empty();
|
||||
m_bQueuedParFilesChanged = false;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
|
||||
if (!requested && !hasMorePars)
|
||||
{
|
||||
m_szErrMsg = (char*)malloc(1024);
|
||||
snprintf(m_szErrMsg, 1024, "not enough par-blocks, %i block(s) needed, but %i block(s) available", missingblockcount, iBlockFound);
|
||||
m_szErrMsg[1024-1] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasMorePars)
|
||||
{
|
||||
// wait until new files are added by "AddParFile" or a change is signaled by "QueueChanged"
|
||||
bool bQueuedParFilesChanged = false;
|
||||
while (!bQueuedParFilesChanged && !IsStopped())
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bQueuedParFilesChanged = m_bQueuedParFilesChanged;
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bMoreFilesLoaded = LoadMorePars();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ParChecker::LoadMorePars()
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
@@ -899,49 +867,6 @@ void ParChecker::Cancel()
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParChecker::WriteBrokenLog(EStatus eStatus)
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", m_szDestDir, (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
|
||||
if (eStatus != psRepairNotNeeded || Util::FileExists(szBrokenLogName))
|
||||
{
|
||||
FILE* file = fopen(szBrokenLogName, "ab");
|
||||
if (file)
|
||||
{
|
||||
if (eStatus == psFailed)
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
fprintf(file, "Repair cancelled for %s\n", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "Repair failed for %s: %s\n", m_szInfoName, m_szErrMsg ? m_szErrMsg : "");
|
||||
}
|
||||
}
|
||||
else if (eStatus == psRepairPossible)
|
||||
{
|
||||
fprintf(file, "Repair possible for %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepaired)
|
||||
{
|
||||
fprintf(file, "Successfully repaired %s\n", m_szInfoName);
|
||||
}
|
||||
else if (eStatus == psRepairNotNeeded)
|
||||
{
|
||||
fprintf(file, "Repair not needed for %s\n", m_szInfoName);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not open file %s", szBrokenLogName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParChecker::SaveSourceList()
|
||||
{
|
||||
// Buliding a list of DiskFile-objects, marked as source-files
|
||||
|
||||
@@ -79,16 +79,13 @@ private:
|
||||
bool m_bCancelled;
|
||||
SourceList m_sourceFiles;
|
||||
|
||||
void Cleanup();
|
||||
EStatus RunParCheck(const char* szParFilename);
|
||||
int PreProcessPar();
|
||||
bool LoadMainParBak();
|
||||
int ProcessMorePars();
|
||||
void WriteBrokenLog(EStatus eStatus);
|
||||
void Cleanup();
|
||||
bool LoadMorePars();
|
||||
bool CheckSplittedFragments();
|
||||
bool AddSplittedFragments(const char* szFilename);
|
||||
bool AddMissingFiles();
|
||||
void WriteBrokenLog(EStatus eStatus);
|
||||
void SaveSourceList();
|
||||
void DeleteLeftovers();
|
||||
void signal_filename(std::string str);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
@@ -216,13 +215,8 @@ bool ParCoordinator::ParseParFilename(const char* szParFilename, int* iBaseNameL
|
||||
char* szEnd = szFilename;
|
||||
while (char* p = strstr(szEnd, ".par2")) szEnd = p + 5;
|
||||
*szEnd = '\0';
|
||||
|
||||
iLen = strlen(szFilename);
|
||||
if (iLen < 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (strcasecmp(szFilename + iLen - 5, ".par2"))
|
||||
{
|
||||
return false;
|
||||
@@ -278,19 +272,9 @@ void ParCoordinator::StartParCheckJob(PostInfo* pPostInfo)
|
||||
*/
|
||||
void ParCoordinator::StartParRenameJob(PostInfo* pPostInfo)
|
||||
{
|
||||
const char* szDestDir = pPostInfo->GetNZBInfo()->GetDestDir();
|
||||
|
||||
char szFinalDir[1024];
|
||||
if (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->BuildFinalDirName(szFinalDir, 1024);
|
||||
szFinalDir[1024-1] = '\0';
|
||||
szDestDir = szFinalDir;
|
||||
}
|
||||
|
||||
m_eCurrentJob = jkParRename;
|
||||
m_ParRenamer.SetPostInfo(pPostInfo);
|
||||
m_ParRenamer.SetDestDir(szDestDir);
|
||||
m_ParRenamer.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
|
||||
m_ParRenamer.SetInfoName(pPostInfo->GetNZBInfo()->GetName());
|
||||
m_ParRenamer.PrintMessage(Message::mkInfo, "Checking renamed files for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pPostInfo->SetWorking(true);
|
||||
@@ -406,7 +390,7 @@ bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilenam
|
||||
FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, true, false, &iCurBlockFound);
|
||||
iBlockFound += iCurBlockFound;
|
||||
}
|
||||
if (iBlockFound < iBlockNeeded)
|
||||
if (iBlockFound < iBlockNeeded && !g_pOptions->GetStrictParName())
|
||||
{
|
||||
FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, false, false, &iCurBlockFound);
|
||||
iBlockFound += iCurBlockFound;
|
||||
|
||||
126
ParRenamer.cpp
126
ParRenamer.cpp
@@ -91,8 +91,14 @@ ParRenamer::~ParRenamer()
|
||||
{
|
||||
debug("Destroying ParRenamer");
|
||||
|
||||
free(m_szDestDir);
|
||||
free(m_szInfoName);
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
free(m_szProgressLabel);
|
||||
|
||||
Cleanup();
|
||||
@@ -100,33 +106,28 @@ ParRenamer::~ParRenamer()
|
||||
|
||||
void ParRenamer::Cleanup()
|
||||
{
|
||||
ClearHashList();
|
||||
|
||||
for (DirList::iterator it = m_DirList.begin(); it != m_DirList.end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
m_DirList.clear();
|
||||
}
|
||||
|
||||
void ParRenamer::ClearHashList()
|
||||
{
|
||||
for (FileHashList::iterator it = m_FileHashList.begin(); it != m_FileHashList.end(); it++)
|
||||
for (FileHashList::iterator it = m_fileHashList.begin(); it != m_fileHashList.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_FileHashList.clear();
|
||||
m_fileHashList.clear();
|
||||
}
|
||||
|
||||
void ParRenamer::SetDestDir(const char * szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void ParRenamer::SetInfoName(const char * szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
}
|
||||
|
||||
@@ -139,8 +140,6 @@ void ParRenamer::Run()
|
||||
{
|
||||
Cleanup();
|
||||
m_bCancelled = false;
|
||||
m_iFileCount = 0;
|
||||
m_iCurFile = 0;
|
||||
m_iRenamedCount = 0;
|
||||
m_eStatus = psFailed;
|
||||
|
||||
@@ -149,16 +148,8 @@ void ParRenamer::Run()
|
||||
m_iStageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
BuildDirList(m_szDestDir);
|
||||
|
||||
for (DirList::iterator it = m_DirList.begin(); it != m_DirList.end(); it++)
|
||||
{
|
||||
char* szDestDir = *it;
|
||||
debug("Checking %s", szDestDir);
|
||||
ClearHashList();
|
||||
LoadParFiles(szDestDir);
|
||||
CheckFiles(szDestDir);
|
||||
}
|
||||
LoadParFiles();
|
||||
CheckFiles();
|
||||
|
||||
if (m_bCancelled)
|
||||
{
|
||||
@@ -178,46 +169,17 @@ void ParRenamer::Run()
|
||||
Completed();
|
||||
}
|
||||
|
||||
void ParRenamer::BuildDirList(const char* szDestDir)
|
||||
{
|
||||
m_DirList.push_back(strdup(szDestDir));
|
||||
|
||||
char* szFullFilename = (char*)malloc(1024);
|
||||
DirBrowser* pDirBrowser = new DirBrowser(szDestDir);
|
||||
|
||||
while (const char* filename = pDirBrowser->Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !m_bCancelled)
|
||||
{
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
BuildDirList(szFullFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iFileCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(szFullFilename);
|
||||
delete pDirBrowser;
|
||||
}
|
||||
|
||||
void ParRenamer::LoadParFiles(const char* szDestDir)
|
||||
void ParRenamer::LoadParFiles()
|
||||
{
|
||||
ParCoordinator::FileList parFileList;
|
||||
ParCoordinator::FindMainPars(szDestDir, &parFileList);
|
||||
ParCoordinator::FindMainPars(m_szDestDir, &parFileList);
|
||||
|
||||
for (ParCoordinator::FileList::iterator it = parFileList.begin(); it != parFileList.end(); it++)
|
||||
{
|
||||
char* szParFilename = *it;
|
||||
|
||||
char szFullParFilename[1024];
|
||||
snprintf(szFullParFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, szParFilename);
|
||||
snprintf(szFullParFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szParFilename);
|
||||
szFullParFilename[1024-1] = '\0';
|
||||
|
||||
LoadParFile(szFullParFilename);
|
||||
@@ -245,39 +207,47 @@ void ParRenamer::LoadParFile(const char* szParFilename)
|
||||
}
|
||||
|
||||
Par2RepairerSourceFile* sourceFile = (*it).second;
|
||||
m_FileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(),
|
||||
m_fileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(),
|
||||
sourceFile->GetDescriptionPacket()->Hash16k().print().c_str()));
|
||||
}
|
||||
|
||||
delete pRepairer;
|
||||
}
|
||||
|
||||
void ParRenamer::CheckFiles(const char* szDestDir)
|
||||
void ParRenamer::CheckFiles()
|
||||
{
|
||||
DirBrowser dir(szDestDir);
|
||||
int iFileCount = 0;
|
||||
DirBrowser dir2(m_szDestDir);
|
||||
while (const char* filename = dir2.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !m_bCancelled)
|
||||
{
|
||||
iFileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int iCurFile = 0;
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !m_bCancelled)
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, filename);
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (!Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
snprintf(m_szProgressLabel, 1024, "Checking file %s", filename);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iStageProgress = m_iCurFile * 1000 / m_iFileCount;
|
||||
UpdateProgress();
|
||||
m_iCurFile++;
|
||||
|
||||
CheckFile(szDestDir, szFullFilename);
|
||||
}
|
||||
snprintf(m_szProgressLabel, 1024, "Checking file %s", filename);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iStageProgress = iCurFile * 1000 / iFileCount;
|
||||
UpdateProgress();
|
||||
iCurFile++;
|
||||
|
||||
CheckFile(szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParRenamer::CheckFile(const char* szDestDir, const char* szFilename)
|
||||
void ParRenamer::CheckFile(const char* szFilename)
|
||||
{
|
||||
debug("Computing hash for %s", szFilename);
|
||||
|
||||
@@ -313,7 +283,7 @@ void ParRenamer::CheckFile(const char* szDestDir, const char* szFilename)
|
||||
|
||||
debug("file: %s; hash16k: %s", Util::BaseFileName(szFilename), hash16k.print().c_str());
|
||||
|
||||
for (FileHashList::iterator it = m_FileHashList.begin(); it != m_FileHashList.end(); it++)
|
||||
for (FileHashList::iterator it = m_fileHashList.begin(); it != m_fileHashList.end(); it++)
|
||||
{
|
||||
FileHash* pFileHash = *it;
|
||||
if (!strcmp(pFileHash->GetHash(), hash16k.print().c_str()))
|
||||
@@ -321,7 +291,7 @@ void ParRenamer::CheckFile(const char* szDestDir, const char* szFilename)
|
||||
debug("Found correct filename: %s", pFileHash->GetFilename());
|
||||
|
||||
char szDstFilename[1024];
|
||||
snprintf(szDstFilename, 1024, "%s%c%s", szDestDir, PATH_SEPARATOR, pFileHash->GetFilename());
|
||||
snprintf(szDstFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, pFileHash->GetFilename());
|
||||
szDstFilename[1024-1] = '\0';
|
||||
|
||||
if (!Util::FileExists(szDstFilename))
|
||||
|
||||
16
ParRenamer.h
16
ParRenamer.h
@@ -56,8 +56,6 @@ public:
|
||||
};
|
||||
|
||||
typedef std::deque<FileHash*> FileHashList;
|
||||
|
||||
typedef std::deque<char*> DirList;
|
||||
|
||||
private:
|
||||
char* m_szInfoName;
|
||||
@@ -66,20 +64,14 @@ private:
|
||||
char* m_szProgressLabel;
|
||||
int m_iStageProgress;
|
||||
bool m_bCancelled;
|
||||
DirList m_DirList;
|
||||
FileHashList m_FileHashList;
|
||||
int m_iFileCount;
|
||||
int m_iCurFile;
|
||||
FileHashList m_fileHashList;
|
||||
int m_iRenamedCount;
|
||||
|
||||
void Cleanup();
|
||||
void ClearHashList();
|
||||
void BuildDirList(const char* szDestDir);
|
||||
void CheckDir(const char* szDestDir);
|
||||
void LoadParFiles(const char* szDestDir);
|
||||
void LoadParFiles();
|
||||
void LoadParFile(const char* szParFilename);
|
||||
void CheckFiles(const char* szDestDir);
|
||||
void CheckFile(const char* szDestDir, const char* szFilename);
|
||||
void CheckFiles();
|
||||
void CheckFile(const char* szFilename);
|
||||
|
||||
protected:
|
||||
virtual void UpdateProgress() {}
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "PrePostProcessor.h"
|
||||
@@ -61,13 +59,6 @@ extern DiskState* g_pDiskState;
|
||||
extern Scheduler* g_pScheduler;
|
||||
extern Scanner* g_pScanner;
|
||||
|
||||
void PrePostProcessor::PostDupeCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo)
|
||||
{
|
||||
HistoryList::iterator it = std::find(pDownloadQueue->GetHistoryList()->begin(),
|
||||
pDownloadQueue->GetHistoryList()->end(), pHistoryInfo);
|
||||
m_pOwner->HistoryRedownload(pDownloadQueue, it, pHistoryInfo, true);
|
||||
}
|
||||
|
||||
PrePostProcessor::PrePostProcessor()
|
||||
{
|
||||
debug("Creating PrePostProcessor");
|
||||
@@ -77,10 +68,10 @@ PrePostProcessor::PrePostProcessor()
|
||||
|
||||
m_QueueCoordinatorObserver.m_pOwner = this;
|
||||
g_pQueueCoordinator->Attach(&m_QueueCoordinatorObserver);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
m_ParCoordinator.m_pOwner = this;
|
||||
#endif
|
||||
m_DupeCoordinator.m_pOwner = this;
|
||||
}
|
||||
|
||||
PrePostProcessor::~PrePostProcessor()
|
||||
@@ -132,7 +123,7 @@ void PrePostProcessor::Run()
|
||||
|
||||
int iDiskSpaceInterval = 1000;
|
||||
int iSchedulerInterval = 1000;
|
||||
int iHistoryInterval = 600000;
|
||||
int iHistoryInterval = 60000;
|
||||
const int iStepMSec = 200;
|
||||
|
||||
while (!IsStopped())
|
||||
@@ -163,9 +154,9 @@ void PrePostProcessor::Run()
|
||||
}
|
||||
iSchedulerInterval += iStepMSec;
|
||||
|
||||
if (iHistoryInterval >= 600000)
|
||||
if (iHistoryInterval >= 60000)
|
||||
{
|
||||
// check history (remove old entries) every 10 minutes
|
||||
// check history (remove old entries) every 1 minute
|
||||
CheckHistory();
|
||||
iHistoryInterval = 0;
|
||||
}
|
||||
@@ -213,11 +204,7 @@ void PrePostProcessor::QueueCoordinatorUpdate(Subject * Caller, void * Aspect)
|
||||
}
|
||||
|
||||
QueueCoordinator::Aspect* pAspect = (QueueCoordinator::Aspect*)Aspect;
|
||||
if (pAspect->eAction == QueueCoordinator::eaNZBFileFound)
|
||||
{
|
||||
NZBFound(pAspect->pDownloadQueue, pAspect->pNZBInfo);
|
||||
}
|
||||
else if (pAspect->eAction == QueueCoordinator::eaNZBFileAdded)
|
||||
if (pAspect->eAction == QueueCoordinator::eaNZBFileAdded)
|
||||
{
|
||||
NZBAdded(pAspect->pDownloadQueue, pAspect->pNZBInfo);
|
||||
}
|
||||
@@ -231,18 +218,15 @@ void PrePostProcessor::QueueCoordinatorUpdate(Subject * Caller, void * Aspect)
|
||||
IsNZBFileCompleted(pAspect->pDownloadQueue, pAspect->pNZBInfo, true, false) &&
|
||||
(!pAspect->pFileInfo->GetPaused() || IsNZBFileCompleted(pAspect->pDownloadQueue, pAspect->pNZBInfo, false, false)))
|
||||
{
|
||||
if ((pAspect->eAction == QueueCoordinator::eaFileCompleted ||
|
||||
if (pAspect->eAction == QueueCoordinator::eaFileCompleted ||
|
||||
(pAspect->pFileInfo->GetAutoDeleted() &&
|
||||
IsNZBFileCompleted(pAspect->pDownloadQueue, pAspect->pNZBInfo, false, true))) &&
|
||||
pAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth)
|
||||
IsNZBFileCompleted(pAspect->pDownloadQueue, pAspect->pNZBInfo, false, true)))
|
||||
{
|
||||
info("Collection %s completely downloaded", pAspect->pNZBInfo->GetName());
|
||||
NZBDownloaded(pAspect->pDownloadQueue, pAspect->pNZBInfo);
|
||||
}
|
||||
else if ((pAspect->eAction == QueueCoordinator::eaFileDeleted ||
|
||||
(pAspect->eAction == QueueCoordinator::eaFileCompleted &&
|
||||
pAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() > NZBInfo::dsNone)) &&
|
||||
!pAspect->pNZBInfo->GetParCleanup() && !pAspect->pNZBInfo->GetPostProcess() &&
|
||||
else if (pAspect->eAction == QueueCoordinator::eaFileDeleted &&
|
||||
!pAspect->pNZBInfo->GetParCleanup() &&
|
||||
IsNZBFileCompleted(pAspect->pDownloadQueue, pAspect->pNZBInfo, false, true))
|
||||
{
|
||||
info("Collection %s deleted from queue", pAspect->pNZBInfo->GetName());
|
||||
@@ -252,27 +236,20 @@ void PrePostProcessor::QueueCoordinatorUpdate(Subject * Caller, void * Aspect)
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce)
|
||||
{
|
||||
m_DupeCoordinator.NZBFound(pDownloadQueue, pNZBInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
PostScriptController::InitParamsForNewNZB(pNZBInfo);
|
||||
|
||||
if (g_pOptions->GetMergeNzb())
|
||||
{
|
||||
pNZBInfo = MergeGroups(pDownloadQueue, 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);
|
||||
}
|
||||
|
||||
if (strlen(g_pOptions->GetNZBAddedProcess()) > 0)
|
||||
{
|
||||
NZBAddedScriptController::StartScript(pDownloadQueue, pNZBInfo, g_pOptions->GetNZBAddedProcess());
|
||||
@@ -294,19 +271,11 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
pNZBInfo->SetParStatus(NZBInfo::psSkipped);
|
||||
}
|
||||
|
||||
if (pNZBInfo->GetRenameStatus() == NZBInfo::rsNone && !g_pOptions->GetParRename())
|
||||
if (pNZBInfo->GetRenameStatus() == NZBInfo::rsNone)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
pNZBInfo->SetPostProcess(true);
|
||||
pDownloadQueue->GetPostQueue()->push_back(pPostInfo);
|
||||
SaveQueue(pDownloadQueue);
|
||||
@@ -320,14 +289,7 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
|
||||
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)
|
||||
if (g_pOptions->GetDeleteCleanupDisk() && pNZBInfo->GetCleanupDisk())
|
||||
{
|
||||
// download was cancelled, deleting already downloaded files from disk
|
||||
for (NZBInfo::Files::reverse_iterator it = pNZBInfo->GetCompletedFiles()->rbegin(); it != pNZBInfo->GetCompletedFiles()->rend(); it++)
|
||||
@@ -361,23 +323,19 @@ void PrePostProcessor::NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBIn
|
||||
{
|
||||
rmdir(pNZBInfo->GetDestDir());
|
||||
}
|
||||
|
||||
if (g_pOptions->GetNzbCleanupDisk())
|
||||
{
|
||||
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
|
||||
}
|
||||
}
|
||||
|
||||
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth)
|
||||
{
|
||||
NZBDownloaded(pDownloadQueue, pNZBInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
NZBCompleted(pDownloadQueue, pNZBInfo, true);
|
||||
}
|
||||
NZBCompleted(pDownloadQueue, pNZBInfo, true);
|
||||
}
|
||||
|
||||
void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue)
|
||||
{
|
||||
bool bNeedSave = false;
|
||||
|
||||
if (g_pOptions->GetKeepHistory() > 0 && !pNZBInfo->GetAvoidHistory())
|
||||
if (g_pOptions->GetKeepHistory() > 0)
|
||||
{
|
||||
//remove old item for the same NZB
|
||||
for (HistoryList::iterator it = pDownloadQueue->GetHistoryList()->begin(); it != pDownloadQueue->GetHistoryList()->end(); it++)
|
||||
@@ -418,34 +376,23 @@ void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZB
|
||||
}
|
||||
pNZBInfo->SetParkedFileCount(iParkedFiles);
|
||||
|
||||
if (bSaveQueue)
|
||||
{
|
||||
SaveQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
info("Collection %s added to history", pNZBInfo->GetName());
|
||||
bNeedSave = true;
|
||||
}
|
||||
|
||||
pNZBInfo->SetAvoidHistory(false);
|
||||
|
||||
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
|
||||
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
|
||||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth))
|
||||
{
|
||||
m_DupeCoordinator.NZBCompleted(pDownloadQueue, pNZBInfo);
|
||||
bNeedSave = true;
|
||||
}
|
||||
|
||||
if (bSaveQueue && bNeedSave)
|
||||
{
|
||||
SaveQueue(pDownloadQueue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes old entries from (recent) history
|
||||
* Removes old entries from history
|
||||
*/
|
||||
void PrePostProcessor::CheckHistory()
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
time_t tMinTime = time(NULL) - g_pOptions->GetKeepHistory() * 60*60*24;
|
||||
time_t tMinTime = time(NULL) - g_pOptions->GetKeepHistory() * 60000;
|
||||
bool bChanged = false;
|
||||
int index = 0;
|
||||
|
||||
@@ -454,29 +401,13 @@ void PrePostProcessor::CheckHistory()
|
||||
for (HistoryList::reverse_iterator it = pDownloadQueue->GetHistoryList()->rbegin(); it != pDownloadQueue->GetHistoryList()->rend(); )
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = *it;
|
||||
if (pHistoryInfo->GetKind() != HistoryInfo::hkDupInfo && pHistoryInfo->GetTime() < tMinTime)
|
||||
if (pHistoryInfo->GetTime() < tMinTime)
|
||||
{
|
||||
if (g_pOptions->GetDupeCheck() && pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
// replace history element
|
||||
m_DupeCoordinator.HistoryTransformToDup(pDownloadQueue, pHistoryInfo, index);
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
|
||||
pDownloadQueue->GetHistoryList()->erase(pDownloadQueue->GetHistoryList()->end() - 1 - index);
|
||||
delete pHistoryInfo;
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
DeleteQueuedFile(pHistoryInfo->GetNZBInfo()->GetQueuedFilename());
|
||||
}
|
||||
info("Collection %s removed from history", szNiceName);
|
||||
}
|
||||
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
pDownloadQueue->GetHistoryList()->erase(pDownloadQueue->GetHistoryList()->end() - 1 - index);
|
||||
delete pHistoryInfo;
|
||||
info("Collection %s removed from history", szNiceName);
|
||||
it = pDownloadQueue->GetHistoryList()->rbegin() + index;
|
||||
bChanged = true;
|
||||
}
|
||||
@@ -497,12 +428,7 @@ void PrePostProcessor::CheckHistory()
|
||||
|
||||
void PrePostProcessor::DeleteQueuedFile(const char* szQueuedFile)
|
||||
{
|
||||
if (!g_pOptions->GetNzbCleanupDisk())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// szQueuedFile may contain one filename or several filenames separated
|
||||
// szQueuedFile may contain one filename or several filenames separated
|
||||
// with "|"-character (for merged groups)
|
||||
char* szFilename = strdup(szQueuedFile);
|
||||
char* szEnd = szFilename - 1;
|
||||
@@ -523,21 +449,44 @@ void PrePostProcessor::DeleteQueuedFile(const char* szQueuedFile)
|
||||
free(szFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find ID of any file in the nzb-file
|
||||
*/
|
||||
int PrePostProcessor::FindGroupID(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
NZBInfo* PrePostProcessor::MergeGroups(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
{
|
||||
int iAddedGroupID = 0;
|
||||
|
||||
// merge(1): find ID of any file in new nzb-file
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo)
|
||||
{
|
||||
return pFileInfo->GetID();
|
||||
iAddedGroupID = pFileInfo->GetID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
// merge(2): check if queue has other nzb-files with the same name
|
||||
if (iAddedGroupID > 0)
|
||||
{
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() != pNZBInfo &&
|
||||
!strcmp(pFileInfo->GetNZBInfo()->GetName(), pNZBInfo->GetName()))
|
||||
{
|
||||
// file found, do merging
|
||||
|
||||
IDList cIDList;
|
||||
cIDList.push_back(pFileInfo->GetID());
|
||||
cIDList.push_back(iAddedGroupID);
|
||||
|
||||
g_pQueueCoordinator->GetQueueEditor()->LockedEditList(pDownloadQueue, &cIDList, false, QueueEditor::eaGroupMerge, 0, NULL);
|
||||
|
||||
return pFileInfo->GetNZBInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pNZBInfo;
|
||||
}
|
||||
|
||||
void PrePostProcessor::CheckDiskSpace()
|
||||
@@ -545,19 +494,9 @@ 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());
|
||||
warn("Low disk space. Pausing download");
|
||||
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()
|
||||
@@ -600,7 +539,14 @@ void PrePostProcessor::CheckPostQueue()
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
|
||||
else if (pPostInfo->GetRequestParRename())
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetRenameStatus(NZBInfo::rsNone);
|
||||
pPostInfo->SetRequestParRename(false);
|
||||
pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
DeletePostThread(pPostInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (pPostInfo->GetDeleted())
|
||||
{
|
||||
@@ -658,8 +604,11 @@ void PrePostProcessor::SanitisePostQueue(PostQueue* pPostQueue)
|
||||
|
||||
void PrePostProcessor::DeletePostThread(PostInfo* pPostInfo)
|
||||
{
|
||||
delete pPostInfo->GetPostThread();
|
||||
pPostInfo->SetPostThread(NULL);
|
||||
if (pPostInfo->GetPostThread())
|
||||
{
|
||||
delete pPostInfo->GetPostThread();
|
||||
pPostInfo->SetPostThread(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
|
||||
@@ -687,29 +636,9 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
|
||||
pPostInfo->GetNZBInfo()->CalcHealth() < pPostInfo->GetNZBInfo()->CalcCriticalHealth() &&
|
||||
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
|
||||
{
|
||||
warn("Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetInfoName(),
|
||||
pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth() / 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->GetInfoName(), 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 bUnpack = g_pOptions->GetUnpack() && (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone);
|
||||
|
||||
bool bParFailed = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible ||
|
||||
@@ -725,8 +654,6 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
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 &&
|
||||
@@ -737,8 +664,9 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
|
||||
|
||||
if (bUnpack && bParFailed)
|
||||
{
|
||||
warn("Skipping unpack for %s due to %s", pPostInfo->GetInfoName(),
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure");
|
||||
warn("Skipping unpack due to %s for %s",
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure",
|
||||
pPostInfo->GetInfoName());
|
||||
pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
|
||||
bUnpack = false;
|
||||
}
|
||||
@@ -801,15 +729,22 @@ void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPo
|
||||
pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess ||
|
||||
(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone &&
|
||||
pPostInfo->GetNZBInfo()->GetScriptStatuses()->CalcTotalStatus() == ScriptStatus::srSuccess);
|
||||
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue)
|
||||
if ((g_pOptions->GetParCleanupQueue() || g_pOptions->GetNzbCleanupDisk()) && bCanCleanupQueue)
|
||||
{
|
||||
FileInfo* pFileInfo = GetQueueGroup(pDownloadQueue, pPostInfo->GetNZBInfo());
|
||||
if (pFileInfo)
|
||||
if (g_pOptions->GetParCleanupQueue())
|
||||
{
|
||||
info("Cleaning up download queue for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pFileInfo->GetNZBInfo()->ClearCompletedFiles();
|
||||
pFileInfo->GetNZBInfo()->SetParCleanup(true);
|
||||
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupDelete, 0, NULL);
|
||||
FileInfo* pFileInfo = GetQueueGroup(pDownloadQueue, pPostInfo->GetNZBInfo());
|
||||
if (pFileInfo)
|
||||
{
|
||||
info("Cleaning up download queue for %s", pPostInfo->GetNZBInfo()->GetName());
|
||||
pFileInfo->GetNZBInfo()->ClearCompletedFiles();
|
||||
pFileInfo->GetNZBInfo()->SetParCleanup(true);
|
||||
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupDelete, 0, NULL);
|
||||
}
|
||||
}
|
||||
if (g_pOptions->GetNzbCleanupDisk())
|
||||
{
|
||||
DeleteQueuedFile(pPostInfo->GetNZBInfo()->GetQueuedFilename());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,9 +814,15 @@ FileInfo* PrePostProcessor::GetQueueGroup(DownloadQueue* pDownloadQueue, NZBInfo
|
||||
|
||||
void PrePostProcessor::ApplySchedulerState()
|
||||
{
|
||||
if (g_pScheduler->GetDownloadRateChanged())
|
||||
{
|
||||
info("Scheduler: set download rate to %i KB/s", g_pScheduler->GetDownloadRate() / 1024);
|
||||
g_pOptions->SetDownloadRate(g_pScheduler->GetDownloadRate());
|
||||
}
|
||||
|
||||
if (g_pScheduler->GetPauseDownloadChanged())
|
||||
{
|
||||
info("Scheduler: %s download queue", g_pScheduler->GetPauseDownload() ? "pausing" : "unpausing");
|
||||
info("Scheduler: %s download queue", g_pScheduler->GetPauseDownload() ? "pause" : "unpause");
|
||||
m_bSchedulerPauseChanged = true;
|
||||
m_bSchedulerPause = g_pScheduler->GetPauseDownload();
|
||||
if (!m_bPostPause)
|
||||
@@ -889,6 +830,12 @@ void PrePostProcessor::ApplySchedulerState()
|
||||
g_pOptions->SetPauseDownload(m_bSchedulerPause);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pScheduler->GetPauseScanChanged())
|
||||
{
|
||||
info("Scheduler: %s scan", g_pScheduler->GetPauseScan() ? "pause" : "unpause");
|
||||
g_pOptions->SetPauseScan(g_pScheduler->GetPauseScan());
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::UpdatePauseState(bool bNeedPause, const char* szReason)
|
||||
@@ -968,17 +915,9 @@ bool PrePostProcessor::QueueEditList(IDList* pIDList, EEditAction eAction, int i
|
||||
return PostQueueDelete(pIDList);
|
||||
|
||||
case eaHistoryDelete:
|
||||
case eaHistoryFinalDelete:
|
||||
case eaHistoryReturn:
|
||||
case eaHistoryProcess:
|
||||
case eaHistoryRedownload:
|
||||
case eaHistorySetParameter:
|
||||
case eaHistorySetDupeKey:
|
||||
case eaHistorySetDupeScore:
|
||||
case eaHistorySetDupeMode:
|
||||
case eaHistorySetDupeBackup:
|
||||
case eaHistoryMarkBad:
|
||||
case eaHistoryMarkGood:
|
||||
return HistoryEdit(pIDList, eAction, iOffset, szText);
|
||||
|
||||
default:
|
||||
@@ -1130,8 +1069,7 @@ bool PrePostProcessor::HistoryEdit(IDList* pIDList, EEditAction eAction, int iOf
|
||||
switch (eAction)
|
||||
{
|
||||
case eaHistoryDelete:
|
||||
case eaHistoryFinalDelete:
|
||||
HistoryDelete(pDownloadQueue, itHistory, pHistoryInfo, eAction == eaHistoryFinalDelete);
|
||||
HistoryDelete(pDownloadQueue, itHistory, pHistoryInfo);
|
||||
break;
|
||||
|
||||
case eaHistoryReturn:
|
||||
@@ -1139,26 +1077,10 @@ bool PrePostProcessor::HistoryEdit(IDList* pIDList, EEditAction eAction, int iOf
|
||||
HistoryReturn(pDownloadQueue, itHistory, pHistoryInfo, eAction == eaHistoryProcess);
|
||||
break;
|
||||
|
||||
case eaHistoryRedownload:
|
||||
HistoryRedownload(pDownloadQueue, itHistory, pHistoryInfo, false);
|
||||
break;
|
||||
|
||||
case eaHistorySetParameter:
|
||||
HistorySetParameter(pHistoryInfo, szText);
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeKey:
|
||||
case eaHistorySetDupeScore:
|
||||
case eaHistorySetDupeMode:
|
||||
case eaHistorySetDupeBackup:
|
||||
HistorySetDupeParam(pHistoryInfo, eAction, szText);
|
||||
break;
|
||||
|
||||
case eaHistoryMarkBad:
|
||||
case eaHistoryMarkGood:
|
||||
m_DupeCoordinator.HistoryMark(pDownloadQueue, pHistoryInfo, eAction == eaHistoryMarkGood);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// nothing, just to avoid compiler warning
|
||||
break;
|
||||
@@ -1180,8 +1102,7 @@ bool PrePostProcessor::HistoryEdit(IDList* pIDList, EEditAction eAction, int iOf
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void PrePostProcessor::HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory,
|
||||
HistoryInfo* pHistoryInfo, bool bFinal)
|
||||
void PrePostProcessor::HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
@@ -1212,36 +1133,10 @@ void PrePostProcessor::HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList:
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo &&
|
||||
g_pOptions->GetDeleteCleanupDisk() &&
|
||||
(pHistoryInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsNone ||
|
||||
pHistoryInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
|
||||
pHistoryInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usFailure ||
|
||||
pHistoryInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usPassword) &&
|
||||
Util::DirectoryExists(pHistoryInfo->GetNZBInfo()->GetDestDir()))
|
||||
{
|
||||
info("Deleting %s", pHistoryInfo->GetNZBInfo()->GetDestDir());
|
||||
Util::DeleteDirectoryWithContent(pHistoryInfo->GetNZBInfo()->GetDestDir());
|
||||
}
|
||||
|
||||
if (bFinal || !g_pOptions->GetDupeCheck() || pHistoryInfo->GetKind() == HistoryInfo::hkUrlInfo)
|
||||
{
|
||||
pDownloadQueue->GetHistoryList()->erase(itHistory);
|
||||
delete pHistoryInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
// replace history element
|
||||
int rindex = pDownloadQueue->GetHistoryList()->size() - 1 - (itHistory - pDownloadQueue->GetHistoryList()->begin());
|
||||
m_DupeCoordinator.HistoryTransformToDup(pDownloadQueue, pHistoryInfo, rindex);
|
||||
}
|
||||
}
|
||||
pDownloadQueue->GetHistoryList()->erase(itHistory);
|
||||
delete pHistoryInfo;
|
||||
}
|
||||
|
||||
void PrePostProcessor::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo, bool bReprocess)
|
||||
@@ -1286,18 +1181,11 @@ void PrePostProcessor::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList:
|
||||
pNZBInfo->SetParCleanup(false);
|
||||
if (!pNZBInfo->GetUnpackCleanedUpDisk())
|
||||
{
|
||||
pNZBInfo->SetParStatus(NZBInfo::psNone);
|
||||
pNZBInfo->SetRenameStatus(NZBInfo::rsNone);
|
||||
pNZBInfo->SetUnpackStatus(NZBInfo::usNone);
|
||||
pNZBInfo->SetCleanupStatus(NZBInfo::csNone);
|
||||
|
||||
if (m_ParCoordinator.FindMainPars(pNZBInfo->GetDestDir(), NULL))
|
||||
{
|
||||
pNZBInfo->SetParStatus(NZBInfo::psNone);
|
||||
pNZBInfo->SetRenameStatus(NZBInfo::rsNone);
|
||||
}
|
||||
}
|
||||
pNZBInfo->SetDeleteStatus(NZBInfo::dsNone);
|
||||
pNZBInfo->SetDeletePaused(false);
|
||||
pNZBInfo->SetMarkStatus(NZBInfo::ksNone);
|
||||
pNZBInfo->GetScriptStatuses()->Clear();
|
||||
pNZBInfo->SetParkedFileCount(0);
|
||||
}
|
||||
@@ -1335,88 +1223,6 @@ void PrePostProcessor::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryList:
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory,
|
||||
HistoryInfo* pHistoryInfo, bool bRestorePauseState)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
|
||||
bool bPaused = bRestorePauseState && pNZBInfo->GetDeletePaused();
|
||||
int iGroupdID = -1;
|
||||
|
||||
if (!Util::FileExists(pNZBInfo->GetQueuedFilename()))
|
||||
{
|
||||
error("Could not return collection %s from history back to queue: could not find source nzb-file %s",
|
||||
pNZBInfo->GetName(), pNZBInfo->GetQueuedFilename());
|
||||
return;
|
||||
}
|
||||
|
||||
NZBFile* pNZBFile = NZBFile::Create(pNZBInfo->GetQueuedFilename(), "");
|
||||
if (pNZBFile == NULL)
|
||||
{
|
||||
error("Could not return collection %s from history back to queue: could not parse nzb-file",
|
||||
pNZBInfo->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
info("Returning collection %s from history back to queue", pNZBInfo->GetName());
|
||||
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
pFileInfo->SetNZBInfo(pNZBInfo);
|
||||
pFileInfo->SetPaused(bPaused);
|
||||
iGroupdID = pFileInfo->GetID();
|
||||
}
|
||||
|
||||
if (Util::DirectoryExists(pNZBInfo->GetDestDir()))
|
||||
{
|
||||
detail("Deleting %s", pNZBInfo->GetDestDir());
|
||||
Util::DeleteDirectoryWithContent(pNZBInfo->GetDestDir());
|
||||
}
|
||||
|
||||
pNZBInfo->BuildDestDirName();
|
||||
if (Util::DirectoryExists(pNZBInfo->GetDestDir()))
|
||||
{
|
||||
detail("Deleting %s", pNZBInfo->GetDestDir());
|
||||
Util::DeleteDirectoryWithContent(pNZBInfo->GetDestDir());
|
||||
}
|
||||
|
||||
// reset status fields (which are not reset by "HistoryReturn")
|
||||
pNZBInfo->SetMoveStatus(NZBInfo::msNone);
|
||||
pNZBInfo->SetUnpackCleanedUpDisk(false);
|
||||
pNZBInfo->SetParStatus(NZBInfo::psNone);
|
||||
pNZBInfo->SetRenameStatus(NZBInfo::rsNone);
|
||||
pNZBInfo->ClearCompletedFiles();
|
||||
pNZBInfo->GetServerStats()->Clear();
|
||||
|
||||
// take file stats from newly read nzb-file
|
||||
pNZBInfo->SetFileCount(pNZBFile->GetNZBInfo()->GetFileCount());
|
||||
pNZBInfo->SetFullContentHash(pNZBFile->GetNZBInfo()->GetFullContentHash());
|
||||
pNZBInfo->SetFilteredContentHash(pNZBFile->GetNZBInfo()->GetFilteredContentHash());
|
||||
pNZBInfo->SetSize(pNZBFile->GetNZBInfo()->GetSize());
|
||||
pNZBInfo->SetSuccessSize(pNZBFile->GetNZBInfo()->GetSuccessSize());
|
||||
pNZBInfo->SetCurrentSuccessSize(pNZBFile->GetNZBInfo()->GetCurrentSuccessSize());
|
||||
pNZBInfo->SetFailedSize(pNZBFile->GetNZBInfo()->GetFailedSize());
|
||||
pNZBInfo->SetCurrentFailedSize(pNZBFile->GetNZBInfo()->GetCurrentFailedSize());
|
||||
pNZBInfo->SetParSize(pNZBFile->GetNZBInfo()->GetParSize());
|
||||
pNZBInfo->SetParSuccessSize(pNZBFile->GetNZBInfo()->GetParSuccessSize());
|
||||
pNZBInfo->SetParCurrentSuccessSize(pNZBFile->GetNZBInfo()->GetParCurrentSuccessSize());
|
||||
pNZBInfo->SetParFailedSize(pNZBFile->GetNZBInfo()->GetParFailedSize());
|
||||
pNZBInfo->SetParCurrentFailedSize(pNZBFile->GetNZBInfo()->GetParCurrentFailedSize());
|
||||
pNZBInfo->SetSuccessArticles(pNZBFile->GetNZBInfo()->GetSuccessArticles());
|
||||
pNZBInfo->SetFailedArticles(pNZBFile->GetNZBInfo()->GetFailedArticles());
|
||||
|
||||
g_pQueueCoordinator->AddFileInfosToFileQueue(pNZBFile, pDownloadQueue->GetParkedFiles(), false);
|
||||
|
||||
delete pNZBFile;
|
||||
|
||||
HistoryReturn(pDownloadQueue, itHistory, pHistoryInfo, false);
|
||||
|
||||
if (!bPaused && g_pOptions->GetParCheck() != Options::pcForce)
|
||||
{
|
||||
g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, iGroupdID, false, QueueEditor::eaGroupPauseExtraPars, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
@@ -1436,7 +1242,7 @@ void PrePostProcessor::HistorySetParameter(HistoryInfo* pHistoryInfo, const char
|
||||
{
|
||||
*szValue = '\0';
|
||||
szValue++;
|
||||
pHistoryInfo->GetNZBInfo()->GetParameters()->SetParameter(szStr, szValue);
|
||||
pHistoryInfo->GetNZBInfo()->SetParameter(szStr, szValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1445,97 +1251,3 @@ void PrePostProcessor::HistorySetParameter(HistoryInfo* pHistoryInfo, const char
|
||||
|
||||
free(szStr);
|
||||
}
|
||||
|
||||
void PrePostProcessor::HistorySetDupeParam(HistoryInfo* pHistoryInfo, EEditAction eAction, const char* szText)
|
||||
{
|
||||
char szNiceName[1024];
|
||||
pHistoryInfo->GetName(szNiceName, 1024);
|
||||
debug("Setting dupe-parameter '%i'='%s' for '%s'", (int)eAction, szText, szNiceName);
|
||||
|
||||
if (!(pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo ||
|
||||
pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo))
|
||||
{
|
||||
error("Could not set duplicate parameter for %s: history item has wrong type", szNiceName);
|
||||
return;
|
||||
}
|
||||
|
||||
EDupeMode eMode = dmScore;
|
||||
if (eAction == eaHistorySetDupeMode)
|
||||
{
|
||||
if (!strcasecmp(szText, "SCORE"))
|
||||
{
|
||||
eMode = dmScore;
|
||||
}
|
||||
else if (!strcasecmp(szText, "ALL"))
|
||||
{
|
||||
eMode = dmAll;
|
||||
}
|
||||
else if (!strcasecmp(szText, "FORCE"))
|
||||
{
|
||||
eMode = dmForce;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not set duplicate mode for %s: incorrect mode (%s)", szNiceName, szText);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pHistoryInfo->GetKind() == HistoryInfo::hkNZBInfo)
|
||||
{
|
||||
switch (eAction)
|
||||
{
|
||||
case eaHistorySetDupeKey:
|
||||
pHistoryInfo->GetNZBInfo()->SetDupeKey(szText);
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeScore:
|
||||
pHistoryInfo->GetNZBInfo()->SetDupeScore(atoi(szText));
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeMode:
|
||||
pHistoryInfo->GetNZBInfo()->SetDupeMode(eMode);
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeBackup:
|
||||
if (pHistoryInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsDupe &&
|
||||
pHistoryInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsManual)
|
||||
{
|
||||
error("Could not set duplicate parameter for %s: history item has wrong delete status", szNiceName);
|
||||
return;
|
||||
}
|
||||
pHistoryInfo->GetNZBInfo()->SetDeleteStatus(!strcasecmp(szText, "YES") ||
|
||||
!strcasecmp(szText, "TRUE") || !strcasecmp(szText, "1") ? NZBInfo::dsDupe : NZBInfo::dsManual);
|
||||
break;
|
||||
|
||||
default:
|
||||
// suppress compiler warning
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pHistoryInfo->GetKind() == HistoryInfo::hkDupInfo)
|
||||
{
|
||||
switch (eAction)
|
||||
{
|
||||
case eaHistorySetDupeKey:
|
||||
pHistoryInfo->GetDupInfo()->SetDupeKey(szText);
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeScore:
|
||||
pHistoryInfo->GetDupInfo()->SetDupeScore(atoi(szText));
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeMode:
|
||||
pHistoryInfo->GetDupInfo()->SetDupeMode(eMode);
|
||||
break;
|
||||
|
||||
case eaHistorySetDupeBackup:
|
||||
error("Could not set duplicate parameter for %s: history item has wrong type", szNiceName);
|
||||
return;
|
||||
|
||||
default:
|
||||
// suppress compiler warning
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,10 @@
|
||||
#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
|
||||
@@ -45,17 +43,9 @@ public:
|
||||
eaPostMoveBottom,
|
||||
eaPostDelete,
|
||||
eaHistoryDelete,
|
||||
eaHistoryFinalDelete,
|
||||
eaHistoryReturn,
|
||||
eaHistoryProcess,
|
||||
eaHistoryRedownload,
|
||||
eaHistorySetParameter,
|
||||
eaHistorySetDupeKey,
|
||||
eaHistorySetDupeScore,
|
||||
eaHistorySetDupeMode,
|
||||
eaHistorySetDupeBackup,
|
||||
eaHistoryMarkBad,
|
||||
eaHistoryMarkGood
|
||||
eaHistorySetParameter
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -73,22 +63,12 @@ private:
|
||||
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;
|
||||
@@ -109,25 +89,21 @@ private:
|
||||
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);
|
||||
NZBInfo* MergeGroups(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 HistoryDelete(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory, HistoryInfo* pHistoryInfo);
|
||||
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 CheckHistory();
|
||||
void DeletePostThread(PostInfo* pPostInfo);
|
||||
|
||||
public:
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "QueueCoordinator.h"
|
||||
@@ -68,7 +67,6 @@ QueueCoordinator::QueueCoordinator()
|
||||
m_tStartDownload = 0;
|
||||
m_tPausedFrom = 0;
|
||||
m_bStandBy = true;
|
||||
m_iServerConfigGeneration = 0;
|
||||
|
||||
YDecoder::Init();
|
||||
}
|
||||
@@ -103,13 +101,6 @@ void QueueCoordinator::Run()
|
||||
|
||||
m_mutexDownloadQueue.Lock();
|
||||
|
||||
if (g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->LoadStats(g_pServerPool->GetServers());
|
||||
// currently there are no any stats but we need to save current server list into diskstate
|
||||
g_pDiskState->SaveStats(g_pServerPool->GetServers());
|
||||
}
|
||||
|
||||
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pDiskState->DownloadQueueExists())
|
||||
{
|
||||
if (g_pOptions->GetReloadQueue())
|
||||
@@ -126,7 +117,17 @@ void QueueCoordinator::Run()
|
||||
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
|
||||
AdjustDownloadsLimit();
|
||||
// compute maximum number of allowed download threads
|
||||
m_iDownloadsLimit = 2; // two extra threads for completing files (when connections are not needed)
|
||||
for (ServerPool::Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (pNewsServer->GetLevel() == 0)
|
||||
{
|
||||
m_iDownloadsLimit += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
}
|
||||
|
||||
m_tStartServer = time(NULL);
|
||||
m_tLastCheck = m_tStartServer;
|
||||
bool bWasStandBy = true;
|
||||
@@ -135,7 +136,6 @@ void QueueCoordinator::Run()
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
bool bDownloadsChecked = false;
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
NNTPConnection* pConnection = g_pServerPool->GetConnection(0, NULL, NULL);
|
||||
@@ -149,7 +149,6 @@ void QueueCoordinator::Run()
|
||||
m_mutexDownloadQueue.Lock();
|
||||
bool bHasMoreArticles = GetNextArticle(pFileInfo, pArticleInfo);
|
||||
bArticeDownloadsRunning = !m_ActiveDownloads.empty();
|
||||
bDownloadsChecked = true;
|
||||
m_bHasMoreJobs = bHasMoreArticles || bArticeDownloadsRunning;
|
||||
if (bHasMoreArticles && !IsStopped() && (int)m_ActiveDownloads.size() < m_iDownloadsLimit)
|
||||
{
|
||||
@@ -168,8 +167,7 @@ void QueueCoordinator::Run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDownloadsChecked)
|
||||
else
|
||||
{
|
||||
m_mutexDownloadQueue.Lock();
|
||||
bArticeDownloadsRunning = !m_ActiveDownloads.empty();
|
||||
@@ -200,7 +198,6 @@ void QueueCoordinator::Run()
|
||||
ResetHangingDownloads();
|
||||
iResetCounter = 0;
|
||||
AdjustStartTime();
|
||||
AdjustDownloadsLimit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,94 +217,16 @@ void QueueCoordinator::Run()
|
||||
debug("Exiting QueueCoordinator-loop");
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute maximum number of allowed download threads
|
||||
**/
|
||||
void QueueCoordinator::AdjustDownloadsLimit()
|
||||
{
|
||||
if (m_iServerConfigGeneration == g_pServerPool->GetGeneration())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// two extra threads for completing files (when connections are not needed)
|
||||
int iDownloadsLimit = 2;
|
||||
|
||||
// allow one thread per 0-level (main) and 1-level (backup) server connection
|
||||
for (Servers::iterator it = g_pServerPool->GetServers()->begin(); it != g_pServerPool->GetServers()->end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if ((pNewsServer->GetNormLevel() == 0 || pNewsServer->GetNormLevel() == 1) && pNewsServer->GetActive())
|
||||
{
|
||||
iDownloadsLimit += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
}
|
||||
|
||||
m_iDownloadsLimit = iDownloadsLimit;
|
||||
}
|
||||
|
||||
void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
{
|
||||
debug("Adding NZBFile to queue");
|
||||
|
||||
m_mutexDownloadQueue.Lock();
|
||||
|
||||
Aspect foundAspect = { eaNZBFileFound, &m_DownloadQueue, pNZBFile->GetNZBInfo(), NULL };
|
||||
Notify(&foundAspect);
|
||||
|
||||
if (pNZBFile->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsNone)
|
||||
{
|
||||
bool bAllPaused = !pNZBFile->GetFileInfos()->empty();
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
bAllPaused &= pFileInfo->GetPaused();
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->DiscardFile(pFileInfo);
|
||||
}
|
||||
}
|
||||
pNZBFile->GetNZBInfo()->SetDeletePaused(bAllPaused);
|
||||
}
|
||||
|
||||
if (pNZBFile->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsManual)
|
||||
{
|
||||
m_mutexDownloadQueue.Unlock(); // UNLOCK
|
||||
return;
|
||||
}
|
||||
|
||||
m_DownloadQueue.GetNZBInfoList()->Add(pNZBFile->GetNZBInfo());
|
||||
|
||||
if (pNZBFile->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
|
||||
{
|
||||
AddFileInfosToFileQueue(pNZBFile, m_DownloadQueue.GetFileQueue(), bAddFirst);
|
||||
}
|
||||
|
||||
char szNZBName[1024];
|
||||
strncpy(szNZBName, pNZBFile->GetNZBInfo()->GetName(), sizeof(szNZBName)-1);
|
||||
|
||||
Aspect aspect = { eaNZBFileAdded, &m_DownloadQueue, pNZBFile->GetNZBInfo(), NULL };
|
||||
Notify(&aspect);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(&m_DownloadQueue);
|
||||
}
|
||||
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
|
||||
if (pNZBFile->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
|
||||
{
|
||||
info("Collection %s added to queue", szNZBName);
|
||||
}
|
||||
}
|
||||
|
||||
void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFileQueue, bool bAddFirst)
|
||||
{
|
||||
debug("Adding NZBFile to queue");
|
||||
|
||||
FileQueue tmpFileQueue;
|
||||
tmpFileQueue.clear();
|
||||
FileQueue DupeList;
|
||||
DupeList.clear();
|
||||
|
||||
int index1 = 0;
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
@@ -315,9 +234,14 @@ void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFi
|
||||
index1++;
|
||||
FileInfo* pFileInfo = *it;
|
||||
|
||||
if (g_pOptions->GetDupeCheck() && !pNZBFile->GetNZBInfo()->GetDupeMode())
|
||||
if (g_pOptions->GetDupeCheck())
|
||||
{
|
||||
bool dupe = false;
|
||||
if (IsDupe(pFileInfo))
|
||||
{
|
||||
warn("File \"%s\" seems to be duplicate, skipping", pFileInfo->GetFilename());
|
||||
dupe = true;
|
||||
}
|
||||
int index2 = 0;
|
||||
for (NZBFile::FileInfos::iterator it2 = pNZBFile->GetFileInfos()->begin(); it2 != pNZBFile->GetFileInfos()->end(); it2++)
|
||||
{
|
||||
@@ -328,7 +252,7 @@ void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFi
|
||||
(pFileInfo->GetSize() < pFileInfo2->GetSize() ||
|
||||
(pFileInfo->GetSize() == pFileInfo2->GetSize() && index2 < index1)))
|
||||
{
|
||||
warn("File \"%s\" appears twice in collection, adding only the biggest file", pFileInfo->GetFilename());
|
||||
warn("File \"%s\" appears twice in nzb-request, adding only the biggest file", pFileInfo->GetFilename());
|
||||
dupe = true;
|
||||
break;
|
||||
}
|
||||
@@ -336,7 +260,6 @@ void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFi
|
||||
if (dupe)
|
||||
{
|
||||
DupeList.push_back(pFileInfo);
|
||||
StatFileInfo(pFileInfo, false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -355,11 +278,11 @@ void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFi
|
||||
{
|
||||
if (bAddFirst)
|
||||
{
|
||||
pFileQueue->push_front(*it);
|
||||
m_DownloadQueue.GetFileQueue()->push_front(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
pFileQueue->push_back(*it);
|
||||
m_DownloadQueue.GetFileQueue()->push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +296,19 @@ void QueueCoordinator::AddFileInfosToFileQueue(NZBFile* pNZBFile, FileQueue* pFi
|
||||
delete pFileInfo;
|
||||
}
|
||||
|
||||
m_DownloadQueue.GetNZBInfoList()->Add(pNZBFile->GetNZBInfo());
|
||||
|
||||
pNZBFile->DetachFileInfos();
|
||||
|
||||
Aspect aspect = { eaNZBFileAdded, &m_DownloadQueue, pNZBFile->GetNZBInfo(), NULL };
|
||||
Notify(&aspect);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(&m_DownloadQueue);
|
||||
}
|
||||
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -512,8 +447,6 @@ bool QueueCoordinator::DeleteQueueEntry(FileInfo* pFileInfo)
|
||||
}
|
||||
if (!hasDownloads)
|
||||
{
|
||||
StatFileInfo(pFileInfo, false);
|
||||
|
||||
Aspect aspect = { eaFileDeleted, &m_DownloadQueue, pFileInfo->GetNZBInfo(), pFileInfo };
|
||||
Notify(&aspect);
|
||||
|
||||
@@ -614,7 +547,10 @@ bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArtic
|
||||
}
|
||||
}
|
||||
|
||||
free(pCheckedFiles);
|
||||
if (pCheckedFiles)
|
||||
{
|
||||
free(pCheckedFiles);
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
@@ -631,7 +567,7 @@ void QueueCoordinator::StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pA
|
||||
pArticleDownloader->SetConnection(pConnection);
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "%s%c%s [%i/%i]", pFileInfo->GetNZBInfo()->GetName(), (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), (int)pFileInfo->GetArticles()->size());
|
||||
snprintf(szInfoName, 1024, "%s%c%s [%i/%i]", pFileInfo->GetNZBInfo()->GetName(), (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
|
||||
szInfoName[1024-1] = '\0';
|
||||
pArticleDownloader->SetInfoName(szInfoName);
|
||||
|
||||
@@ -680,18 +616,10 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
if (pArticleDownloader->GetStatus() == ArticleDownloader::adFinished)
|
||||
{
|
||||
pArticleInfo->SetStatus(ArticleInfo::aiFinished);
|
||||
pFileInfo->SetSuccessSize(pFileInfo->GetSuccessSize() + pArticleInfo->GetSize());
|
||||
pFileInfo->GetNZBInfo()->SetCurrentSuccessSize(pFileInfo->GetNZBInfo()->GetCurrentSuccessSize() + pArticleInfo->GetSize());
|
||||
pFileInfo->GetNZBInfo()->SetParCurrentSuccessSize(pFileInfo->GetNZBInfo()->GetParCurrentSuccessSize() + (pFileInfo->GetParFile() ? pArticleInfo->GetSize() : 0));
|
||||
pFileInfo->SetSuccessArticles(pFileInfo->GetSuccessArticles() + 1);
|
||||
}
|
||||
else if (pArticleDownloader->GetStatus() == ArticleDownloader::adFailed)
|
||||
{
|
||||
pArticleInfo->SetStatus(ArticleInfo::aiFailed);
|
||||
pFileInfo->SetFailedSize(pFileInfo->GetFailedSize() + pArticleInfo->GetSize());
|
||||
pFileInfo->GetNZBInfo()->SetCurrentFailedSize(pFileInfo->GetNZBInfo()->GetCurrentFailedSize() + pArticleInfo->GetSize());
|
||||
pFileInfo->GetNZBInfo()->SetParCurrentFailedSize(pFileInfo->GetNZBInfo()->GetParCurrentFailedSize() + (pFileInfo->GetParFile() ? pArticleInfo->GetSize() : 0));
|
||||
pFileInfo->SetFailedArticles(pFileInfo->GetFailedArticles() + 1);
|
||||
}
|
||||
else if (pArticleDownloader->GetStatus() == ArticleDownloader::adRetry)
|
||||
{
|
||||
@@ -704,7 +632,6 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
pFileInfo->SetRemainingSize(pFileInfo->GetRemainingSize() - pArticleInfo->GetSize());
|
||||
pFileInfo->SetCompleted(pFileInfo->GetCompleted() + 1);
|
||||
fileCompleted = (int)pFileInfo->GetArticles()->size() == pFileInfo->GetCompleted();
|
||||
pFileInfo->GetNZBInfo()->GetServerStats()->Add(pArticleDownloader->GetServerStats());
|
||||
}
|
||||
|
||||
if (!pFileInfo->GetFilenameConfirmed() &&
|
||||
@@ -713,10 +640,7 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
{
|
||||
pFileInfo->SetFilename(pArticleDownloader->GetArticleFilename());
|
||||
pFileInfo->SetFilenameConfirmed(true);
|
||||
if (g_pOptions->GetDupeCheck() &&
|
||||
pFileInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
|
||||
!pFileInfo->GetNZBInfo()->GetManyDupeFiles() &&
|
||||
Util::FileExists(pFileInfo->GetNZBInfo()->GetDestDir(), pFileInfo->GetFilename()))
|
||||
if (g_pOptions->GetDupeCheck() && pFileInfo->IsDupe(pFileInfo->GetFilename()))
|
||||
{
|
||||
warn("File \"%s\" seems to be duplicate, cancelling download and deleting file from queue", pFileInfo->GetFilename());
|
||||
fileCompleted = false;
|
||||
@@ -727,6 +651,23 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
|
||||
bool deleteFileObj = false;
|
||||
|
||||
if (pFileInfo->GetDeleted())
|
||||
{
|
||||
int cnt = 0;
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
if ((*it)->GetFileInfo() == pFileInfo)
|
||||
{
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt == 1)
|
||||
{
|
||||
// this was the last Download for a file deleted from queue
|
||||
deleteFileObj = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fileCompleted && !IsStopped() && !pFileInfo->GetDeleted())
|
||||
{
|
||||
// all jobs done
|
||||
@@ -736,22 +677,16 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
deleteFileObj = true;
|
||||
}
|
||||
|
||||
CheckHealth(pFileInfo);
|
||||
|
||||
bool hasOtherDownloaders = false;
|
||||
// delete Download from Queue
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
ArticleDownloader* pDownloader = *it;
|
||||
if (pDownloader != pArticleDownloader && pDownloader->GetFileInfo() == pFileInfo)
|
||||
ArticleDownloader* pa = *it;
|
||||
if (pa == pArticleDownloader)
|
||||
{
|
||||
hasOtherDownloaders = true;
|
||||
m_ActiveDownloads.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
deleteFileObj |= pFileInfo->GetDeleted() && !hasOtherDownloaders;
|
||||
|
||||
// remove downloader from downloader list
|
||||
m_ActiveDownloads.erase(std::find(m_ActiveDownloads.begin(), m_ActiveDownloads.end(), pArticleDownloader));
|
||||
|
||||
pFileInfo->SetActiveDownloads(pFileInfo->GetActiveDownloads() - 1);
|
||||
|
||||
@@ -761,8 +696,6 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
// delete File from Queue
|
||||
pFileInfo->SetDeleted(true);
|
||||
|
||||
StatFileInfo(pFileInfo, fileCompleted);
|
||||
|
||||
Aspect aspect = { fileCompleted && !fileDeleted ? eaFileCompleted : eaFileDeleted, &m_DownloadQueue, pFileInfo->GetNZBInfo(), pFileInfo };
|
||||
Notify(&aspect);
|
||||
|
||||
@@ -776,40 +709,6 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
}
|
||||
|
||||
void QueueCoordinator::StatFileInfo(FileInfo* pFileInfo, bool bCompleted)
|
||||
{
|
||||
NZBInfo* pNZBInfo = pFileInfo->GetNZBInfo();
|
||||
if (bCompleted || pNZBInfo->GetDeleting())
|
||||
{
|
||||
pNZBInfo->SetSuccessSize(pNZBInfo->GetSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetFailedSize(pNZBInfo->GetFailedSize() + pFileInfo->GetFailedSize());
|
||||
pNZBInfo->SetFailedArticles(pNZBInfo->GetFailedArticles() + pFileInfo->GetFailedArticles() + pFileInfo->GetMissedArticles());
|
||||
pNZBInfo->SetSuccessArticles(pNZBInfo->GetSuccessArticles() + pFileInfo->GetSuccessArticles());
|
||||
if (pFileInfo->GetParFile())
|
||||
{
|
||||
pNZBInfo->SetParSuccessSize(pNZBInfo->GetParSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetParFailedSize(pNZBInfo->GetParFailedSize() + pFileInfo->GetFailedSize());
|
||||
}
|
||||
}
|
||||
else if (!pNZBInfo->GetDeleting() && !pNZBInfo->GetParCleanup())
|
||||
{
|
||||
// file deleted but not the whole nzb and not par-cleanup
|
||||
pNZBInfo->SetFileCount(pNZBInfo->GetFileCount() - 1);
|
||||
pNZBInfo->SetSize(pNZBInfo->GetSize() - pFileInfo->GetSize());
|
||||
pNZBInfo->SetCurrentSuccessSize(pNZBInfo->GetCurrentSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetFailedSize(pNZBInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
pNZBInfo->SetCurrentFailedSize(pNZBInfo->GetCurrentFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
pNZBInfo->SetTotalArticles(pNZBInfo->GetTotalArticles() - pFileInfo->GetTotalArticles());
|
||||
if (pFileInfo->GetParFile())
|
||||
{
|
||||
pNZBInfo->SetParSize(pNZBInfo->GetParSize() - pFileInfo->GetSize());
|
||||
pNZBInfo->SetParCurrentSuccessSize(pNZBInfo->GetParCurrentSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetParFailedSize(pNZBInfo->GetParFailedSize() - pFileInfo->GetMissedSize());
|
||||
pNZBInfo->SetParCurrentFailedSize(pNZBInfo->GetParCurrentFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueueCoordinator::DeleteFileInfo(FileInfo* pFileInfo, bool bCompleted)
|
||||
{
|
||||
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
|
||||
@@ -857,30 +756,29 @@ void QueueCoordinator::DiscardDiskFile(FileInfo* pFileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void QueueCoordinator::CheckHealth(FileInfo* pFileInfo)
|
||||
bool QueueCoordinator::IsDupe(FileInfo* pFileInfo)
|
||||
{
|
||||
if (g_pOptions->GetHealthCheck() == Options::hcNone ||
|
||||
pFileInfo->GetNZBInfo()->GetHealthPaused() ||
|
||||
pFileInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsHealth ||
|
||||
pFileInfo->GetNZBInfo()->CalcHealth() >= pFileInfo->GetNZBInfo()->CalcCriticalHealth())
|
||||
debug("Checking if the file is already queued");
|
||||
|
||||
// checking on disk
|
||||
if (pFileInfo->IsDupe(pFileInfo->GetFilename()))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetHealthCheck() == Options::hcPause)
|
||||
// checking in queue
|
||||
for (FileQueue::iterator it = m_DownloadQueue.GetFileQueue()->begin(); it != m_DownloadQueue.GetFileQueue()->end(); it++)
|
||||
{
|
||||
warn("Pausing %s due to health %.1f%% below critical %.1f%%", pFileInfo->GetNZBInfo()->GetName(),
|
||||
pFileInfo->GetNZBInfo()->CalcHealth() / 10.0, pFileInfo->GetNZBInfo()->CalcCriticalHealth() / 10.0);
|
||||
pFileInfo->GetNZBInfo()->SetHealthPaused(true);
|
||||
m_QueueEditor.LockedEditEntry(&m_DownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupPause, 0, NULL);
|
||||
}
|
||||
else if (g_pOptions->GetHealthCheck() == Options::hcDelete)
|
||||
{
|
||||
warn("Cancelling download and deleting %s due to health %.1f%% below critical %.1f%%", pFileInfo->GetNZBInfo()->GetName(),
|
||||
pFileInfo->GetNZBInfo()->CalcHealth() / 10.0, pFileInfo->GetNZBInfo()->CalcCriticalHealth() / 10.0);
|
||||
pFileInfo->GetNZBInfo()->SetDeleteStatus(NZBInfo::dsHealth);
|
||||
m_QueueEditor.LockedEditEntry(&m_DownloadQueue, pFileInfo->GetID(), false, QueueEditor::eaGroupDelete, 0, NULL);
|
||||
FileInfo* pQueueEntry = *it;
|
||||
if (!strcmp(pFileInfo->GetNZBInfo()->GetDestDir(), pQueueEntry->GetNZBInfo()->GetDestDir()) &&
|
||||
!strcmp(pFileInfo->GetFilename(), pQueueEntry->GetFilename()) &&
|
||||
pFileInfo != pQueueEntry)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QueueCoordinator::LogDebugInfo()
|
||||
@@ -1113,20 +1011,7 @@ bool QueueCoordinator::MergeQueueEntries(NZBInfo* pDestNZBInfo, NZBInfo* pSrcNZB
|
||||
}
|
||||
|
||||
pDestNZBInfo->SetFileCount(pDestNZBInfo->GetFileCount() + pSrcNZBInfo->GetFileCount());
|
||||
pDestNZBInfo->SetFullContentHash(0);
|
||||
pDestNZBInfo->SetFilteredContentHash(0);
|
||||
|
||||
pDestNZBInfo->SetSize(pDestNZBInfo->GetSize() + pSrcNZBInfo->GetSize());
|
||||
pDestNZBInfo->SetSuccessSize(pDestNZBInfo->GetSuccessSize() + pSrcNZBInfo->GetSuccessSize());
|
||||
pDestNZBInfo->SetCurrentSuccessSize(pDestNZBInfo->GetCurrentSuccessSize() + pSrcNZBInfo->GetCurrentSuccessSize());
|
||||
pDestNZBInfo->SetFailedSize(pDestNZBInfo->GetFailedSize() + pSrcNZBInfo->GetFailedSize());
|
||||
pDestNZBInfo->SetCurrentFailedSize(pDestNZBInfo->GetCurrentFailedSize() + pSrcNZBInfo->GetCurrentFailedSize());
|
||||
|
||||
pDestNZBInfo->SetParSize(pDestNZBInfo->GetParSize() + pSrcNZBInfo->GetParSize());
|
||||
pDestNZBInfo->SetParSuccessSize(pDestNZBInfo->GetParSuccessSize() + pSrcNZBInfo->GetParSuccessSize());
|
||||
pDestNZBInfo->SetParCurrentSuccessSize(pDestNZBInfo->GetParCurrentSuccessSize() + pSrcNZBInfo->GetParCurrentSuccessSize());
|
||||
pDestNZBInfo->SetParFailedSize(pDestNZBInfo->GetParFailedSize() + pSrcNZBInfo->GetParFailedSize());
|
||||
pDestNZBInfo->SetParCurrentFailedSize(pDestNZBInfo->GetParCurrentFailedSize() + pSrcNZBInfo->GetParCurrentFailedSize());
|
||||
|
||||
// reattach completed file items to new NZBInfo-object
|
||||
for (NZBInfo::Files::iterator it = pSrcNZBInfo->GetCompletedFiles()->begin(); it != pSrcNZBInfo->GetCompletedFiles()->end(); it++)
|
||||
@@ -1183,20 +1068,20 @@ bool QueueCoordinator::SplitQueueEntries(FileQueue* pFileList, const char* szNam
|
||||
}
|
||||
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
pNZBInfo->Retain();
|
||||
pNZBInfo->AddReference();
|
||||
m_DownloadQueue.GetNZBInfoList()->Add(pNZBInfo);
|
||||
|
||||
pNZBInfo->SetFilename(pSrcNZBInfo->GetFilename());
|
||||
pNZBInfo->SetName(szName);
|
||||
pNZBInfo->SetCategory(pSrcNZBInfo->GetCategory());
|
||||
pNZBInfo->SetFullContentHash(0);
|
||||
pNZBInfo->SetFilteredContentHash(0);
|
||||
pNZBInfo->BuildDestDirName();
|
||||
pNZBInfo->SetQueuedFilename(pSrcNZBInfo->GetQueuedFilename());
|
||||
pNZBInfo->GetParameters()->CopyFrom(pSrcNZBInfo->GetParameters());
|
||||
|
||||
pSrcNZBInfo->SetFullContentHash(0);
|
||||
pSrcNZBInfo->SetFilteredContentHash(0);
|
||||
for (NZBParameterList::iterator it = pSrcNZBInfo->GetParameters()->begin(); it != pSrcNZBInfo->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pNZBParameter = *it;
|
||||
pNZBInfo->SetParameter(pNZBParameter->GetName(), pNZBParameter->GetValue());
|
||||
}
|
||||
|
||||
for (FileQueue::iterator it = pFileList->begin(); it != pFileList->end(); it++)
|
||||
{
|
||||
@@ -1209,32 +1094,9 @@ bool QueueCoordinator::SplitQueueEntries(FileQueue* pFileList, const char* szNam
|
||||
|
||||
pSrcNZBInfo->SetFileCount(pSrcNZBInfo->GetFileCount() - 1);
|
||||
pSrcNZBInfo->SetSize(pSrcNZBInfo->GetSize() - pFileInfo->GetSize());
|
||||
pSrcNZBInfo->SetSuccessSize(pSrcNZBInfo->GetSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pSrcNZBInfo->SetCurrentSuccessSize(pSrcNZBInfo->GetCurrentSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pSrcNZBInfo->SetFailedSize(pSrcNZBInfo->GetFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
pSrcNZBInfo->SetCurrentFailedSize(pSrcNZBInfo->GetCurrentFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
|
||||
pNZBInfo->SetFileCount(pNZBInfo->GetFileCount() + 1);
|
||||
pNZBInfo->SetSize(pNZBInfo->GetSize() + pFileInfo->GetSize());
|
||||
pNZBInfo->SetSuccessSize(pNZBInfo->GetSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetCurrentSuccessSize(pNZBInfo->GetCurrentSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetFailedSize(pNZBInfo->GetFailedSize() + pFileInfo->GetFailedSize() + pFileInfo->GetMissedSize());
|
||||
pNZBInfo->SetCurrentFailedSize(pNZBInfo->GetCurrentFailedSize() + pFileInfo->GetFailedSize() + pFileInfo->GetMissedSize());
|
||||
|
||||
if (pFileInfo->GetParFile())
|
||||
{
|
||||
pSrcNZBInfo->SetParSize(pSrcNZBInfo->GetParSize() - pFileInfo->GetSize());
|
||||
pSrcNZBInfo->SetParSuccessSize(pSrcNZBInfo->GetParSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pSrcNZBInfo->SetParCurrentSuccessSize(pSrcNZBInfo->GetParCurrentSuccessSize() - pFileInfo->GetSuccessSize());
|
||||
pSrcNZBInfo->SetParFailedSize(pSrcNZBInfo->GetParFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
pSrcNZBInfo->SetParCurrentFailedSize(pSrcNZBInfo->GetParCurrentFailedSize() - pFileInfo->GetFailedSize() - pFileInfo->GetMissedSize());
|
||||
|
||||
pNZBInfo->SetParSize(pNZBInfo->GetParSize() + pFileInfo->GetSize());
|
||||
pNZBInfo->SetParSuccessSize(pNZBInfo->GetParSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetParCurrentSuccessSize(pNZBInfo->GetParCurrentSuccessSize() + pFileInfo->GetSuccessSize());
|
||||
pNZBInfo->SetParFailedSize(pNZBInfo->GetParFailedSize() + pFileInfo->GetFailedSize() + pFileInfo->GetMissedSize());
|
||||
pNZBInfo->SetParCurrentFailedSize(pNZBInfo->GetParCurrentFailedSize() + pFileInfo->GetFailedSize() + pFileInfo->GetMissedSize());
|
||||
}
|
||||
}
|
||||
|
||||
pNZBInfo->Release();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,15 +43,12 @@ class QueueCoordinator : public Thread, public Observer, public Subject, public
|
||||
{
|
||||
public:
|
||||
typedef std::list<ArticleDownloader*> ActiveDownloads;
|
||||
|
||||
enum EAspectAction
|
||||
{
|
||||
eaNZBFileFound,
|
||||
eaNZBFileAdded,
|
||||
eaFileCompleted,
|
||||
eaFileDeleted
|
||||
};
|
||||
|
||||
struct Aspect
|
||||
{
|
||||
EAspectAction eAction;
|
||||
@@ -67,7 +64,6 @@ private:
|
||||
Mutex m_mutexDownloadQueue;
|
||||
bool m_bHasMoreJobs;
|
||||
int m_iDownloadsLimit;
|
||||
int m_iServerConfigGeneration;
|
||||
|
||||
// statistics
|
||||
static const int SPEEDMETER_SLOTS = 30;
|
||||
@@ -94,15 +90,13 @@ private:
|
||||
|
||||
bool GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArticleInfo);
|
||||
void StartArticleDownload(FileInfo* pFileInfo, ArticleInfo* pArticleInfo, NNTPConnection* pConnection);
|
||||
bool IsDupe(FileInfo* pFileInfo);
|
||||
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();
|
||||
@@ -121,7 +115,6 @@ public:
|
||||
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);
|
||||
|
||||
239
QueueEditor.cpp
239
QueueEditor.cpp
@@ -116,14 +116,7 @@ void QueueEditor::PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause)
|
||||
*/
|
||||
void QueueEditor::DeleteEntry(FileInfo* pFileInfo)
|
||||
{
|
||||
if (pFileInfo->GetNZBInfo()->GetDeleting())
|
||||
{
|
||||
detail("Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
}
|
||||
info("Deleting file %s from download queue", pFileInfo->GetFilename());
|
||||
g_pQueueCoordinator->DeleteQueueEntry(pFileInfo);
|
||||
}
|
||||
|
||||
@@ -228,93 +221,85 @@ bool QueueEditor::InternEditList(DownloadQueue* pDownloadQueue, IDList* pIDList,
|
||||
ItemList cItemList;
|
||||
PrepareList(pDownloadQueue, &cItemList, pIDList, bSmartOrder, eAction, iOffset);
|
||||
|
||||
switch (eAction)
|
||||
if (eAction == eaFilePauseAllPars || eAction == eaFilePauseExtraPars)
|
||||
{
|
||||
case eaFilePauseAllPars:
|
||||
case eaFilePauseExtraPars:
|
||||
PauseParsInGroups(&cItemList, eAction == eaFilePauseExtraPars);
|
||||
break;
|
||||
|
||||
case eaGroupMerge:
|
||||
return MergeGroups(pDownloadQueue, &cItemList);
|
||||
|
||||
case eaFileSplit:
|
||||
return SplitGroup(pDownloadQueue, &cItemList, szText);
|
||||
|
||||
case eaFileReorder:
|
||||
ReorderFiles(pDownloadQueue, &cItemList);
|
||||
break;
|
||||
|
||||
default:
|
||||
for (ItemList::iterator it = cItemList.begin(); it != cItemList.end(); it++)
|
||||
PauseParsInGroups(&cItemList, eAction == eaFilePauseExtraPars);
|
||||
}
|
||||
else if (eAction == eaGroupMerge)
|
||||
{
|
||||
return MergeGroups(pDownloadQueue, &cItemList);
|
||||
}
|
||||
else if (eAction == eaFileSplit)
|
||||
{
|
||||
return SplitGroup(pDownloadQueue, &cItemList, szText);
|
||||
}
|
||||
else if (eAction == eaFileReorder)
|
||||
{
|
||||
ReorderFiles(pDownloadQueue, &cItemList);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ItemList::iterator it = cItemList.begin(); it != cItemList.end(); it++)
|
||||
{
|
||||
EditItem* pItem = *it;
|
||||
switch (eAction)
|
||||
{
|
||||
EditItem* pItem = *it;
|
||||
switch (eAction)
|
||||
{
|
||||
case eaFilePause:
|
||||
PauseUnpauseEntry(pItem->m_pFileInfo, true);
|
||||
break;
|
||||
case eaFilePause:
|
||||
PauseUnpauseEntry(pItem->m_pFileInfo, true);
|
||||
break;
|
||||
|
||||
case eaFileResume:
|
||||
PauseUnpauseEntry(pItem->m_pFileInfo, false);
|
||||
break;
|
||||
case eaFileResume:
|
||||
PauseUnpauseEntry(pItem->m_pFileInfo, false);
|
||||
break;
|
||||
|
||||
case eaFileMoveOffset:
|
||||
case eaFileMoveTop:
|
||||
case eaFileMoveBottom:
|
||||
MoveEntry(pDownloadQueue, pItem->m_pFileInfo, pItem->m_iOffset);
|
||||
break;
|
||||
case eaFileMoveOffset:
|
||||
case eaFileMoveTop:
|
||||
case eaFileMoveBottom:
|
||||
MoveEntry(pDownloadQueue, pItem->m_pFileInfo, pItem->m_iOffset);
|
||||
break;
|
||||
|
||||
case eaFileDelete:
|
||||
DeleteEntry(pItem->m_pFileInfo);
|
||||
break;
|
||||
case eaFileDelete:
|
||||
DeleteEntry(pItem->m_pFileInfo);
|
||||
break;
|
||||
|
||||
case eaFileSetPriority:
|
||||
SetPriorityEntry(pItem->m_pFileInfo, szText);
|
||||
break;
|
||||
case eaFileSetPriority:
|
||||
SetPriorityEntry(pItem->m_pFileInfo, szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetCategory:
|
||||
SetNZBCategory(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
case eaGroupSetCategory:
|
||||
SetNZBCategory(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetName:
|
||||
SetNZBName(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
case eaGroupSetName:
|
||||
SetNZBName(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetDupeKey:
|
||||
case eaGroupSetDupeScore:
|
||||
case eaGroupSetDupeMode:
|
||||
SetNZBDupeParam(pItem->m_pFileInfo->GetNZBInfo(), eAction, szText);
|
||||
break;
|
||||
case eaGroupSetParameter:
|
||||
SetNZBParameter(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetParameter:
|
||||
SetNZBParameter(pItem->m_pFileInfo->GetNZBInfo(), szText);
|
||||
break;
|
||||
case eaGroupPause:
|
||||
case eaGroupResume:
|
||||
case eaGroupDelete:
|
||||
case eaGroupMoveTop:
|
||||
case eaGroupMoveBottom:
|
||||
case eaGroupMoveOffset:
|
||||
case eaGroupPauseAllPars:
|
||||
case eaGroupPauseExtraPars:
|
||||
case eaGroupSetPriority:
|
||||
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset, szText);
|
||||
break;
|
||||
|
||||
case eaGroupPause:
|
||||
case eaGroupResume:
|
||||
case eaGroupDelete:
|
||||
case eaGroupDupeDelete:
|
||||
case eaGroupFinalDelete:
|
||||
case eaGroupMoveTop:
|
||||
case eaGroupMoveBottom:
|
||||
case eaGroupMoveOffset:
|
||||
case eaGroupPauseAllPars:
|
||||
case eaGroupPauseExtraPars:
|
||||
case eaGroupSetPriority:
|
||||
EditGroup(pDownloadQueue, pItem->m_pFileInfo, eAction, iOffset, szText);
|
||||
break;
|
||||
|
||||
case eaFilePauseAllPars:
|
||||
case eaFilePauseExtraPars:
|
||||
case eaGroupMerge:
|
||||
case eaFileReorder:
|
||||
case eaFileSplit:
|
||||
// remove compiler warning "enumeration not handled in switch"
|
||||
break;
|
||||
}
|
||||
delete pItem;
|
||||
case eaFilePauseAllPars:
|
||||
case eaFilePauseExtraPars:
|
||||
case eaGroupMerge:
|
||||
case eaFileReorder:
|
||||
case eaFileSplit:
|
||||
// remove compiler warning "enumeration not handled in switch"
|
||||
break;
|
||||
}
|
||||
delete pItem;
|
||||
}
|
||||
}
|
||||
|
||||
return cItemList.size() > 0;
|
||||
@@ -483,7 +468,10 @@ bool QueueEditor::BuildIDListFromNameList(DownloadQueue* pDownloadQueue, IDList*
|
||||
}
|
||||
}
|
||||
|
||||
delete pRegEx;
|
||||
if (pRegEx)
|
||||
{
|
||||
delete pRegEx;
|
||||
}
|
||||
|
||||
if (!bFound && (eMatchMode == mmName))
|
||||
{
|
||||
@@ -498,7 +486,6 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
{
|
||||
IDList cIDList;
|
||||
cIDList.clear();
|
||||
bool bAllPaused = true;
|
||||
|
||||
// collecting files belonging to group
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
@@ -507,7 +494,6 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
if (pFileInfo2->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
cIDList.push_back(pFileInfo2->GetID());
|
||||
bAllPaused &= pFileInfo2->GetPaused();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,21 +542,15 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
}
|
||||
iOffset = iFileOffset;
|
||||
}
|
||||
else if (eAction == eaGroupDelete || eAction == eaGroupDupeDelete || eAction == eaGroupFinalDelete)
|
||||
else if (eAction == eaGroupDelete)
|
||||
{
|
||||
pFileInfo->GetNZBInfo()->SetDeleting(true);
|
||||
pFileInfo->GetNZBInfo()->SetAvoidHistory(eAction == eaGroupFinalDelete);
|
||||
pFileInfo->GetNZBInfo()->SetDeletePaused(bAllPaused);
|
||||
if (eAction == eaGroupDupeDelete)
|
||||
{
|
||||
pFileInfo->GetNZBInfo()->SetDeleteStatus(NZBInfo::dsDupe);
|
||||
}
|
||||
pFileInfo->GetNZBInfo()->SetDeleted(true);
|
||||
pFileInfo->GetNZBInfo()->SetCleanupDisk(CanCleanupDisk(pDownloadQueue, pFileInfo->GetNZBInfo()));
|
||||
}
|
||||
|
||||
EEditAction GroupToFileMap[] = { (EEditAction)0, eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause,
|
||||
eaFileResume, eaFileDelete, eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority, eaFileReorder, eaFileSplit,
|
||||
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete, eaFileDelete, eaFileDelete,
|
||||
eaFileMoveOffset, eaFileMoveTop, eaFileMoveBottom, eaFilePause, eaFileResume, eaFileDelete,
|
||||
eaFilePauseAllPars, eaFilePauseExtraPars, eaFileSetPriority,
|
||||
(EEditAction)0, (EEditAction)0, (EEditAction)0 };
|
||||
|
||||
@@ -649,7 +629,7 @@ void QueueEditor::AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pID
|
||||
}
|
||||
if (iOffset > 0)
|
||||
{
|
||||
for (int i = iNum + 1; i <= (int)cGroupList.size() - iOffset; i++)
|
||||
for (unsigned int i = iNum + 1; i <= cGroupList.size() - iOffset; i++)
|
||||
{
|
||||
if (!ItemExists(&cAffectedGroupList, cGroupList[i]))
|
||||
{
|
||||
@@ -835,7 +815,7 @@ void QueueEditor::SetNZBName(NZBInfo* pNZBInfo, const char* szName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if deletion of already downloaded files is possible (when nzb is deleted from queue).
|
||||
* Check if deletion of already downloaded files is possible (when nzb id deleted from queue).
|
||||
* The deletion is most always possible, except the case if all remaining files in queue
|
||||
* (belonging to this nzb-file) are PARS.
|
||||
*/
|
||||
@@ -844,18 +824,15 @@ bool QueueEditor::CanCleanupDisk(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInf
|
||||
for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (pFileInfo->GetNZBInfo() == pNZBInfo)
|
||||
{
|
||||
char szLoFileName[1024];
|
||||
strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
|
||||
szLoFileName[1024-1] = '\0';
|
||||
for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
char szLoFileName[1024];
|
||||
strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
|
||||
szLoFileName[1024-1] = '\0';
|
||||
for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
if (!strstr(szLoFileName, ".par2"))
|
||||
{
|
||||
// non-par file found
|
||||
return true;
|
||||
}
|
||||
if (!strstr(szLoFileName, ".par2"))
|
||||
{
|
||||
// non-par file found
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,7 +953,7 @@ void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
|
||||
{
|
||||
*szValue = '\0';
|
||||
szValue++;
|
||||
pNZBInfo->GetParameters()->SetParameter(szStr, szValue);
|
||||
pNZBInfo->SetParameter(szStr, szValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -985,47 +962,3 @@ void QueueEditor::SetNZBParameter(NZBInfo* pNZBInfo, const char* szParamString)
|
||||
|
||||
free(szStr);
|
||||
}
|
||||
|
||||
void QueueEditor::SetNZBDupeParam(NZBInfo* pNZBInfo, EEditAction eAction, const char* szText)
|
||||
{
|
||||
debug("QueueEditor: setting dupe parameter %i='%s' for '%s'", (int)eAction, szText, pNZBInfo->GetName());
|
||||
|
||||
switch (eAction)
|
||||
{
|
||||
case eaGroupSetDupeKey:
|
||||
pNZBInfo->SetDupeKey(szText);
|
||||
break;
|
||||
|
||||
case eaGroupSetDupeScore:
|
||||
pNZBInfo->SetDupeScore(atoi(szText));
|
||||
break;
|
||||
|
||||
case eaGroupSetDupeMode:
|
||||
{
|
||||
EDupeMode eMode = dmScore;
|
||||
if (!strcasecmp(szText, "SCORE"))
|
||||
{
|
||||
eMode = dmScore;
|
||||
}
|
||||
else if (!strcasecmp(szText, "ALL"))
|
||||
{
|
||||
eMode = dmAll;
|
||||
}
|
||||
else if (!strcasecmp(szText, "FORCE"))
|
||||
{
|
||||
eMode = dmForce;
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not set duplicate mode for %s: incorrect mode (%s)", pNZBInfo->GetName(), szText);
|
||||
return;
|
||||
}
|
||||
pNZBInfo->SetDupeMode(eMode);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// suppress compiler warning
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
* This file if part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -33,7 +33,6 @@
|
||||
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
|
||||
@@ -53,18 +52,13 @@ public:
|
||||
eaGroupPause,
|
||||
eaGroupResume,
|
||||
eaGroupDelete,
|
||||
eaGroupDupeDelete,
|
||||
eaGroupFinalDelete,
|
||||
eaGroupPauseAllPars,
|
||||
eaGroupPauseExtraPars,
|
||||
eaGroupSetPriority,
|
||||
eaGroupSetCategory,
|
||||
eaGroupMerge,
|
||||
eaGroupSetParameter,
|
||||
eaGroupSetName,
|
||||
eaGroupSetDupeKey,
|
||||
eaGroupSetDupeScore,
|
||||
eaGroupSetDupeMode
|
||||
eaGroupSetName
|
||||
};
|
||||
|
||||
enum EMatchMode
|
||||
@@ -107,7 +101,6 @@ private:
|
||||
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);
|
||||
|
||||
@@ -76,7 +76,10 @@ RemoteClient::RemoteClient()
|
||||
|
||||
RemoteClient::~RemoteClient()
|
||||
{
|
||||
delete m_pConnection;
|
||||
if (m_pConnection)
|
||||
{
|
||||
delete m_pConnection;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::printf(const char * msg,...)
|
||||
@@ -210,7 +213,10 @@ bool RemoteClient::RequestServerDownload(const char* szFilename, const char* szC
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
free(szBuffer);
|
||||
if (szBuffer)
|
||||
{
|
||||
free(szBuffer);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -244,7 +250,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
pNZBInfo->SetQueuedFilename(m_szQueuedFilename);
|
||||
pNZBInfo->m_bMatch = ntohl(pListAnswer->m_bMatch);
|
||||
|
||||
pNZBInfo->Retain();
|
||||
pNZBInfo->AddReference();
|
||||
pDownloadQueue->GetNZBInfoList()->Add(pNZBInfo);
|
||||
|
||||
pBufPtr += sizeof(SNZBListResponseNZBEntry) + ntohl(pListAnswer->m_iFilenameLen) +
|
||||
@@ -261,7 +267,7 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
|
||||
const char* szValue = pBufPtr + sizeof(SNZBListResponsePPPEntry) + ntohl(pListAnswer->m_iNameLen);
|
||||
|
||||
NZBInfo* pNZBInfo = pDownloadQueue->GetNZBInfoList()->at(ntohl(pListAnswer->m_iNZBIndex) - 1);
|
||||
pNZBInfo->GetParameters()->SetParameter(szName, szValue);
|
||||
pNZBInfo->SetParameter(szName, szValue);
|
||||
|
||||
pBufPtr += sizeof(SNZBListResponsePPPEntry) + ntohl(pListAnswer->m_iNameLen) +
|
||||
ntohl(pListAnswer->m_iValueLen);
|
||||
@@ -521,20 +527,20 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
{
|
||||
if (szParameters[0] == '\0')
|
||||
{
|
||||
strncat(szParameters, " (", sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, " (", 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncat(szParameters, ", ", sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, ", ", 1024);
|
||||
}
|
||||
NZBParameter* pNZBParameter = *it;
|
||||
strncat(szParameters, pNZBParameter->GetName(), sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, "=", sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, pNZBParameter->GetValue(), sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, pNZBParameter->GetName(), 1024);
|
||||
strncat(szParameters, "=", 1024);
|
||||
strncat(szParameters, pNZBParameter->GetValue(), 1024);
|
||||
}
|
||||
if (szParameters[0] != '\0')
|
||||
{
|
||||
strncat(szParameters, ")", sizeof(szParameters) - strlen(szParameters) - 1);
|
||||
strncat(szParameters, ")", 1024);
|
||||
}
|
||||
|
||||
if (!szPattern || ((MatchedNZBInfo*)pGroupInfo->GetNZBInfo())->m_bMatch)
|
||||
@@ -545,6 +551,8 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
szPaused, szThreads, szCategory, szParameters);
|
||||
iMatches++;
|
||||
}
|
||||
|
||||
delete pGroupInfo;
|
||||
}
|
||||
|
||||
for (FileQueue::iterator it = cRemoteQueue.GetFileQueue()->begin(); it != cRemoteQueue.GetFileQueue()->end(); it++)
|
||||
@@ -650,10 +658,10 @@ bool RemoteClient::RequestServerList(bool bFiles, bool bGroups, const char* szPa
|
||||
|
||||
if (ntohl(ListResponse.m_iPostJobCount) > 0 || ntohl(ListResponse.m_bPostPaused))
|
||||
{
|
||||
strncat(szServerState, strlen(szServerState) > 0 ? ", Post-Processing" : "Post-Processing", sizeof(szServerState) - strlen(szServerState) - 1);
|
||||
strncat(szServerState, strlen(szServerState) > 0 ? ", Post-Processing" : "Post-Processing", sizeof(szServerState));
|
||||
if (ntohl(ListResponse.m_bPostPaused))
|
||||
{
|
||||
strncat(szServerState, " paused", sizeof(szServerState) - strlen(szServerState) - 1);
|
||||
strncat(szServerState, " paused", sizeof(szServerState));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,10 @@ RemoteServer::~RemoteServer()
|
||||
{
|
||||
debug("Destroying RemoteServer");
|
||||
|
||||
delete m_pConnection;
|
||||
if (m_pConnection)
|
||||
{
|
||||
delete m_pConnection;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteServer::Run()
|
||||
|
||||
190
Scanner.cpp
190
Scanner.cpp
@@ -67,24 +67,23 @@ 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, EAddStatus* pAddStatus)
|
||||
Scanner::QueueData::QueueData(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused)
|
||||
{
|
||||
m_szFilename = strdup(szFilename);
|
||||
m_szNZBName = strdup(szNZBName);
|
||||
m_szCategory = strdup(szCategory ? szCategory : "");
|
||||
m_iPriority = iPriority;
|
||||
m_szDupeKey = strdup(szDupeKey ? szDupeKey : "");
|
||||
m_iDupeScore = iDupeScore;
|
||||
m_eDupeMode = eDupeMode;
|
||||
m_bAddTop = bAddTop;
|
||||
m_bAddPaused = bAddPaused;
|
||||
m_pAddStatus = pAddStatus;
|
||||
|
||||
if (pParameters)
|
||||
{
|
||||
m_Parameters.CopyFrom(pParameters);
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
NZBParameter* pNZBParameter = *it;
|
||||
m_Parameters.SetParameter(pNZBParameter->GetName(), pNZBParameter->GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,15 +92,12 @@ Scanner::QueueData::~QueueData()
|
||||
free(m_szFilename);
|
||||
free(m_szNZBName);
|
||||
free(m_szCategory);
|
||||
free(m_szDupeKey);
|
||||
}
|
||||
|
||||
void Scanner::QueueData::SetAddStatus(EAddStatus eAddStatus)
|
||||
{
|
||||
if (m_pAddStatus)
|
||||
for (NZBParameterList::iterator it = m_Parameters.begin(); it != m_Parameters.end(); it++)
|
||||
{
|
||||
*m_pAddStatus = eAddStatus;
|
||||
delete *it;
|
||||
}
|
||||
m_Parameters.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -182,10 +178,10 @@ void Scanner::Check()
|
||||
}
|
||||
|
||||
DropOldFiles();
|
||||
ClearQueueList();
|
||||
}
|
||||
m_iNZBDirInterval += 200;
|
||||
|
||||
ClearQueueList();
|
||||
m_mutexScan.Unlock();
|
||||
}
|
||||
|
||||
@@ -323,8 +319,7 @@ void Scanner::DropOldFiles()
|
||||
}
|
||||
}
|
||||
|
||||
void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename,
|
||||
const char* szFullFilename, const char* szCategory)
|
||||
void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename, const char* szFullFilename, const char* szCategory)
|
||||
{
|
||||
const char* szExtension = strrchr(szBaseFilename, '.');
|
||||
if (!szExtension)
|
||||
@@ -338,35 +333,22 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
|
||||
int iPriority = 0;
|
||||
bool bAddTop = false;
|
||||
bool bAddPaused = false;
|
||||
const char* szDupeKey = NULL;
|
||||
int iDupeScore = 0;
|
||||
EDupeMode eDupeMode = dmScore;
|
||||
EAddStatus eAddStatus = asSkipped;
|
||||
bool bAdded = false;
|
||||
QueueData* pQueueData = NULL;
|
||||
|
||||
for (QueueList::iterator it = m_QueueList.begin(); it != m_QueueList.end(); it++)
|
||||
{
|
||||
QueueData* pQueueData1 = *it;
|
||||
if (Util::SameFilename(pQueueData1->GetFilename(), szFullFilename))
|
||||
QueueData* pQueueData = *it;
|
||||
if (Util::SameFilename(pQueueData->GetFilename(), szFullFilename))
|
||||
{
|
||||
pQueueData = pQueueData1;
|
||||
free(szNZBName);
|
||||
szNZBName = strdup(pQueueData->GetNZBName());
|
||||
free(szNZBCategory);
|
||||
szNZBCategory = strdup(pQueueData->GetCategory());
|
||||
iPriority = pQueueData->GetPriority();
|
||||
szDupeKey = pQueueData->GetDupeKey();
|
||||
iDupeScore = pQueueData->GetDupeScore();
|
||||
eDupeMode = pQueueData->GetDupeMode();
|
||||
bAddTop = pQueueData->GetAddTop();
|
||||
bAddPaused = pQueueData->GetAddPaused();
|
||||
pParameters->CopyFrom(pQueueData->GetParameters());
|
||||
}
|
||||
}
|
||||
|
||||
InitPPParameters(szNZBCategory, pParameters);
|
||||
|
||||
bool bExists = true;
|
||||
|
||||
if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed"))
|
||||
@@ -392,77 +374,31 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
|
||||
bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024);
|
||||
if (bRenameOK)
|
||||
{
|
||||
bAdded = AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority,
|
||||
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused);
|
||||
AddFileToQueue(szRenamedName, szNZBName, szNZBCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
}
|
||||
else
|
||||
{
|
||||
char szSysErrStr[256];
|
||||
error("Could not rename file %s to %s: %s", szFullFilename, szRenamedName, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
eAddStatus = asFailed;
|
||||
}
|
||||
}
|
||||
else if (bExists && !strcasecmp(szExtension, ".nzb"))
|
||||
{
|
||||
bAdded = AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority,
|
||||
szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused);
|
||||
AddFileToQueue(szFullFilename, szNZBName, szNZBCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
}
|
||||
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
pParameters->clear();
|
||||
delete pParameters;
|
||||
|
||||
free(szNZBName);
|
||||
free(szNZBCategory);
|
||||
|
||||
if (pQueueData)
|
||||
{
|
||||
pQueueData->SetAddStatus(eAddStatus == asFailed ? asFailed : bAdded ? asSuccess : asSkipped);
|
||||
}
|
||||
}
|
||||
|
||||
void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParameters)
|
||||
{
|
||||
bool bUnpack = g_pOptions->GetUnpack();
|
||||
const char* szDefScript = g_pOptions->GetDefScript();
|
||||
|
||||
if (szCategory && *szCategory)
|
||||
{
|
||||
Options::Category* pCategory = g_pOptions->FindCategory(szCategory, false);
|
||||
if (pCategory)
|
||||
{
|
||||
bUnpack = pCategory->GetUnpack();
|
||||
if (pCategory->GetDefScript() && *pCategory->GetDefScript())
|
||||
{
|
||||
szDefScript = pCategory->GetDefScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pParameters->SetParameter("*Unpack:", bUnpack ? "yes" : "no");
|
||||
|
||||
if (szDefScript && *szDefScript)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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,
|
||||
void Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused)
|
||||
{
|
||||
const char* szBasename = Util::BaseFileName(szFilename);
|
||||
@@ -470,49 +406,36 @@ bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, cons
|
||||
info("Collection %s found", szBasename);
|
||||
|
||||
NZBFile* pNZBFile = NZBFile::Create(szFilename, szCategory);
|
||||
bool bOK = pNZBFile != NULL;
|
||||
if (!bOK)
|
||||
if (!pNZBFile)
|
||||
{
|
||||
error("Could not add collection %s to queue", szBasename);
|
||||
}
|
||||
|
||||
char bakname2[1024];
|
||||
if (!Util::RenameBak(szFilename, pNZBFile ? "queued" : "error", false, bakname2, 1024))
|
||||
bool bRenameOK = Util::RenameBak(szFilename, pNZBFile ? "queued" : "error", false, bakname2, 1024);
|
||||
if (!bRenameOK)
|
||||
{
|
||||
bOK = false;
|
||||
char szSysErrStr[256];
|
||||
error("Could not rename file %s to %s: %s", szFilename, bakname2, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
}
|
||||
|
||||
if (bOK)
|
||||
if (pNZBFile && bRenameOK)
|
||||
{
|
||||
pNZBFile->GetNZBInfo()->SetQueuedFilename(bakname2);
|
||||
|
||||
if (szNZBName && strlen(szNZBName) > 0)
|
||||
{
|
||||
pNZBFile->GetNZBInfo()->SetName(NULL);
|
||||
#ifdef WIN32
|
||||
char* szAnsiFilename = strdup(szNZBName);
|
||||
WebUtil::Utf8ToAnsi(szAnsiFilename, strlen(szAnsiFilename) + 1);
|
||||
pNZBFile->GetNZBInfo()->SetFilename(szAnsiFilename);
|
||||
free(szAnsiFilename);
|
||||
#else
|
||||
pNZBFile->GetNZBInfo()->SetFilename(szNZBName);
|
||||
#endif
|
||||
pNZBFile->GetNZBInfo()->BuildDestDirName();
|
||||
}
|
||||
|
||||
pNZBFile->GetNZBInfo()->SetDupeKey(szDupeKey);
|
||||
pNZBFile->GetNZBInfo()->SetDupeScore(iDupeScore);
|
||||
pNZBFile->GetNZBInfo()->SetDupeMode(eDupeMode);
|
||||
|
||||
if (pNZBFile->GetPassword())
|
||||
for (NZBParameterList::iterator it = pParameters->begin(); it != pParameters->end(); it++)
|
||||
{
|
||||
pNZBFile->GetNZBInfo()->GetParameters()->SetParameter("*Unpack:Password", pNZBFile->GetPassword());
|
||||
NZBParameter* pParameter = *it;
|
||||
pNZBFile->GetNZBInfo()->SetParameter(pParameter->GetName(), pParameter->GetValue());
|
||||
}
|
||||
|
||||
pNZBFile->GetNZBInfo()->GetParameters()->CopyFrom(pParameters);
|
||||
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
@@ -521,11 +444,13 @@ bool Scanner::AddFileToQueue(const char* szFilename, const char* szNZBName, cons
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, bAddTop);
|
||||
info("Collection %s added to queue", szBasename);
|
||||
}
|
||||
|
||||
delete pNZBFile;
|
||||
|
||||
return bOK;
|
||||
if (pNZBFile)
|
||||
{
|
||||
delete pNZBFile;
|
||||
}
|
||||
}
|
||||
|
||||
void Scanner::ScanNZBDir(bool bSyncMode)
|
||||
@@ -541,12 +466,10 @@ void Scanner::ScanNZBDir(bool bSyncMode)
|
||||
}
|
||||
}
|
||||
|
||||
Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char* szCategory,
|
||||
int iPriority, const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
|
||||
bool Scanner::AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused,
|
||||
const char* szFileName, const char* szBuffer, int iBufSize)
|
||||
const char* szFileName, const char* szBuffer, int iBufSize, bool bSyncMode)
|
||||
{
|
||||
bool bNZB = false;
|
||||
char szTempFileName[1024];
|
||||
|
||||
if (szFileName)
|
||||
@@ -567,13 +490,8 @@ Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char*
|
||||
if (!Util::SaveBufferIntoFile(szTempFileName, szBuffer, iBufSize))
|
||||
{
|
||||
error("Could not create file %s", szTempFileName);
|
||||
return asFailed;
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
strncpy(buf, szBuffer, 1024);
|
||||
buf[1024-1] = '\0';
|
||||
bNZB = !strncmp(buf, "<?xml", 5) && strstr(buf, "<nzb");
|
||||
}
|
||||
|
||||
// move file into NzbDir, make sure the file name is unique
|
||||
@@ -582,16 +500,6 @@ Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char*
|
||||
szValidNZBName[1024-1] = '\0';
|
||||
Util::MakeValidFilename(szValidNZBName, '_', false);
|
||||
|
||||
#ifdef WIN32
|
||||
WebUtil::Utf8ToAnsi(szValidNZBName, 1024);
|
||||
#endif
|
||||
|
||||
const char* szExtension = strrchr(szNZBName, '.');
|
||||
if (bNZB && (!szExtension || strcasecmp(szExtension, ".nzb")))
|
||||
{
|
||||
strncat(szValidNZBName, ".nzb", 1024 - strlen(szValidNZBName) - 1);
|
||||
}
|
||||
|
||||
char szScanFileName[1024];
|
||||
snprintf(szScanFileName, 1024, "%s%s", g_pOptions->GetNzbDir(), szValidNZBName);
|
||||
|
||||
@@ -617,35 +525,21 @@ Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char*
|
||||
iNum++;
|
||||
}
|
||||
|
||||
m_mutexScan.Lock();
|
||||
|
||||
if (!Util::MoveFile(szTempFileName, szScanFileName))
|
||||
{
|
||||
char szSysErrStr[256];
|
||||
error("Could not move file %s to %s: %s", szTempFileName, szScanFileName, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
|
||||
remove(szTempFileName);
|
||||
m_mutexScan.Unlock(); // UNLOCK
|
||||
return asFailed;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* szUseCategory = strdup(szCategory ? szCategory : "");
|
||||
Options::Category *pCategory = g_pOptions->FindCategory(szCategory, true);
|
||||
if (pCategory && strcmp(szCategory, pCategory->GetName()))
|
||||
{
|
||||
free(szUseCategory);
|
||||
szUseCategory = strdup(pCategory->GetName());
|
||||
detail("Category %s matched to %s for %s", szCategory, szUseCategory, szNZBName);
|
||||
}
|
||||
QueueData* pQueueData = new QueueData(szScanFileName, szNZBName, szCategory, iPriority, pParameters, bAddTop, bAddPaused);
|
||||
|
||||
EAddStatus eAddStatus = asSkipped;
|
||||
QueueData* pQueueData = new QueueData(szScanFileName, szNZBName, szUseCategory,
|
||||
iPriority, szDupeKey, iDupeScore, eDupeMode, pParameters, bAddTop, bAddPaused, &eAddStatus);
|
||||
free(szUseCategory);
|
||||
m_mutexScan.Lock();
|
||||
m_QueueList.push_back(pQueueData);
|
||||
|
||||
m_mutexScan.Unlock();
|
||||
|
||||
ScanNZBDir(true);
|
||||
ScanNZBDir(bSyncMode);
|
||||
|
||||
return eAddStatus;
|
||||
return true;
|
||||
}
|
||||
|
||||
35
Scanner.h
35
Scanner.h
@@ -33,14 +33,6 @@
|
||||
|
||||
class Scanner
|
||||
{
|
||||
public:
|
||||
enum EAddStatus
|
||||
{
|
||||
asSkipped,
|
||||
asSuccess,
|
||||
asFailed
|
||||
};
|
||||
|
||||
private:
|
||||
class FileData
|
||||
{
|
||||
@@ -68,30 +60,21 @@ private:
|
||||
char* m_szNZBName;
|
||||
char* m_szCategory;
|
||||
int m_iPriority;
|
||||
char* m_szDupeKey;
|
||||
int m_iDupeScore;
|
||||
EDupeMode m_eDupeMode;
|
||||
NZBParameterList m_Parameters;
|
||||
bool m_bAddTop;
|
||||
bool m_bAddPaused;
|
||||
EAddStatus* m_pAddStatus;
|
||||
|
||||
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, EAddStatus* pAddStatus);
|
||||
QueueData(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused);
|
||||
~QueueData();
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
const char* GetNZBName() { return m_szNZBName; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
int GetPriority() { return m_iPriority; }
|
||||
const char* GetDupeKey() { return m_szDupeKey; }
|
||||
int GetDupeScore() { return m_iDupeScore; }
|
||||
EDupeMode GetDupeMode() { return m_eDupeMode; }
|
||||
NZBParameterList* GetParameters() { return &m_Parameters; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
bool GetAddPaused() { return m_bAddPaused; }
|
||||
void SetAddStatus(EAddStatus eAddStatus);
|
||||
};
|
||||
|
||||
typedef std::deque<QueueData*> QueueList;
|
||||
@@ -106,13 +89,10 @@ private:
|
||||
Mutex m_mutexScan;
|
||||
|
||||
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,
|
||||
void AddFileToQueue(const char* szFilename, const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused);
|
||||
void ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename,
|
||||
const char* szFullFilename, const char* szCategory);
|
||||
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();
|
||||
|
||||
@@ -121,10 +101,9 @@ public:
|
||||
~Scanner();
|
||||
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,
|
||||
const char* szFileName, const char* szBuffer, int iBufSize);
|
||||
bool AddExternalFile(const char* szNZBName, const char* szCategory, int iPriority,
|
||||
NZBParameterList* pParameters, bool bAddPaused, bool bAddTop,
|
||||
const char* szFileName, const char* szBuffer, int iBufSize, bool bSyncMode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
179
Scheduler.cpp
179
Scheduler.cpp
@@ -42,28 +42,31 @@
|
||||
#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)
|
||||
Scheduler::Task::Task(int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand,
|
||||
int iDownloadRate, const char* szProcess)
|
||||
{
|
||||
m_iHours = iHours;
|
||||
m_iMinutes = iMinutes;
|
||||
m_iWeekDaysBits = iWeekDaysBits;
|
||||
m_eCommand = eCommand;
|
||||
m_szParam = szParam ? strdup(szParam) : NULL;
|
||||
m_iDownloadRate = iDownloadRate;
|
||||
m_szProcess = NULL;
|
||||
if (szProcess)
|
||||
{
|
||||
m_szProcess = strdup(szProcess);
|
||||
}
|
||||
m_tLastExecuted = 0;
|
||||
}
|
||||
|
||||
Scheduler::Task::~Task()
|
||||
{
|
||||
free(m_szParam);
|
||||
if (m_szProcess)
|
||||
{
|
||||
free(m_szProcess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +112,9 @@ void Scheduler::FirstCheck()
|
||||
m_tLastCheck = tCurrent - 60*60*24*7;
|
||||
m_bDetectClockChanges = false;
|
||||
m_bExecuteProcess = false;
|
||||
m_bDownloadRateChanged = false;
|
||||
m_bPauseDownloadChanged = false;
|
||||
m_bPauseScanChanged = false;
|
||||
CheckTasks();
|
||||
}
|
||||
|
||||
@@ -116,16 +122,21 @@ void Scheduler::IntervalCheck()
|
||||
{
|
||||
m_bDetectClockChanges = true;
|
||||
m_bExecuteProcess = true;
|
||||
m_bDownloadRateChanged = false;
|
||||
m_bPauseDownloadChanged = false;
|
||||
m_bPauseScanChanged = false;
|
||||
CheckTasks();
|
||||
}
|
||||
|
||||
void Scheduler::CheckTasks()
|
||||
{
|
||||
PrepareLog();
|
||||
|
||||
m_mutexTaskList.Lock();
|
||||
|
||||
time_t tCurrent = time(NULL);
|
||||
struct tm tmCurrent;
|
||||
localtime_r(&tCurrent, &tmCurrent);
|
||||
|
||||
struct tm tmLastCheck;
|
||||
|
||||
if (m_bDetectClockChanges)
|
||||
{
|
||||
@@ -145,12 +156,9 @@ void Scheduler::CheckTasks()
|
||||
}
|
||||
}
|
||||
|
||||
tm tmCurrent;
|
||||
localtime_r(&tCurrent, &tmCurrent);
|
||||
tm tmLastCheck;
|
||||
localtime_r(&m_tLastCheck, &tmLastCheck);
|
||||
|
||||
tm tmLoop;
|
||||
struct tm tmLoop;
|
||||
memcpy(&tmLoop, &tmLastCheck, sizeof(tmLastCheck));
|
||||
tmLoop.tm_hour = tmCurrent.tm_hour;
|
||||
tmLoop.tm_min = tmCurrent.tm_min;
|
||||
@@ -164,15 +172,13 @@ void Scheduler::CheckTasks()
|
||||
Task* pTask = *it;
|
||||
if (pTask->m_tLastExecuted != tLoop)
|
||||
{
|
||||
tm tmAppoint;
|
||||
struct 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)
|
||||
{
|
||||
@@ -198,24 +204,25 @@ void Scheduler::CheckTasks()
|
||||
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]);
|
||||
if (pTask->m_eCommand == scDownloadRate)
|
||||
{
|
||||
debug("Executing scheduled command: Set download rate to %i", pTask->m_iDownloadRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* szCommandName[] = { "Pause", "Unpause", "Set download rate", "Execute program", "Pause Scan", "Unpause Scan" };
|
||||
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;
|
||||
}
|
||||
m_iDownloadRate = pTask->m_iDownloadRate;
|
||||
m_bDownloadRateChanged = true;
|
||||
break;
|
||||
|
||||
case scPauseDownload:
|
||||
@@ -227,126 +234,14 @@ void Scheduler::ExecuteTask(Task* pTask)
|
||||
case scProcess:
|
||||
if (m_bExecuteProcess)
|
||||
{
|
||||
SchedulerScriptController::StartScript(pTask->m_szParam);
|
||||
SchedulerScriptController::StartScript(pTask->m_szProcess);
|
||||
}
|
||||
break;
|
||||
|
||||
case scPauseScan:
|
||||
case scUnpauseScan:
|
||||
g_pOptions->SetPauseScan(pTask->m_eCommand == scPauseScan);
|
||||
m_bPauseScan = 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);
|
||||
}
|
||||
|
||||
26
Scheduler.h
26
Scheduler.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2008-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2008-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,7 +27,6 @@
|
||||
#define SCHEDULER_H
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
#include "Thread.h"
|
||||
@@ -42,10 +41,7 @@ public:
|
||||
scDownloadRate,
|
||||
scProcess,
|
||||
scPauseScan,
|
||||
scUnpauseScan,
|
||||
scActivateServer,
|
||||
scDeactivateServer,
|
||||
scFetchFeed
|
||||
scUnpauseScan
|
||||
};
|
||||
|
||||
class Task
|
||||
@@ -55,12 +51,13 @@ public:
|
||||
int m_iMinutes;
|
||||
int m_iWeekDaysBits;
|
||||
ECommand m_eCommand;
|
||||
char* m_szParam;
|
||||
int m_iDownloadRate;
|
||||
char* m_szProcess;
|
||||
time_t m_tLastExecuted;
|
||||
|
||||
public:
|
||||
Task(int iHours, int iMinutes, int iWeekDaysBits, ECommand eCommand,
|
||||
const char* szParam);
|
||||
int iDownloadRate, const char* szProcess);
|
||||
~Task();
|
||||
friend class Scheduler;
|
||||
};
|
||||
@@ -68,7 +65,6 @@ public:
|
||||
private:
|
||||
|
||||
typedef std::list<Task*> TaskList;
|
||||
typedef std::vector<bool> ServerStatusList;
|
||||
|
||||
TaskList m_TaskList;
|
||||
Mutex m_mutexTaskList;
|
||||
@@ -76,18 +72,14 @@ private:
|
||||
bool m_bDetectClockChanges;
|
||||
bool m_bDownloadRateChanged;
|
||||
bool m_bExecuteProcess;
|
||||
int m_iDownloadRate;
|
||||
bool m_bPauseDownloadChanged;
|
||||
bool m_bPauseDownload;
|
||||
bool m_bPauseScanChanged;
|
||||
bool m_bServerChanged;
|
||||
ServerStatusList m_ServerStatusList;
|
||||
bool m_bPauseScan;
|
||||
void ExecuteTask(Task* pTask);
|
||||
void CheckTasks();
|
||||
static bool CompareTasks(Scheduler::Task* pTask1, Scheduler::Task* pTask2);
|
||||
void PrepareLog();
|
||||
void PrintLog();
|
||||
void EditServer(bool bActive, const char* szServerList);
|
||||
void FetchFeed(const char* szFeedList);
|
||||
|
||||
public:
|
||||
Scheduler();
|
||||
@@ -95,8 +87,12 @@ public:
|
||||
void AddTask(Task* pTask);
|
||||
void FirstCheck();
|
||||
void IntervalCheck();
|
||||
bool GetDownloadRateChanged() { return m_bDownloadRateChanged; }
|
||||
int GetDownloadRate() { return m_iDownloadRate; }
|
||||
bool GetPauseDownloadChanged() { return m_bPauseDownloadChanged; }
|
||||
bool GetPauseDownload() { return m_bPauseDownload; }
|
||||
bool GetPauseScanChanged() { return m_bPauseScanChanged; }
|
||||
bool GetPauseScan() { return m_bPauseScan; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -199,7 +199,6 @@ ScriptController::ScriptController()
|
||||
m_szInfoName = NULL;
|
||||
m_szLogPrefix = NULL;
|
||||
m_bTerminated = false;
|
||||
m_bDetached = false;
|
||||
m_environmentStrings.InitFromCurrentProcess();
|
||||
}
|
||||
|
||||
@@ -229,14 +228,6 @@ void ScriptController::SetEnvVar(const char* szName, const char* szValue)
|
||||
m_environmentStrings.Append(szVar);
|
||||
}
|
||||
|
||||
void ScriptController::SetIntEnvVar(const char* szName, int iValue)
|
||||
{
|
||||
char szValue[1024];
|
||||
snprintf(szValue, 10, "%i", iValue);
|
||||
szValue[1024-1] = '\0';
|
||||
SetEnvVar(szName, szValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* If szStripPrefix is not NULL, only options, whose names start with the prefix
|
||||
* are processed. The prefix is then stripped from the names.
|
||||
@@ -277,26 +268,15 @@ void ScriptController::PrepareEnvParameters(NZBInfo* pNZBInfo, const char* szStr
|
||||
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);
|
||||
SetEnvVarSpecial("NZBPR", pParameter->GetName() + iPrefixLen, pParameter->GetValue());
|
||||
}
|
||||
else if (!szStripPrefix)
|
||||
{
|
||||
SetEnvVarSpecial("NZBPR", pParameter->GetName(), szValue);
|
||||
SetEnvVarSpecial("NZBPR", pParameter->GetName(), pParameter->GetValue());
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
free(szAnsiValue);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,15 +497,6 @@ int ScriptController::Execute()
|
||||
chdir(m_szWorkingDir);
|
||||
environ = pEnvironmentStrings;
|
||||
execvp(m_szScript, (char* const*)m_szArgs);
|
||||
|
||||
if (errno == EACCES)
|
||||
{
|
||||
fprintf(stdout, "[WARNING] Fixing permissions for %s\n", m_szScript);
|
||||
fflush(stdout);
|
||||
Util::FixExecPermission(m_szScript);
|
||||
execvp(m_szScript, (char* const*)m_szArgs);
|
||||
}
|
||||
|
||||
// NOTE: the text "[ERROR] Could not start " is checked later,
|
||||
// by changing adjust the dependent code below.
|
||||
fprintf(stdout, "[ERROR] Could not start %s: %s", m_szScript, strerror(errno));
|
||||
@@ -546,8 +517,8 @@ int ScriptController::Execute()
|
||||
#endif
|
||||
|
||||
// open the read end
|
||||
m_pReadpipe = fdopen(pipein, "r");
|
||||
if (!m_pReadpipe)
|
||||
FILE* readpipe = fdopen(pipein, "r");
|
||||
if (!readpipe)
|
||||
{
|
||||
error("Could not open pipe to %s", m_szInfoName);
|
||||
return -1;
|
||||
@@ -566,9 +537,9 @@ int ScriptController::Execute()
|
||||
debug("Entering pipe-loop");
|
||||
bool bFirstLine = true;
|
||||
bool bStartError = false;
|
||||
while (!m_bTerminated && !m_bDetached && !feof(m_pReadpipe))
|
||||
while (!feof(readpipe) && !m_bTerminated)
|
||||
{
|
||||
if (ReadLine(buf, 10240, m_pReadpipe) && m_pReadpipe)
|
||||
if (ReadLine(buf, 10240, readpipe))
|
||||
{
|
||||
#ifdef CHILD_WATCHDOG
|
||||
if (!bChildConfirmed)
|
||||
@@ -603,10 +574,7 @@ int ScriptController::Execute()
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
if (m_pReadpipe)
|
||||
{
|
||||
fclose(m_pReadpipe);
|
||||
}
|
||||
fclose(readpipe);
|
||||
|
||||
if (m_bTerminated)
|
||||
{
|
||||
@@ -615,8 +583,6 @@ int ScriptController::Execute()
|
||||
|
||||
iExitCode = 0;
|
||||
|
||||
if (!m_bTerminated && !m_bDetached)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WaitForSingleObject(m_hProcess, INFINITE);
|
||||
DWORD dExitCode = 0;
|
||||
@@ -634,7 +600,6 @@ int ScriptController::Execute()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CHILD_WATCHDOG
|
||||
} // while (!bChildConfirmed && !m_bTerminated)
|
||||
@@ -674,16 +639,6 @@ void ScriptController::Terminate()
|
||||
debug("Stopped %s", m_szInfoName);
|
||||
}
|
||||
|
||||
void ScriptController::Detach()
|
||||
{
|
||||
debug("Detaching %s", m_szInfoName);
|
||||
m_bDetached = true;
|
||||
FILE* pReadpipe = m_pReadpipe;
|
||||
m_pReadpipe = NULL;
|
||||
fclose(pReadpipe);
|
||||
}
|
||||
|
||||
|
||||
bool ScriptController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
return fgets(szBuf, iBufSize, pStream);
|
||||
@@ -703,27 +658,27 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
|
||||
if (!strncmp(szText, "[INFO] ", 7))
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s", szText + 7);
|
||||
PrintMessage(Message::mkInfo, szText + 7);
|
||||
}
|
||||
else if (!strncmp(szText, "[WARNING] ", 10))
|
||||
{
|
||||
PrintMessage(Message::mkWarning, "%s", szText + 10);
|
||||
PrintMessage(Message::mkWarning, szText + 10);
|
||||
}
|
||||
else if (!strncmp(szText, "[ERROR] ", 8))
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s", szText + 8);
|
||||
PrintMessage(Message::mkError, szText + 8);
|
||||
}
|
||||
else if (!strncmp(szText, "[DETAIL] ", 9))
|
||||
{
|
||||
PrintMessage(Message::mkDetail, "%s", szText + 9);
|
||||
PrintMessage(Message::mkDetail, szText + 9);
|
||||
}
|
||||
else if (!strncmp(szText, "[DEBUG] ", 8))
|
||||
{
|
||||
PrintMessage(Message::mkDebug, "%s", szText + 8);
|
||||
PrintMessage(Message::mkDebug, szText + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s", szText);
|
||||
PrintMessage(Message::mkInfo, szText);
|
||||
}
|
||||
|
||||
debug("Processing output received from script - completed");
|
||||
@@ -785,7 +740,6 @@ void PostScriptController::StartJob(PostInfo* pPostInfo)
|
||||
pScriptController->m_pPostInfo = pPostInfo;
|
||||
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
|
||||
pScriptController->SetAutoDestroy(false);
|
||||
pScriptController->m_iPrefixLen = 0;
|
||||
|
||||
pPostInfo->SetPostThread(pScriptController);
|
||||
|
||||
@@ -852,7 +806,6 @@ void PostScriptController::ExecuteScript(const char* szScriptName, const char* s
|
||||
SetInfoName(szInfoName);
|
||||
|
||||
SetLogPrefix(szDisplayName);
|
||||
m_iPrefixLen = strlen(szDisplayName) + 2; // 2 = strlen(": ");
|
||||
PrepareParams(szScriptName);
|
||||
|
||||
int iExitCode = Execute();
|
||||
@@ -873,43 +826,46 @@ void PostScriptController::PrepareParams(const char* szScriptName)
|
||||
// the locking is needed for accessing the members of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
|
||||
char szNZBName[1024];
|
||||
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
|
||||
szNZBName[1024-1] = '\0';
|
||||
|
||||
int iParStatus[] = { 0, 0, 1, 2, 3, 4 };
|
||||
char szParStatus[10];
|
||||
snprintf(szParStatus, 10, "%i", iParStatus[m_pPostInfo->GetNZBInfo()->GetParStatus()]);
|
||||
szParStatus[10-1] = '\0';
|
||||
|
||||
int iUnpackStatus[] = { 0, 0, 1, 2 };
|
||||
char szUnpackStatus[10];
|
||||
snprintf(szUnpackStatus, 10, "%i", iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
|
||||
szUnpackStatus[10-1] = '\0';
|
||||
|
||||
char szDestDir[1024];
|
||||
strncpy(szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
|
||||
szDestDir[1024-1] = '\0';
|
||||
|
||||
char szNZBID[10];
|
||||
snprintf(szNZBID, 10, "%i", m_pPostInfo->GetNZBInfo()->GetID());
|
||||
szNZBID[10-1] = '\0';
|
||||
|
||||
char szNZBFilename[1024];
|
||||
strncpy(szNZBFilename, m_pPostInfo->GetNZBInfo()->GetFilename(), 1024);
|
||||
szNZBFilename[1024-1] = '\0';
|
||||
|
||||
char szCategory[1024];
|
||||
strncpy(szCategory, m_pPostInfo->GetNZBInfo()->GetCategory(), 1024);
|
||||
szCategory[1024-1] = '\0';
|
||||
|
||||
// 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());
|
||||
}
|
||||
SetEnvVar("NZBPP_NZBNAME", szNZBName);
|
||||
SetEnvVar("NZBPP_NZBID", szNZBID);
|
||||
SetEnvVar("NZBPP_DIRECTORY", szDestDir);
|
||||
SetEnvVar("NZBPP_NZBFILENAME", szNZBFilename);
|
||||
SetEnvVar("NZBPP_PARSTATUS", szParStatus);
|
||||
SetEnvVar("NZBPP_UNPACKSTATUS", szUnpackStatus);
|
||||
SetEnvVar("NZBPP_CATEGORY", szCategory);
|
||||
|
||||
PrepareEnvParameters(m_pPostInfo->GetNZBInfo(), NULL);
|
||||
|
||||
@@ -966,42 +922,9 @@ ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int iExitCode)
|
||||
|
||||
void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
const char* szMsgText = szText + m_iPrefixLen;
|
||||
|
||||
if (!strncmp(szMsgText, "[NZB] ", 6))
|
||||
if (!strncmp(szText, "[HISTORY] ", 10))
|
||||
{
|
||||
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);
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1044,6 +967,45 @@ void PostScriptController::Stop()
|
||||
Terminate();
|
||||
}
|
||||
|
||||
/**
|
||||
* DownloadQueue must be locked prior to call of this function.
|
||||
*/
|
||||
void PostScriptController::InitParamsForNewNZB(NZBInfo* pNZBInfo)
|
||||
{
|
||||
const char* szDefScript = g_pOptions->GetDefScript();
|
||||
|
||||
if (pNZBInfo->GetCategory() && strlen(pNZBInfo->GetCategory()) > 0)
|
||||
{
|
||||
Options::Category* pCategory = g_pOptions->FindCategory(pNZBInfo->GetCategory());
|
||||
if (pCategory && pCategory->GetDefScript() && strlen(pCategory->GetDefScript()) > 0)
|
||||
{
|
||||
szDefScript = pCategory->GetDefScript();
|
||||
}
|
||||
}
|
||||
|
||||
if (!szDefScript || strlen(szDefScript) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
szScriptName = Util::Trim(szScriptName);
|
||||
if (szScriptName[0] != '\0')
|
||||
{
|
||||
char szParam[1024];
|
||||
snprintf(szParam, 1024, "%s:", szScriptName);
|
||||
szParam[1024-1] = '\0';
|
||||
pNZBInfo->GetParameters()->SetParameter(szParam, "yes");
|
||||
}
|
||||
szScriptName = strtok_r(NULL, ",;", &saveptr);
|
||||
}
|
||||
free(szDefScript2);
|
||||
}
|
||||
|
||||
void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory,
|
||||
char** pNZBName, char** pCategory, int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused)
|
||||
@@ -1064,13 +1026,6 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
|
||||
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);
|
||||
@@ -1080,7 +1035,18 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
|
||||
{
|
||||
szDir[iLen-1] = '\0';
|
||||
}
|
||||
pScriptController->SetEnvVar("NZBNP_DIRECTORY", szDir);
|
||||
|
||||
char szPriority[20];
|
||||
snprintf(szPriority, 20, "%i", *iPriority);
|
||||
szPriority[20-1] = '\0';
|
||||
|
||||
char szAddTop[10];
|
||||
snprintf(szAddTop, 10, "%i", *bAddTop ? 1 : 0);
|
||||
szAddTop[10-1] = '\0';
|
||||
|
||||
char szAddPaused[10];
|
||||
snprintf(szAddPaused, 10, "%i", *bAddPaused ? 1 : 0);
|
||||
szAddPaused[10-1] = '\0';
|
||||
|
||||
char szLogPrefix[1024];
|
||||
strncpy(szLogPrefix, Util::BaseFileName(szScript), 1024);
|
||||
@@ -1089,6 +1055,14 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
|
||||
pScriptController->SetLogPrefix(szLogPrefix);
|
||||
pScriptController->m_iPrefixLen = strlen(szLogPrefix) + 2; // 2 = strlen(": ");
|
||||
|
||||
pScriptController->SetEnvVar("NZBNP_DIRECTORY", szDir);
|
||||
pScriptController->SetEnvVar("NZBNP_FILENAME", szNZBFilename);
|
||||
pScriptController->SetEnvVar("NZBNP_NZBNAME", strlen(*pNZBName) > 0 ? *pNZBName : Util::BaseFileName(szNZBFilename));
|
||||
pScriptController->SetEnvVar("NZBNP_CATEGORY", *pCategory);
|
||||
pScriptController->SetEnvVar("NZBNP_PRIORITY", szPriority);
|
||||
pScriptController->SetEnvVar("NZBNP_TOP", szAddTop);
|
||||
pScriptController->SetEnvVar("NZBNP_PAUSED", szAddPaused);
|
||||
|
||||
pScriptController->Execute();
|
||||
|
||||
delete pScriptController;
|
||||
@@ -1176,8 +1150,13 @@ void NZBAddedScriptController::StartScript(DownloadQueue* pDownloadQueue, NZBInf
|
||||
}
|
||||
}
|
||||
|
||||
pScriptController->SetIntEnvVar("NZBNA_LASTID", iLastID);
|
||||
pScriptController->SetIntEnvVar("NZBNA_PRIORITY", iMaxPriority);
|
||||
char buf[100];
|
||||
|
||||
snprintf(buf, 100, "%i", iLastID);
|
||||
pScriptController->SetEnvVar("NZBNA_LASTID", buf);
|
||||
|
||||
snprintf(buf, 100, "%i", iMaxPriority);
|
||||
pScriptController->SetEnvVar("NZBNA_PRIORITY", buf);
|
||||
|
||||
pScriptController->PrepareEnvParameters(pNZBInfo, NULL);
|
||||
|
||||
|
||||
@@ -65,8 +65,6 @@ private:
|
||||
const char* m_szLogPrefix;
|
||||
EnvironmentStrings m_environmentStrings;
|
||||
bool m_bTerminated;
|
||||
bool m_bDetached;
|
||||
FILE* m_pReadpipe;
|
||||
#ifdef WIN32
|
||||
HANDLE m_hProcess;
|
||||
char m_szCmdLine[2048];
|
||||
@@ -90,7 +88,6 @@ public:
|
||||
virtual ~ScriptController();
|
||||
int Execute();
|
||||
void Terminate();
|
||||
void Detach();
|
||||
|
||||
void SetScript(const char* szScript) { m_szScript = szScript; }
|
||||
const char* GetScript() { return m_szScript; }
|
||||
@@ -101,7 +98,6 @@ public:
|
||||
void SetLogPrefix(const char* szLogPrefix) { m_szLogPrefix = szLogPrefix; }
|
||||
void SetEnvVar(const char* szName, const char* szValue);
|
||||
void SetEnvVarSpecial(const char* szPrefix, const char* szName, const char* szValue);
|
||||
void SetIntEnvVar(const char* szName, int iValue);
|
||||
};
|
||||
|
||||
class PostScriptController : public Thread, public ScriptController
|
||||
@@ -109,8 +105,7 @@ 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);
|
||||
|
||||
181
ServerPool.cpp
181
ServerPool.cpp
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -56,9 +56,8 @@ ServerPool::ServerPool()
|
||||
{
|
||||
debug("Creating ServerPool");
|
||||
|
||||
m_iMaxNormLevel = 0;
|
||||
m_iMaxLevel = 0;
|
||||
m_iTimeout = 60;
|
||||
m_iGeneration = 0;
|
||||
}
|
||||
|
||||
ServerPool::~ ServerPool()
|
||||
@@ -72,7 +71,6 @@ ServerPool::~ ServerPool()
|
||||
delete *it;
|
||||
}
|
||||
m_Servers.clear();
|
||||
m_SortedServers.clear();
|
||||
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
@@ -85,16 +83,16 @@ void ServerPool::AddServer(NewsServer* pNewsServer)
|
||||
{
|
||||
debug("Adding server to ServerPool");
|
||||
|
||||
m_Servers.push_back(pNewsServer);
|
||||
m_SortedServers.push_back(pNewsServer);
|
||||
if (pNewsServer->GetMaxConnections() > 0)
|
||||
{
|
||||
m_Servers.push_back(pNewsServer);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pNewsServer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate normalized levels for all servers.
|
||||
* Normalized Level means: starting from 0 with step 1.
|
||||
* The servers of minimum Level must be always used even if they are not active;
|
||||
* this is to prevent backup servers to act as main servers.
|
||||
**/
|
||||
void ServerPool::NormalizeLevels()
|
||||
{
|
||||
if (m_Servers.empty())
|
||||
@@ -102,38 +100,21 @@ void ServerPool::NormalizeLevels()
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(m_SortedServers.begin(), m_SortedServers.end(), CompareServers);
|
||||
std::sort(m_Servers.begin(), m_Servers.end(), CompareServers);
|
||||
|
||||
// find minimum level
|
||||
int iMinLevel = m_SortedServers.front()->GetLevel();
|
||||
for (Servers::iterator it = m_SortedServers.begin(); it != m_SortedServers.end(); it++)
|
||||
NewsServer* pNewsServer = m_Servers.front();
|
||||
|
||||
m_iMaxLevel = 0;
|
||||
int iCurLevel = pNewsServer->GetLevel();
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if (pNewsServer->GetLevel() < iMinLevel)
|
||||
if (pNewsServer->GetLevel() != iCurLevel)
|
||||
{
|
||||
iMinLevel = pNewsServer->GetLevel();
|
||||
m_iMaxLevel++;
|
||||
}
|
||||
}
|
||||
|
||||
m_iMaxNormLevel = 0;
|
||||
int iLastLevel = iMinLevel;
|
||||
for (Servers::iterator it = m_SortedServers.begin(); it != m_SortedServers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
if ((pNewsServer->GetActive() && pNewsServer->GetMaxConnections() > 0) ||
|
||||
(pNewsServer->GetLevel() == iMinLevel))
|
||||
{
|
||||
if (pNewsServer->GetLevel() != iLastLevel)
|
||||
{
|
||||
m_iMaxNormLevel++;
|
||||
}
|
||||
pNewsServer->SetNormLevel(m_iMaxNormLevel);
|
||||
iLastLevel = pNewsServer->GetLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewsServer->SetNormLevel(-1);
|
||||
}
|
||||
pNewsServer->SetLevel(m_iMaxLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,51 +127,28 @@ void ServerPool::InitConnections()
|
||||
{
|
||||
debug("Initializing connections in ServerPool");
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
NormalizeLevels();
|
||||
m_Levels.clear();
|
||||
|
||||
for (Servers::iterator it = m_SortedServers.begin(); it != m_SortedServers.end(); it++)
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
int iNormLevel = pNewsServer->GetNormLevel();
|
||||
if (pNewsServer->GetNormLevel() > -1)
|
||||
for (int i = 0; i < pNewsServer->GetMaxConnections(); i++)
|
||||
{
|
||||
if ((int)m_Levels.size() <= iNormLevel)
|
||||
{
|
||||
m_Levels.push_back(0);
|
||||
}
|
||||
|
||||
if (pNewsServer->GetActive())
|
||||
{
|
||||
int iConnections = 0;
|
||||
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection = *it;
|
||||
if (pConnection->GetNewsServer() == pNewsServer)
|
||||
{
|
||||
iConnections++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = iConnections; i < pNewsServer->GetMaxConnections(); i++)
|
||||
{
|
||||
PooledConnection* pConnection = new PooledConnection(pNewsServer);
|
||||
pConnection->SetTimeout(m_iTimeout);
|
||||
m_Connections.push_back(pConnection);
|
||||
iConnections++;
|
||||
}
|
||||
|
||||
m_Levels[iNormLevel] += iConnections;
|
||||
}
|
||||
PooledConnection* pConnection = new PooledConnection(pNewsServer);
|
||||
pConnection->SetTimeout(m_iTimeout);
|
||||
m_Connections.push_back(pConnection);
|
||||
}
|
||||
if ((int)m_Levels.size() <= pNewsServer->GetLevel())
|
||||
{
|
||||
m_Levels.push_back(0);
|
||||
}
|
||||
m_Levels[pNewsServer->GetLevel()] += pNewsServer->GetMaxConnections();
|
||||
}
|
||||
|
||||
m_iGeneration++;
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
if (m_Levels.empty())
|
||||
{
|
||||
warn("No news servers defined, download is not possible");
|
||||
}
|
||||
}
|
||||
|
||||
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers)
|
||||
@@ -205,8 +163,7 @@ NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, S
|
||||
{
|
||||
PooledConnection* pCandidateConnection = *it;
|
||||
NewsServer* pCandidateServer = pCandidateConnection->GetNewsServer();
|
||||
if (!pCandidateConnection->GetInUse() && pCandidateServer->GetActive() &&
|
||||
pCandidateServer->GetNormLevel() == iLevel &&
|
||||
if (!pCandidateConnection->GetInUse() && pCandidateServer->GetLevel() == iLevel &&
|
||||
(!pWantServer || pCandidateServer == pWantServer ||
|
||||
(pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())))
|
||||
{
|
||||
@@ -219,7 +176,7 @@ NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, S
|
||||
NewsServer* pIgnoreServer = *it;
|
||||
if (pIgnoreServer == pCandidateServer ||
|
||||
(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
|
||||
pIgnoreServer->GetNormLevel() == pCandidateServer->GetNormLevel()))
|
||||
pIgnoreServer->GetLevel() == pCandidateServer->GetLevel()))
|
||||
{
|
||||
bUseConnection = false;
|
||||
break;
|
||||
@@ -261,11 +218,7 @@ void ServerPool::FreeConnection(NNTPConnection* pConnection, bool bUsed)
|
||||
{
|
||||
((PooledConnection*)pConnection)->SetFreeTimeNow();
|
||||
}
|
||||
|
||||
if (pConnection->GetNewsServer()->GetNormLevel() > -1 && pConnection->GetNewsServer()->GetActive())
|
||||
{
|
||||
m_Levels[pConnection->GetNewsServer()->GetNormLevel()]++;
|
||||
}
|
||||
m_Levels[pConnection->GetNewsServer()->GetLevel()]++;
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
}
|
||||
@@ -276,88 +229,36 @@ void ServerPool::CloseUnusedConnections()
|
||||
|
||||
time_t curtime = ::time(NULL);
|
||||
|
||||
int i = 0;
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); )
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection = *it;
|
||||
bool bDeleted = false;
|
||||
|
||||
if (!pConnection->GetInUse() &&
|
||||
(pConnection->GetNewsServer()->GetNormLevel() == -1 ||
|
||||
!pConnection->GetNewsServer()->GetActive()))
|
||||
{
|
||||
debug("Closing (and deleting) unused connection to server%i", pConnection->GetNewsServer()->GetID());
|
||||
if (pConnection->GetStatus() == Connection::csConnected)
|
||||
{
|
||||
pConnection->Disconnect();
|
||||
}
|
||||
delete pConnection;
|
||||
m_Connections.erase(it);
|
||||
it = m_Connections.begin() + i;
|
||||
bDeleted = true;
|
||||
}
|
||||
|
||||
if (!bDeleted && !pConnection->GetInUse() && pConnection->GetStatus() == Connection::csConnected)
|
||||
if (!pConnection->GetInUse() && pConnection->GetStatus() == Connection::csConnected)
|
||||
{
|
||||
int tdiff = (int)(curtime - pConnection->GetFreeTime());
|
||||
if (tdiff > CONNECTION_HOLD_SECODNS)
|
||||
{
|
||||
debug("Closing (and keeping) unused connection to server%i", pConnection->GetNewsServer()->GetID());
|
||||
debug("Closing unused connection to %s", pConnection->GetHost());
|
||||
pConnection->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDeleted)
|
||||
{
|
||||
it++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
}
|
||||
|
||||
void ServerPool::Changed()
|
||||
{
|
||||
debug("Server config has been changed");
|
||||
|
||||
InitConnections();
|
||||
CloseUnusedConnections();
|
||||
}
|
||||
|
||||
void ServerPool::LogDebugInfo()
|
||||
{
|
||||
debug(" ServerPool");
|
||||
debug(" ----------------");
|
||||
|
||||
debug(" Max-Level: %i", m_iMaxNormLevel);
|
||||
debug(" Max-Level: %i", m_iMaxLevel);
|
||||
|
||||
m_mutexConnections.Lock();
|
||||
|
||||
debug(" Servers: %i", m_Servers.size());
|
||||
for (Servers::iterator it = m_Servers.begin(); it != m_Servers.end(); it++)
|
||||
{
|
||||
NewsServer* pNewsServer = *it;
|
||||
debug(" %i) %s (%s): Level=%i, NormLevel=%i", pNewsServer->GetID(), pNewsServer->GetName(),
|
||||
pNewsServer->GetHost(), pNewsServer->GetLevel(), pNewsServer->GetNormLevel());
|
||||
}
|
||||
|
||||
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;
|
||||
debug(" %i: Size=%i", index, iSize);
|
||||
}
|
||||
|
||||
debug(" Connections: %i", m_Connections.size());
|
||||
for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
|
||||
{
|
||||
PooledConnection* pConnection = *it;
|
||||
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());
|
||||
debug(" %s: Level=%i, InUse:%i", (*it)->GetNewsServer()->GetHost(), (*it)->GetNewsServer()->GetLevel(), (int)(*it)->GetInUse());
|
||||
}
|
||||
|
||||
m_mutexConnections.Unlock();
|
||||
|
||||
13
ServerPool.h
13
ServerPool.h
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
class ServerPool
|
||||
{
|
||||
public:
|
||||
typedef std::vector<NewsServer*> Servers;
|
||||
|
||||
private:
|
||||
class PooledConnection : public NNTPConnection
|
||||
{
|
||||
@@ -54,13 +57,11 @@ private:
|
||||
typedef std::vector<PooledConnection*> Connections;
|
||||
|
||||
Servers m_Servers;
|
||||
Servers m_SortedServers;
|
||||
Connections m_Connections;
|
||||
Levels m_Levels;
|
||||
int m_iMaxNormLevel;
|
||||
int m_iMaxLevel;
|
||||
Mutex m_mutexConnections;
|
||||
int m_iTimeout;
|
||||
int m_iGeneration;
|
||||
|
||||
void NormalizeLevels();
|
||||
static bool CompareServers(NewsServer* pServer1, NewsServer* pServer2);
|
||||
@@ -71,13 +72,11 @@ public:
|
||||
void SetTimeout(int iTimeout) { m_iTimeout = iTimeout; }
|
||||
void AddServer(NewsServer* pNewsServer);
|
||||
void InitConnections();
|
||||
int GetMaxNormLevel() { return m_iMaxNormLevel; }
|
||||
int GetMaxLevel() { return m_iMaxLevel; }
|
||||
Servers* GetServers() { return &m_Servers; } // Only for read access (no lockings)
|
||||
NNTPConnection* GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers);
|
||||
void FreeConnection(NNTPConnection* pConnection, bool bUsed);
|
||||
void CloseUnusedConnections();
|
||||
void Changed();
|
||||
int GetGeneration() { return m_iGeneration; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
15
TLS.cpp
15
TLS.cpp
@@ -275,9 +275,18 @@ TLSSocket::TLSSocket(SOCKET iSocket, bool bIsClient, const char* szCertFile, con
|
||||
|
||||
TLSSocket::~TLSSocket()
|
||||
{
|
||||
free(m_szCertFile);
|
||||
free(m_szKeyFile);
|
||||
free(m_szCipher);
|
||||
if (m_szCertFile)
|
||||
{
|
||||
free(m_szCertFile);
|
||||
}
|
||||
if (m_szKeyFile)
|
||||
{
|
||||
free(m_szKeyFile);
|
||||
}
|
||||
if (m_szCipher)
|
||||
{
|
||||
free(m_szCipher);
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
196
Unpack.cpp
196
Unpack.cpp
@@ -72,6 +72,11 @@ bool UnpackController::FileList::Exists(const char* szFilename)
|
||||
return false;
|
||||
}
|
||||
|
||||
UnpackController::~UnpackController()
|
||||
{
|
||||
m_archiveFiles.Clear();
|
||||
}
|
||||
|
||||
void UnpackController::StartJob(PostInfo* pPostInfo)
|
||||
{
|
||||
UnpackController* pUnpackController = new UnpackController();
|
||||
@@ -95,18 +100,22 @@ void UnpackController::Run()
|
||||
m_szName[1024-1] = '\0';
|
||||
|
||||
m_bCleanedUpDisk = false;
|
||||
bool bUnpack = true;
|
||||
m_szPassword[0] = '\0';
|
||||
m_szFinalDir[0] = '\0';
|
||||
m_bFinalDirCreated = false;
|
||||
|
||||
NZBParameter* pParameter = m_pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
|
||||
bool bUnpack = !(pParameter && !strcasecmp(pParameter->GetValue(), "no"));
|
||||
|
||||
pParameter = m_pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:Password", false);
|
||||
if (pParameter)
|
||||
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
|
||||
{
|
||||
strncpy(m_szPassword, pParameter->GetValue(), 1024-1);
|
||||
m_szPassword[1024-1] = '\0';
|
||||
NZBParameter* pParameter = *it;
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:") && !strcasecmp(pParameter->GetValue(), "no"))
|
||||
{
|
||||
bUnpack = false;
|
||||
}
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:Password"))
|
||||
{
|
||||
strncpy(m_szPassword, pParameter->GetValue(), 1024-1);
|
||||
m_szPassword[1024-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
@@ -117,7 +126,17 @@ void UnpackController::Run()
|
||||
snprintf(m_szInfoNameUp, 1024, "Unpack for %s", m_szName); // first letter in upper case
|
||||
m_szInfoNameUp[1024-1] = '\0';
|
||||
|
||||
m_bHasParFiles = ParCoordinator::FindMainPars(m_szDestDir, NULL);
|
||||
CheckStateFiles();
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && m_bHasBrokenFiles && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && m_bHasParFiles)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s has broken files", m_szName);
|
||||
RequestParCheck(false);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bUnpack)
|
||||
{
|
||||
@@ -138,8 +157,6 @@ void UnpackController::Run()
|
||||
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
m_bUnpackSpaceError = false;
|
||||
m_bUnpackPasswordError = false;
|
||||
|
||||
if (m_bHasRarFiles || m_bHasNonStdRarFiles)
|
||||
{
|
||||
@@ -163,10 +180,9 @@ void UnpackController::Run()
|
||||
PrintMessage(Message::mkInfo, (bUnpack ? "Nothing to unpack for %s" : "Unpack for %s skipped"), m_szName);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
|
||||
m_pPostInfo->GetNZBInfo()->GetRenameStatus() <= NZBInfo::rsSkipped && m_bHasParFiles)
|
||||
if (bUnpack && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && m_bHasParFiles)
|
||||
{
|
||||
RequestParCheck();
|
||||
RequestParCheck(m_pPostInfo->GetNZBInfo()->GetRenameStatus() <= NZBInfo::rsSkipped);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -214,8 +230,6 @@ void UnpackController::ExecuteUnrar()
|
||||
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
m_bUnpackSpaceError = iExitCode == 5;
|
||||
m_bUnpackPasswordError = iExitCode == 11; // only for rar5-archives
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
@@ -281,44 +295,51 @@ void UnpackController::Completed()
|
||||
PrintMessage(Message::mkInfo, "%s %s", m_szInfoNameUp, "successful");
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSuccess);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackCleanedUpDisk(m_bCleanedUpDisk);
|
||||
if (g_pOptions->GetParRename())
|
||||
{
|
||||
//request par-rename check for extracted files
|
||||
m_pPostInfo->GetNZBInfo()->SetRenameStatus(NZBInfo::rsNone);
|
||||
}
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (!m_bUnpackOK && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
|
||||
!m_bUnpackStartError && !m_bUnpackSpaceError && !m_bUnpackPasswordError &&
|
||||
!GetTerminated() && m_bHasParFiles)
|
||||
if (!m_bUnpackOK && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped && !m_bUnpackStartError && !GetTerminated() && m_bHasParFiles)
|
||||
{
|
||||
RequestParCheck();
|
||||
RequestParCheck(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(
|
||||
m_bUnpackSpaceError ? NZBInfo::usSpace :
|
||||
m_bUnpackPasswordError ? NZBInfo::usPassword :
|
||||
NZBInfo::usFailure);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usFailure);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void UnpackController::RequestParCheck()
|
||||
void UnpackController::RequestParCheck(bool bRename)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s requested par-check/repair", m_szInfoNameUp);
|
||||
m_pPostInfo->SetRequestParCheck(true);
|
||||
PrintMessage(Message::mkInfo, "%s requested %s", m_szInfoNameUp, bRename ? "par-rename": "par-check/repair");
|
||||
if (bRename)
|
||||
{
|
||||
m_pPostInfo->SetRequestParRename(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPostInfo->SetRequestParCheck(true);
|
||||
}
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
#endif
|
||||
|
||||
void UnpackController::CheckStateFiles()
|
||||
{
|
||||
char szBrokenLog[1024];
|
||||
snprintf(szBrokenLog, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_brokenlog.txt");
|
||||
szBrokenLog[1024-1] = '\0';
|
||||
m_bHasBrokenFiles = Util::FileExists(szBrokenLog);
|
||||
|
||||
m_bHasParFiles = ParCoordinator::FindMainPars(m_szDestDir, NULL);
|
||||
}
|
||||
|
||||
void UnpackController::CreateUnpackDir()
|
||||
{
|
||||
m_bInterDir = strlen(g_pOptions->GetInterDir()) > 0 &&
|
||||
@@ -328,7 +349,6 @@ void UnpackController::CreateUnpackDir()
|
||||
m_pPostInfo->GetNZBInfo()->BuildFinalDirName(m_szFinalDir, 1024);
|
||||
m_szFinalDir[1024-1] = '\0';
|
||||
snprintf(m_szUnpackDir, 1024, "%s%c%s", m_szFinalDir, PATH_SEPARATOR, "_unpack");
|
||||
m_bFinalDirCreated = !Util::DirectoryExists(m_szFinalDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -354,8 +374,7 @@ void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExRarMultiSeq(".*\\.(r|s)[0-9][0-9]$");
|
||||
RegEx regExSevenZip(".*\\.7z$");
|
||||
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]+$");
|
||||
RegEx regExNumExt(".*\\.[0-9]+$");
|
||||
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
@@ -378,37 +397,28 @@ void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
|
||||
{
|
||||
m_bHasSevenZipMultiFiles = true;
|
||||
}
|
||||
else if (bScanNonStdFiles && !m_bHasNonStdRarFiles &&
|
||||
!regExRarMultiSeq.Match(filename) && regExNumExt.Match(filename) &&
|
||||
FileHasRarSignature(szFullFilename))
|
||||
else if (bScanNonStdFiles && !m_bHasNonStdRarFiles && !regExRarMultiSeq.Match(filename))
|
||||
{
|
||||
m_bHasNonStdRarFiles = true;
|
||||
// Check if file has RAR signature
|
||||
char rarSignature[] = {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00};
|
||||
char fileSignature[7];
|
||||
|
||||
FILE* infile;
|
||||
infile = fopen(szFullFilename, "rb");
|
||||
if (infile)
|
||||
{
|
||||
int cnt = (int)fread(fileSignature, 1, sizeof(fileSignature), infile);
|
||||
fclose(infile);
|
||||
if (cnt == sizeof(fileSignature) && !strcmp(rarSignature, fileSignature))
|
||||
{
|
||||
m_bHasNonStdRarFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UnpackController::FileHasRarSignature(const char* szFilename)
|
||||
{
|
||||
char rar4Signature[] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 };
|
||||
char rar5Signature[] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00 };
|
||||
|
||||
char fileSignature[8];
|
||||
|
||||
int cnt = 0;
|
||||
FILE* infile;
|
||||
infile = fopen(szFilename, "rb");
|
||||
if (infile)
|
||||
{
|
||||
cnt = (int)fread(fileSignature, 1, sizeof(fileSignature), infile);
|
||||
fclose(infile);
|
||||
}
|
||||
|
||||
bool bRar = cnt == sizeof(fileSignature) &&
|
||||
(!strcmp(rar4Signature, fileSignature) || !strcmp(rar5Signature, fileSignature));
|
||||
return bRar;
|
||||
}
|
||||
|
||||
bool UnpackController::Cleanup()
|
||||
{
|
||||
// By success:
|
||||
@@ -428,8 +438,7 @@ bool UnpackController::Cleanup()
|
||||
DirBrowser dir(m_szUnpackDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") &&
|
||||
strcmp(filename, ".AppleDouble") && strcmp(filename, ".DS_Store"))
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szUnpackDir, PATH_SEPARATOR, filename);
|
||||
@@ -458,19 +467,35 @@ bool UnpackController::Cleanup()
|
||||
PrintMessage(Message::mkError, "Could not remove temporary directory %s", m_szUnpackDir);
|
||||
}
|
||||
|
||||
if (!m_bUnpackOK && m_bFinalDirCreated)
|
||||
{
|
||||
Util::RemoveDirectory(m_szFinalDir);
|
||||
}
|
||||
|
||||
if (m_bUnpackOK && bOK && g_pOptions->GetUnpackCleanupDisk())
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting archive files");
|
||||
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExRarMultiSeq(".*\\.[r-z][0-9][0-9]$");
|
||||
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]+$");
|
||||
RegEx regExNumExt(".*\\.[0-9]+$");
|
||||
// Delete rar-files (only files which were used by unrar)
|
||||
for (FileList::iterator it = m_archiveFiles.begin(); it != m_archiveFiles.end(); it++)
|
||||
{
|
||||
char* szFilename = *it;
|
||||
|
||||
if (m_bInterDir || !extractedFiles.Exists(szFilename))
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szFilename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", szFilename);
|
||||
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately 7-Zip doesn't print the processed archive-files to the output.
|
||||
// Therefore we don't know for sure which files were extracted.
|
||||
// We just delete all 7z-files in the directory.
|
||||
|
||||
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
@@ -479,12 +504,8 @@ bool UnpackController::Cleanup()
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") &&
|
||||
!Util::DirectoryExists(szFullFilename) &&
|
||||
(m_bInterDir || !extractedFiles.Exists(filename)) &&
|
||||
(regExRar.Match(filename) || regExSevenZip.Match(filename) ||
|
||||
(regExRarMultiSeq.Match(filename) && FileHasRarSignature(szFullFilename)) ||
|
||||
(m_bHasNonStdRarFiles && regExNumExt.Match(filename) && FileHasRarSignature(szFullFilename))))
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename)
|
||||
&& regExSevenZip.Match(filename) && (m_bInterDir || !extractedFiles.Exists(filename)))
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
|
||||
|
||||
@@ -601,6 +622,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
|
||||
{
|
||||
const char *szFilename = szText + 23;
|
||||
debug("Filename: %s", szFilename);
|
||||
m_archiveFiles.push_back(strdup(szFilename));
|
||||
SetProgressLabel(szText + 7);
|
||||
}
|
||||
|
||||
@@ -697,15 +719,24 @@ bool MoveController::MoveFiles()
|
||||
DirBrowser dir(m_szInterDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") &&
|
||||
strcmp(filename, ".AppleDouble") && strcmp(filename, ".DS_Store"))
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szInterDir, PATH_SEPARATOR, filename);
|
||||
szSrcFile[1024-1] = '\0';
|
||||
|
||||
char szDstFile[1024];
|
||||
Util::MakeUniqueFilename(szDstFile, 1024, m_szDestDir, filename);
|
||||
snprintf(szDstFile, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szDstFile[1024-1] = '\0';
|
||||
|
||||
// prevent overwriting of existing files
|
||||
int dupcount = 0;
|
||||
while (Util::FileExists(szDstFile))
|
||||
{
|
||||
dupcount++;
|
||||
snprintf(szDstFile, 1024, "%s%c%s_duplicate%d", m_szDestDir, PATH_SEPARATOR, filename, dupcount);
|
||||
szDstFile[1024-1] = '\0';
|
||||
}
|
||||
|
||||
PrintMessage(Message::mkInfo, "Moving file %s to %s", Util::BaseFileName(szSrcFile), m_szDestDir);
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
@@ -716,10 +747,7 @@ bool MoveController::MoveFiles()
|
||||
}
|
||||
}
|
||||
|
||||
if (bOK && !Util::DeleteDirectoryWithContent(m_szInterDir))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not remove intermediate directory %s", m_szInterDir);
|
||||
}
|
||||
Util::RemoveDirectory(m_szInterDir);
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
10
Unpack.h
10
Unpack.h
@@ -63,17 +63,16 @@ private:
|
||||
bool m_bAllOKMessageReceived;
|
||||
bool m_bNoFilesMessageReceived;
|
||||
bool m_bHasParFiles;
|
||||
bool m_bHasBrokenFiles;
|
||||
bool m_bHasRarFiles;
|
||||
bool m_bHasNonStdRarFiles;
|
||||
bool m_bHasSevenZipFiles;
|
||||
bool m_bHasSevenZipMultiFiles;
|
||||
bool m_bUnpackOK;
|
||||
bool m_bUnpackStartError;
|
||||
bool m_bUnpackSpaceError;
|
||||
bool m_bUnpackPasswordError;
|
||||
bool m_bCleanedUpDisk;
|
||||
EUnpacker m_eUnpacker;
|
||||
bool m_bFinalDirCreated;
|
||||
FileList m_archiveFiles;
|
||||
|
||||
protected:
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
@@ -83,14 +82,15 @@ protected:
|
||||
void Completed();
|
||||
void CreateUnpackDir();
|
||||
bool Cleanup();
|
||||
void CheckStateFiles();
|
||||
void CheckArchiveFiles(bool bScanNonStdFiles);
|
||||
void SetProgressLabel(const char* szProgressLabel);
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RequestParCheck();
|
||||
void RequestParCheck(bool bRename);
|
||||
#endif
|
||||
bool FileHasRarSignature(const char* szFilename);
|
||||
|
||||
public:
|
||||
virtual ~UnpackController();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartJob(PostInfo* pPostInfo);
|
||||
|
||||
@@ -64,46 +64,36 @@ UrlDownloader::UrlDownloader() : WebDownloader()
|
||||
|
||||
UrlDownloader::~UrlDownloader()
|
||||
{
|
||||
free(m_szCategory);
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
}
|
||||
|
||||
void UrlDownloader::ProcessHeader(const char* szLine)
|
||||
{
|
||||
WebDownloader::ProcessHeader(szLine);
|
||||
|
||||
if (!strncmp(szLine, "X-DNZB-Category:", 16))
|
||||
if (!strncmp(szLine, "X-DNZB-Category: ", 17))
|
||||
{
|
||||
free(m_szCategory);
|
||||
char* szCategory = strdup(szLine + 16);
|
||||
m_szCategory = strdup(Util::Trim(szCategory));
|
||||
free(szCategory);
|
||||
if (m_szCategory)
|
||||
{
|
||||
free(m_szCategory);
|
||||
}
|
||||
|
||||
const char *szCat = szLine + 17;
|
||||
|
||||
int iCatLen = strlen(szCat);
|
||||
|
||||
// trim trailing CR/LF/spaces
|
||||
while (iCatLen > 0 && (szCat[iCatLen-1] == '\n' || szCat[iCatLen-1] == '\r' || szCat[iCatLen-1] == ' ')) iCatLen--;
|
||||
|
||||
m_szCategory = (char*)malloc(iCatLen + 1);
|
||||
strncpy(m_szCategory, szCat, iCatLen);
|
||||
m_szCategory[iCatLen] = '\0';
|
||||
|
||||
debug("Category: %s", m_szCategory);
|
||||
}
|
||||
else if (!strncmp(szLine, "X-DNZB-", 7))
|
||||
{
|
||||
char* szModLine = strdup(szLine);
|
||||
char* szValue = strchr(szModLine, ':');
|
||||
if (szValue)
|
||||
{
|
||||
*szValue = NULL;
|
||||
szValue++;
|
||||
while (*szValue == ' ') szValue++;
|
||||
Util::Trim(szValue);
|
||||
|
||||
debug("X-DNZB: %s", szModLine);
|
||||
debug("Value: %s", szValue);
|
||||
|
||||
char szParamName[100];
|
||||
snprintf(szParamName, 100, "*DNZB:%s", szModLine + 7);
|
||||
szParamName[100-1] = '\0';
|
||||
|
||||
char* szVal = WebUtil::Latin1ToUtf8(szValue);
|
||||
m_ppParameters.SetParameter(szParamName, szVal);
|
||||
free(szVal);
|
||||
}
|
||||
free(szModLine);
|
||||
}
|
||||
}
|
||||
|
||||
UrlCoordinator::UrlCoordinator()
|
||||
@@ -111,7 +101,6 @@ UrlCoordinator::UrlCoordinator()
|
||||
debug("Creating UrlCoordinator");
|
||||
|
||||
m_bHasMoreJobs = true;
|
||||
m_bForce = false;
|
||||
}
|
||||
|
||||
UrlCoordinator::~UrlCoordinator()
|
||||
@@ -145,7 +134,7 @@ void UrlCoordinator::Run()
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()) || m_bForce || g_pOptions->GetUrlForce())
|
||||
if (!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
// start download for next URL
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
@@ -160,10 +149,6 @@ void UrlCoordinator::Run()
|
||||
{
|
||||
StartUrlDownload(pUrlInfo);
|
||||
}
|
||||
if (!bHasMoreUrls)
|
||||
{
|
||||
m_bForce = false;
|
||||
}
|
||||
}
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
@@ -278,11 +263,6 @@ void UrlCoordinator::AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst)
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
if (pUrlInfo->GetForce())
|
||||
{
|
||||
m_bForce = true;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
}
|
||||
|
||||
@@ -291,19 +271,19 @@ void UrlCoordinator::AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst)
|
||||
*/
|
||||
bool UrlCoordinator::GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo)
|
||||
{
|
||||
bool bPauseDownload = g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2();
|
||||
bool bOK = false;
|
||||
|
||||
for (UrlQueue::iterator at = pDownloadQueue->GetUrlQueue()->begin(); at != pDownloadQueue->GetUrlQueue()->end(); at++)
|
||||
{
|
||||
pUrlInfo = *at;
|
||||
if (pUrlInfo->GetStatus() == 0 && (!bPauseDownload || pUrlInfo->GetForce() || g_pOptions->GetUrlForce()))
|
||||
if (pUrlInfo->GetStatus() == 0)
|
||||
{
|
||||
return true;
|
||||
bOK = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
|
||||
@@ -315,7 +295,6 @@ void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
|
||||
pUrlDownloader->Attach(this);
|
||||
pUrlDownloader->SetUrlInfo(pUrlInfo);
|
||||
pUrlDownloader->SetURL(pUrlInfo->GetURL());
|
||||
pUrlDownloader->SetForce(pUrlInfo->GetForce() || g_pOptions->GetUrlForce());
|
||||
|
||||
char tmp[1024];
|
||||
|
||||
@@ -332,11 +311,11 @@ void UrlCoordinator::StartUrlDownload(UrlInfo* pUrlInfo)
|
||||
pUrlDownloader->Start();
|
||||
}
|
||||
|
||||
void UrlCoordinator::Update(Subject* pCaller, void* pAspect)
|
||||
void UrlCoordinator::Update(Subject* Caller, void* Aspect)
|
||||
{
|
||||
debug("Notification from UrlDownloader received");
|
||||
|
||||
UrlDownloader* pUrlDownloader = (UrlDownloader*) pCaller;
|
||||
UrlDownloader* pUrlDownloader = (UrlDownloader*) Caller;
|
||||
if ((pUrlDownloader->GetStatus() == WebDownloader::adFinished) ||
|
||||
(pUrlDownloader->GetStatus() == WebDownloader::adFailed) ||
|
||||
(pUrlDownloader->GetStatus() == WebDownloader::adRetry))
|
||||
@@ -382,8 +361,9 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
|
||||
debug("Filename: [%s]", filename);
|
||||
|
||||
// delete Download from active jobs
|
||||
g_pQueueCoordinator->LockQueue();
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
// delete Download from Queue
|
||||
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
|
||||
{
|
||||
UrlDownloader* pa = *it;
|
||||
@@ -393,32 +373,12 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
Aspect aspect = { eaUrlCompleted, pUrlInfo };
|
||||
Notify(&aspect);
|
||||
bool bDeleteObj = false;
|
||||
|
||||
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished)
|
||||
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished || pUrlInfo->GetStatus() == UrlInfo::aiFailed)
|
||||
{
|
||||
// add nzb-file to download queue
|
||||
Scanner::EAddStatus eAddStatus = g_pScanner->AddExternalFile(
|
||||
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)
|
||||
{
|
||||
pUrlInfo->SetStatus(eAddStatus == Scanner::asFailed ? UrlInfo::aiScanFailed : UrlInfo::aiScanSkipped);
|
||||
}
|
||||
}
|
||||
|
||||
// delete Download from Url Queue
|
||||
if (pUrlInfo->GetStatus() != UrlInfo::aiRetry)
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
// delete UrlInfo from Queue
|
||||
for (UrlQueue::iterator it = pDownloadQueue->GetUrlQueue()->begin(); it != pDownloadQueue->GetUrlQueue()->end(); it++)
|
||||
{
|
||||
UrlInfo* pa = *it;
|
||||
@@ -429,9 +389,9 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
}
|
||||
}
|
||||
|
||||
bool bDeleteObj = true;
|
||||
bDeleteObj = true;
|
||||
|
||||
if (g_pOptions->GetKeepHistory() > 0 && pUrlInfo->GetStatus() != UrlInfo::aiFinished)
|
||||
if (g_pOptions->GetKeepHistory() > 0 && pUrlInfo->GetStatus() == UrlInfo::aiFailed)
|
||||
{
|
||||
HistoryInfo* pHistoryInfo = new HistoryInfo(pUrlInfo);
|
||||
pHistoryInfo->SetTime(time(NULL));
|
||||
@@ -443,12 +403,26 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader)
|
||||
{
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (bDeleteObj)
|
||||
{
|
||||
delete pUrlInfo;
|
||||
}
|
||||
if (pUrlInfo->GetStatus() == UrlInfo::aiFinished)
|
||||
{
|
||||
// add nzb-file to download queue
|
||||
AddToNZBQueue(pUrlInfo, pUrlDownloader->GetOutputFilename(), filename, pUrlDownloader->GetCategory());
|
||||
}
|
||||
|
||||
if (bDeleteObj)
|
||||
{
|
||||
delete pUrlInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void UrlCoordinator::AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory)
|
||||
{
|
||||
g_pScanner->AddExternalFile(
|
||||
pUrlInfo->GetNZBFilename() && strlen(pUrlInfo->GetNZBFilename()) > 0 ? pUrlInfo->GetNZBFilename() : szOriginalFilename,
|
||||
strlen(pUrlInfo->GetCategory()) > 0 ? pUrlInfo->GetCategory() : szOriginalCategory,
|
||||
pUrlInfo->GetPriority(), NULL, pUrlInfo->GetAddTop(), pUrlInfo->GetAddPaused(), szTempFilename, NULL, 0, false);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -41,33 +41,23 @@ class UrlCoordinator : public Thread, public Observer, public Subject
|
||||
{
|
||||
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;
|
||||
|
||||
bool GetNextUrl(DownloadQueue* pDownloadQueue, UrlInfo* &pUrlInfo);
|
||||
void StartUrlDownload(UrlInfo* pUrlInfo);
|
||||
void UrlCompleted(UrlDownloader* pUrlDownloader);
|
||||
void ResetHangingDownloads();
|
||||
void AddToNZBQueue(UrlInfo* pUrlInfo, const char* szTempFilename, const char* szOriginalFilename, const char* szOriginalCategory);
|
||||
|
||||
public:
|
||||
UrlCoordinator();
|
||||
virtual ~UrlCoordinator();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
void Update(Subject* pCaller, void* pAspect);
|
||||
void Update(Subject* Caller, void* Aspect);
|
||||
|
||||
// Editing the queue
|
||||
void AddUrlToQueue(UrlInfo* pUrlInfo, bool AddFirst);
|
||||
@@ -81,7 +71,6 @@ class UrlDownloader : public WebDownloader
|
||||
private:
|
||||
UrlInfo* m_pUrlInfo;
|
||||
char* m_szCategory;
|
||||
NZBParameterList m_ppParameters;
|
||||
|
||||
protected:
|
||||
virtual void ProcessHeader(const char* szLine);
|
||||
@@ -92,7 +81,6 @@ public:
|
||||
void SetUrlInfo(UrlInfo* pUrlInfo) { m_pUrlInfo = pUrlInfo; }
|
||||
UrlInfo* GetUrlInfo() { return m_pUrlInfo; }
|
||||
const char* GetCategory() { return m_szCategory; }
|
||||
NZBParameterList* GetParameters() { return &m_ppParameters; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
531
Util.cpp
531
Util.cpp
@@ -36,7 +36,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#include <WinIoCtl.h>
|
||||
@@ -51,7 +50,6 @@
|
||||
#ifndef DISABLE_GZIP
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Util.h"
|
||||
@@ -215,7 +213,10 @@ StringBuilder::StringBuilder()
|
||||
|
||||
StringBuilder::~StringBuilder()
|
||||
{
|
||||
free(m_szBuffer);
|
||||
if (m_szBuffer)
|
||||
{
|
||||
free(m_szBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void StringBuilder::Append(const char* szStr)
|
||||
@@ -427,7 +428,7 @@ bool Util::SaveBufferIntoFile(const char* szFileName, const char* szBuffer, int
|
||||
int iWrittenBytes = fwrite(szBuffer, 1, iBufLen, pFile);
|
||||
fclose(pFile);
|
||||
|
||||
return iWrittenBytes == iBufLen;
|
||||
return iWrittenBytes = iBufLen;
|
||||
}
|
||||
|
||||
bool Util::CreateSparseFile(const char* szFilename, int iSize)
|
||||
@@ -520,48 +521,6 @@ void Util::MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSla
|
||||
}
|
||||
}
|
||||
|
||||
// returns TRUE if the name was changed by adding duplicate-suffix
|
||||
bool Util::MakeUniqueFilename(char* szDestBufFilename, int iDestBufSize, const char* szDestDir, const char* szBasename)
|
||||
{
|
||||
snprintf(szDestBufFilename, iDestBufSize, "%s%c%s", szDestDir, (int)PATH_SEPARATOR, szBasename);
|
||||
szDestBufFilename[iDestBufSize-1] = '\0';
|
||||
|
||||
int iDupeNumber = 0;
|
||||
while (FileExists(szDestBufFilename))
|
||||
{
|
||||
iDupeNumber++;
|
||||
|
||||
const char* szExtension = strrchr(szBasename, '.');
|
||||
if (szExtension && szExtension != szBasename)
|
||||
{
|
||||
char szFilenameWithoutExt[1024];
|
||||
strncpy(szFilenameWithoutExt, szBasename, 1024);
|
||||
int iEnd = szExtension - szBasename;
|
||||
szFilenameWithoutExt[iEnd < 1024 ? iEnd : 1024-1] = '\0';
|
||||
|
||||
if (!strcasecmp(szExtension, ".par2"))
|
||||
{
|
||||
char* szVolExtension = strrchr(szFilenameWithoutExt, '.');
|
||||
if (szVolExtension && szVolExtension != szFilenameWithoutExt && !strncasecmp(szVolExtension, ".vol", 4))
|
||||
{
|
||||
*szVolExtension = '\0';
|
||||
szExtension = szBasename + (szVolExtension - szFilenameWithoutExt);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(szDestBufFilename, iDestBufSize, "%s%c%s.duplicate%d%s", szDestDir, (int)PATH_SEPARATOR, szFilenameWithoutExt, iDupeNumber, szExtension);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szDestBufFilename, iDestBufSize, "%s%c%s.duplicate%d", szDestDir, (int)PATH_SEPARATOR, szBasename, iDupeNumber);
|
||||
}
|
||||
|
||||
szDestBufFilename[iDestBufSize-1] = '\0';
|
||||
}
|
||||
|
||||
return iDupeNumber > 0;
|
||||
}
|
||||
|
||||
long long Util::JoinInt64(unsigned long Hi, unsigned long Lo)
|
||||
{
|
||||
return (((long long)Hi) << 32) + Lo;
|
||||
@@ -697,15 +656,6 @@ bool Util::FileExists(const char* szFilename)
|
||||
return bExists;
|
||||
}
|
||||
|
||||
bool Util::FileExists(const char* szPath, const char* szFilenameWithoutPath)
|
||||
{
|
||||
char fullFilename[1024];
|
||||
snprintf(fullFilename, 1024, "%s%c%s", szPath, (int)PATH_SEPARATOR, szFilenameWithoutPath);
|
||||
fullFilename[1024-1] = '\0';
|
||||
bool bExists = Util::FileExists(fullFilename);
|
||||
return bExists;
|
||||
}
|
||||
|
||||
bool Util::DirectoryExists(const char* szDirFilename)
|
||||
{
|
||||
struct stat buffer;
|
||||
@@ -917,19 +867,6 @@ bool Util::SameFilename(const char* szFilename1, const char* szFilename2)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
void Util::FixExecPermission(const char* szFilename)
|
||||
{
|
||||
struct stat buffer;
|
||||
bool bOK = !stat(szFilename, &buffer);
|
||||
if (bOK)
|
||||
{
|
||||
buffer.st_mode = buffer.st_mode | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
chmod(szFilename, buffer.st_mode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
char* Util::GetLastErrorMessage(char* szBuffer, int iBufLen)
|
||||
{
|
||||
szBuffer[0] = '\0';
|
||||
@@ -1034,114 +971,28 @@ bool Util::SplitCommandLine(const char* szCommandLine, char*** argv)
|
||||
|
||||
void Util::TrimRight(char* szStr)
|
||||
{
|
||||
char* szEnd = szStr + strlen(szStr) - 1;
|
||||
while (szEnd >= szStr && (*szEnd == '\n' || *szEnd == '\r' || *szEnd == ' ' || *szEnd == '\t'))
|
||||
int iLen = strlen(szStr);
|
||||
char ch = szStr[iLen-1];
|
||||
while (iLen > 0 && (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t'))
|
||||
{
|
||||
*szEnd = '\0';
|
||||
szEnd--;
|
||||
szStr[iLen-1] = 0;
|
||||
iLen--;
|
||||
ch = szStr[iLen-1];
|
||||
}
|
||||
}
|
||||
|
||||
char* Util::Trim(char* szStr)
|
||||
{
|
||||
TrimRight(szStr);
|
||||
while (*szStr == '\n' || *szStr == '\r' || *szStr == ' ' || *szStr == '\t')
|
||||
char ch = *szStr;
|
||||
while (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t')
|
||||
{
|
||||
szStr++;
|
||||
ch = *szStr;
|
||||
}
|
||||
return szStr;
|
||||
}
|
||||
|
||||
char* Util::ReduceStr(char* szStr, const char* szFrom, const char* szTo)
|
||||
{
|
||||
int iLenFrom = strlen(szFrom);
|
||||
int iLenTo = strlen(szTo);
|
||||
// assert(iLenTo < iLenFrom);
|
||||
|
||||
while (char* p = strstr(szStr, szFrom))
|
||||
{
|
||||
const char* src = szTo;
|
||||
while ((*p++ = *src++)) ;
|
||||
|
||||
src = --p - iLenTo + iLenFrom;
|
||||
while ((*p++ = *src++)) ;
|
||||
}
|
||||
|
||||
return szStr;
|
||||
}
|
||||
|
||||
/* Calculate Hash using Bob Jenkins (1996) algorithm
|
||||
* http://burtleburtle.net/bob/c/lookup2.c
|
||||
*/
|
||||
typedef unsigned int ub4; /* unsigned 4-byte quantities */
|
||||
typedef unsigned char ub1;
|
||||
|
||||
#define hashsize(n) ((ub4)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
ub4 hash(register ub1 *k, register ub4 length, register ub4 initval)
|
||||
// register ub1 *k; /* the key */
|
||||
// register ub4 length; /* the length of the key */
|
||||
// register ub4 initval; /* the previous hash, or an arbitrary value */
|
||||
{
|
||||
register ub4 a,b,c,len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = initval; /* the previous hash value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 12)
|
||||
{
|
||||
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
|
||||
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
|
||||
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
|
||||
mix(a,b,c);
|
||||
k += 12; len -= 12;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 11 bytes */
|
||||
c += length;
|
||||
switch(len) /* all the case statements fall through */
|
||||
{
|
||||
case 11: c+=((ub4)k[10]<<24);
|
||||
case 10: c+=((ub4)k[9]<<16);
|
||||
case 9 : c+=((ub4)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((ub4)k[7]<<24);
|
||||
case 7 : b+=((ub4)k[6]<<16);
|
||||
case 6 : b+=((ub4)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((ub4)k[3]<<24);
|
||||
case 3 : a+=((ub4)k[2]<<16);
|
||||
case 2 : a+=((ub4)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned int Util::HashBJ96(const char* szBuffer, int iBufSize, unsigned int iInitValue)
|
||||
{
|
||||
return (unsigned int)hash((ub1*)szBuffer, (ub4)iBufSize, (ub4)iInitValue);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
bool Util::RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName, char* szBuffer, int* iBufLen)
|
||||
{
|
||||
@@ -1356,13 +1207,6 @@ void WebUtil::XmlDecode(char* raw)
|
||||
*output++ = '\"';
|
||||
p += 5;
|
||||
}
|
||||
else if (*p == '#')
|
||||
{
|
||||
int code = atoi(p+1);
|
||||
p = strchr(p+1, ';');
|
||||
if (p) p++;
|
||||
*output++ = (char)code;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown entity
|
||||
@@ -1693,103 +1537,6 @@ BreakLoop:
|
||||
*output = '\0';
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
bool WebUtil::Utf8ToAnsi(char* szBuffer, int iBufLen)
|
||||
{
|
||||
WCHAR* wstr = (WCHAR*)malloc(iBufLen * 2);
|
||||
int errcode = MultiByteToWideChar(CP_UTF8, 0, szBuffer, -1, wstr, iBufLen);
|
||||
if (errcode > 0)
|
||||
{
|
||||
errcode = WideCharToMultiByte(CP_ACP, 0, wstr, -1, szBuffer, iBufLen, "_", NULL);
|
||||
}
|
||||
free(wstr);
|
||||
return errcode > 0;
|
||||
}
|
||||
|
||||
bool WebUtil::AnsiToUtf8(char* szBuffer, int iBufLen)
|
||||
{
|
||||
WCHAR* wstr = (WCHAR*)malloc(iBufLen * 2);
|
||||
int errcode = MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wstr, iBufLen);
|
||||
if (errcode > 0)
|
||||
{
|
||||
errcode = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, szBuffer, iBufLen, NULL, NULL);
|
||||
}
|
||||
free(wstr);
|
||||
return errcode > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* WebUtil::Latin1ToUtf8(const char* szStr)
|
||||
{
|
||||
char *res = (char*)malloc(strlen(szStr) * 2 + 1);
|
||||
const unsigned char *in = (const unsigned char*)szStr;
|
||||
unsigned char *out = (unsigned char*)res;
|
||||
while (*in)
|
||||
{
|
||||
if (*in < 128)
|
||||
{
|
||||
*out++ = *in++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = 0xc2 + (*in > 0xbf);
|
||||
*out++ = (*in++ & 0x3f) + 0x80;
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
The date/time can be formatted according to RFC822 in different ways. Examples:
|
||||
Wed, 26 Jun 2013 01:02:54 -0600
|
||||
Wed, 26 Jun 2013 01:02:54 GMT
|
||||
26 Jun 2013 01:02:54 -0600
|
||||
26 Jun 2013 01:02 -0600
|
||||
26 Jun 2013 01:02 A
|
||||
This function however supports only the first format!
|
||||
*/
|
||||
time_t WebUtil::ParseRfc822DateTime(const char* szDateTimeStr)
|
||||
{
|
||||
char month[4];
|
||||
int day, year, hours, minutes, seconds, zonehours, zoneminutes;
|
||||
int r = sscanf(szDateTimeStr, "%*s %d %3s %d %d:%d:%d %3d %2d", &day, &month[0], &year, &hours, &minutes, &seconds, &zonehours, &zoneminutes);
|
||||
if (r != 8)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mon = 0;
|
||||
if (!strcasecmp(month, "Jan")) mon = 0;
|
||||
else if (!strcasecmp(month, "Feb")) mon = 1;
|
||||
else if (!strcasecmp(month, "Mar")) mon = 2;
|
||||
else if (!strcasecmp(month, "Apr")) mon = 3;
|
||||
else if (!strcasecmp(month, "May")) mon = 4;
|
||||
else if (!strcasecmp(month, "Jun")) mon = 5;
|
||||
else if (!strcasecmp(month, "Jul")) mon = 6;
|
||||
else if (!strcasecmp(month, "Aug")) mon = 7;
|
||||
else if (!strcasecmp(month, "Sep")) mon = 8;
|
||||
else if (!strcasecmp(month, "Oct")) mon = 9;
|
||||
else if (!strcasecmp(month, "Nov")) mon = 10;
|
||||
else if (!strcasecmp(month, "Dec")) mon = 11;
|
||||
|
||||
struct tm rawtime;
|
||||
memset(&rawtime, 0, sizeof(rawtime));
|
||||
|
||||
rawtime.tm_year = year - 1900;
|
||||
rawtime.tm_mon = mon;
|
||||
rawtime.tm_mday = day;
|
||||
rawtime.tm_hour = hours;
|
||||
rawtime.tm_min = minutes;
|
||||
rawtime.tm_sec = seconds;
|
||||
|
||||
time_t enctime = mktime(&rawtime);
|
||||
|
||||
enctime = enctime - (zonehours * 60 + (zonehours > 0 ? zoneminutes : -zoneminutes)) * 60;
|
||||
|
||||
return enctime;
|
||||
}
|
||||
|
||||
|
||||
URL::URL(const char* szAddress)
|
||||
{
|
||||
@@ -1812,12 +1559,30 @@ URL::URL(const char* szAddress)
|
||||
|
||||
URL::~URL()
|
||||
{
|
||||
free(m_szAddress);
|
||||
free(m_szProtocol);
|
||||
free(m_szUser);
|
||||
free(m_szPassword);
|
||||
free(m_szHost);
|
||||
free(m_szResource);
|
||||
if (m_szAddress)
|
||||
{
|
||||
free(m_szAddress);
|
||||
}
|
||||
if (m_szProtocol)
|
||||
{
|
||||
free(m_szProtocol);
|
||||
}
|
||||
if (m_szUser)
|
||||
{
|
||||
free(m_szUser);
|
||||
}
|
||||
if (m_szPassword)
|
||||
{
|
||||
free(m_szPassword);
|
||||
}
|
||||
if (m_szHost)
|
||||
{
|
||||
free(m_szHost);
|
||||
}
|
||||
if (m_szResource)
|
||||
{
|
||||
free(m_szResource);
|
||||
}
|
||||
}
|
||||
|
||||
void URL::ParseURL()
|
||||
@@ -1903,20 +1668,11 @@ void URL::ParseURL()
|
||||
m_bValid = true;
|
||||
}
|
||||
|
||||
RegEx::RegEx(const char *szPattern, int iMatchBufSize)
|
||||
RegEx::RegEx(const char *szPattern)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
m_pContext = malloc(sizeof(regex_t));
|
||||
m_bValid = regcomp((regex_t*)m_pContext, szPattern, REG_EXTENDED | REG_ICASE | (iMatchBufSize > 0 ? 0 : REG_NOSUB)) == 0;
|
||||
m_iMatchBufSize = iMatchBufSize;
|
||||
if (iMatchBufSize > 0)
|
||||
{
|
||||
m_pMatches = malloc(sizeof(regmatch_t) * iMatchBufSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pMatches = NULL;
|
||||
}
|
||||
m_bValid = regcomp((regex_t*)m_pContext, szPattern, REG_EXTENDED | REG_ICASE | REG_NOSUB) == 0;
|
||||
#else
|
||||
m_bValid = false;
|
||||
#endif
|
||||
@@ -1927,223 +1683,18 @@ RegEx::~RegEx()
|
||||
#ifdef HAVE_REGEX_H
|
||||
regfree((regex_t*)m_pContext);
|
||||
free(m_pContext);
|
||||
free(m_pMatches);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RegEx::Match(const char *szStr)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
return m_bValid ? regexec((regex_t*)m_pContext, szStr, m_iMatchBufSize, (regmatch_t*)m_pMatches, 0) == 0 : false;
|
||||
return m_bValid ? regexec((regex_t*)m_pContext, szStr, 0, NULL, 0) == 0 : false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int RegEx::GetMatchCount()
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
int iCount = 0;
|
||||
if (m_pMatches)
|
||||
{
|
||||
regmatch_t* pMatches = (regmatch_t*)m_pMatches;
|
||||
while (iCount < m_iMatchBufSize && pMatches[iCount].rm_so > -1)
|
||||
{
|
||||
iCount++;
|
||||
}
|
||||
}
|
||||
return iCount;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int RegEx::GetMatchStart(int index)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
regmatch_t* pMatches = (regmatch_t*)m_pMatches;
|
||||
return pMatches[index].rm_so;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int RegEx::GetMatchLen(int index)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
regmatch_t* pMatches = (regmatch_t*)m_pMatches;
|
||||
return pMatches[index].rm_eo - pMatches[index].rm_so;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
WildMask::WildMask(const char *szPattern, bool bWantsPositions)
|
||||
{
|
||||
m_szPattern = strdup(szPattern);
|
||||
m_bWantsPositions = bWantsPositions;
|
||||
m_WildStart = NULL;
|
||||
m_WildLen = NULL;
|
||||
m_iArrLen = 0;
|
||||
}
|
||||
|
||||
WildMask::~WildMask()
|
||||
{
|
||||
free(m_szPattern);
|
||||
free(m_WildStart);
|
||||
free(m_WildLen);
|
||||
}
|
||||
|
||||
void WildMask::ExpandArray()
|
||||
{
|
||||
m_iWildCount++;
|
||||
if (m_iWildCount > m_iArrLen)
|
||||
{
|
||||
m_iArrLen += 100;
|
||||
m_WildStart = (int*)realloc(m_WildStart, sizeof(*m_WildStart) * m_iArrLen);
|
||||
m_WildLen = (int*)realloc(m_WildLen, sizeof(*m_WildLen) * m_iArrLen);
|
||||
}
|
||||
}
|
||||
|
||||
// Based on code from http://bytes.com/topic/c/answers/212179-string-matching
|
||||
// Extended to save positions of matches.
|
||||
bool WildMask::Match(const char *szStr)
|
||||
{
|
||||
const char* pat = m_szPattern;
|
||||
const char* str = szStr;
|
||||
const char *spos, *wpos;
|
||||
m_iWildCount = 0;
|
||||
bool qmark = false;
|
||||
bool star = false;
|
||||
|
||||
spos = wpos = str;
|
||||
while (*str && *pat != '*')
|
||||
{
|
||||
if (m_bWantsPositions && (*pat == '?' || *pat == '#'))
|
||||
{
|
||||
if (!qmark)
|
||||
{
|
||||
ExpandArray();
|
||||
m_WildStart[m_iWildCount-1] = str - szStr;
|
||||
m_WildLen[m_iWildCount-1] = 0;
|
||||
qmark = true;
|
||||
}
|
||||
}
|
||||
else if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
qmark = false;
|
||||
}
|
||||
|
||||
if (!(tolower(*pat) == tolower(*str) || *pat == '?' ||
|
||||
(*pat == '#' && strchr("0123456789", *str))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
str++;
|
||||
pat++;
|
||||
}
|
||||
|
||||
if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
qmark = false;
|
||||
}
|
||||
|
||||
while (*str)
|
||||
{
|
||||
if (*pat == '*')
|
||||
{
|
||||
if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
qmark = false;
|
||||
}
|
||||
if (m_bWantsPositions && !star)
|
||||
{
|
||||
ExpandArray();
|
||||
m_WildStart[m_iWildCount-1] = str - szStr;
|
||||
m_WildLen[m_iWildCount-1] = 0;
|
||||
star = true;
|
||||
}
|
||||
|
||||
if (*++pat == '\0')
|
||||
{
|
||||
if (m_bWantsPositions && star)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = strlen(str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
wpos = pat;
|
||||
spos = str + 1;
|
||||
}
|
||||
else if (*pat == '?' || (*pat == '#' && strchr("0123456789", *str)))
|
||||
{
|
||||
if (m_bWantsPositions && !qmark)
|
||||
{
|
||||
ExpandArray();
|
||||
m_WildStart[m_iWildCount-1] = str - szStr;
|
||||
m_WildLen[m_iWildCount-1] = 0;
|
||||
qmark = true;
|
||||
}
|
||||
|
||||
pat++;
|
||||
str++;
|
||||
}
|
||||
else if (tolower(*pat) == tolower(*str))
|
||||
{
|
||||
if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
qmark = false;
|
||||
}
|
||||
else if (m_bWantsPositions && star)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
star = false;
|
||||
}
|
||||
|
||||
pat++;
|
||||
str++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_iWildCount--;
|
||||
qmark = false;
|
||||
}
|
||||
|
||||
pat = wpos;
|
||||
str = spos++;
|
||||
star = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bWantsPositions && qmark)
|
||||
{
|
||||
m_WildLen[m_iWildCount-1] = str - (szStr + m_WildStart[m_iWildCount-1]);
|
||||
}
|
||||
|
||||
if (*pat == '*' && m_bWantsPositions && !star)
|
||||
{
|
||||
ExpandArray();
|
||||
m_WildStart[m_iWildCount-1] = str - szStr;
|
||||
m_WildLen[m_iWildCount-1] = strlen(str);
|
||||
}
|
||||
|
||||
while (*pat == '*')
|
||||
{
|
||||
pat++;
|
||||
}
|
||||
|
||||
return *pat == '\0';
|
||||
}
|
||||
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
unsigned int ZLib::GZipLen(int iInputBufferLength)
|
||||
{
|
||||
|
||||
52
Util.h
52
Util.h
@@ -81,10 +81,8 @@ public:
|
||||
static bool CreateSparseFile(const char* szFilename, int iSize);
|
||||
static bool TruncateFile(const char* szFilename, int iSize);
|
||||
static void MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSlashes);
|
||||
static bool MakeUniqueFilename(char* szDestBufFilename, int iDestBufSize, const char* szDestDir, const char* szBasename);
|
||||
static bool MoveFile(const char* szSrcFilename, const char* szDstFilename);
|
||||
static bool FileExists(const char* szFilename);
|
||||
static bool FileExists(const char* szPath, const char* szFilenameWithoutPath);
|
||||
static bool DirectoryExists(const char* szDirFilename);
|
||||
static bool CreateDirectory(const char* szDirFilename);
|
||||
static bool RemoveDirectory(const char* szDirFilename);
|
||||
@@ -98,7 +96,6 @@ public:
|
||||
static bool RenameBak(const char* szFilename, const char* szBakPart, bool bRemoveOldExtension, char* szNewNameBuf, int iNewNameBufSize);
|
||||
#ifndef WIN32
|
||||
static bool ExpandHomePath(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
static void FixExecPermission(const char* szFilename);
|
||||
#endif
|
||||
static void ExpandFileName(const char* szFilename, char* szBuffer, int iBufSize);
|
||||
static void FormatFileSize(char* szBuffer, int iBufLen, long long lFileSize);
|
||||
@@ -130,14 +127,8 @@ public:
|
||||
static float Int64ToFloat(long long Int64);
|
||||
|
||||
static void TrimRight(char* szStr);
|
||||
|
||||
static char* Trim(char* szStr);
|
||||
static bool EmptyStr(const char* szStr) { return !szStr || !*szStr; }
|
||||
|
||||
/* replace all occurences of szFrom to szTo in string szStr with a limitation that szTo must be shorter than szFrom */
|
||||
static char* ReduceStr(char* szStr, const char* szFrom, const char* szTo);
|
||||
|
||||
/* Calculate Hash using Bob Jenkins (1996) algorithm */
|
||||
static unsigned int HashBJ96(const char* szBuffer, int iBufSize, unsigned int iInitValue);
|
||||
|
||||
#ifdef WIN32
|
||||
static bool RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName, char* szBuffer, int* iBufLen);
|
||||
@@ -216,19 +207,6 @@ public:
|
||||
* The string is decoded on the place overwriting the content of raw-data.
|
||||
*/
|
||||
static void HttpUnquote(char* raw);
|
||||
|
||||
#ifdef WIN32
|
||||
static bool Utf8ToAnsi(char* szBuffer, int iBufLen);
|
||||
static bool AnsiToUtf8(char* szBuffer, int iBufLen);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Converts ISO-8859-1 (aka Latin-1) into UTF-8.
|
||||
* Returns new string allocated with malloc, it needs to be freed by caller.
|
||||
*/
|
||||
static char* Latin1ToUtf8(const char* szStr);
|
||||
|
||||
static time_t ParseRfc822DateTime(const char* szDateTimeStr);
|
||||
};
|
||||
|
||||
class URL
|
||||
@@ -264,38 +242,12 @@ class RegEx
|
||||
private:
|
||||
void* m_pContext;
|
||||
bool m_bValid;
|
||||
void* m_pMatches;
|
||||
int m_iMatchBufSize;
|
||||
|
||||
public:
|
||||
RegEx(const char *szPattern, int iMatchBufSize = 100);
|
||||
RegEx(const char *szPattern);
|
||||
~RegEx();
|
||||
bool IsValid() { return m_bValid; }
|
||||
bool Match(const char *szStr);
|
||||
int GetMatchCount();
|
||||
int GetMatchStart(int index);
|
||||
int GetMatchLen(int index);
|
||||
};
|
||||
|
||||
class WildMask
|
||||
{
|
||||
private:
|
||||
char* m_szPattern;
|
||||
bool m_bWantsPositions;
|
||||
int m_iWildCount;
|
||||
int* m_WildStart;
|
||||
int* m_WildLen;
|
||||
int m_iArrLen;
|
||||
|
||||
void ExpandArray();
|
||||
|
||||
public:
|
||||
WildMask(const char *szPattern, bool bWantsPositions = false);
|
||||
~WildMask();
|
||||
bool Match(const char *szStr);
|
||||
int GetMatchCount() { return m_iWildCount; }
|
||||
int GetMatchStart(int index) { return m_WildStart[index]; }
|
||||
int GetMatchLen(int index) { return m_WildLen[index]; }
|
||||
};
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
|
||||
@@ -62,8 +62,6 @@ WebDownloader::WebDownloader()
|
||||
m_bConfirmedLength = false;
|
||||
m_eStatus = adUndefined;
|
||||
m_szOriginalFilename = NULL;
|
||||
m_bForce = false;
|
||||
m_bRetry = true;
|
||||
SetLastUpdateTimeNow();
|
||||
}
|
||||
|
||||
@@ -71,10 +69,22 @@ WebDownloader::~WebDownloader()
|
||||
{
|
||||
debug("Destroying WebDownloader");
|
||||
|
||||
free(m_szURL);
|
||||
free(m_szInfoName);
|
||||
free(m_szOutputFilename);
|
||||
free(m_szOriginalFilename);
|
||||
if (m_szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szOutputFilename)
|
||||
{
|
||||
free(m_szOutputFilename);
|
||||
}
|
||||
if (m_szOriginalFilename)
|
||||
{
|
||||
free(m_szOriginalFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void WebDownloader::SetOutputFilename(const char* v)
|
||||
@@ -89,7 +99,6 @@ void WebDownloader::SetInfoName(const char* v)
|
||||
|
||||
void WebDownloader::SetURL(const char * szURL)
|
||||
{
|
||||
free(m_szURL);
|
||||
m_szURL = strdup(szURL);
|
||||
}
|
||||
|
||||
@@ -107,13 +116,7 @@ void WebDownloader::Run()
|
||||
|
||||
int iRemainedDownloadRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
|
||||
int iRemainedConnectRetries = iRemainedDownloadRetries > 10 ? iRemainedDownloadRetries : 10;
|
||||
if (!m_bRetry)
|
||||
{
|
||||
iRemainedDownloadRetries = 1;
|
||||
iRemainedConnectRetries = 1;
|
||||
}
|
||||
|
||||
m_iRedirects = 0;
|
||||
EStatus Status = adFailed;
|
||||
|
||||
while (!IsStopped() && iRemainedDownloadRetries > 0 && iRemainedConnectRetries > 0)
|
||||
@@ -124,19 +127,19 @@ void WebDownloader::Run()
|
||||
|
||||
if ((((Status == adFailed) && (iRemainedDownloadRetries > 1)) ||
|
||||
((Status == adConnectError) && (iRemainedConnectRetries > 1)))
|
||||
&& !IsStopped() && !(!m_bForce && (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())))
|
||||
&& !IsStopped() && !(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
int msec = 0;
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000) &&
|
||||
!(!m_bForce && (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())))
|
||||
!(g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2()))
|
||||
{
|
||||
usleep(100 * 1000);
|
||||
msec += 100;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped() || (!m_bForce && (g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())))
|
||||
if (IsStopped() || g_pOptions->GetPauseDownload() || g_pOptions->GetPauseDownload2())
|
||||
{
|
||||
Status = adRetry;
|
||||
break;
|
||||
@@ -147,17 +150,6 @@ void WebDownloader::Run()
|
||||
break;
|
||||
}
|
||||
|
||||
if (Status == adRedirect)
|
||||
{
|
||||
m_iRedirects++;
|
||||
if (m_iRedirects > 5)
|
||||
{
|
||||
warn("Too many redirects for %s", m_szInfoName);
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Status != adConnectError)
|
||||
{
|
||||
iRemainedDownloadRetries--;
|
||||
@@ -320,8 +312,6 @@ WebDownloader::EStatus WebDownloader::DownloadHeaders()
|
||||
m_iContentLen = -1;
|
||||
bool bFirstLine = true;
|
||||
m_bGZip = false;
|
||||
m_bRedirecting = false;
|
||||
m_bRedirected = false;
|
||||
|
||||
// Headers
|
||||
while (!IsStopped())
|
||||
@@ -364,14 +354,7 @@ WebDownloader::EStatus WebDownloader::DownloadHeaders()
|
||||
break;
|
||||
}
|
||||
|
||||
Util::TrimRight(line);
|
||||
ProcessHeader(line);
|
||||
|
||||
if (m_bRedirected)
|
||||
{
|
||||
Status = adRedirect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(szLineBuf);
|
||||
@@ -414,7 +397,7 @@ WebDownloader::EStatus WebDownloader::DownloadBody()
|
||||
// Have we encountered a timeout?
|
||||
if (iLen <= 0)
|
||||
{
|
||||
if (m_iContentLen == -1 && iWrittenLen > 0)
|
||||
if (m_iContentLen == -1)
|
||||
{
|
||||
bEnd = true;
|
||||
break;
|
||||
@@ -447,7 +430,10 @@ WebDownloader::EStatus WebDownloader::DownloadBody()
|
||||
free(szLineBuf);
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
delete m_pGUnzipStream;
|
||||
if (m_pGUnzipStream)
|
||||
{
|
||||
delete m_pGUnzipStream;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_pOutFile)
|
||||
@@ -499,11 +485,6 @@ WebDownloader::EStatus WebDownloader::CheckResponse(const char* szResponse)
|
||||
warn("URL %s failed: %s", m_szInfoName, szHTTPResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szHTTPResponse, "301", 3) || !strncmp(szHTTPResponse, "302", 3))
|
||||
{
|
||||
m_bRedirecting = true;
|
||||
return adRunning;
|
||||
}
|
||||
else if (!strncmp(szHTTPResponse, "200", 3))
|
||||
{
|
||||
// OK
|
||||
@@ -519,24 +500,21 @@ WebDownloader::EStatus WebDownloader::CheckResponse(const char* szResponse)
|
||||
|
||||
void WebDownloader::ProcessHeader(const char* szLine)
|
||||
{
|
||||
if (!strncasecmp(szLine, "Content-Length: ", 16))
|
||||
if (!strncmp(szLine, "Content-Length: ", 16))
|
||||
{
|
||||
m_iContentLen = atoi(szLine + 16);
|
||||
m_bConfirmedLength = true;
|
||||
}
|
||||
else if (!strncasecmp(szLine, "Content-Encoding: gzip", 22))
|
||||
|
||||
if (!strncmp(szLine, "Content-Encoding: gzip", 22))
|
||||
{
|
||||
m_bGZip = true;
|
||||
}
|
||||
else if (!strncasecmp(szLine, "Content-Disposition: ", 21))
|
||||
|
||||
if (!strncmp(szLine, "Content-Disposition: ", 21))
|
||||
{
|
||||
ParseFilename(szLine);
|
||||
}
|
||||
else if (m_bRedirecting && !strncasecmp(szLine, "Location: ", 10))
|
||||
{
|
||||
ParseRedirect(szLine + 10);
|
||||
m_bRedirected = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WebDownloader::ParseFilename(const char* szContentDisposition)
|
||||
@@ -573,36 +551,15 @@ void WebDownloader::ParseFilename(const char* szContentDisposition)
|
||||
|
||||
WebUtil::HttpUnquote(fname);
|
||||
|
||||
free(m_szOriginalFilename);
|
||||
if (m_szOriginalFilename)
|
||||
{
|
||||
free(m_szOriginalFilename);
|
||||
}
|
||||
m_szOriginalFilename = strdup(Util::BaseFileName(fname));
|
||||
|
||||
debug("OriginalFilename: %s", m_szOriginalFilename);
|
||||
}
|
||||
|
||||
void WebDownloader::ParseRedirect(const char* szLocation)
|
||||
{
|
||||
const char* szNewURL = szLocation;
|
||||
char szUrlBuf[1024];
|
||||
URL newUrl(szNewURL);
|
||||
if (!newUrl.IsValid())
|
||||
{
|
||||
// relative address
|
||||
URL oldUrl(m_szURL);
|
||||
if (oldUrl.GetPort() > 0)
|
||||
{
|
||||
snprintf(szUrlBuf, 1024, "%s://%s:%i%s", oldUrl.GetProtocol(), oldUrl.GetHost(), oldUrl.GetPort(), szNewURL);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(szUrlBuf, 1024, "%s://%s%s", oldUrl.GetProtocol(), oldUrl.GetHost(), szNewURL);
|
||||
}
|
||||
szUrlBuf[1024-1] = '\0';
|
||||
szNewURL = szUrlBuf;
|
||||
}
|
||||
detail("URL %s redirected to %s", m_szURL, szNewURL);
|
||||
SetURL(szNewURL);
|
||||
}
|
||||
|
||||
bool WebDownloader::Write(void* pBuffer, int iLen)
|
||||
{
|
||||
if (!m_pOutFile && !PrepareFile())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
adFailed,
|
||||
adRetry,
|
||||
adNotFound,
|
||||
adRedirect,
|
||||
adConnectError,
|
||||
adFatalError
|
||||
};
|
||||
@@ -61,12 +60,7 @@ private:
|
||||
int m_iContentLen;
|
||||
bool m_bConfirmedLength;
|
||||
char* m_szOriginalFilename;
|
||||
bool m_bForce;
|
||||
bool m_bRedirecting;
|
||||
bool m_bRedirected;
|
||||
int m_iRedirects;
|
||||
bool m_bGZip;
|
||||
bool m_bRetry;
|
||||
#ifndef DISABLE_GZIP
|
||||
GUnzipStream* m_pGUnzipStream;
|
||||
#endif
|
||||
@@ -76,12 +70,12 @@ private:
|
||||
bool PrepareFile();
|
||||
void FreeConnection();
|
||||
EStatus CheckResponse(const char* szResponse);
|
||||
EStatus Download();
|
||||
EStatus CreateConnection(URL *pUrl);
|
||||
void ParseFilename(const char* szContentDisposition);
|
||||
void SendHeaders(URL *pUrl);
|
||||
EStatus DownloadHeaders();
|
||||
EStatus DownloadBody();
|
||||
void ParseRedirect(const char* szLocation);
|
||||
|
||||
protected:
|
||||
virtual void ProcessHeader(const char* szLine);
|
||||
@@ -92,7 +86,6 @@ public:
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
EStatus Download();
|
||||
bool Terminate();
|
||||
void SetInfoName(const char* v);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
@@ -103,8 +96,6 @@ public:
|
||||
void SetLastUpdateTimeNow() { m_tLastUpdateTime = ::time(NULL); }
|
||||
bool GetConfirmedLength() { return m_bConfirmedLength; }
|
||||
const char* GetOriginalFilename() { return m_szOriginalFilename; }
|
||||
void SetForce(bool bForce) { m_bForce = bForce; }
|
||||
void SetRetry(bool bRetry) { m_bRetry = bRetry; }
|
||||
|
||||
void LogDebugInfo();
|
||||
};
|
||||
|
||||
@@ -66,9 +66,18 @@ WebProcessor::WebProcessor()
|
||||
|
||||
WebProcessor::~WebProcessor()
|
||||
{
|
||||
free(m_szRequest);
|
||||
free(m_szUrl);
|
||||
free(m_szOrigin);
|
||||
if (m_szRequest)
|
||||
{
|
||||
free(m_szRequest);
|
||||
}
|
||||
if (m_szUrl)
|
||||
{
|
||||
free(m_szUrl);
|
||||
}
|
||||
if (m_szOrigin)
|
||||
{
|
||||
free(m_szOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
void WebProcessor::SetUrl(const char* szUrl)
|
||||
@@ -176,8 +185,7 @@ void WebProcessor::Execute()
|
||||
|
||||
debug("Final URL=%s", m_szUrl);
|
||||
|
||||
if (strlen(g_pOptions->GetControlPassword()) > 0 &&
|
||||
!(strlen(g_pOptions->GetAuthorizedIP()) > 0 && IsAuthorizedIP(m_pConnection->GetRemoteAddr())))
|
||||
if (strlen(g_pOptions->GetControlPassword()) > 0)
|
||||
{
|
||||
if (strlen(szAuthInfo) == 0)
|
||||
{
|
||||
@@ -217,30 +225,6 @@ void WebProcessor::Execute()
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
bool WebProcessor::IsAuthorizedIP(const char* szRemoteAddr)
|
||||
{
|
||||
const char* szRemoteIP = m_pConnection->GetRemoteAddr();
|
||||
|
||||
// split option AuthorizedIP into tokens and check each token
|
||||
bool bAuthorized = false;
|
||||
char* szAuthorizedIP = strdup(g_pOptions->GetAuthorizedIP());
|
||||
char* saveptr;
|
||||
char* szIP = strtok_r(szAuthorizedIP, ",;", &saveptr);
|
||||
while (szIP)
|
||||
{
|
||||
szIP = Util::Trim(szIP);
|
||||
if (szIP[0] != '\0' && !strcmp(szIP, szRemoteIP))
|
||||
{
|
||||
bAuthorized = true;
|
||||
break;
|
||||
}
|
||||
szIP = strtok_r(NULL, ",;", &saveptr);
|
||||
}
|
||||
free(szAuthorizedIP);
|
||||
|
||||
return bAuthorized;
|
||||
}
|
||||
|
||||
void WebProcessor::Dispatch()
|
||||
{
|
||||
if (*m_szUrl != '/')
|
||||
@@ -441,7 +425,10 @@ void WebProcessor::SendBodyResponse(const char* szBody, int iBodyLen, const char
|
||||
m_pConnection->Send(szBody, iBodyLen);
|
||||
|
||||
#ifndef DISABLE_GZIP
|
||||
free(szGBuf);
|
||||
if (szGBuf)
|
||||
{
|
||||
free(szGBuf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ private:
|
||||
void SendBodyResponse(const char* szBody, int iBodyLen, const char* szContentType);
|
||||
void SendRedirectResponse(const char* szURL);
|
||||
const char* DetectContentType(const char* szFilename);
|
||||
bool IsAuthorizedIP(const char* szRemoteAddr);
|
||||
|
||||
public:
|
||||
WebProcessor();
|
||||
|
||||
1593
XmlRpc.cpp
1593
XmlRpc.cpp
File diff suppressed because it is too large
Load Diff
171
XmlRpc.h
171
XmlRpc.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2010 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -109,4 +109,173 @@ public:
|
||||
bool GetFault() { return m_bFault; }
|
||||
};
|
||||
|
||||
class ErrorXmlCommand: public XmlCommand
|
||||
{
|
||||
private:
|
||||
int m_iErrCode;
|
||||
const char* m_szErrText;
|
||||
|
||||
public:
|
||||
ErrorXmlCommand(int iErrCode, const char* szErrText);
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PauseUnpauseXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
enum EPauseAction
|
||||
{
|
||||
paDownload,
|
||||
paDownload2,
|
||||
paPostProcess,
|
||||
paScan
|
||||
};
|
||||
|
||||
private:
|
||||
bool m_bPause;
|
||||
EPauseAction m_eEPauseAction;
|
||||
|
||||
public:
|
||||
PauseUnpauseXmlCommand(bool bPause, EPauseAction eEPauseAction);
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScheduleResumeXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ReloadXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DumpDebugXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SetDownloadRateXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class StatusXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LogXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListFilesXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListGroupsXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class EditQueueXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DownloadXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PostQueueXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class WriteLogXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ClearLogXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ScanXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class HistoryXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DownloadUrlXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UrlQueueXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LoadConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SaveConfigXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ConfigTemplatesXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
20
configure
vendored
20
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 12.0.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 11.0.
|
||||
#
|
||||
# Report bugs to <hugbug@users.sourceforge.net>.
|
||||
#
|
||||
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='nzbget'
|
||||
PACKAGE_TARNAME='nzbget'
|
||||
PACKAGE_VERSION='12.0'
|
||||
PACKAGE_STRING='nzbget 12.0'
|
||||
PACKAGE_VERSION='11.0'
|
||||
PACKAGE_STRING='nzbget 11.0'
|
||||
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
|
||||
|
||||
ac_unique_file="nzbget.cpp"
|
||||
@@ -1235,7 +1235,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures nzbget 12.0 to adapt to many kinds of systems.
|
||||
\`configure' configures nzbget 11.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1306,7 +1306,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of nzbget 12.0:";;
|
||||
short | recursive ) echo "Configuration of nzbget 11.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1453,7 +1453,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
nzbget configure 12.0
|
||||
nzbget configure 11.0
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1467,7 +1467,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by nzbget $as_me 12.0, which was
|
||||
It was created by nzbget $as_me 11.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2263,7 +2263,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=nzbget
|
||||
VERSION=12.0
|
||||
VERSION=11.0
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -9537,7 +9537,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by nzbget $as_me 12.0, which was
|
||||
This file was extended by nzbget $as_me 11.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -9590,7 +9590,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
nzbget config.status 12.0
|
||||
nzbget config.status 11.0
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 12.0, hugbug@users.sourceforge.net)
|
||||
AC_INIT(nzbget, 11.0, hugbug@users.sourceforge.net)
|
||||
AC_CANONICAL_SYSTEM
|
||||
AM_INIT_AUTOMAKE(nzbget, 12.0)
|
||||
AM_INIT_AUTOMAKE(nzbget, 11.0)
|
||||
AC_CONFIG_SRCDIR([nzbget.cpp])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
|
||||
619
nzbget.conf
619
nzbget.conf
@@ -21,8 +21,8 @@
|
||||
|
||||
# Root directory for all tasks.
|
||||
#
|
||||
# On POSIX you can use "~" as alias for home directory (e.g. "~/downloads").
|
||||
# On Windows use absolute paths (e.g. "C:\Downloads").
|
||||
# On POSIX you can use "~" as alias for home directory (e.g. "~/download").
|
||||
# On Windows use absolute paths (e.g. "C:\Download").
|
||||
MainDir=~/downloads
|
||||
|
||||
# Destination directory for downloaded files.
|
||||
@@ -46,24 +46,16 @@ DestDir=${MainDir}/dst
|
||||
#
|
||||
# NOTE: If the option <InterDir> is set to empty value the downloaded
|
||||
# files are put directly to destination directory (option <DestDir>).
|
||||
InterDir=${MainDir}/inter
|
||||
InterDir=
|
||||
|
||||
# Directory for incoming nzb-files.
|
||||
# Directory to monitor for incoming nzb-jobs.
|
||||
#
|
||||
# If a new nzb-file is added to queue via web-interface or RPC-API, it
|
||||
# is saved into this directory and then processed by pre-processing
|
||||
# script (option <NzbProcess>).
|
||||
#
|
||||
# This directory is also monitored for new nzb-files. If a new file
|
||||
# is found it is added to download queue. The directory can have
|
||||
# sub-directories. A nzb-file queued from a subdirectory is automatically
|
||||
# assigned to category with sub-directory-name.
|
||||
# Can have subdirectories.
|
||||
# A nzb-file queued from a subdirectory will be automatically assigned to
|
||||
# category with the directory-name.
|
||||
NzbDir=${MainDir}/nzb
|
||||
|
||||
# Directory to store program state.
|
||||
#
|
||||
# This directory is used to save download queue, history, information
|
||||
# about fetched RSS feeds, statistics, etc.
|
||||
# Directory to store download queue.
|
||||
QueueDir=${MainDir}/queue
|
||||
|
||||
# Directory to store temporary files.
|
||||
@@ -120,17 +112,6 @@ ConfigTemplate=
|
||||
# change the name of Server3 to Server2. Otherwise it will not be properly
|
||||
# read from the config file. Server number doesn't affect its priority (level).
|
||||
|
||||
# Use this news server (yes, no).
|
||||
#
|
||||
# Set to "no" to temporary disable the server.
|
||||
Server1.Active=yes
|
||||
|
||||
# Name of news server.
|
||||
#
|
||||
# The name is used in UI and for logging. It can be any string, you
|
||||
# may even leave it empty.
|
||||
Server1.Name=
|
||||
|
||||
# Level (priority) of news server (0-99).
|
||||
#
|
||||
# The servers are ordered by their level. NZBGet first tries to download
|
||||
@@ -219,7 +200,7 @@ Server1.Connections=4
|
||||
|
||||
|
||||
##############################################################################
|
||||
### SECURITY ###
|
||||
### REMOTE CONTROL ###
|
||||
|
||||
# IP on which NZBGet server listen and which clients use to contact NZBGet.
|
||||
#
|
||||
@@ -276,16 +257,9 @@ SecureCert=
|
||||
# Full path to key file for encrypted communication.
|
||||
SecureKey=
|
||||
|
||||
# IP-addresses allowed to connect without authorization.
|
||||
#
|
||||
# Comma separated list of privileged IPs for easy access to NZBGet
|
||||
# built-in web-server (web-interface and RPC).
|
||||
#
|
||||
# Example: 127.0.0.1,192.168.178.2.
|
||||
#
|
||||
# NOTE: Do not use this option if the program works behind another
|
||||
# web-server because all requests will have the address of this server.
|
||||
AuthorizedIP=
|
||||
|
||||
##############################################################################
|
||||
### PERMISSIONS ###
|
||||
|
||||
# User name for daemon-mode, POSIX only.
|
||||
#
|
||||
@@ -309,228 +283,6 @@ DaemonUsername=root
|
||||
UMask=1000
|
||||
|
||||
|
||||
##############################################################################
|
||||
### CATEGORIES ###
|
||||
|
||||
# This section defines categories available in web-interface.
|
||||
|
||||
# Category name.
|
||||
#
|
||||
# Each nzb-file can be assigned to a category.
|
||||
# Category name is passed to post-processing script and can be used by it
|
||||
# to perform category specific processing.
|
||||
Category1.Name=Movies
|
||||
|
||||
# Destination directory for this category.
|
||||
#
|
||||
# If this option is empty, then the default destination directory
|
||||
# (option <DestDir>) is used. In this case if the option <AppendCategoryDir>
|
||||
# is active, the program creates a subdirectory with category name within
|
||||
# destination directory.
|
||||
Category1.DestDir=
|
||||
|
||||
# Unpack downloaded nzb-files (yes, no).
|
||||
#
|
||||
# For more information see global option <Unpack>.
|
||||
Category1.Unpack=yes
|
||||
|
||||
# Default list of post-processing scripts.
|
||||
#
|
||||
# For more information see global option <DefScript>.
|
||||
Category1.DefScript=
|
||||
|
||||
# List of aliases.
|
||||
#
|
||||
# When a nzb-file is added from URL, RSS or RPC the category name
|
||||
# is usually supplied by nzb-site or by application accessing
|
||||
# NZBGet. Using Aliases you can match their categories with your owns.
|
||||
#
|
||||
# Separate aliases with commas or semicolons. Use wildcard-characters
|
||||
# * and ? for pattern matching.
|
||||
#
|
||||
# Example: TV - HD, TV - SD, TV*
|
||||
Category1.Aliases=
|
||||
|
||||
Category2.Name=Series
|
||||
Category3.Name=Music
|
||||
Category4.Name=Software
|
||||
|
||||
|
||||
##############################################################################
|
||||
### RSS FEEDS ###
|
||||
|
||||
# Name of RSS Feed.
|
||||
#
|
||||
# The name is used in UI and for logging. It can be any string.
|
||||
#Feed1.Name=my feed
|
||||
|
||||
# Address (URL) of RSS Feed.
|
||||
#
|
||||
# Example: https://myindexer.com/api?apikey=3544646bfd1c535a9654645609800901&t=search&q=game.
|
||||
#
|
||||
# NOTE: When the feed is fetched for the very first time all existing
|
||||
# items are ignored. The items found on subsequentional fetches are processed.
|
||||
#Feed1.URL=
|
||||
|
||||
# Filter rules for items.
|
||||
#
|
||||
# Use filter to ignore unwanted items in the feed. In its simplest version
|
||||
# the filter is a space separated list of words which must be present in
|
||||
# the item title.
|
||||
#
|
||||
# Example: linux debian dvd.
|
||||
#
|
||||
# MORE INFO:
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.sourceforge.net/RSS.
|
||||
#
|
||||
# Feed filter consists of rules - one rule per line. Each rule defines
|
||||
# a search string and a command, which must be performed if the search
|
||||
# string matches. There are five kinds of rule-commands: Accept,
|
||||
# Reject, Require, Options, Comment.
|
||||
#
|
||||
# NOTE: Since options in the configuration file can not span multiple
|
||||
# lines, the lines (rules) must be separated with %-character (percent).
|
||||
#
|
||||
# Definition of a rule:
|
||||
# [A:|A(options):|R:|Q:|O(options):|#] search-string
|
||||
#
|
||||
# A - declares Accept-rule. Rules are accept-rules by default, the
|
||||
# "A:" can be imitted. If the feed item matches to the rule the
|
||||
# item is considered good and no further rules are checked.
|
||||
# R - declares Reject-rule. If the feed item matches to the rule the
|
||||
# item is considered bad and no further rules are checked.
|
||||
# Q - declares Require-rule. If the feed item DOES NOT match to the rule
|
||||
# the item is considered bad and no further rules are checked.
|
||||
# O - declares Options-rule. If the feed item matches to the rule the
|
||||
# options declared in the rule are set for the item. The item is
|
||||
# neither accepted nor rejected via this rule but can be accepted
|
||||
# later by one of Accept-rules. In this case the item will have its
|
||||
# options already set (unless the Accept-rule overrides them).
|
||||
# # - lines starting with # are considered comments and are ignored. You
|
||||
# can use comments to explain complex rules or to temporary disable
|
||||
# rules for debugging.
|
||||
#
|
||||
# Options allow to set properties on nzb-file. It's a comma-separated
|
||||
# list of property names with their values.
|
||||
#
|
||||
# Definition of an option:
|
||||
# name:value
|
||||
#
|
||||
# Options can be defined using long option names or short names:
|
||||
# category (cat, c) - set category name, value is a string;
|
||||
# pause (p) - add nzb in paused or unpaused state, possible
|
||||
# values are: yes (y), no (n);
|
||||
# priority (pr, r) - set priority, value is a signed integer number;
|
||||
# priority+ (pr+, r+) - increase priority, value is a signed integer number;
|
||||
# dupescore (ds, s) - set duplicate score, value is a signed integer number;
|
||||
# dupescore+ (ds+, s+) - increase duplicate score, value is a signed integer number;
|
||||
# dupekey (dk, k) - set duplicate key, value is a string;
|
||||
# dupekey+ (dk+, k+) - add to duplicate key, value is a string;
|
||||
# dupemode (dm, m) - set duplicate check mode, possible values
|
||||
# are: score (s), all (a), force (f);
|
||||
# rageid - generate duplicate key using this rageid
|
||||
# (integer number) and season/episode numbers;
|
||||
# series - generate duplicate key using series identifier
|
||||
# (any unique string) and season/episode numbers.
|
||||
#
|
||||
# Examples of option definitions:
|
||||
# Accept(category:my series, pause:yes, priority:100): my show 1080p;
|
||||
# Options(c:my series, p:y, r:100): 1080p;
|
||||
# Options(s:1000): 1080p;
|
||||
# Options(k+:1080p): 1080p;
|
||||
# Options(dupemode:force): BluRay.
|
||||
#
|
||||
# Rule-options override values set in feed-options.
|
||||
#
|
||||
# The search-string is similar to used in search engines. It consists of
|
||||
# search terms separated with spaces. Every term is checked for a feed
|
||||
# item and if they all succeed the rule is considered matching.
|
||||
#
|
||||
# Definition of a term:
|
||||
# [+|-][field:][command]param
|
||||
#
|
||||
# + - declares a positive term. Terms are positive by default,
|
||||
# the "+" can be omitted;
|
||||
# - - declares a negative term. If the term succeed the feed
|
||||
# item is ignored;
|
||||
# field - field to which apply the term. If not specified
|
||||
# the default field "title" is used;
|
||||
# command - a special character defining how to interpret the
|
||||
# parameter (followed after the command):
|
||||
# @ - search for string "param". This is default command,
|
||||
# the "@" can be omitted;
|
||||
# $ - "param" defines a regular expression (using POSIX Extended
|
||||
# Regular Expressions syntax);
|
||||
# = - equal;
|
||||
# < - less than;
|
||||
# <= - equal or less than;
|
||||
# > - greater than;
|
||||
# >= - equal or greater than;
|
||||
# param - parameter for command.
|
||||
#
|
||||
# Commands @ and $ are for use with text fields (title, filename, category,
|
||||
# link, description, dupekey). Commands =, <, <=, > and >= are for use
|
||||
# with numeric fields (size, age, imdbid, rageid, season, episode, priority,
|
||||
# dupescore).
|
||||
#
|
||||
# Only fields title, filename and age are always present. The availability of
|
||||
# other fields depend on rss feed provider.
|
||||
#
|
||||
# Any newznab attribute (encoded as "newznab:attr" in the RSS feed) can
|
||||
# be used as search field with prefix "attr-", for example "attr-genre".
|
||||
#
|
||||
# Text search (Command @) supports supports wildcard characters * (matches
|
||||
# any number of any characters), ? (matches any one character)
|
||||
# and # (matches one digit).
|
||||
# Text search is by default performed against words (word-search mode): the
|
||||
# field content is separated into words and then each word is checked
|
||||
# against pattern. If the search pattern starts and ends with * (star)
|
||||
# the search is performed against the whole field content
|
||||
# (substring-search mode). If the search pattern contains word separator
|
||||
# characters (except * and ?) the search is performed on the whole
|
||||
# field (the word-search would be obviously never successful in this
|
||||
# case). Word separators are: !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~.
|
||||
#
|
||||
# Field "size" can have suffixes "K" or "KB" for kilobytes, "M" or "MB"
|
||||
# for megabytes and "G" or "GB" for gigabytes. Field "age" can have
|
||||
# suffixes "m" for minutes, "h" for hours and "d" for days. If suffix
|
||||
# is not specified default is days.
|
||||
#
|
||||
# Examples (the trailing ; or . is not part of filter):
|
||||
# 1) A: s01* -category:anime;
|
||||
# 2) my show WEB-DL;
|
||||
# 3) *my?show* WEB-DL size:<1.8GB age:>2h;
|
||||
# 4) R: size:>9GB;
|
||||
# 5) Q: HDTV.
|
||||
#
|
||||
# NOTE: This is a short documentation, for more information visit
|
||||
# http://nzbget.sourceforge.net/RSS.
|
||||
#Feed1.Filter=
|
||||
|
||||
# How often to check for new items (minutes).
|
||||
#
|
||||
# Value "0" disables the automatic check of this feed.
|
||||
#Feed1.Interval=15
|
||||
|
||||
# Add nzb-files as paused (yes, no).
|
||||
#Feed1.PauseNzb=no
|
||||
|
||||
# Category for added nzb-files.
|
||||
#
|
||||
# NOTE: Feed providers may include category name within response when nzb-file
|
||||
# is downloaded. If you want to use the providers category leave the option empty.
|
||||
#Feed1.Category=
|
||||
|
||||
# Priority for added nzb-files (number).
|
||||
#
|
||||
# Priority can be any integer value. The web-interface however operates
|
||||
# with only five predefined priorities: -100 (very low priority), -50
|
||||
# (low priority), 0 (normal priority, default), 50 (high priority),
|
||||
# 100 (very high priority).
|
||||
#Feed1.Priority=0
|
||||
|
||||
|
||||
##############################################################################
|
||||
### INCOMING NZBS ###
|
||||
|
||||
@@ -551,6 +303,17 @@ NzbDirInterval=5
|
||||
# downloaded in web-browser.
|
||||
NzbDirFileAge=60
|
||||
|
||||
# Automatic merging of nzb-files with the same filename (yes, no).
|
||||
#
|
||||
# A typical scenario: you put nzb-file into incoming directory, NZBGet adds
|
||||
# file to queue. You find out, that the file doesn't have par-files. You
|
||||
# find required par-files, put nzb-file with the par-files into incoming
|
||||
# directory, NZBGet adds it to queue as a separate group. You want the second
|
||||
# file to be merged with the first for parchecking to work properly. With
|
||||
# option "MergeNzb" NZBGet can merge files automatically. You only need to
|
||||
# save the second file under the same filename as the first one.
|
||||
MergeNzb=no
|
||||
|
||||
# Set path to program, that must be executed before a nzb-file is added
|
||||
# to queue.
|
||||
#
|
||||
@@ -684,29 +447,20 @@ NzbProcess=
|
||||
# "$NZBOP_APPBIN" -c "$NZBOP_CONFIGFILE" -E FR P "$NZBNA_NZBNAME/.*\.nzb";
|
||||
NzbAddedProcess=
|
||||
|
||||
# Check for duplicate titles (yes, no).
|
||||
# Check for duplicate files (yes, no).
|
||||
#
|
||||
# If this option is enabled the program checks by adding of a new nzb-file:
|
||||
# 1) if history contains the same title (see below) with success status
|
||||
# the nzb-file is not added to queue;
|
||||
# 2) if download queue already contains the same title the nzb-file is
|
||||
# added to queue for backup (if firt file fails);
|
||||
# 3) if nzb-file contains duplicate entries. This helps to find errors
|
||||
# in bad nzb-files.
|
||||
# 1) if nzb-file contains duplicate entries. This check aims on detecting
|
||||
# of reposted files (if first file was not fully uploaded).
|
||||
# If the program find two files with identical names, only the
|
||||
# biggest of these files will be added to queue;
|
||||
# 2) if download queue already contains file with the same name;
|
||||
# 3) if destination file on disk already exists.
|
||||
# In last two cases: if the file exists it will not be added to queue.
|
||||
#
|
||||
# "Same title" means the nzb file name is same or the duplicate key is
|
||||
# same. Duplicate keys are set by fetching from RSS feeds using title
|
||||
# identifier fields provided by RSS provider (imdbid or rageid/season/episode).
|
||||
#
|
||||
# If duplicates were detected only one of them is downloaded. If download
|
||||
# fails another duplicate is tried. If download succeeds all remaining
|
||||
# duplicates are deleted from queue.
|
||||
#
|
||||
# NOTE: for automatic duplicate handling option <HealthCheck> must be
|
||||
# set to "Delete" or "None". If it is set to "Pause" you will need to
|
||||
# manually unpause another duplicate (if any exists in queue).
|
||||
#
|
||||
# NOTE: For more info on duplicates see http://nzbget.sourceforge.net/RSS.
|
||||
# If this option is disabled, all files are downloaded and duplicate files
|
||||
# are renamed to "filename_duplicate1".
|
||||
# Existing files are never deleted or overwritten.
|
||||
DupeCheck=yes
|
||||
|
||||
|
||||
@@ -828,9 +582,8 @@ TerminateTimeout=600
|
||||
|
||||
# Set the maximum download rate on program start (kilobytes/sec).
|
||||
#
|
||||
# The download rate can be changed later via remote calls.
|
||||
#
|
||||
# Value "0" means no speed control.
|
||||
# The download rate can be changed later via remote calls.
|
||||
DownloadRate=0
|
||||
|
||||
# Accurate speed rate calculation (yes, no).
|
||||
@@ -876,65 +629,34 @@ WriteBufferSize=0
|
||||
|
||||
# Pause if disk space gets below this value (megabytes).
|
||||
#
|
||||
# Disk space is checked for directories pointed by option <DestDir> and
|
||||
# option <InterDir>.
|
||||
#
|
||||
# Value "0" disables the check.
|
||||
# Only the disk space on the drive with <DestDir> is checked.
|
||||
# The drive with <TempDir> is not checked.
|
||||
DiskSpace=250
|
||||
|
||||
# Delete already downloaded files from disk when nzb-file is deleted
|
||||
# (yes, no).
|
||||
# Delete already downloaded files from disk, if the download of nzb-file was
|
||||
# cancelled (nzb-file was deleted from queue) (yes, no).
|
||||
#
|
||||
# This option defines if downloaded files must be deleted when:
|
||||
# 1) download of nzb-file is cancelled (deleted from queue);
|
||||
# 2) history record with failure-status (par-failure or unpack-failure)
|
||||
# is deleted from history.
|
||||
DeleteCleanupDisk=yes
|
||||
|
||||
# Delete source nzb-file when it is not needed anymore (yes, no).
|
||||
#
|
||||
# Enable this option for automatic deletion of source nzb-file from
|
||||
# incoming directory when the program doesn't require it anymore (the
|
||||
# nzb-file has been deleted from queue and history).
|
||||
NzbCleanupDisk=yes
|
||||
# NOTE: NZBGet does not delete files in a case if all remaining files in
|
||||
# queue are par-files. That prevents the accidental deletion if the option
|
||||
# <ParCleanupQueue> is disabled or if the program was interrupted during
|
||||
# parcheck and later restarted without reloading of post queue (option
|
||||
# <ReloadPostQueue> disabled).
|
||||
DeleteCleanupDisk=no
|
||||
|
||||
# Keep the history of downloaded nzb-files (days).
|
||||
#
|
||||
# After download and post-processing the items are added to history where
|
||||
# their status can be checked and they can be post-processed again if
|
||||
# neccessary.
|
||||
# Value "0" disables the history.
|
||||
#
|
||||
# After expiring of defined period:
|
||||
#
|
||||
# If option <DupeCheck> is active the items become hidden and the amount
|
||||
# of data kept is significantly reduced (for better performance), only
|
||||
# fields necessary for duplicate check are kept. The item remain in the
|
||||
# hidden history (forever);
|
||||
#
|
||||
# If option <DupeCheck> is NOT active the items are removed from history.
|
||||
#
|
||||
# Value "0" disables history. Duplicate check will not work.
|
||||
KeepHistory=30
|
||||
|
||||
# Keep the history of outdated feed items (days).
|
||||
#
|
||||
# After fetching of an RSS feed the information about included items (nzb-files)
|
||||
# is saved to disk. This allows to detect new items on next fetch. Feed
|
||||
# providers update RSS feeds constantly. Since the feed length is limited
|
||||
# (usually 100 items or less) the old items get pushed away by new
|
||||
# ones. When an item is not present in the feed anymore it's not necessary
|
||||
# to keep the information about this item on the disk.
|
||||
#
|
||||
# If option is set to "0", the outdated items are deleted from history
|
||||
# immediately.
|
||||
#
|
||||
# Otherwise the items are held in the history for defined number of
|
||||
# days. Keeping of items for few days helps in situations when feed provider
|
||||
# has technical issues and may response with empty feeds (or with missing
|
||||
# items). When the technical issue is fixed the items may reappear in the
|
||||
# feed causing the program to redownload items if they were not found in
|
||||
# the feed history.
|
||||
FeedHistory=7
|
||||
# NOTE: When a collection having paused files is added to history all remaining
|
||||
# files are moved from download queue to a list of parked files. It holds files
|
||||
# which could be required later if the collection will be moved back to
|
||||
# download queue for downloading of remaining files. The parked files still
|
||||
# consume some amount of memory and disk space. If the collection was downloaded
|
||||
# and successfully par-checked or postprocessed it is recommended to discard the
|
||||
# unneeded parked files before adding the collection to history. For par2-files
|
||||
# that can be achieved with the option <ParCleanupQueue>.
|
||||
KeepHistory=7
|
||||
|
||||
# Maximum number of simultaneous connections for nzb URL downloads (0-999).
|
||||
#
|
||||
@@ -943,12 +665,35 @@ FeedHistory=7
|
||||
# used for this purpose, when multiple URLs were added at the same time.
|
||||
UrlConnections=4
|
||||
|
||||
# Force URL-downloads even if download queue is paused (yes, no).
|
||||
|
||||
##############################################################################
|
||||
### CATEGORIES ###
|
||||
|
||||
# This section defines categories available in web-interface.
|
||||
|
||||
# Category name.
|
||||
#
|
||||
# If option is active the URL-downloads (such as appending of nzb-files
|
||||
# via URL or fetching of RSS feeds and nzb-files from feeds) are performed
|
||||
# even if download is in paused state.
|
||||
UrlForce=yes
|
||||
# Each nzb-file can be assigned to a category.
|
||||
# Category name is passed to post-processing script and can be used by it
|
||||
# to perform category specific processing.
|
||||
Category1.Name=Movies
|
||||
|
||||
# Destination directory for this category.
|
||||
#
|
||||
# If this option is empty, then the default destination directory
|
||||
# (option <DestDir>) is used. In this case if the option <AppendCategoryDir>
|
||||
# is active, the program creates a subdirectory with category name within
|
||||
# destination directory.
|
||||
Category1.DestDir=
|
||||
|
||||
# Default list of post-processing scripts.
|
||||
#
|
||||
# For more information see global option <DefScript>.
|
||||
Category1.DefScript=
|
||||
|
||||
Category2.Name=Series
|
||||
Category3.Name=Music
|
||||
Category4.Name=Software
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -996,22 +741,6 @@ CreateBrokenLog=yes
|
||||
# newsserver etc.
|
||||
DumpCore=no
|
||||
|
||||
# Local time correction (hours or minutes).
|
||||
#
|
||||
# The option allows to adjust timestamps when converting system time to
|
||||
# local time and vice versa. The conversion is used when printing messages
|
||||
# to the log-file and by option "TaskX.Time" in the scheduler settings.
|
||||
#
|
||||
# The option is usually not needed if the time zone is set up correctly.
|
||||
# However, sometimes, especially when using a binary compiled on onother
|
||||
# platform (cross-compiling) the conversion between system and local time
|
||||
# may not work properly and requires adjustment.
|
||||
#
|
||||
# Values in the range -24..+24 are interpreted as hours, other values as minutes.
|
||||
# Example 1: set time correction to one hour: TimeCorrection=1;
|
||||
# Example 2: set time correction to one hour and a half: TimeCorrection=90.
|
||||
TimeCorrection=0
|
||||
|
||||
# See also option <LogFile> in section "PATHS"
|
||||
|
||||
|
||||
@@ -1068,8 +797,6 @@ UpdateInterval=200
|
||||
# Asterix as hours-part means "every hour".
|
||||
#
|
||||
# Examples: "08:00", "00:00,06:00,12:00,18:00", "*:00", "*:00,*:30".
|
||||
#
|
||||
# NOTE: also see option <TimeCorrection>.
|
||||
#Task1.Time=08:00
|
||||
|
||||
# Week days to execute the command (1-7).
|
||||
@@ -1081,56 +808,47 @@ UpdateInterval=200
|
||||
# Examples: "1-7", "1-5", "5,6", "1-5, 7".
|
||||
#Task1.WeekDays=1-7
|
||||
|
||||
# Command to be executed ( PauseDownload, UnpauseDownload, PauseScan, UnpauseScan,
|
||||
# DownloadRate, Process, ActivateServer, DeactivateServer, FetchFeed).
|
||||
# Command to be executed (DownloadRate, PauseDownload, UnpauseDownload, PauseScan,
|
||||
# UnpauseScan, Process).
|
||||
#
|
||||
# Possible commands:
|
||||
# PauseDownload - pauses download;
|
||||
# UnpauseDownload - resumes download;
|
||||
# PauseScan - pauses scan of incoming nzb-directory;
|
||||
# UnpauseScan - resumes scan of incoming nzb-directory;
|
||||
# DownloadRate - sets download rate limit;
|
||||
# Process - executes external program;
|
||||
# ActivateServer - activate news-server;
|
||||
# DeactivateServer - deactivate news-server;
|
||||
# FetchFeed - fetch RSS feed.
|
||||
#
|
||||
# On start the program checks all tasks and determines current state
|
||||
# for download-pause, scan-pause, download-rate and active servers.
|
||||
#Task1.Command=PauseDownload
|
||||
# DownloadRate - sets download rate in KB/s;
|
||||
# PauseDownload - pauses download;
|
||||
# UnpauseDownload - resumes download;
|
||||
# PauseScan - pauses scan of incoming nzb-directory;
|
||||
# UnpauseScan - resumes scan of incoming nzb-directory;
|
||||
# Process - executes external program.
|
||||
#Task1.Command=DownloadRate
|
||||
|
||||
# Parameters for the command if needed.
|
||||
# Download rate to be set if the command is "DownloadRate" (kilobytes/sec).
|
||||
#
|
||||
# Some scheduler commands require additional parameters:
|
||||
# DownloadRate - download rate limit to be set (kilobytes/sec).
|
||||
# Example: 1000;
|
||||
# Process - path to the program to execute and its parameters.
|
||||
# Example: /home/user/fetch.sh.
|
||||
# If filename or any parameter contains spaces it
|
||||
# must be surrounded with single quotation
|
||||
# marks. If filename/parameter contains single quotation marks,
|
||||
# each of them must be replaced with two single quotation
|
||||
# marks and the resulting filename/parameter must be
|
||||
# surrounded with single quotation marks.
|
||||
# Example: '/home/user/download/my scripts/task process.sh' 'world''s fun'.
|
||||
# In this example one parameter (world's fun) is passed
|
||||
# to the script (task process.sh).
|
||||
# ActivateServer - comma separated list of news server ids or server names.
|
||||
# Example: 1,3.
|
||||
# Example: my news server 1, my news server 2.
|
||||
# NOTE: server names should not have commas.
|
||||
# DeactivateServer - see ActivateServer.
|
||||
# FetchFeed - comma separated list of RSS feed ids or feed names.
|
||||
# Example: 1,3.
|
||||
# Example: bookmarks feed, another feed.
|
||||
# NOTE: feed names should not have commas.
|
||||
# NOTE: use feed id "0" to fetch all feeds.
|
||||
#Task1.Param=
|
||||
# Value "0" means no speed control.
|
||||
#
|
||||
# If the option <TaskX.Command> is not set to "DownloadRate" this option
|
||||
# is ignored and can be omitted.
|
||||
#Task1.DownloadRate=100
|
||||
|
||||
# Path to the program to execute if the command is "Process".
|
||||
#
|
||||
# Example: /home/user/fetch-nzb.sh.
|
||||
#
|
||||
# If the option <TaskX.Command> is not set to "Process" this option
|
||||
# is ignored and can be omitted.
|
||||
#
|
||||
# NOTE: It's allowed to add parameters to command line. If filename or
|
||||
# any parameter contains spaces it must be surrounded with single quotation
|
||||
# marks. If filename/parameter contains single quotation marks, each of them
|
||||
# must be replaced with two single quotation marks and the resulting filename/
|
||||
# parameter must be surrounded with single quotation marks.
|
||||
# Example: '/home/user/download/my scripts/task process.sh' 'world''s fun'.
|
||||
# In this example one parameter (world's fun) is passed to the script
|
||||
# (task process.sh).
|
||||
#Task1.Process=/home/user/script.sh
|
||||
|
||||
#Task2.Time=20:00
|
||||
#Task2.WeekDays=1-7
|
||||
#Task2.Command=UnpauseDownload
|
||||
#Task2.Param=
|
||||
#Task2.Command=DownloadRate
|
||||
#Task2.DownloadRate=0
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -1160,8 +878,8 @@ ParCheck=auto
|
||||
# may take too much resources and time on a slow computers.
|
||||
ParRepair=yes
|
||||
|
||||
# What files should be scanned during par-verification (auto, limited,
|
||||
# full).
|
||||
# What files should be scanned during par-verification (limited,
|
||||
# full, auto).
|
||||
#
|
||||
# Limited - scan only files belonging to the par-set;
|
||||
# Full - scan all files in the directory. This helps if the
|
||||
@@ -1170,38 +888,35 @@ ParRepair=yes
|
||||
# detects missing files, it scans other files in the
|
||||
# directory until all required files are found.
|
||||
#
|
||||
# NOTE: for par-check/repair NZBGet uses library libpar2. The widely
|
||||
# used version 0.2 of the library has few bugs, sometimes causing
|
||||
# NOTE: for par-check/repair NZBGet uses library libpar2. The last and
|
||||
# widely used version 0.2 of the library has few bugs, sometimes causing
|
||||
# a crash of the program. This is especially true when using "full" or
|
||||
# "auto" par-scan. NZBGet is supplied with patches addressing these
|
||||
# issues. Please apply the patches to libpar2 and recompile it.
|
||||
ParScan=auto
|
||||
|
||||
# Check for renamed files (yes, no).
|
||||
# Use only par2-files with matching names (yes, no).
|
||||
#
|
||||
# Par-rename restores original file names using information stored
|
||||
# in par2-files. When enabled the par-rename is performed as a first
|
||||
# step of post-processing for every nzb-file having par2-files.
|
||||
# If par-check needs extra par-blocks it looks for paused par2-files
|
||||
# in the download queue. These par2-files should have the same base name
|
||||
# as the main par2-file, currently loaded in par-checker. Sometimes extra
|
||||
# par2-files have non-matching names (especially if they were uploaded
|
||||
# by a different poster). Normally par-checker does not use these files, but
|
||||
# you can allow it to use them by setting <StrictParName> to "no".
|
||||
# There is a small side effect then: if NZB-file contains more than one
|
||||
# collection of files (with different par-sets), par-checker may download
|
||||
# par2-files from a wrong collection and will need to unpause other
|
||||
# par2-files until all required files are downloaded. This increases the
|
||||
# traffic (but not harm the par-check).
|
||||
#
|
||||
# Par-rename is very fast and is highly recommended, especially if
|
||||
# unpack is disabled.
|
||||
ParRename=yes
|
||||
|
||||
# What to do if download health goes down below critical health (delete,
|
||||
# pause, none).
|
||||
#
|
||||
# Delete - delete nzb-file from queue. If option <DeleteCleanupDisk>
|
||||
# is active the already downloaded files will be deleted too;
|
||||
# Pause - pause nzb-file;
|
||||
# None - do nothing (continue download).
|
||||
#
|
||||
# NOTE: for automatic duplicate handling option must be set to "Delete"
|
||||
# or "None". If it is set to "Pause" you will need to manually unpause
|
||||
# another duplicate (if any exists in queue). See also option <DupeCheck>.
|
||||
HealthCheck=delete
|
||||
# NOTE: Par-checker always uses only par-files added from the same NZB-file
|
||||
# and the option <StrictParName> does not change this behavior.
|
||||
StrictParName=yes
|
||||
|
||||
# Maximum allowed time for par-repair (minutes).
|
||||
#
|
||||
# Value "0" means unlimited.
|
||||
#
|
||||
# If you use NZBGet on a very slow computer like NAS-device, it may be good to
|
||||
# limit the time allowed for par-repair. NZBGet calculates the estimated time
|
||||
# required for par-repair. If the estimated value exceeds the limit defined
|
||||
@@ -1213,8 +928,6 @@ HealthCheck=delete
|
||||
# set to a value smaller than 5 minutes, the comparison is made after the first
|
||||
# whole minute.
|
||||
#
|
||||
# Value "0" means unlimited.
|
||||
#
|
||||
# NOTE: The option limits only the time required for repairing. It doesn't
|
||||
# affect the first stage of parcheck - verification of files. However the
|
||||
# verification speed is constant, it doesn't depend on files integrity and
|
||||
@@ -1242,6 +955,12 @@ ParPauseQueue=no
|
||||
# from download queue after successful check/repair.
|
||||
ParCleanupQueue=yes
|
||||
|
||||
# Delete source nzb-file after successful check/repair (yes, no).
|
||||
#
|
||||
# Enable this option for automatic deletion of nzb-file from incoming directory
|
||||
# after successful check/repair.
|
||||
NzbCleanupDisk=no
|
||||
|
||||
# Files to delete after successful check/repair.
|
||||
#
|
||||
# List of file extensions or file names to delete after successful
|
||||
@@ -1257,19 +976,12 @@ ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
|
||||
|
||||
# Unpack downloaded nzb-files (yes, no).
|
||||
#
|
||||
# Each download (nzb-file) has a post-processing parameter "Unpack". The option
|
||||
# <Unpack> is the default value assigned to this pp-parameter of the download
|
||||
# when it is added to queue.
|
||||
#
|
||||
# When nzb-file is added to queue it can have a category assigned to it. In this
|
||||
# case the option <CategoryX.Unpack> overrides the global option <Unpack>.
|
||||
#
|
||||
# If the download is damaged and could not be repaired using par-files
|
||||
# the unpacking is not performed.
|
||||
#
|
||||
# If the option <ParCheck> is set to "Auto" the program tries to unpack
|
||||
# If the option <ParCheck> is disabled the program will try to unpack
|
||||
# downloaded files first. If the unpacking fails the par-check/repair
|
||||
# is performed and the unpack is executed again.
|
||||
# is performed and the unpack will be executed again.
|
||||
Unpack=yes
|
||||
|
||||
# Pause download queue during unpack (yes, no).
|
||||
@@ -1343,19 +1055,7 @@ SevenZipCmd=7z
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file. It includes file extension and also
|
||||
# may include full path;
|
||||
# NZBPP_FINALDIR - final destination path if set by one of previous pp-scripts;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# NZBPP_HEALTH - download health: an integer value in the range
|
||||
# from 0 (all articles failed) to 1000 (all articles
|
||||
# successfully downloaded);
|
||||
# NZBPP_CRITICALHEALTH - critical health for this nzb-file: an integer
|
||||
# value in the range 0-1000. The critical health
|
||||
# is calculated based on number and size of
|
||||
# par-files. If nzb-file doesn't have any par-files
|
||||
# the critical health is 1000 (100.0%). If a half
|
||||
# of nzb-file were par-files its critical health
|
||||
# would be 0. If NZBPP_HEALTH goes down below
|
||||
# NZBPP_CRITICALHEALTH the download becomes unrepairable;
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check is disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
@@ -1365,20 +1065,9 @@ SevenZipCmd=7z
|
||||
# 4 = par-check needed but skipped (option ParCheck=manual);
|
||||
# NZBPP_UNPACKSTATUS - result of unpack:
|
||||
# 0 = unpack is disabled or was skipped due to nzb-file
|
||||
# parameters or due to errors during par-check;
|
||||
# properties or due to errors during par-check;
|
||||
# 1 = unpack failed;
|
||||
# 2 = unpack successful;
|
||||
# 3 = write error (usually not enough disk space);
|
||||
# 4 = wrong password (only for rar5 archives);
|
||||
# NZBPP_HEALTHDELETED - indicates if nzb-file was deleted by health
|
||||
# check (1);
|
||||
# NZBPP_TOTALARTICLES - number of articles in nzb-file;
|
||||
# NZBPP_SUCCESSARTICLES - number of successfully downloaded articles;
|
||||
# NZBPP_FAILEDARTICLES - number of failed articles;
|
||||
# NZBPP_SERVERX_SUCCESSARTICLES - number of successfully downloaded
|
||||
# articles from ServerX (X is replaced with server
|
||||
# number, for example NZBPP_SERVER1_SUCCESSARTICLES);
|
||||
# NZBPP_SERVERX_FAILEDARTICLES - number of failed articles from ServerX.
|
||||
# 2 = unpack successful.
|
||||
#
|
||||
# If the script defines own options they are also passed as environment
|
||||
# variables. These variables have prefix "NZBPO_" in their names. For
|
||||
@@ -1398,18 +1087,6 @@ SevenZipCmd=7z
|
||||
# "SERVER1_HOST". For options with predefined possible values (yes/no, etc.)
|
||||
# the values are passed always in lower case.
|
||||
#
|
||||
# If the script moves files it can inform the program about new location
|
||||
# by printing special message into standard output (which is processed
|
||||
# by NZBGet):
|
||||
# echo "[NZB] FINALDIR=/path/to/moved/files";
|
||||
#
|
||||
# To assign post-processing parameters:
|
||||
# echo "[NZB] NZBPR_myvar=my value";
|
||||
#
|
||||
# The prefix "NZBPR_" will be removed. In this example a post-processing
|
||||
# parameter with name "myvar" and value "my value" will be associated
|
||||
# with nzb-file.
|
||||
#
|
||||
# Return value: NZBGet processes the exit code returned by the script:
|
||||
# 93 - post-process successful (status = SUCCESS);
|
||||
# 94 - post-process failed (status = FAILURE);
|
||||
|
||||
122
nzbget.cpp
122
nzbget.cpp
@@ -75,8 +75,6 @@
|
||||
#include "ParChecker.h"
|
||||
#include "Scheduler.h"
|
||||
#include "Scanner.h"
|
||||
#include "FeedCoordinator.h"
|
||||
#include "Maintenance.h"
|
||||
#include "Util.h"
|
||||
#ifdef WIN32
|
||||
#include "NTService.h"
|
||||
@@ -117,8 +115,6 @@ PrePostProcessor* g_pPrePostProcessor = NULL;
|
||||
DiskState* g_pDiskState = NULL;
|
||||
Scheduler* g_pScheduler = NULL;
|
||||
Scanner* g_pScanner = NULL;
|
||||
FeedCoordinator* g_pFeedCoordinator = NULL;
|
||||
Maintenance* g_pMaintenance = NULL;
|
||||
int g_iArgumentCount;
|
||||
char* (*g_szEnvironmentVariables)[] = NULL;
|
||||
char* (*g_szArguments)[] = NULL;
|
||||
@@ -151,8 +147,6 @@ int main(int argc, char *argv[], char *argp[])
|
||||
DisableCout();
|
||||
#endif
|
||||
|
||||
srand (time(NULL));
|
||||
|
||||
g_iArgumentCount = argc;
|
||||
g_szArguments = (char*(*)[])argv;
|
||||
g_szEnvironmentVariables = (char*(*)[])argp;
|
||||
@@ -211,12 +205,6 @@ void Run(bool bReload)
|
||||
|
||||
g_pServerPool = new ServerPool();
|
||||
g_pScheduler = new Scheduler();
|
||||
g_pQueueCoordinator = new QueueCoordinator();
|
||||
g_pDownloadSpeedMeter = g_pQueueCoordinator;
|
||||
g_pDownloadQueueHolder = g_pQueueCoordinator;
|
||||
g_pUrlCoordinator = new UrlCoordinator();
|
||||
g_pFeedCoordinator = new FeedCoordinator();
|
||||
g_pMaintenance = new Maintenance();
|
||||
|
||||
debug("Reading options");
|
||||
g_pOptions = new Options(g_iArgumentCount, *g_szArguments);
|
||||
@@ -266,6 +254,9 @@ void Run(bool bReload)
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
g_pServerPool->InitConnections();
|
||||
#ifdef DEBUG
|
||||
g_pServerPool->LogDebugInfo();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
@@ -295,6 +286,16 @@ void Run(bool bReload)
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the queue coordinator
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
g_pQueueCoordinator = new QueueCoordinator();
|
||||
g_pDownloadSpeedMeter = g_pQueueCoordinator;
|
||||
g_pDownloadQueueHolder = g_pQueueCoordinator;
|
||||
|
||||
g_pUrlCoordinator = new UrlCoordinator();
|
||||
}
|
||||
|
||||
// Setup the network-server
|
||||
if (g_pOptions->GetServerMode())
|
||||
{
|
||||
@@ -364,13 +365,11 @@ void Run(bool bReload)
|
||||
g_pQueueCoordinator->Start();
|
||||
g_pUrlCoordinator->Start();
|
||||
g_pPrePostProcessor->Start();
|
||||
g_pFeedCoordinator->Start();
|
||||
|
||||
// enter main program-loop
|
||||
while (g_pQueueCoordinator->IsRunning() ||
|
||||
g_pUrlCoordinator->IsRunning() ||
|
||||
g_pPrePostProcessor->IsRunning() ||
|
||||
g_pFeedCoordinator->IsRunning())
|
||||
g_pPrePostProcessor->IsRunning())
|
||||
{
|
||||
if (!g_pOptions->GetServerMode() &&
|
||||
!g_pQueueCoordinator->HasMoreJobs() &&
|
||||
@@ -390,10 +389,6 @@ void Run(bool bReload)
|
||||
{
|
||||
g_pPrePostProcessor->Stop();
|
||||
}
|
||||
if (!g_pFeedCoordinator->IsStopped())
|
||||
{
|
||||
g_pFeedCoordinator->Stop();
|
||||
}
|
||||
}
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
@@ -402,7 +397,6 @@ void Run(bool bReload)
|
||||
debug("QueueCoordinator stopped");
|
||||
debug("UrlCoordinator stopped");
|
||||
debug("PrePostProcessor stopped");
|
||||
debug("FeedCoordinator stopped");
|
||||
}
|
||||
|
||||
// Stop network-server
|
||||
@@ -601,7 +595,6 @@ void ExitProc()
|
||||
g_pQueueCoordinator->Stop();
|
||||
g_pUrlCoordinator->Stop();
|
||||
g_pPrePostProcessor->Stop();
|
||||
g_pFeedCoordinator->Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -726,40 +719,64 @@ void Cleanup()
|
||||
debug("Cleaning up global objects");
|
||||
|
||||
debug("Deleting UrlCoordinator");
|
||||
delete g_pUrlCoordinator;
|
||||
g_pUrlCoordinator = NULL;
|
||||
if (g_pUrlCoordinator)
|
||||
{
|
||||
delete g_pUrlCoordinator;
|
||||
g_pUrlCoordinator = NULL;
|
||||
}
|
||||
debug("UrlCoordinator deleted");
|
||||
|
||||
debug("Deleting RemoteServer");
|
||||
delete g_pRemoteServer;
|
||||
g_pRemoteServer = NULL;
|
||||
if (g_pRemoteServer)
|
||||
{
|
||||
delete g_pRemoteServer;
|
||||
g_pRemoteServer = NULL;
|
||||
}
|
||||
debug("RemoteServer deleted");
|
||||
|
||||
debug("Deleting RemoteSecureServer");
|
||||
delete g_pRemoteSecureServer;
|
||||
g_pRemoteSecureServer = NULL;
|
||||
if (g_pRemoteSecureServer)
|
||||
{
|
||||
delete g_pRemoteSecureServer;
|
||||
g_pRemoteSecureServer = NULL;
|
||||
}
|
||||
debug("RemoteSecureServer deleted");
|
||||
|
||||
debug("Deleting PrePostProcessor");
|
||||
delete g_pPrePostProcessor;
|
||||
g_pPrePostProcessor = NULL;
|
||||
delete g_pScanner;
|
||||
g_pScanner = NULL;
|
||||
if (g_pPrePostProcessor)
|
||||
{
|
||||
delete g_pPrePostProcessor;
|
||||
g_pPrePostProcessor = NULL;
|
||||
}
|
||||
if (g_pScanner)
|
||||
{
|
||||
delete g_pScanner;
|
||||
g_pScanner = NULL;
|
||||
}
|
||||
debug("PrePostProcessor deleted");
|
||||
|
||||
debug("Deleting Frontend");
|
||||
delete g_pFrontend;
|
||||
g_pFrontend = NULL;
|
||||
if (g_pFrontend)
|
||||
{
|
||||
delete g_pFrontend;
|
||||
g_pFrontend = NULL;
|
||||
}
|
||||
debug("Frontend deleted");
|
||||
|
||||
debug("Deleting QueueCoordinator");
|
||||
delete g_pQueueCoordinator;
|
||||
g_pQueueCoordinator = NULL;
|
||||
if (g_pQueueCoordinator)
|
||||
{
|
||||
delete g_pQueueCoordinator;
|
||||
g_pQueueCoordinator = NULL;
|
||||
}
|
||||
debug("QueueCoordinator deleted");
|
||||
|
||||
debug("Deleting DiskState");
|
||||
delete g_pDiskState;
|
||||
g_pDiskState = NULL;
|
||||
if (g_pDiskState)
|
||||
{
|
||||
delete g_pDiskState;
|
||||
g_pDiskState = NULL;
|
||||
}
|
||||
debug("DiskState deleted");
|
||||
|
||||
debug("Deleting Options");
|
||||
@@ -776,25 +793,21 @@ void Cleanup()
|
||||
debug("Options deleted");
|
||||
|
||||
debug("Deleting ServerPool");
|
||||
delete g_pServerPool;
|
||||
g_pServerPool = NULL;
|
||||
if (g_pServerPool)
|
||||
{
|
||||
delete g_pServerPool;
|
||||
g_pServerPool = NULL;
|
||||
}
|
||||
debug("ServerPool deleted");
|
||||
|
||||
debug("Deleting Scheduler");
|
||||
delete g_pScheduler;
|
||||
g_pScheduler = NULL;
|
||||
if (g_pScheduler)
|
||||
{
|
||||
delete g_pScheduler;
|
||||
g_pScheduler = NULL;
|
||||
}
|
||||
debug("Scheduler deleted");
|
||||
|
||||
debug("Deleting FeedCoordinator");
|
||||
delete g_pFeedCoordinator;
|
||||
g_pFeedCoordinator = NULL;
|
||||
debug("FeedCoordinator deleted");
|
||||
|
||||
debug("Deleting Maintenance");
|
||||
delete g_pMaintenance;
|
||||
g_pMaintenance = NULL;
|
||||
debug("Maintenance deleted");
|
||||
|
||||
if (!g_bReloading)
|
||||
{
|
||||
Connection::Final();
|
||||
@@ -803,8 +816,11 @@ void Cleanup()
|
||||
|
||||
debug("Global objects cleaned up");
|
||||
|
||||
delete g_pLog;
|
||||
g_pLog = NULL;
|
||||
if (g_pLog)
|
||||
{
|
||||
delete g_pLog;
|
||||
g_pLog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
1
nzbget.h
1
nzbget.h
@@ -58,7 +58,6 @@
|
||||
#define ALT_PATH_SEPARATOR '/'
|
||||
#define LINE_ENDING "\r\n"
|
||||
#define pid_t int
|
||||
#define atoll _atoi64
|
||||
#ifndef FSCTL_SET_SPARSE
|
||||
#define FSCTL_SET_SPARSE 590020
|
||||
#endif
|
||||
|
||||
@@ -299,46 +299,6 @@
|
||||
RelativePath=".\DownloadInfo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\DupeCoordinator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\DupeCoordinator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedCoordinator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedCoordinator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedFile.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedFile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedFilter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedFilter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedInfo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FeedInfo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Frontend.cpp"
|
||||
>
|
||||
@@ -363,14 +323,6 @@
|
||||
RelativePath=".\LoggableFrontend.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Maintenance.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Maintenance.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\MessageBase.h"
|
||||
>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
#else
|
||||
# define DLog(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define SuppressPerformSelectorLeakWarning(Stuff) \
|
||||
do { \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
|
||||
Stuff; \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
} while (0)
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@protocol DaemonControllerDelegate
|
||||
|
||||
- (void)daemonConfigLoaded;
|
||||
- (void)daemonStatusUpdated;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface DaemonController : NSObject {
|
||||
NSString* lockFilePath;
|
||||
NSDictionary* config;
|
||||
int restartCounter;
|
||||
int restartPid;
|
||||
NSTimer* updateTimer;
|
||||
int lastUptime;
|
||||
BOOL factoryReset;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval updateInterval;
|
||||
@property (nonatomic, readonly) BOOL connected;
|
||||
@property (nonatomic, readonly) BOOL restarting;
|
||||
@property (nonatomic, readonly) BOOL recoveryMode;
|
||||
@property (nonatomic, readonly) NSString* configFilePath;
|
||||
@property (nonatomic, readonly) NSString* browserUrl;
|
||||
@property (nonatomic, readonly) NSDate* lastUpdate;
|
||||
@property (nonatomic, assign) id<DaemonControllerDelegate> delegate;
|
||||
@property (nonatomic, readonly) NSDictionary* status;
|
||||
|
||||
- (id)init;
|
||||
|
||||
- (NSString*)valueForOption:(NSString*)option;
|
||||
|
||||
- (void)start;
|
||||
|
||||
- (void)stop;
|
||||
|
||||
- (void)restartInRecoveryMode:(BOOL)recovery withFactoryReset:(BOOL)reset;
|
||||
|
||||
- (NSString *)browserUrl;
|
||||
|
||||
- (void)updateStatus;
|
||||
|
||||
- (void)rpc:(NSString*)method success:(SEL)successCallback failure:(SEL)failureCallback;
|
||||
|
||||
- (void)setUpdateInterval:(NSTimeInterval)updateInterval;
|
||||
|
||||
@end
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libproc.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "DaemonController.h"
|
||||
#import "RPC.h"
|
||||
|
||||
NSString* MAIN_DIR = @"${AppSupDir}";
|
||||
NSString* LOCK_FILE = @"${AppSupDir}/nzbget.lock";
|
||||
NSString* CONFIG_FILE = @"${AppSupDir}/nzbget.conf";
|
||||
NSString* PPSCRIPTS_DIR = @"${AppSupDir}/ppscripts";
|
||||
NSString* NZB_DIR = @"${AppSupDir}/nzb";
|
||||
NSString* QUEUE_DIR = @"${AppSupDir}/queue";
|
||||
NSString* TMP_DIR = @"${AppSupDir}/tmp";
|
||||
|
||||
@implementation DaemonController
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
|
||||
_configFilePath = [self resolveAppSupDir:CONFIG_FILE];
|
||||
lockFilePath = [self resolveAppSupDir:LOCK_FILE];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *) bundlePath {
|
||||
return [[NSBundle mainBundle] pathForResource:@"daemon" ofType:nil];
|
||||
}
|
||||
|
||||
- (NSString *) resolveAppSupDir:(NSString *)dir {
|
||||
NSString *appSupPath = [@"${AppSupDir}/Application Support/NZBGet" stringByExpandingTildeInPath];
|
||||
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
if (paths.count > 0)
|
||||
{
|
||||
appSupPath = [paths objectAtIndex:0];
|
||||
appSupPath = [appSupPath stringByAppendingPathComponent:@"NZBGet"];
|
||||
}
|
||||
|
||||
dir = [dir stringByReplacingOccurrencesOfString:@"${AppSupDir}"
|
||||
withString:appSupPath
|
||||
options:NSCaseInsensitiveSearch
|
||||
range:NSMakeRange(0, dir.length)];
|
||||
return dir;
|
||||
}
|
||||
|
||||
- (void) checkDefaults {
|
||||
NSString* mainDir = [self resolveAppSupDir:MAIN_DIR];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:mainDir]) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:mainDir withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
NSString* bundlePath = [self bundlePath];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:_configFilePath]) {
|
||||
NSString* configTemplate = [NSString stringWithFormat:@"%@/usr/local/share/nzbget/nzbget.conf", bundlePath];
|
||||
[[NSFileManager defaultManager] copyItemAtPath:configTemplate toPath:_configFilePath error:nil];
|
||||
}
|
||||
|
||||
NSString* ppscriptsDir = [self resolveAppSupDir:PPSCRIPTS_DIR];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:ppscriptsDir]) {
|
||||
NSString* ppscriptsTemplate = [NSString stringWithFormat:@"%@/usr/local/share/nzbget/ppscripts", bundlePath];
|
||||
[[NSFileManager defaultManager] copyItemAtPath:ppscriptsTemplate toPath:ppscriptsDir error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)readLockFilePid {
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:lockFilePath]) {
|
||||
// Lock file exists
|
||||
// read pid from lock file
|
||||
int pid = [[NSString stringWithContentsOfFile:lockFilePath encoding:NSUTF8StringEncoding error:nil] intValue];
|
||||
DLog(@"pid: %i", pid);
|
||||
|
||||
// check if the process name is "nzbget" to avoid killing of other proceses
|
||||
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
|
||||
int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
|
||||
if (ret <= 0) {
|
||||
// error
|
||||
return 0;
|
||||
}
|
||||
|
||||
DLog(@"proc %d: %s\n", pid, pathbuf);
|
||||
|
||||
NSString* instancePath = [NSString stringWithUTF8String:pathbuf];
|
||||
if ([instancePath hasSuffix:@".app/Contents/Resources/daemon/usr/local/bin/nzbget"]) {
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)killDaemonWithSignal:(int)signal {
|
||||
int pid = [self readLockFilePid];
|
||||
if (pid > 0) {
|
||||
kill(pid, signal);
|
||||
[[NSFileManager defaultManager] removeItemAtPath:lockFilePath error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
DLog(@"DaemonController->start");
|
||||
|
||||
[self checkDefaults];
|
||||
[self killDaemonWithSignal:SIGKILL];
|
||||
[self readConfigFile];
|
||||
[self initRpcUrl];
|
||||
[self initBrowserUrl];
|
||||
|
||||
NSString* bundlePath = [self bundlePath];
|
||||
NSString* daemonPath = [NSString stringWithFormat:@"%@/usr/local/bin/nzbget", bundlePath];
|
||||
NSString* optionWebDir = [NSString stringWithFormat:@"WebDir=%@/usr/local/share/nzbget/webui", bundlePath];
|
||||
NSString* optionConfigTemplate = [NSString stringWithFormat:@"ConfigTemplate=%@/usr/local/share/nzbget/nzbget.conf", bundlePath];
|
||||
NSString* optionLockFile = [NSString stringWithFormat:@"LockFile=%@", lockFilePath];
|
||||
|
||||
NSMutableArray* arguments = [NSMutableArray arrayWithObjects:
|
||||
@"-c", _configFilePath,
|
||||
@"-D",
|
||||
@"-o", optionWebDir,
|
||||
@"-o", optionConfigTemplate,
|
||||
@"-o", optionLockFile,
|
||||
nil];
|
||||
|
||||
if (_recoveryMode) {
|
||||
[arguments addObjectsFromArray: [NSArray arrayWithObjects:
|
||||
@"-o", @"ControlIP=127.0.0.1",
|
||||
@"-o", @"ControlPort=6789",
|
||||
@"-o", @"ControlPassword=",
|
||||
@"-o", @"SecureControl=no",
|
||||
nil
|
||||
]];
|
||||
}
|
||||
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
[task setLaunchPath: daemonPath];
|
||||
[task setArguments: arguments];
|
||||
[task launch];
|
||||
|
||||
_restarting = NO;
|
||||
[self scheduleNextUpdate];
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
DLog(@"DaemonController->stop");
|
||||
[self killDaemonWithSignal:SIGTERM];
|
||||
}
|
||||
|
||||
- (void)restartInRecoveryMode:(BOOL)recovery withFactoryReset:(BOOL)reset {
|
||||
_recoveryMode = recovery;
|
||||
factoryReset = reset;
|
||||
_restarting = YES;
|
||||
restartPid = [self readLockFilePid];
|
||||
[self stop];
|
||||
|
||||
// in timer wait for deletion of lockfile for 10 seconds,
|
||||
// after that call "start" which will kill the old process.
|
||||
restartCounter = 0;
|
||||
[self restartWait];
|
||||
}
|
||||
|
||||
- (void)restartWait {
|
||||
DLog(@"DaemonController->restartWait");
|
||||
restartCounter++;
|
||||
|
||||
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
|
||||
int ret = proc_pidpath(restartPid, pathbuf, sizeof(pathbuf));
|
||||
if (ret > 0 && restartCounter < 100) {
|
||||
DLog(@"restartWait: scheduleNextRestartWait");
|
||||
[self scheduleNextRestartWait];
|
||||
} else {
|
||||
DLog(@"restartWait: start");
|
||||
if (factoryReset) {
|
||||
[self resetToFactoryDefaults];
|
||||
}
|
||||
[self start];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetToFactoryDefaults {
|
||||
DLog(@"DaemonController->resetToFactoryDefaults");
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_configFilePath error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:QUEUE_DIR] error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:PPSCRIPTS_DIR] error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:NZB_DIR] error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:TMP_DIR] error:nil];
|
||||
}
|
||||
|
||||
- (void)scheduleNextRestartWait {
|
||||
NSTimer* timer = [NSTimer timerWithTimeInterval:0.100 target:self selector:@selector(restartWait) userInfo:nil repeats:NO];
|
||||
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)readConfigFile {
|
||||
DLog(@"DaemonController->readConfigFile");
|
||||
NSString* str = [NSString stringWithContentsOfFile:_configFilePath encoding:NSUTF8StringEncoding error:nil];
|
||||
NSArray* conf = [str componentsSeparatedByString: @"\n"];
|
||||
config = [[NSMutableDictionary alloc] init];
|
||||
|
||||
for (NSString* opt in conf) {
|
||||
if ([opt hasPrefix:@"#"]) {
|
||||
continue;
|
||||
}
|
||||
NSRange pos = [opt rangeOfString:@"="];
|
||||
if (pos.location != NSNotFound) {
|
||||
NSString* name = [opt substringToIndex:pos.location];
|
||||
name = [name stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
|
||||
NSString* value = [opt substringFromIndex:pos.location + 1];
|
||||
value = [value stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
|
||||
[config setValue:value forKey:[name uppercaseString]];
|
||||
}
|
||||
}
|
||||
|
||||
if (_recoveryMode) {
|
||||
[config setValue:@"localhost" forKey:@"CONTROLIP"];
|
||||
[config setValue:@"6789" forKey:@"CONTROLPORT"];
|
||||
[config setValue:@"" forKey:@"CONTROLPASSWORD"];
|
||||
}
|
||||
|
||||
[_delegate daemonConfigLoaded];
|
||||
}
|
||||
|
||||
- (NSString*)valueForOption:(NSString*)option {
|
||||
return [config valueForKey:[option uppercaseString]];
|
||||
}
|
||||
|
||||
- (void)initBrowserUrl {
|
||||
NSString* ip = [self valueForOption:@"ControlIP"];
|
||||
if ([ip isEqualToString:@"0.0.0.0"] || [ip isEqualToString:@"127.0.0.1"]) {
|
||||
ip = @"localhost";
|
||||
}
|
||||
NSString* port = [self valueForOption:@"ControlPort"];
|
||||
_browserUrl = [NSString stringWithFormat:@"http://@%@:%@", ip, port];
|
||||
}
|
||||
|
||||
- (void)initRpcUrl {
|
||||
NSString* ip = [self valueForOption:@"ControlIP"];
|
||||
if ([ip isEqualToString:@"0.0.0.0"]) {
|
||||
ip = @"127.0.0.1";
|
||||
}
|
||||
NSString* port = [self valueForOption:@"ControlPort"];
|
||||
NSString* username = [self valueForOption:@"ControlUsername"];
|
||||
NSString* password = [self valueForOption:@"ControlPassword"];
|
||||
NSString* RpcUrl = [NSString stringWithFormat:@"http://%@:%@/%@:%@/jsonrpc/", ip, port, username, password];
|
||||
[RPC setRpcUrl:RpcUrl];
|
||||
}
|
||||
|
||||
- (void)setUpdateInterval:(NSTimeInterval)updateInterval {
|
||||
_updateInterval = updateInterval;
|
||||
if (_connected) {
|
||||
[updateTimer invalidate];
|
||||
[self updateStatus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scheduleNextUpdate {
|
||||
updateTimer = [NSTimer timerWithTimeInterval:_updateInterval target:self selector:@selector(updateStatus) userInfo:nil repeats:NO];
|
||||
[[NSRunLoop currentRunLoop] addTimer:updateTimer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)rpc:(NSString*)method success:(SEL)successCallback failure:(SEL)failureCallback {
|
||||
RPC* rpc = [[RPC alloc] initWithMethod:method receiver:self success:successCallback failure:failureCallback];
|
||||
[rpc start];
|
||||
}
|
||||
|
||||
- (void)receiveStatus:(NSDictionary*)status {
|
||||
//DLog(@"receiveStatus");
|
||||
if (_restarting) {
|
||||
return;
|
||||
}
|
||||
|
||||
_connected = YES;
|
||||
_lastUpdate = [NSDate date];
|
||||
_status = status;
|
||||
|
||||
//DLog(@"response: %@", status);
|
||||
|
||||
int uptime = [(NSNumber*)[status objectForKey:@"UpTimeSec"] integerValue];
|
||||
if (lastUptime == 0) {
|
||||
lastUptime = uptime;
|
||||
} else if (lastUptime > uptime) {
|
||||
// daemon was reloaded (soft-restart)
|
||||
[self readConfigFile];
|
||||
}
|
||||
|
||||
[_delegate daemonStatusUpdated];
|
||||
[self scheduleNextUpdate];
|
||||
}
|
||||
|
||||
- (void)failureStatus {
|
||||
DLog(@"failureStatus");
|
||||
if (_restarting) {
|
||||
return;
|
||||
}
|
||||
|
||||
_connected = NO;
|
||||
|
||||
int pid = [self readLockFilePid];
|
||||
if (pid == 0) {
|
||||
// Daemon is not running. Crashed?
|
||||
_restarting = YES;
|
||||
[_delegate daemonStatusUpdated];
|
||||
[self start];
|
||||
} else {
|
||||
[_delegate daemonStatusUpdated];
|
||||
[self scheduleNextUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateStatus {
|
||||
if (_restarting) {
|
||||
return;
|
||||
}
|
||||
[self rpc:@"status" success:@selector(receiveStatus:) failure:@selector(failureStatus)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "DaemonController.h"
|
||||
|
||||
@interface MainApp : NSObject <NSMenuDelegate, DaemonControllerDelegate> {
|
||||
IBOutlet NSMenu *statusMenu;
|
||||
NSStatusItem *statusItem;
|
||||
IBOutlet NSMenuItem *webuiItem;
|
||||
IBOutlet NSMenuItem *homePageItem;
|
||||
IBOutlet NSMenuItem *downloadsItem;
|
||||
IBOutlet NSMenuItem *forumItem;
|
||||
IBOutlet NSMenuItem *info1Item;
|
||||
IBOutlet NSMenuItem *info2Item;
|
||||
IBOutlet NSMenuItem *restartRecoveryItem;
|
||||
IBOutlet NSMenuItem *factoryResetItem;
|
||||
IBOutlet NSMenuItem *destDirItem;
|
||||
IBOutlet NSMenuItem *interDirItem;
|
||||
IBOutlet NSMenuItem *nzbDirItem;
|
||||
IBOutlet NSMenuItem *scriptDirItem;
|
||||
IBOutlet NSMenuItem *configFileItem;
|
||||
IBOutlet NSMenuItem *logFileItem;
|
||||
IBOutlet NSMenuItem *destDirSeparator;
|
||||
NSWindowController *welcomeDialog;
|
||||
NSWindowController *preferencesDialog;
|
||||
DaemonController *daemonController;
|
||||
int connectionAttempts;
|
||||
BOOL restarting;
|
||||
BOOL resetting;
|
||||
NSTimer* restartTimer;
|
||||
NSMutableArray* categoryItems;
|
||||
NSMutableArray* categoryDirs;
|
||||
}
|
||||
|
||||
+ (void)setupAppDefaults;
|
||||
|
||||
- (void)setupDefaultsObserver;
|
||||
|
||||
- (IBAction)quitClicked:(id)sender;
|
||||
|
||||
- (IBAction)preferencesClicked:(id)sender;
|
||||
|
||||
- (void)userDefaultsDidChange:(id)sender;
|
||||
|
||||
- (IBAction)aboutClicked:(id)sender;
|
||||
|
||||
+ (BOOL)wasLaunchedAsLoginItem;
|
||||
|
||||
- (IBAction)webuiClicked:(id)sender;
|
||||
|
||||
- (IBAction)infoLinkClicked:(id)sender;
|
||||
|
||||
- (IBAction)openConfigInTextEditClicked:(id)sender;
|
||||
|
||||
- (IBAction)restartClicked:(id)sender;
|
||||
|
||||
- (IBAction)showInFinderClicked:(id)sender;
|
||||
|
||||
@end
|
||||
579
osx/MainApp.m
579
osx/MainApp.m
@@ -1,579 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import "MainApp.h"
|
||||
#import "PreferencesDialog.h"
|
||||
#import "WelcomeDialog.h"
|
||||
#import "PFMoveApplication.h"
|
||||
|
||||
NSString *PreferencesContext = @"PreferencesContext";
|
||||
const NSTimeInterval NORMAL_UPDATE_INTERVAL = 10.000;
|
||||
const NSTimeInterval MENUOPEN_UPDATE_INTERVAL = 1.000;
|
||||
const NSTimeInterval START_UPDATE_INTERVAL = 0.500;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return NSApplicationMain(argc, (const char **)argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler
|
||||
*/
|
||||
void SignalProc(int iSignal)
|
||||
{
|
||||
switch (iSignal)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
signal(iSignal, SIG_DFL); // Reset the signal handler
|
||||
[NSApp terminate:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we install seignal handler in order to properly terminat app from Activity Mo1nitor
|
||||
void InstallSignalHandlers()
|
||||
{
|
||||
signal(SIGINT, SignalProc);
|
||||
signal(SIGTERM, SignalProc);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
@implementation MainApp
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
|
||||
[self checkOtherRunningInstances];
|
||||
#ifndef DEBUG
|
||||
PFMoveToApplicationsFolderIfNecessary();
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)checkOtherRunningInstances {
|
||||
for (NSRunningApplication *runningApplication in [NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]]) {
|
||||
if (![[runningApplication executableURL] isEqualTo:[[NSRunningApplication currentApplication] executableURL]]) {
|
||||
NSString *executablePath = [[runningApplication executableURL] path];
|
||||
executablePath = [[[executablePath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
|
||||
DLog(@"Switching to an already running instance: %@", executablePath);
|
||||
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open"
|
||||
arguments:[NSArray arrayWithObjects:executablePath, @"--args", @"--second-instance", nil]] waitUntilExit];
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
BOOL autoStartWebUI = [[NSUserDefaults standardUserDefaults] boolForKey:@"AutoStartWebUI"];
|
||||
|
||||
daemonController = [[DaemonController alloc] init];
|
||||
daemonController.updateInterval = autoStartWebUI ? START_UPDATE_INTERVAL : NORMAL_UPDATE_INTERVAL;
|
||||
daemonController.delegate = self;
|
||||
|
||||
[self setupDefaultsObserver];
|
||||
[self userDefaultsDidChange:nil];
|
||||
|
||||
if (![MainApp wasLaunchedAsLoginItem]) {
|
||||
[self showWelcomeScreen];
|
||||
}
|
||||
|
||||
InstallSignalHandlers();
|
||||
|
||||
DLog(@"Start Daemon");
|
||||
[daemonController start];
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
|
||||
DLog(@"applicationShouldHandleReopen");
|
||||
[self showAlreadyRunning];
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
[self setupAppDefaults];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
DLog(@"awakeFromNib");
|
||||
[statusMenu setDelegate:self];
|
||||
}
|
||||
|
||||
+ (void)setupAppDefaults {
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"YES", @"ShowInMenubar",
|
||||
@"NO", @"Autostart",
|
||||
@"YES", @"AutoStartWebUI",
|
||||
nil];
|
||||
[userDefaults registerDefaults:appDefaults];
|
||||
}
|
||||
|
||||
- (void)setupDefaultsObserver {
|
||||
NSUserDefaultsController *sdc = [NSUserDefaultsController sharedUserDefaultsController];
|
||||
[sdc addObserver:self forKeyPath:@"values.ShowInMenubar" options:0 context:(__bridge void *)(PreferencesContext)];
|
||||
[sdc addObserver:self forKeyPath:@"values.AutoStartWebUI" options:0 context:(__bridge void *)(PreferencesContext)];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if (context == (__bridge void *)(PreferencesContext)) {
|
||||
[self userDefaultsDidChange:nil];
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userDefaultsDidChange:(id)sender {
|
||||
DLog(@"userDefaultsDidChange: %@", sender);
|
||||
BOOL showInMenubar = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowInMenubar"];
|
||||
if (showInMenubar != (statusItem != nil)) {
|
||||
if (showInMenubar) {
|
||||
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
|
||||
[statusItem setHighlightMode:YES];
|
||||
[statusItem setMenu:statusMenu];
|
||||
[statusItem setImage:[NSImage imageNamed:@"statusicon.png"]];
|
||||
[statusItem setAlternateImage:[NSImage imageNamed:@"statusicon-inv.png"]];
|
||||
}
|
||||
else {
|
||||
statusItem = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)preferencesClicked:(id)sender {
|
||||
[self showPreferences];
|
||||
}
|
||||
|
||||
- (void)showPreferences {
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
if (preferencesDialog) {
|
||||
return;
|
||||
}
|
||||
preferencesDialog = [[PreferencesDialog alloc] init];
|
||||
[[preferencesDialog window] center];
|
||||
[preferencesDialog showWindow:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(preferencesWillClose:)
|
||||
name:NSWindowWillCloseNotification
|
||||
object:[preferencesDialog window]];
|
||||
}
|
||||
|
||||
- (void)preferencesWillClose:(NSNotification *)notification {
|
||||
DLog(@"Pref Closed");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSWindowWillCloseNotification
|
||||
object:[preferencesDialog window]];
|
||||
preferencesDialog = nil;
|
||||
[self userDefaultsDidChange:nil];
|
||||
}
|
||||
|
||||
- (IBAction)aboutClicked:(id)sender {
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
[NSApp orderFrontStandardAboutPanel:nil];
|
||||
}
|
||||
|
||||
- (IBAction)quitClicked:(id)sender {
|
||||
DLog(@"Quit");
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
- (void)showWelcomeScreen {
|
||||
welcomeDialog = [[WelcomeDialog alloc] init];
|
||||
[(WelcomeDialog*)welcomeDialog setMainDelegate:self];
|
||||
[(WelcomeDialog*)welcomeDialog showDialog];
|
||||
}
|
||||
|
||||
- (void)showAlreadyRunning {
|
||||
BOOL showInMenubar = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowInMenubar"];
|
||||
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedString(@"AlreadyRunning.MessageText", nil)];
|
||||
[alert setInformativeText:NSLocalizedString(showInMenubar ? @"AlreadyRunning.InformativeTextWithIcon" : @"AlreadyRunning.InformativeTextWithoutIcon", nil)];
|
||||
NSButton* webUIButton = [alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.WebUI", nil)];
|
||||
[alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.Preferences", nil)];
|
||||
[alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.Quit", nil)];
|
||||
[alert.window makeFirstResponder:webUIButton];
|
||||
[webUIButton setKeyEquivalent:@"\r"];
|
||||
switch ([alert runModal]) {
|
||||
case NSAlertFirstButtonReturn:
|
||||
[self showWebUI];
|
||||
break;
|
||||
|
||||
case NSAlertSecondButtonReturn:
|
||||
[self showPreferences];
|
||||
break;
|
||||
|
||||
case NSAlertThirdButtonReturn:
|
||||
[self quitClicked:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)wasLaunchedByProcess:(NSString*)creator {
|
||||
BOOL wasLaunchedByProcess = NO;
|
||||
|
||||
// Get our PSN
|
||||
OSStatus err;
|
||||
ProcessSerialNumber currPSN;
|
||||
err = GetCurrentProcess (&currPSN);
|
||||
if (!err) {
|
||||
// We don't use ProcessInformationCopyDictionary() because the 'ParentPSN' item in the dictionary
|
||||
// has endianness problems in 10.4, fixed in 10.5 however.
|
||||
ProcessInfoRec procInfo;
|
||||
bzero (&procInfo, sizeof (procInfo));
|
||||
procInfo.processInfoLength = (UInt32)sizeof (ProcessInfoRec);
|
||||
err = GetProcessInformation (&currPSN, &procInfo);
|
||||
if (!err) {
|
||||
ProcessSerialNumber parentPSN = procInfo.processLauncher;
|
||||
|
||||
// Get info on the launching process
|
||||
NSDictionary* parentDict = (__bridge NSDictionary*)ProcessInformationCopyDictionary (&parentPSN, kProcessDictionaryIncludeAllInformationMask);
|
||||
|
||||
// Test the creator code of the launching app
|
||||
if (parentDict) {
|
||||
wasLaunchedByProcess = [[parentDict objectForKey:@"FileCreator"] isEqualToString:creator];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wasLaunchedByProcess;
|
||||
}
|
||||
|
||||
+ (BOOL)wasLaunchedAsLoginItem {
|
||||
// If the launching process was 'loginwindow', we were launched as a login item
|
||||
return [self wasLaunchedByProcess:@"lgnw"];
|
||||
}
|
||||
|
||||
- (IBAction)webuiClicked:(id)sender {
|
||||
if (daemonController.connected) {
|
||||
[self showWebUI];
|
||||
} else {
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedString(@"ShowWebUINoConnection.MessageText", nil)];
|
||||
[alert setInformativeText:NSLocalizedString(@"ShowWebUINoConnection.InformativeText", nil)];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert runModal];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showWebUI {
|
||||
DLog(@"showWebUI");
|
||||
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:daemonController.browserUrl]];
|
||||
}
|
||||
|
||||
- (IBAction)openConfigInTextEditClicked:(id)sender {
|
||||
NSString *configFile = [daemonController configFilePath];
|
||||
[[NSWorkspace sharedWorkspace] openFile:configFile withApplication:@"TextEdit"];
|
||||
}
|
||||
|
||||
- (IBAction)restartClicked:(id)sender {
|
||||
if (sender == factoryResetItem) {
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedString(@"FactoryReset.MessageText", nil)];
|
||||
[alert setInformativeText:NSLocalizedString(@"FactoryReset.InformativeText", nil)];
|
||||
[alert setAlertStyle:NSCriticalAlertStyle];
|
||||
NSButton* cancelButton = [alert addButtonWithTitle:NSLocalizedString(@"FactoryReset.Cancel", nil)];
|
||||
// we use middle invisible button to align the third RESET-button at left side
|
||||
[[alert addButtonWithTitle:@"Cancel"] setHidden:YES];
|
||||
[alert addButtonWithTitle:NSLocalizedString(@"FactoryReset.Reset", nil)];
|
||||
[alert.window makeFirstResponder:cancelButton];
|
||||
[cancelButton setKeyEquivalent:@"\E"];
|
||||
if ([alert runModal] != NSAlertThirdButtonReturn) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
restarting = YES;
|
||||
resetting = sender == factoryResetItem;
|
||||
[self updateStatus];
|
||||
[daemonController restartInRecoveryMode: sender == restartRecoveryItem withFactoryReset: sender == factoryResetItem];
|
||||
daemonController.updateInterval = START_UPDATE_INTERVAL;
|
||||
|
||||
restartTimer = [NSTimer timerWithTimeInterval:10.000 target:self selector:@selector(restartFailed) userInfo:nil repeats:NO];
|
||||
[[NSRunLoop currentRunLoop] addTimer:restartTimer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)welcomeContinue {
|
||||
DLog(@"welcomeContinue");
|
||||
BOOL autoStartWebUI = [[NSUserDefaults standardUserDefaults] boolForKey:@"AutoStartWebUI"];
|
||||
if (autoStartWebUI) {
|
||||
if (daemonController.connected) {
|
||||
if (daemonController.updateInterval == START_UPDATE_INTERVAL)
|
||||
{
|
||||
daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
|
||||
}
|
||||
[self showWebUI];
|
||||
} else {
|
||||
// try again in 100 msec for max. 25 seconds, then give up
|
||||
connectionAttempts++;
|
||||
if (connectionAttempts < 250) {
|
||||
[self performSelector:@selector(welcomeContinue) withObject:nil afterDelay: 0.100];
|
||||
} else {
|
||||
// show error message
|
||||
[self webuiClicked:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||
DLog(@"Stop Daemon");
|
||||
[daemonController stop];
|
||||
}
|
||||
|
||||
- (void)menuWillOpen:(NSMenu *)menu {
|
||||
DLog(@"menuWillOpen");
|
||||
daemonController.updateInterval = MENUOPEN_UPDATE_INTERVAL;
|
||||
}
|
||||
|
||||
- (void)menuDidClose:(NSMenu *)menu {
|
||||
DLog(@"menuDidClose");
|
||||
daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
|
||||
}
|
||||
|
||||
- (IBAction)infoLinkClicked:(id)sender {
|
||||
NSString *url;
|
||||
|
||||
if (sender == homePageItem) {
|
||||
url = NSLocalizedString(@"Menu.LinkHomePage", nil);
|
||||
}
|
||||
else if (sender == downloadsItem) {
|
||||
url = NSLocalizedString(@"Menu.LinkDownloads", nil);
|
||||
}
|
||||
else if (sender == forumItem) {
|
||||
url = NSLocalizedString(@"Menu.LinkForum", nil);
|
||||
}
|
||||
|
||||
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:url]];
|
||||
}
|
||||
|
||||
- (void)restartFailed {
|
||||
if (restarting) {
|
||||
restarting = NO;
|
||||
resetting = NO;
|
||||
daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedString(@"RestartNoConnection.MessageText", nil)];
|
||||
[alert setInformativeText:NSLocalizedString(@"RestartNoConnection.InformativeText", nil)];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert runModal];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)showInFinderClicked:(id)sender {
|
||||
NSString* dir = nil;
|
||||
NSString* option = nil;
|
||||
|
||||
if (sender == destDirItem) {
|
||||
option = @"DestDir";
|
||||
} else if (sender == interDirItem) {
|
||||
option = @"InterDir";
|
||||
} else if (sender == nzbDirItem) {
|
||||
option = @"NzbDir";
|
||||
} else if (sender == scriptDirItem) {
|
||||
option = @"ScriptDir";
|
||||
} else if (sender == logFileItem) {
|
||||
option = @"LogFile";
|
||||
} else if (sender == configFileItem) {
|
||||
dir = [daemonController configFilePath];
|
||||
} else if ([categoryItems containsObject:sender]) {
|
||||
int index = [categoryItems indexOfObject:sender];
|
||||
dir = [categoryDirs objectAtIndex:index];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir == nil) {
|
||||
NSString* mainDir = [[daemonController valueForOption:@"MainDir"] stringByExpandingTildeInPath];
|
||||
dir = [[daemonController valueForOption:option] stringByExpandingTildeInPath];
|
||||
dir = [dir stringByReplacingOccurrencesOfString:@"${MainDir}"
|
||||
withString:mainDir
|
||||
options:NSCaseInsensitiveSearch
|
||||
range:NSMakeRange(0, [dir length])];
|
||||
}
|
||||
|
||||
if (dir.length == 0 || ![[NSFileManager defaultManager] fileExistsAtPath:dir]) {
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"CantShowInFinder.MessageText", nil), dir]];
|
||||
[alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(option == nil ? @"CantShowInFinder.InformativeTextForCategory" : @"CantShowInFinder.InformativeTextWithOption", nil), option]];
|
||||
[alert runModal];
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[[NSURL fileURLWithPath:dir isDirectory:YES]]];
|
||||
}
|
||||
|
||||
- (void)daemonStatusUpdated {
|
||||
if (restarting && daemonController.connected) {
|
||||
restarting = NO;
|
||||
[restartTimer invalidate];
|
||||
[NSApp activateIgnoringOtherApps:TRUE];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedString(resetting ? @"FactoryResetted.MessageText" : daemonController.recoveryMode ? @"RestartedRecoveryMode.MessageText" : @"Restarted.MessageText", nil)];
|
||||
[alert setInformativeText:NSLocalizedString(resetting ? @"FactoryResetted.InformativeText" : daemonController.recoveryMode ? @"RestartedRecoveryMode.InformativeText" : @"Restarted.InformativeText", nil)];
|
||||
[alert setAlertStyle:NSInformationalAlertStyle];
|
||||
[alert addButtonWithTitle:NSLocalizedString(@"Restarted.OK", nil)];
|
||||
[alert addButtonWithTitle:NSLocalizedString(@"Restarted.WebUI", nil)];
|
||||
if ([alert runModal] == NSAlertSecondButtonReturn) {
|
||||
[self showWebUI];
|
||||
}
|
||||
resetting = NO;
|
||||
} else {
|
||||
[self updateStatus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateStatus {
|
||||
//DLog(@"updateStatus");
|
||||
|
||||
NSString* info1 = @"";
|
||||
NSString* info2 = nil;
|
||||
|
||||
NSDictionary* status = [daemonController status];
|
||||
if (restarting || daemonController.restarting) {
|
||||
info1 = NSLocalizedString(@"Status.Restarting", nil);
|
||||
} else if (!daemonController.connected) {
|
||||
info1 = NSLocalizedString(@"Status.NoConnection", nil);
|
||||
} else if ([(NSNumber*)[status objectForKey:@"ServerStandBy"] integerValue] == 1) {
|
||||
if ([(NSNumber*)[status objectForKey:@"PostJobCount"] integerValue] > 0) {
|
||||
info1 = NSLocalizedString(@"Status.Post-Processing", nil);
|
||||
}
|
||||
else if ([(NSNumber*)[status objectForKey:@"UrlCount"] integerValue] > 0) {
|
||||
info1 = NSLocalizedString(@"Status.Fetching NZBs", nil);
|
||||
}
|
||||
else if ([(NSNumber*)[status objectForKey:@"FeedActive"] integerValue] == 1) {
|
||||
info1 = NSLocalizedString(@"Status.Fetching Feeds", nil);
|
||||
}
|
||||
else if ([(NSNumber*)[status objectForKey:@"DownloadPaused"] integerValue] == 1 ||
|
||||
[(NSNumber*)[status objectForKey:@"Download2Paused"] integerValue] == 1) {
|
||||
info1 = NSLocalizedString(@"Status.Paused", nil);
|
||||
} else {
|
||||
info1 = NSLocalizedString(@"Status.Idle", nil);
|
||||
}
|
||||
} else {
|
||||
int speed = [(NSNumber*)[status objectForKey:@"DownloadRate"] integerValue];
|
||||
info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.Downloading", nil), speed / 1024];
|
||||
|
||||
if (speed > 0) {
|
||||
long long remaining = ([(NSNumber*)[status objectForKey:@"RemainingSizeHi"] integerValue] << 32) + [(NSNumber*)[status objectForKey:@"RemainingSizeLo"] integerValue];
|
||||
int secondsLeft = remaining / speed;
|
||||
info2 = [NSString stringWithFormat:NSLocalizedString(@"Status.Left", nil), [self formatTimeLeft:secondsLeft]];
|
||||
}
|
||||
}
|
||||
|
||||
[info1Item setTitle:info1];
|
||||
|
||||
[info2Item setHidden:info2 == nil];
|
||||
if (info2 != nil) {
|
||||
[info2Item setTitle:info2];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString*)formatTimeLeft:(int)sec {
|
||||
int days = floor(sec / 86400);
|
||||
int hours = floor((sec % 86400) / 3600);
|
||||
int minutes = floor((sec / 60) % 60);
|
||||
int seconds = floor(sec % 60);
|
||||
|
||||
if (days > 10)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Days", nil), days];
|
||||
}
|
||||
if (days > 0)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Days.Hours", nil), days, hours];
|
||||
}
|
||||
if (hours > 10)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Hours", nil), hours];
|
||||
}
|
||||
if (hours > 0)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Hours.Minutes", nil), hours, minutes];
|
||||
}
|
||||
if (minutes > 10)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Minutes", nil), minutes];
|
||||
}
|
||||
if (minutes > 0)
|
||||
{
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Minutes.Seconds", nil), minutes, seconds];
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:NSLocalizedString(@"Left.Seconds", nil), seconds];
|
||||
}
|
||||
|
||||
- (void)daemonConfigLoaded {
|
||||
DLog(@"config loaded");
|
||||
[self updateCategoriesMenu];
|
||||
}
|
||||
|
||||
- (void)updateCategoriesMenu {
|
||||
NSMenu *submenu = destDirItem.parentItem.submenu;
|
||||
|
||||
for (NSMenuItem* item in categoryItems) {
|
||||
[submenu removeItem:item];
|
||||
}
|
||||
|
||||
categoryItems = [NSMutableArray array];
|
||||
categoryDirs = [NSMutableArray array];
|
||||
|
||||
NSString* mainDir = [[daemonController valueForOption:@"MainDir"] stringByExpandingTildeInPath];
|
||||
NSString* destDir = [[daemonController valueForOption:@"DestDir"] stringByExpandingTildeInPath];
|
||||
|
||||
for (int i=1; ; i++) {
|
||||
NSString* catName = [daemonController valueForOption:[NSString stringWithFormat:@"Category%i.Name", i]];
|
||||
NSString* catDir = [daemonController valueForOption:[NSString stringWithFormat:@"Category%i.DestDir", i]];
|
||||
|
||||
if (catName.length == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (catDir.length == 0) {
|
||||
catDir = [destDir stringByAppendingPathComponent:catName];
|
||||
}
|
||||
|
||||
NSString* dir = [catDir stringByExpandingTildeInPath];
|
||||
dir = [dir stringByReplacingOccurrencesOfString:@"${MainDir}"
|
||||
withString:mainDir
|
||||
options:NSCaseInsensitiveSearch
|
||||
range:NSMakeRange(0, dir.length)];
|
||||
dir = [dir stringByReplacingOccurrencesOfString:@"${DestDir}"
|
||||
withString:destDir
|
||||
options:NSCaseInsensitiveSearch
|
||||
range:NSMakeRange(0, dir.length)];
|
||||
|
||||
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Category%i: %@", i, catName]
|
||||
action:@selector(showInFinderClicked:) keyEquivalent:@""];
|
||||
[item setTarget:self];
|
||||
[submenu insertItem:item atIndex:[submenu indexOfItem:destDirSeparator]];
|
||||
|
||||
[categoryItems addObject:item];
|
||||
[categoryDirs addObject:dir];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
989
osx/MainApp.xib
989
osx/MainApp.xib
@@ -1,989 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1070</int>
|
||||
<string key="IBDocument.SystemVersion">11G63</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.51</string>
|
||||
<string key="IBDocument.HIToolboxVersion">569.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">3084</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSCustomObject</string>
|
||||
<string>NSMenu</string>
|
||||
<string>NSMenuItem</string>
|
||||
<string>NSUserDefaultsController</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSCustomObject" id="1021">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1014">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1050">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="163992474">
|
||||
<string key="NSClassName">NSFontManager</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="584004514">
|
||||
<string key="NSClassName">MainApp</string>
|
||||
</object>
|
||||
<object class="NSMenu" id="1071488544">
|
||||
<string key="NSTitle"/>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="913321237">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<string key="NSTitle">Starting</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<object class="NSCustomResource" key="NSOnImage" id="723905397">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
||||
</object>
|
||||
<object class="NSCustomResource" key="NSMixedImage" id="488763290">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuMixedState</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="687450617">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsHidden">YES</bool>
|
||||
<string key="NSTitle">Left</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="893657456">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="332065098">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Show Web-Interface</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="984846223">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Show in Finder</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="309075451">
|
||||
<string key="NSTitle">Show in Finder</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="19318460">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Default Destination</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="945655763">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="833448292">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Intermediate Files</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="374625387">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Incoming NZBs</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="942754376">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Post-Processing Scripts</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="831099071">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="163691210">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Config-File</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="297452147">
|
||||
<reference key="NSMenu" ref="309075451"/>
|
||||
<string key="NSTitle">Log-File</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="750438089">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Info-Links</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="322188981">
|
||||
<string key="NSTitle">Info-Links</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="812981948">
|
||||
<reference key="NSMenu" ref="322188981"/>
|
||||
<string key="NSTitle">Home Page</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="179994147">
|
||||
<reference key="NSMenu" ref="322188981"/>
|
||||
<string key="NSTitle">Downloads</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="100406801">
|
||||
<reference key="NSMenu" ref="322188981"/>
|
||||
<string key="NSTitle">Forum</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="22060917">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Troubleshooting</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
<string key="NSAction">submenuAction:</string>
|
||||
<object class="NSMenu" key="NSSubmenu" id="987038733">
|
||||
<string key="NSTitle">Troubleshooting</string>
|
||||
<object class="NSMutableArray" key="NSMenuItems">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMenuItem" id="305652885">
|
||||
<reference key="NSMenu" ref="987038733"/>
|
||||
<string key="NSTitle">Restart</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="298404849">
|
||||
<reference key="NSMenu" ref="987038733"/>
|
||||
<string key="NSTitle">Restart in Recovery Mode</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="846476020">
|
||||
<reference key="NSMenu" ref="987038733"/>
|
||||
<string key="NSTitle">Open Config in TextEdit</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="631055199">
|
||||
<reference key="NSMenu" ref="987038733"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="408663019">
|
||||
<reference key="NSMenu" ref="987038733"/>
|
||||
<string key="NSTitle">Reset to Factory Defaults</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="239974611">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="7270580">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">About NZBGet</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="845819171">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Preferences...</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="4615620">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<bool key="NSIsSeparator">YES</bool>
|
||||
<string key="NSTitle"/>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="667042401">
|
||||
<reference key="NSMenu" ref="1071488544"/>
|
||||
<string key="NSTitle">Quit NZBGet</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="723905397"/>
|
||||
<reference key="NSMixedImage" ref="488763290"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSUserDefaultsController" id="821481866">
|
||||
<bool key="NSSharedInstance">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="1021"/>
|
||||
<reference key="destination" ref="584004514"/>
|
||||
</object>
|
||||
<int key="connectionID">824</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">statusMenu</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="1071488544"/>
|
||||
</object>
|
||||
<int key="connectionID">831</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">quitClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="667042401"/>
|
||||
</object>
|
||||
<int key="connectionID">832</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">preferencesClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="845819171"/>
|
||||
</object>
|
||||
<int key="connectionID">850</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">aboutClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="7270580"/>
|
||||
</object>
|
||||
<int key="connectionID">856</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">webuiClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="332065098"/>
|
||||
</object>
|
||||
<int key="connectionID">865</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">webuiItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="332065098"/>
|
||||
</object>
|
||||
<int key="connectionID">866</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">homePageItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="812981948"/>
|
||||
</object>
|
||||
<int key="connectionID">874</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">downloadsItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="179994147"/>
|
||||
</object>
|
||||
<int key="connectionID">875</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">forumItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="100406801"/>
|
||||
</object>
|
||||
<int key="connectionID">876</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">infoLinkClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="812981948"/>
|
||||
</object>
|
||||
<int key="connectionID">877</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">infoLinkClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="179994147"/>
|
||||
</object>
|
||||
<int key="connectionID">878</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">infoLinkClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="100406801"/>
|
||||
</object>
|
||||
<int key="connectionID">879</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">infoItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="913321237"/>
|
||||
</object>
|
||||
<int key="connectionID">893</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">restartRecoveryItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="298404849"/>
|
||||
</object>
|
||||
<int key="connectionID">896</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">destDirItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="19318460"/>
|
||||
</object>
|
||||
<int key="connectionID">911</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">interDirItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="833448292"/>
|
||||
</object>
|
||||
<int key="connectionID">912</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">nzbDirItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="374625387"/>
|
||||
</object>
|
||||
<int key="connectionID">913</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">scriptDirItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="942754376"/>
|
||||
</object>
|
||||
<int key="connectionID">915</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="19318460"/>
|
||||
</object>
|
||||
<int key="connectionID">916</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="833448292"/>
|
||||
</object>
|
||||
<int key="connectionID">917</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="374625387"/>
|
||||
</object>
|
||||
<int key="connectionID">918</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="942754376"/>
|
||||
</object>
|
||||
<int key="connectionID">919</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="163691210"/>
|
||||
</object>
|
||||
<int key="connectionID">922</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">info2Item</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="687450617"/>
|
||||
</object>
|
||||
<int key="connectionID">925</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">info1Item</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="913321237"/>
|
||||
</object>
|
||||
<int key="connectionID">926</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">destDirSeparator</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="945655763"/>
|
||||
</object>
|
||||
<int key="connectionID">927</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">showInFinderClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="297452147"/>
|
||||
</object>
|
||||
<int key="connectionID">929</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">configFileItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="163691210"/>
|
||||
</object>
|
||||
<int key="connectionID">930</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">logFileItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="297452147"/>
|
||||
</object>
|
||||
<int key="connectionID">931</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">restartClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="298404849"/>
|
||||
</object>
|
||||
<int key="connectionID">940</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">openConfigInTextEditClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="846476020"/>
|
||||
</object>
|
||||
<int key="connectionID">941</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">restartClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="305652885"/>
|
||||
</object>
|
||||
<int key="connectionID">943</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">restartClicked:</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="408663019"/>
|
||||
</object>
|
||||
<int key="connectionID">944</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">factoryResetItem</string>
|
||||
<reference key="source" ref="584004514"/>
|
||||
<reference key="destination" ref="408663019"/>
|
||||
</object>
|
||||
<int key="connectionID">945</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1048"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1021"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1014"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1050"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">373</int>
|
||||
<reference key="object" ref="163992474"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">823</int>
|
||||
<reference key="object" ref="584004514"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">827</int>
|
||||
<reference key="object" ref="1071488544"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="667042401"/>
|
||||
<reference ref="332065098"/>
|
||||
<reference ref="893657456"/>
|
||||
<reference ref="22060917"/>
|
||||
<reference ref="239974611"/>
|
||||
<reference ref="913321237"/>
|
||||
<reference ref="7270580"/>
|
||||
<reference ref="845819171"/>
|
||||
<reference ref="4615620"/>
|
||||
<reference ref="750438089"/>
|
||||
<reference ref="984846223"/>
|
||||
<reference ref="687450617"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">828</int>
|
||||
<reference key="object" ref="667042401"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">840</int>
|
||||
<reference key="object" ref="821481866"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">849</int>
|
||||
<reference key="object" ref="845819171"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">851</int>
|
||||
<reference key="object" ref="7270580"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">860</int>
|
||||
<reference key="object" ref="893657456"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">861</int>
|
||||
<reference key="object" ref="332065098"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">867</int>
|
||||
<reference key="object" ref="750438089"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="322188981"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">868</int>
|
||||
<reference key="object" ref="322188981"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="812981948"/>
|
||||
<reference ref="100406801"/>
|
||||
<reference ref="179994147"/>
|
||||
</object>
|
||||
<reference key="parent" ref="750438089"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">869</int>
|
||||
<reference key="object" ref="812981948"/>
|
||||
<reference key="parent" ref="322188981"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">870</int>
|
||||
<reference key="object" ref="100406801"/>
|
||||
<reference key="parent" ref="322188981"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">872</int>
|
||||
<reference key="object" ref="179994147"/>
|
||||
<reference key="parent" ref="322188981"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">880</int>
|
||||
<reference key="object" ref="22060917"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="987038733"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">881</int>
|
||||
<reference key="object" ref="987038733"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="305652885"/>
|
||||
<reference ref="846476020"/>
|
||||
<reference ref="298404849"/>
|
||||
<reference ref="631055199"/>
|
||||
<reference ref="408663019"/>
|
||||
</object>
|
||||
<reference key="parent" ref="22060917"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">882</int>
|
||||
<reference key="object" ref="305652885"/>
|
||||
<reference key="parent" ref="987038733"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">885</int>
|
||||
<reference key="object" ref="846476020"/>
|
||||
<reference key="parent" ref="987038733"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">887</int>
|
||||
<reference key="object" ref="298404849"/>
|
||||
<reference key="parent" ref="987038733"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">889</int>
|
||||
<reference key="object" ref="239974611"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">890</int>
|
||||
<reference key="object" ref="913321237"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">897</int>
|
||||
<reference key="object" ref="4615620"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">898</int>
|
||||
<reference key="object" ref="984846223"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="309075451"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">899</int>
|
||||
<reference key="object" ref="309075451"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="19318460"/>
|
||||
<reference ref="942754376"/>
|
||||
<reference ref="831099071"/>
|
||||
<reference ref="945655763"/>
|
||||
<reference ref="374625387"/>
|
||||
<reference ref="833448292"/>
|
||||
<reference ref="163691210"/>
|
||||
<reference ref="297452147"/>
|
||||
</object>
|
||||
<reference key="parent" ref="984846223"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">900</int>
|
||||
<reference key="object" ref="19318460"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">902</int>
|
||||
<reference key="object" ref="833448292"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">906</int>
|
||||
<reference key="object" ref="374625387"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">908</int>
|
||||
<reference key="object" ref="942754376"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">910</int>
|
||||
<reference key="object" ref="831099071"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">920</int>
|
||||
<reference key="object" ref="945655763"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">921</int>
|
||||
<reference key="object" ref="163691210"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">924</int>
|
||||
<reference key="object" ref="687450617"/>
|
||||
<reference key="parent" ref="1071488544"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">928</int>
|
||||
<reference key="object" ref="297452147"/>
|
||||
<reference key="parent" ref="309075451"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">934</int>
|
||||
<reference key="object" ref="631055199"/>
|
||||
<reference key="parent" ref="987038733"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">935</int>
|
||||
<reference key="object" ref="408663019"/>
|
||||
<reference key="parent" ref="987038733"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>373.IBPluginDependency</string>
|
||||
<string>823.IBPluginDependency</string>
|
||||
<string>827.IBPluginDependency</string>
|
||||
<string>828.IBPluginDependency</string>
|
||||
<string>840.IBPluginDependency</string>
|
||||
<string>849.IBPluginDependency</string>
|
||||
<string>851.IBPluginDependency</string>
|
||||
<string>860.IBPluginDependency</string>
|
||||
<string>861.IBPluginDependency</string>
|
||||
<string>867.IBPluginDependency</string>
|
||||
<string>868.IBPluginDependency</string>
|
||||
<string>869.IBPluginDependency</string>
|
||||
<string>870.IBPluginDependency</string>
|
||||
<string>872.IBPluginDependency</string>
|
||||
<string>880.IBPluginDependency</string>
|
||||
<string>881.IBPluginDependency</string>
|
||||
<string>882.IBPluginDependency</string>
|
||||
<string>885.IBPluginDependency</string>
|
||||
<string>887.IBPluginDependency</string>
|
||||
<string>889.IBPluginDependency</string>
|
||||
<string>890.IBPluginDependency</string>
|
||||
<string>897.IBPluginDependency</string>
|
||||
<string>898.IBPluginDependency</string>
|
||||
<string>899.IBPluginDependency</string>
|
||||
<string>900.IBPluginDependency</string>
|
||||
<string>902.IBPluginDependency</string>
|
||||
<string>906.IBPluginDependency</string>
|
||||
<string>908.IBPluginDependency</string>
|
||||
<string>910.IBPluginDependency</string>
|
||||
<string>920.IBPluginDependency</string>
|
||||
<string>921.IBPluginDependency</string>
|
||||
<string>924.IBPluginDependency</string>
|
||||
<string>928.IBPluginDependency</string>
|
||||
<string>934.IBPluginDependency</string>
|
||||
<string>935.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">945</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<real value="1070" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSMenuCheckmark</string>
|
||||
<string>NSMenuMixedState</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>{11, 11}</string>
|
||||
<string>{10, 3}</string>
|
||||
</object>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>mainicon.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>net.sourceforge.nzbget</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>12.0-testing-r831M</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2007-2013 Andrey Prygunkov</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainApp</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,409 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||
F20FC6E217C6BAAE00C392AC /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
F20FC6E417C6BC8D00C392AC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F20FC6E317C6BC8D00C392AC /* Security.framework */; };
|
||||
F21D369B13BF387F00E6D821 /* PreferencesDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = F21D369A13BF387F00E6D821 /* PreferencesDialog.m */; };
|
||||
F26CBA8B136DE86A00DCB596 /* MainApp.m in Sources */ = {isa = PBXBuildFile; fileRef = F26CBA8A136DE86A00DCB596 /* MainApp.m */; };
|
||||
F26D959317C0E81800E58E5D /* Welcome.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F26D959217C0E81800E58E5D /* Welcome.rtf */; };
|
||||
F26D959517C0E86300E58E5D /* MainApp.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959417C0E86300E58E5D /* MainApp.xib */; };
|
||||
F26D959717C0E87E00E58E5D /* PreferencesDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */; };
|
||||
F26D959917C0E88700E58E5D /* WelcomeDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959817C0E88700E58E5D /* WelcomeDialog.xib */; };
|
||||
F26D959B17C0E89D00E58E5D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F26D959A17C0E89D00E58E5D /* Localizable.strings */; };
|
||||
F29ABB2617BFC61B0023A423 /* DaemonController.m in Sources */ = {isa = PBXBuildFile; fileRef = F29ABB2417BFC03D0023A423 /* DaemonController.m */; };
|
||||
F29ABB2B17C00E150023A423 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
|
||||
F29ABB2C17C00E190023A423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
|
||||
F2A55D3717C4CA9000D6FFE1 /* daemon in Resources */ = {isa = PBXBuildFile; fileRef = F2A55D3617C4CA9000D6FFE1 /* daemon */; };
|
||||
F2A55D3B17C4CAF800D6FFE1 /* tools in Resources */ = {isa = PBXBuildFile; fileRef = F2A55D3A17C4CAF800D6FFE1 /* tools */; };
|
||||
F2A6E11017C8E42300D910CB /* statusicon-inv@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F2A6E10E17C8E42300D910CB /* statusicon-inv@2x.png */; };
|
||||
F2A6E11117C8E42300D910CB /* statusicon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F2A6E10F17C8E42300D910CB /* statusicon@2x.png */; };
|
||||
F2BBD9C613E083160037473A /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F2FC0F8B13BF595700D834E3 /* Credits.rtf */; };
|
||||
F2CD856817C282080019D2CA /* RPC.m in Sources */ = {isa = PBXBuildFile; fileRef = F2CD856517C254A90019D2CA /* RPC.m */; };
|
||||
F2CD856B17C282820019D2CA /* WebClient.m in Sources */ = {isa = PBXBuildFile; fileRef = F2CD856A17C282800019D2CA /* WebClient.m */; };
|
||||
F2D2A2F113CBA680000824B4 /* WelcomeDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */; };
|
||||
F2F9804A17C9081D004623D6 /* licenses in Resources */ = {isa = PBXBuildFile; fileRef = F2F9804917C9081D004623D6 /* licenses */; };
|
||||
F2FCD73B13BB9CE900FC81F5 /* mainicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */; };
|
||||
F2FCD7D913BBDAED00FC81F5 /* statusicon.png in Resources */ = {isa = PBXBuildFile; fileRef = F2FCD7D813BBDAED00FC81F5 /* statusicon.png */; };
|
||||
F2FCD84D13BCFD0900FC81F5 /* statusicon-inv.png in Resources */ = {isa = PBXBuildFile; fileRef = F2FCD84C13BCFD0900FC81F5 /* statusicon-inv.png */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
256AC3F00F4B6AF500CF3369 /* App_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = App_Prefix.pch; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
8D1107310486CEB800E47090 /* NZBGet-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "NZBGet-Info.plist"; sourceTree = "<group>"; };
|
||||
8D1107320486CEB800E47090 /* NZBGet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NZBGet.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F20FC6DE17C6B9FC00C392AC /* PFMoveApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PFMoveApplication.h; sourceTree = "<group>"; };
|
||||
F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = "<group>"; };
|
||||
F20FC6E317C6BC8D00C392AC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
|
||||
F21D369913BF387F00E6D821 /* PreferencesDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesDialog.h; sourceTree = "<group>"; };
|
||||
F21D369A13BF387F00E6D821 /* PreferencesDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesDialog.m; sourceTree = "<group>"; };
|
||||
F26CBA89136DE86A00DCB596 /* MainApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainApp.h; sourceTree = "<group>"; };
|
||||
F26CBA8A136DE86A00DCB596 /* MainApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MainApp.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
F26D959217C0E81800E58E5D /* Welcome.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = Welcome.rtf; path = Resources/Welcome.rtf; sourceTree = "<group>"; };
|
||||
F26D959417C0E86300E58E5D /* MainApp.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainApp.xib; sourceTree = "<group>"; };
|
||||
F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesDialog.xib; sourceTree = "<group>"; };
|
||||
F26D959817C0E88700E58E5D /* WelcomeDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WelcomeDialog.xib; sourceTree = "<group>"; };
|
||||
F26D959A17C0E89D00E58E5D /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = Resources/Localizable.strings; sourceTree = "<group>"; };
|
||||
F29ABB2317BFC03D0023A423 /* DaemonController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DaemonController.h; sourceTree = "<group>"; };
|
||||
F29ABB2417BFC03D0023A423 /* DaemonController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DaemonController.m; sourceTree = "<group>"; };
|
||||
F2A55D3617C4CA9000D6FFE1 /* daemon */ = {isa = PBXFileReference; lastKnownFileType = folder; name = daemon; path = Resources/daemon; sourceTree = "<group>"; };
|
||||
F2A55D3A17C4CAF800D6FFE1 /* tools */ = {isa = PBXFileReference; lastKnownFileType = folder; name = tools; path = Resources/tools; sourceTree = "<group>"; };
|
||||
F2A6E10E17C8E42300D910CB /* statusicon-inv@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "statusicon-inv@2x.png"; path = "Images/statusicon-inv@2x.png"; sourceTree = "<group>"; };
|
||||
F2A6E10F17C8E42300D910CB /* statusicon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "statusicon@2x.png"; path = "Images/statusicon@2x.png"; sourceTree = "<group>"; };
|
||||
F2CD856417C254A90019D2CA /* RPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RPC.h; sourceTree = "<group>"; };
|
||||
F2CD856517C254A90019D2CA /* RPC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RPC.m; sourceTree = "<group>"; };
|
||||
F2CD856917C282800019D2CA /* WebClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebClient.h; sourceTree = "<group>"; };
|
||||
F2CD856A17C282800019D2CA /* WebClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebClient.m; sourceTree = "<group>"; };
|
||||
F2D2A2EE13CBA680000824B4 /* WelcomeDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WelcomeDialog.h; sourceTree = "<group>"; };
|
||||
F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WelcomeDialog.m; sourceTree = "<group>"; };
|
||||
F2F9804917C9081D004623D6 /* licenses */ = {isa = PBXFileReference; lastKnownFileType = folder; name = licenses; path = Resources/licenses; sourceTree = "<group>"; };
|
||||
F2FC0F8B13BF595700D834E3 /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = Credits.rtf; path = Resources/Credits.rtf; sourceTree = "<group>"; };
|
||||
F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = mainicon.icns; path = Images/mainicon.icns; sourceTree = "<group>"; };
|
||||
F2FCD7D813BBDAED00FC81F5 /* statusicon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = statusicon.png; path = Images/statusicon.png; sourceTree = "<group>"; };
|
||||
F2FCD84C13BCFD0900FC81F5 /* statusicon-inv.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "statusicon-inv.png"; path = "Images/statusicon-inv.png"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8D11072E0486CEB800E47090 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F20FC6E417C6BC8D00C392AC /* Security.framework in Frameworks */,
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
F29ABB2B17C00E150023A423 /* AppKit.framework in Frameworks */,
|
||||
F29ABB2C17C00E190023A423 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
19C28FACFE9D520D11CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8D1107320486CEB800E47090 /* NZBGet.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97314FDCFA39411CA2CEA /* NZBGet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F26CBA8C136DE87500DCB596 /* Main */,
|
||||
F29ABB2517BFC0450023A423 /* DaemonController */,
|
||||
F2D2A2F213CBA7C8000824B4 /* WelcomeDialog */,
|
||||
F21D343013BE339300E6D821 /* Preferences */,
|
||||
F20FC6E017C6BA0100C392AC /* LetsMove */,
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||
29B97317FDCFA39411CA2CEA /* Resources */,
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||
);
|
||||
name = "NZBGet";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
256AC3F00F4B6AF500CF3369 /* App_Prefix.pch */,
|
||||
);
|
||||
name = "Other Sources";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F2F9804917C9081D004623D6 /* licenses */,
|
||||
F2A55D3617C4CA9000D6FFE1 /* daemon */,
|
||||
F2A55D3A17C4CAF800D6FFE1 /* tools */,
|
||||
F2D370AE13C0859A002C0573 /* Images */,
|
||||
F26D959A17C0E89D00E58E5D /* Localizable.strings */,
|
||||
F26D959217C0E81800E58E5D /* Welcome.rtf */,
|
||||
F2FC0F8B13BF595700D834E3 /* Credits.rtf */,
|
||||
8D1107310486CEB800E47090 /* NZBGet-Info.plist */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */,
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
|
||||
F20FC6E317C6BC8D00C392AC /* Security.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F20FC6E017C6BA0100C392AC /* LetsMove */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F20FC6DE17C6B9FC00C392AC /* PFMoveApplication.h */,
|
||||
F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */,
|
||||
);
|
||||
name = LetsMove;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F21D343013BE339300E6D821 /* Preferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */,
|
||||
F21D369913BF387F00E6D821 /* PreferencesDialog.h */,
|
||||
F21D369A13BF387F00E6D821 /* PreferencesDialog.m */,
|
||||
);
|
||||
name = Preferences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F26CBA8C136DE87500DCB596 /* Main */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F26D959417C0E86300E58E5D /* MainApp.xib */,
|
||||
F26CBA89136DE86A00DCB596 /* MainApp.h */,
|
||||
F26CBA8A136DE86A00DCB596 /* MainApp.m */,
|
||||
);
|
||||
name = Main;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F29ABB2517BFC0450023A423 /* DaemonController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F2CD856917C282800019D2CA /* WebClient.h */,
|
||||
F2CD856A17C282800019D2CA /* WebClient.m */,
|
||||
F2CD856417C254A90019D2CA /* RPC.h */,
|
||||
F2CD856517C254A90019D2CA /* RPC.m */,
|
||||
F29ABB2317BFC03D0023A423 /* DaemonController.h */,
|
||||
F29ABB2417BFC03D0023A423 /* DaemonController.m */,
|
||||
);
|
||||
name = DaemonController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F2D2A2F213CBA7C8000824B4 /* WelcomeDialog */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F26D959817C0E88700E58E5D /* WelcomeDialog.xib */,
|
||||
F2D2A2EE13CBA680000824B4 /* WelcomeDialog.h */,
|
||||
F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */,
|
||||
);
|
||||
name = WelcomeDialog;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F2D370AE13C0859A002C0573 /* Images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */,
|
||||
F2A6E10E17C8E42300D910CB /* statusicon-inv@2x.png */,
|
||||
F2A6E10F17C8E42300D910CB /* statusicon@2x.png */,
|
||||
F2FCD84C13BCFD0900FC81F5 /* statusicon-inv.png */,
|
||||
F2FCD7D813BBDAED00FC81F5 /* statusicon.png */,
|
||||
);
|
||||
name = Images;
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8D1107260486CEB800E47090 /* NZBGet */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "NZBGet" */;
|
||||
buildPhases = (
|
||||
8D1107290486CEB800E47090 /* Resources */,
|
||||
8D11072C0486CEB800E47090 /* Sources */,
|
||||
8D11072E0486CEB800E47090 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = NZBGet;
|
||||
productInstallPath = "$(HOME)/Applications";
|
||||
productName = "NZBGet";
|
||||
productReference = 8D1107320486CEB800E47090 /* NZBGet.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0460;
|
||||
ORGANIZATIONNAME = "Andrey Prygunkov";
|
||||
};
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NZBGet" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
Russian,
|
||||
de,
|
||||
ru,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* NZBGet */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8D1107260486CEB800E47090 /* NZBGet */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8D1107290486CEB800E47090 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F2FCD73B13BB9CE900FC81F5 /* mainicon.icns in Resources */,
|
||||
F2FCD7D913BBDAED00FC81F5 /* statusicon.png in Resources */,
|
||||
F2FCD84D13BCFD0900FC81F5 /* statusicon-inv.png in Resources */,
|
||||
F2BBD9C613E083160037473A /* Credits.rtf in Resources */,
|
||||
F26D959317C0E81800E58E5D /* Welcome.rtf in Resources */,
|
||||
F26D959517C0E86300E58E5D /* MainApp.xib in Resources */,
|
||||
F26D959717C0E87E00E58E5D /* PreferencesDialog.xib in Resources */,
|
||||
F26D959917C0E88700E58E5D /* WelcomeDialog.xib in Resources */,
|
||||
F26D959B17C0E89D00E58E5D /* Localizable.strings in Resources */,
|
||||
F2A55D3717C4CA9000D6FFE1 /* daemon in Resources */,
|
||||
F2A55D3B17C4CAF800D6FFE1 /* tools in Resources */,
|
||||
F2A6E11017C8E42300D910CB /* statusicon-inv@2x.png in Resources */,
|
||||
F2A6E11117C8E42300D910CB /* statusicon@2x.png in Resources */,
|
||||
F2F9804A17C9081D004623D6 /* licenses in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8D11072C0486CEB800E47090 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F26CBA8B136DE86A00DCB596 /* MainApp.m in Sources */,
|
||||
F21D369B13BF387F00E6D821 /* PreferencesDialog.m in Sources */,
|
||||
F2D2A2F113CBA680000824B4 /* WelcomeDialog.m in Sources */,
|
||||
F29ABB2617BFC61B0023A423 /* DaemonController.m in Sources */,
|
||||
F2CD856817C282080019D2CA /* RPC.m in Sources */,
|
||||
F2CD856B17C282820019D2CA /* WebClient.m in Sources */,
|
||||
F20FC6E217C6BAAE00C392AC /* PFMoveApplication.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C01FCF4B08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\"",
|
||||
);
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = App_Prefix.pch;
|
||||
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = DEBUG;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = "NZBGet-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_NAME = NZBGet;
|
||||
SDKROOT = macosx10.7;
|
||||
VALID_ARCHS = x86_64;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF4C08A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\"",
|
||||
);
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = App_Prefix.pch;
|
||||
INFOPLIST_FILE = "NZBGet-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
PRODUCT_NAME = NZBGet;
|
||||
SDKROOT = macosx10.7;
|
||||
VALID_ARCHS = x86_64;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C01FCF4F08A954540054247B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "";
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C01FCF5008A954540054247B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PRODUCT_NAME = "";
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "NZBGet" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C01FCF4B08A954540054247B /* Debug */,
|
||||
C01FCF4C08A954540054247B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NZBGet" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C01FCF4F08A954540054247B /* Debug */,
|
||||
C01FCF5008A954540054247B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
//
|
||||
// PFMoveApplication.h, version 1.8
|
||||
// LetsMove
|
||||
//
|
||||
// Created by Andy Kim at Potion Factory LLC on 9/17/09
|
||||
//
|
||||
// The contents of this file are dedicated to the public domain.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
void PFMoveToApplicationsFolderIfNecessary(void);
|
||||
@@ -1,460 +0,0 @@
|
||||
//
|
||||
// PFMoveApplication.m, version 1.8
|
||||
// LetsMove
|
||||
//
|
||||
// Created by Andy Kim at Potion Factory LLC on 9/17/09
|
||||
//
|
||||
// The contents of this file are dedicated to the public domain.
|
||||
|
||||
#import "PFMoveApplication.h"
|
||||
// Andrey Prygunkov (NZBGet):
|
||||
// all references to "NSString+SymlinksAndAliases.h" removed because
|
||||
// it has a BSD like license which might not be compatible with GPLv2.
|
||||
// This makes the function a little bit less robust not properly handle some rare cases.
|
||||
//#import "NSString+SymlinksAndAliases.h"
|
||||
#import <Security/Security.h>
|
||||
#import <dlfcn.h>
|
||||
|
||||
// Strings
|
||||
// These are macros to be able to use custom i18n tools
|
||||
#define _I10NS(nsstr) NSLocalizedStringFromTable(nsstr, @"MoveApplication", nil)
|
||||
#define kStrMoveApplicationCouldNotMove _I10NS(@"Could not move to Applications folder")
|
||||
#define kStrMoveApplicationQuestionTitle _I10NS(@"Move to Applications folder?")
|
||||
#define kStrMoveApplicationQuestionTitleHome _I10NS(@"Move to Applications folder in your Home folder?")
|
||||
#define kStrMoveApplicationQuestionMessage _I10NS(@"NZBGet can move itself to the Applications folder if you'd like.")
|
||||
#define kStrMoveApplicationButtonMove _I10NS(@"Move to Applications Folder")
|
||||
#define kStrMoveApplicationButtonDoNotMove _I10NS(@"Do Not Move")
|
||||
#define kStrMoveApplicationQuestionInfoWillRequirePasswd _I10NS(@"Note that this will require an administrator password.")
|
||||
#define kStrMoveApplicationQuestionInfoInDownloadsFolder _I10NS(@"This will keep your Downloads folder uncluttered.")
|
||||
|
||||
// Needs to be defined for compiling under 10.4 SDK
|
||||
#ifndef NSAppKitVersionNumber10_4
|
||||
#define NSAppKitVersionNumber10_4 824
|
||||
#endif
|
||||
// Needs to be defined for compiling under 10.5 SDK
|
||||
#ifndef NSAppKitVersionNumber10_5
|
||||
#define NSAppKitVersionNumber10_5 949
|
||||
#endif
|
||||
|
||||
// By default, we use a small control/font for the suppression button.
|
||||
// If you prefer to use the system default (to match your other alerts),
|
||||
// set this to 0.
|
||||
#define PFUseSmallAlertSuppressCheckbox 1
|
||||
|
||||
|
||||
static NSString *AlertSuppressKey = @"moveToApplicationsFolderAlertSuppress";
|
||||
|
||||
|
||||
// Helper functions
|
||||
static NSString *PreferredInstallLocation(BOOL *isUserDirectory);
|
||||
static BOOL IsInApplicationsFolder(NSString *path);
|
||||
static BOOL IsInDownloadsFolder(NSString *path);
|
||||
static BOOL IsLaunchedFromDMG();
|
||||
static BOOL Trash(NSString *path);
|
||||
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled);
|
||||
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath);
|
||||
static void Relaunch();
|
||||
|
||||
// Main worker function
|
||||
void PFMoveToApplicationsFolderIfNecessary(void) {
|
||||
// Skip if user suppressed the alert before
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return;
|
||||
|
||||
// Path of the bundle
|
||||
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
// Skip if the application is already in some Applications folder
|
||||
if (IsInApplicationsFolder(bundlePath)) return;
|
||||
|
||||
// File Manager
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
BOOL isLaunchedFromDMG = IsLaunchedFromDMG();
|
||||
|
||||
// Since we are good to go, get the preferred installation directory.
|
||||
BOOL installToUserApplications = NO;
|
||||
NSString *applicationsDirectory = PreferredInstallLocation(&installToUserApplications);
|
||||
NSString *bundleName = [bundlePath lastPathComponent];
|
||||
NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName];
|
||||
|
||||
// Check if we need admin password to write to the Applications directory
|
||||
BOOL needAuthorization = ([fm isWritableFileAtPath:applicationsDirectory] == NO);
|
||||
|
||||
// Check if the destination bundle is already there but not writable
|
||||
needAuthorization |= ([fm fileExistsAtPath:destinationPath] && ![fm isWritableFileAtPath:destinationPath]);
|
||||
|
||||
// Setup the alert
|
||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||
{
|
||||
NSString *informativeText = nil;
|
||||
|
||||
[alert setMessageText:(installToUserApplications ? kStrMoveApplicationQuestionTitleHome : kStrMoveApplicationQuestionTitle)];
|
||||
|
||||
informativeText = kStrMoveApplicationQuestionMessage;
|
||||
|
||||
if (needAuthorization) {
|
||||
informativeText = [informativeText stringByAppendingString:@" "];
|
||||
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoWillRequirePasswd];
|
||||
}
|
||||
else if (IsInDownloadsFolder(bundlePath)) {
|
||||
// Don't mention this stuff if we need authentication. The informative text is long enough as it is in that case.
|
||||
informativeText = [informativeText stringByAppendingString:@" "];
|
||||
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoInDownloadsFolder];
|
||||
}
|
||||
|
||||
[alert setInformativeText:informativeText];
|
||||
|
||||
// Add accept button
|
||||
[alert addButtonWithTitle:kStrMoveApplicationButtonMove];
|
||||
|
||||
// Add deny button
|
||||
NSButton *cancelButton = [alert addButtonWithTitle:kStrMoveApplicationButtonDoNotMove];
|
||||
[cancelButton setKeyEquivalent:@"\e"];
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
|
||||
// Setup suppression button
|
||||
[alert setShowsSuppressionButton:YES];
|
||||
|
||||
if (PFUseSmallAlertSuppressCheckbox) {
|
||||
[[[alert suppressionButton] cell] setControlSize:NSSmallControlSize];
|
||||
[[[alert suppressionButton] cell] setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Activate app -- work-around for focus issues related to "scary file from internet" OS dialog.
|
||||
if (![NSApp isActive]) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
DLog(@"INFO -- Moving myself to the Applications folder");
|
||||
|
||||
// Move
|
||||
if (needAuthorization) {
|
||||
BOOL authorizationCanceled;
|
||||
|
||||
if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) {
|
||||
if (authorizationCanceled) {
|
||||
DLog(@"INFO -- Not moving because user canceled authorization");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
DLog(@"ERROR -- Could not copy myself to /Applications with authorization");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If a copy already exists in the Applications folder, put it in the Trash
|
||||
if ([fm fileExistsAtPath:destinationPath]) {
|
||||
// But first, make sure that it's not running
|
||||
BOOL destinationIsRunning = NO;
|
||||
|
||||
// Use the shell to determine if the app is already running on systems 10.5 or lower
|
||||
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {
|
||||
NSString *script = [NSString stringWithFormat:@"ps ax -o comm | grep '%@/' | grep -v grep >/dev/null", destinationPath];
|
||||
NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
||||
[task waitUntilExit];
|
||||
|
||||
// If the task terminated with status 0, it means that the final grep produced 1 or more lines of output.
|
||||
// Which means that the app is already running
|
||||
destinationIsRunning = ([task terminationStatus] == 0);
|
||||
}
|
||||
// Use the new API on 10.6 or higher
|
||||
else {
|
||||
for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
||||
NSString *executablePath = [[runningApplication executableURL] path];
|
||||
if ([executablePath hasPrefix:destinationPath]) {
|
||||
destinationIsRunning = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (destinationIsRunning) {
|
||||
// Give the running app focus and terminate myself
|
||||
DLog(@"INFO -- Switching to an already running version");
|
||||
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit];
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName]))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CopyBundle(bundlePath, destinationPath)) {
|
||||
DLog(@"ERROR -- Could not copy myself to %@", destinationPath);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// Trash the original app. It's okay if this fails.
|
||||
// NOTE: This final delete does not work if the source bundle is in a network mounted volume.
|
||||
// Calling rm or file manager's delete method doesn't work either. It's unlikely to happen
|
||||
// but it'd be great if someone could fix this.
|
||||
if (!isLaunchedFromDMG && !Trash(bundlePath)) {
|
||||
DLog(@"WARNING -- Could not delete application after moving it to Applications folder");
|
||||
}
|
||||
|
||||
// Relaunch.
|
||||
Relaunch(destinationPath);
|
||||
}
|
||||
else {
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
|
||||
// Save the alert suppress preference if checked
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
|
||||
if ([[alert suppressionButton] state] == NSOnState) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Always suppress after the first decline on 10.4 since there is no suppression checkbox
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
{
|
||||
// Show failure message
|
||||
alert = [[[NSAlert alloc] init] autorelease];
|
||||
[alert setMessageText:kStrMoveApplicationCouldNotMove];
|
||||
[alert runModal];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Helper Functions
|
||||
|
||||
static NSString *PreferredInstallLocation(BOOL *isUserDirectory) {
|
||||
// Return the preferred install location.
|
||||
// Assume that if the user has a ~/Applications folder, they'd prefer their
|
||||
// applications to go there.
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSArray *userApplicationsDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
|
||||
|
||||
if ([userApplicationsDirs count] > 0) {
|
||||
NSString *userApplicationsDir = [userApplicationsDirs objectAtIndex:0];
|
||||
BOOL isDirectory;
|
||||
|
||||
if ([fm fileExistsAtPath:userApplicationsDir isDirectory:&isDirectory] && isDirectory) {
|
||||
// User Applications directory exists. Get the directory contents.
|
||||
NSArray *contents = [fm contentsOfDirectoryAtPath:userApplicationsDir error:NULL];
|
||||
|
||||
// Check if there is at least one ".app" inside the directory.
|
||||
for (NSString *contentsPath in contents) {
|
||||
if ([[contentsPath pathExtension] isEqualToString:@"app"]) {
|
||||
if (isUserDirectory) *isUserDirectory = YES;
|
||||
//return [userApplicationsDir stringByResolvingSymlinksAndAliases];
|
||||
return userApplicationsDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No user Applications directory in use. Return the machine local Applications directory
|
||||
if (isUserDirectory) *isUserDirectory = NO;
|
||||
//return [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByResolvingSymlinksAndAliases];
|
||||
return [NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject];
|
||||
}
|
||||
|
||||
static BOOL IsInApplicationsFolder(NSString *path) {
|
||||
// Check all the normal Application directories
|
||||
NSEnumerator *e = [NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES) objectEnumerator];
|
||||
NSString *appDirPath = nil;
|
||||
|
||||
while ((appDirPath = [e nextObject])) {
|
||||
if ([path hasPrefix:appDirPath]) return YES;
|
||||
}
|
||||
|
||||
// Also, handle the case that the user has some other Application directory (perhaps on a separate data partition).
|
||||
if ([[path pathComponents] containsObject:@"Applications"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL IsInDownloadsFolder(NSString *path) {
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
|
||||
// 10.5 or higher has NSDownloadsDirectory
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
|
||||
NSEnumerator *e = [NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSAllDomainsMask, YES) objectEnumerator];
|
||||
NSString *downloadsDirPath = nil;
|
||||
|
||||
while ((downloadsDirPath = [e nextObject])) {
|
||||
if ([path hasPrefix:downloadsDirPath]) return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
#endif
|
||||
// 10.4
|
||||
return [[[path stringByDeletingLastPathComponent] lastPathComponent] isEqualToString:@"Downloads"];
|
||||
}
|
||||
|
||||
static BOOL IsLaunchedFromDMG() {
|
||||
// Guess if we have launched from a disk image
|
||||
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
BOOL bundlePathIsWritable = [fm isWritableFileAtPath:bundlePath];
|
||||
|
||||
return [bundlePath hasPrefix:@"/Volumes/"] && !bundlePathIsWritable;
|
||||
}
|
||||
|
||||
static BOOL Trash(NSString *path) {
|
||||
if ([[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
||||
source:[path stringByDeletingLastPathComponent]
|
||||
destination:@""
|
||||
files:[NSArray arrayWithObject:[path lastPathComponent]]
|
||||
tag:NULL]) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
DLog(@"ERROR -- Could not trash '%@'", path);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled) {
|
||||
if (canceled) *canceled = NO;
|
||||
|
||||
// Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf'
|
||||
// so we really don't want to fuck this up.
|
||||
if (![dstPath hasSuffix:@".app"]) return NO;
|
||||
|
||||
// Do some more checks
|
||||
if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
|
||||
if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
|
||||
|
||||
int pid, status;
|
||||
AuthorizationRef myAuthorizationRef;
|
||||
|
||||
// Get the authorization
|
||||
OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef);
|
||||
if (err != errAuthorizationSuccess) return NO;
|
||||
|
||||
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
|
||||
AuthorizationRights myRights = {1, &myItems};
|
||||
AuthorizationFlags myFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
||||
|
||||
err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL);
|
||||
if (err != errAuthorizationSuccess) {
|
||||
if (err == errAuthorizationCanceled && canceled)
|
||||
*canceled = YES;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool,
|
||||
AuthorizationFlags options, char * const *arguments,
|
||||
FILE **communicationsPipe) = NULL;
|
||||
if (!security_AuthorizationExecuteWithPrivileges) {
|
||||
// On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no
|
||||
// good alternative (without requiring code signing). We'll look up the function through dyld and fail
|
||||
// if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If
|
||||
// they keep the function and throw some sort of exception, this won't fail gracefully, but that's a
|
||||
// risk we'll have to take for now.
|
||||
security_AuthorizationExecuteWithPrivileges = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
|
||||
}
|
||||
if (!security_AuthorizationExecuteWithPrivileges) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Delete the destination
|
||||
{
|
||||
char *args[] = {"-rf", (char *)[dstPath fileSystemRepresentation], NULL};
|
||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
|
||||
if (err != errAuthorizationSuccess) goto fail;
|
||||
|
||||
// Wait until it's done
|
||||
pid = wait(&status);
|
||||
if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist
|
||||
}
|
||||
|
||||
// Copy
|
||||
{
|
||||
char *args[] = {"-pR", (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL};
|
||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
|
||||
if (err != errAuthorizationSuccess) goto fail;
|
||||
|
||||
// Wait until it's done
|
||||
pid = wait(&status);
|
||||
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail;
|
||||
}
|
||||
|
||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
||||
return YES;
|
||||
|
||||
fail:
|
||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath) {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
|
||||
// 10.5 or higher
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
|
||||
NSError *error = nil;
|
||||
if ([fm copyItemAtPath:srcPath toPath:dstPath error:&error]) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
DLog(@"ERROR -- Could not copy '%@' to '%@' (%@)", srcPath, dstPath, error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
|
||||
if ([fm copyPath:srcPath toPath:dstPath handler:nil]) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
DLog(@"ERROR -- Could not copy '%@' to '%@'", srcPath, dstPath);
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
static void Relaunch(NSString *destinationPath) {
|
||||
// The shell script waits until the original app process terminates.
|
||||
// This is done so that the relaunched app opens as the front-most app.
|
||||
int pid = [[NSProcessInfo processInfo] processIdentifier];
|
||||
|
||||
// Command run just before running open /final/path
|
||||
NSString *preOpenCmd = @"";
|
||||
|
||||
// OS X >=10.5:
|
||||
// Before we launch the new app, clear xattr:com.apple.quarantine to avoid
|
||||
// duplicate "scary file from the internet" dialog.
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
|
||||
// Add the -r flag on 10.6
|
||||
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine '%@';", destinationPath];
|
||||
}
|
||||
else if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
|
||||
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine '%@';", destinationPath];
|
||||
}
|
||||
#endif
|
||||
|
||||
NSString *script = [NSString stringWithFormat:@"(while [ `ps -p %d | wc -l` -gt 1 ]; do sleep 0.1; done; %@ open '%@') &", pid, preOpenCmd, destinationPath];
|
||||
|
||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
||||
|
||||
// Launched from within a DMG? -- unmount (if no files are open after 5 seconds,
|
||||
// otherwise leave it mounted).
|
||||
if (IsLaunchedFromDMG()) {
|
||||
script = [NSString stringWithFormat:@"(sleep 5 && hdiutil detach '%@') &", [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent]];
|
||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface PreferencesDialog : NSWindowController {
|
||||
IBOutlet NSButton *autostartButton;
|
||||
IBOutlet NSButton *showStatusIconButton;
|
||||
IBOutlet NSTextField *generalText;
|
||||
IBOutlet NSTextField *appearanceText;
|
||||
IBOutlet NSButton *autoShowWebUI;
|
||||
}
|
||||
|
||||
- (IBAction)autostartButtonClicked:(id)sender;
|
||||
|
||||
@end
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import "PreferencesDialog.h"
|
||||
|
||||
|
||||
@implementation PreferencesDialog
|
||||
|
||||
- (id)init {
|
||||
return [super initWithWindowNibName:@"PreferencesDialog"];
|
||||
}
|
||||
|
||||
- (void)windowDidLoad {
|
||||
}
|
||||
|
||||
- (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
|
||||
// We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list.
|
||||
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
|
||||
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL);
|
||||
if (item)
|
||||
CFRelease(item);
|
||||
}
|
||||
|
||||
- (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
|
||||
UInt32 seedValue;
|
||||
CFURLRef thePath;
|
||||
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
|
||||
// and pop it in an array so we can iterate through it to find our item.
|
||||
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
|
||||
for (id item in (__bridge NSArray *)loginItemsArray) {
|
||||
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
|
||||
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
|
||||
if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
|
||||
LSSharedFileListItemRemove(theLoginItemsRefs, itemRef); // Deleting the item
|
||||
}
|
||||
// Docs for LSSharedFileListItemResolve say we're responsible
|
||||
// for releasing the CFURLRef that is returned
|
||||
CFRelease(thePath);
|
||||
}
|
||||
}
|
||||
CFRelease(loginItemsArray);
|
||||
}
|
||||
|
||||
- (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath {
|
||||
BOOL found = NO;
|
||||
UInt32 seedValue;
|
||||
CFURLRef thePath;
|
||||
|
||||
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
|
||||
// and pop it in an array so we can iterate through it to find our item.
|
||||
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
|
||||
for (id item in (__bridge NSArray *)loginItemsArray) {
|
||||
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
|
||||
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
|
||||
if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
// Docs for LSSharedFileListItemResolve say we're responsible
|
||||
// for releasing the CFURLRef that is returned
|
||||
CFRelease(thePath);
|
||||
}
|
||||
}
|
||||
CFRelease(loginItemsArray);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
// This will retrieve the path for the application
|
||||
// For example, /Applications/test.app
|
||||
NSString * appPath = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
||||
if ([self loginItemExistsWithLoginItemReference:loginItems ForPath:appPath]) {
|
||||
[autostartButton setState:NSOnState];
|
||||
}
|
||||
CFRelease(loginItems);
|
||||
}
|
||||
|
||||
- (IBAction)autostartButtonClicked:(id)sender {
|
||||
NSString * appPath = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
// Create a reference to the shared file list.
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
||||
if (loginItems) {
|
||||
if ([sender state] == NSOnState)
|
||||
[self enableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
|
||||
else
|
||||
[self disableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
|
||||
}
|
||||
CFRelease(loginItems);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,623 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1070</int>
|
||||
<string key="IBDocument.SystemVersion">11G63</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.51</string>
|
||||
<string key="IBDocument.HIToolboxVersion">569.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">3084</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSButton</string>
|
||||
<string>NSButtonCell</string>
|
||||
<string>NSCustomObject</string>
|
||||
<string>NSImageCell</string>
|
||||
<string>NSImageView</string>
|
||||
<string>NSTextField</string>
|
||||
<string>NSTextFieldCell</string>
|
||||
<string>NSUserDefaultsController</string>
|
||||
<string>NSView</string>
|
||||
<string>NSWindowTemplate</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSCustomObject" id="1001">
|
||||
<string key="NSClassName">PreferencesDialog</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1003">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1004">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSWindowTemplate" id="1005">
|
||||
<int key="NSWindowStyleMask">3</int>
|
||||
<int key="NSWindowBacking">2</int>
|
||||
<string key="NSWindowRect">{{196, 436}, {357, 155}}</string>
|
||||
<int key="NSWTFlags">544735232</int>
|
||||
<string key="NSWindowTitle">NZBGet Preferences</string>
|
||||
<string key="NSWindowClass">NSWindow</string>
|
||||
<nil key="NSViewClass"/>
|
||||
<nil key="NSUserInterfaceItemIdentifier"/>
|
||||
<object class="NSView" key="NSWindowView" id="1006">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSButton" id="668723838">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{67, 119}, {213, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="445769"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="474631304">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Start at login</string>
|
||||
<object class="NSFont" key="NSSupport" id="1028951332">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">13</double>
|
||||
<int key="NSfFlags">1044</int>
|
||||
</object>
|
||||
<reference key="NSControlView" ref="668723838"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<object class="NSCustomResource" key="NSNormalImage" id="167410980">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSSwitch</string>
|
||||
</object>
|
||||
<object class="NSButtonImageSource" key="NSAlternateImage" id="341711700">
|
||||
<string key="NSImageName">NSSwitch</string>
|
||||
</object>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="445769">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{67, 99}, {213, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="897618223"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="741315823">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Show in menubar</string>
|
||||
<reference key="NSSupport" ref="1028951332"/>
|
||||
<reference key="NSControlView" ref="445769"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSNormalImage" ref="167410980"/>
|
||||
<reference key="NSAlternateImage" ref="341711700"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSButton" id="897618223">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{67, 79}, {213, 18}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="205669972"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSButtonCell" key="NSCell" id="395093705">
|
||||
<int key="NSCellFlags">67239424</int>
|
||||
<int key="NSCellFlags2">0</int>
|
||||
<string key="NSContents">Show Web-Interface on start</string>
|
||||
<reference key="NSSupport" ref="1028951332"/>
|
||||
<reference key="NSControlView" ref="897618223"/>
|
||||
<int key="NSButtonFlags">1211912703</int>
|
||||
<int key="NSButtonFlags2">2</int>
|
||||
<reference key="NSNormalImage" ref="167410980"/>
|
||||
<reference key="NSAlternateImage" ref="341711700"/>
|
||||
<string key="NSAlternateContents"/>
|
||||
<string key="NSKeyEquivalent"/>
|
||||
<int key="NSPeriodicDelay">200</int>
|
||||
<int key="NSPeriodicInterval">25</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSImageView" id="205669972">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<object class="NSMutableSet" key="NSDragTypes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="set.sortedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>Apple PDF pasteboard type</string>
|
||||
<string>Apple PICT pasteboard type</string>
|
||||
<string>Apple PNG pasteboard type</string>
|
||||
<string>NSFilenamesPboardType</string>
|
||||
<string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
|
||||
<string>NeXT TIFF v4.0 pasteboard type</string>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{20, 30}, {32, 32}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="371541245"/>
|
||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSImageCell" key="NSCell" id="15570902">
|
||||
<int key="NSCellFlags">134348288</int>
|
||||
<int key="NSCellFlags2">33554432</int>
|
||||
<object class="NSCustomResource" key="NSContents">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSInfo</string>
|
||||
</object>
|
||||
<int key="NSAlign">0</int>
|
||||
<int key="NSScale">3</int>
|
||||
<int key="NSStyle">0</int>
|
||||
<bool key="NSAnimates">NO</bool>
|
||||
</object>
|
||||
<bool key="NSEditable">YES</bool>
|
||||
</object>
|
||||
<object class="NSTextField" id="371541245">
|
||||
<reference key="NSNextResponder" ref="1006"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrame">{{66, 20}, {244, 42}}</string>
|
||||
<reference key="NSSuperview" ref="1006"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:1535</string>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSTextFieldCell" key="NSCell" id="833412041">
|
||||
<int key="NSCellFlags">67108864</int>
|
||||
<int key="NSCellFlags2">4325376</int>
|
||||
<string key="NSContents">Only OSX-specific options are located here. For all other options see Settings page in Web-Interface.</string>
|
||||
<object class="NSFont" key="NSSupport">
|
||||
<string key="NSName">LucidaGrande</string>
|
||||
<double key="NSSize">11</double>
|
||||
<int key="NSfFlags">3100</int>
|
||||
</object>
|
||||
<string key="NSCellIdentifier">_NS:1535</string>
|
||||
<reference key="NSControlView" ref="371541245"/>
|
||||
<object class="NSColor" key="NSBackgroundColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSColor" key="NSTextColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">controlTextColor</string>
|
||||
<object class="NSColor" key="NSColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MAA</bytes>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{357, 155}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="668723838"/>
|
||||
</object>
|
||||
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
|
||||
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
|
||||
<bool key="NSWindowIsRestorable">YES</bool>
|
||||
</object>
|
||||
<object class="NSUserDefaultsController" id="575306214">
|
||||
<bool key="NSSharedInstance">YES</bool>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">window</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="1005"/>
|
||||
</object>
|
||||
<int key="connectionID">11</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">autostartButtonClicked:</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="668723838"/>
|
||||
</object>
|
||||
<int key="connectionID">24</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">autostartButton</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="668723838"/>
|
||||
</object>
|
||||
<int key="connectionID">25</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">showStatusIconButton</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="445769"/>
|
||||
</object>
|
||||
<int key="connectionID">28</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">autoShowWebUI</string>
|
||||
<reference key="source" ref="1001"/>
|
||||
<reference key="destination" ref="897618223"/>
|
||||
</object>
|
||||
<int key="connectionID">32</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="1005"/>
|
||||
<reference key="destination" ref="1001"/>
|
||||
</object>
|
||||
<int key="connectionID">12</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBBindingConnection" key="connection">
|
||||
<string key="label">value: values.ShowInMenubar</string>
|
||||
<reference key="source" ref="445769"/>
|
||||
<reference key="destination" ref="575306214"/>
|
||||
<object class="NSNibBindingConnector" key="connector">
|
||||
<reference key="NSSource" ref="445769"/>
|
||||
<reference key="NSDestination" ref="575306214"/>
|
||||
<string key="NSLabel">value: values.ShowInMenubar</string>
|
||||
<string key="NSBinding">value</string>
|
||||
<string key="NSKeyPath">values.ShowInMenubar</string>
|
||||
<object class="NSDictionary" key="NSOptions">
|
||||
<string key="NS.key.0">NSValidatesImmediately</string>
|
||||
<boolean value="YES" key="NS.object.0"/>
|
||||
</object>
|
||||
<int key="NSNibBindingConnectorVersion">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<int key="connectionID">23</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBBindingConnection" key="connection">
|
||||
<string key="label">value: values.AutoStartWebUI</string>
|
||||
<reference key="source" ref="897618223"/>
|
||||
<reference key="destination" ref="575306214"/>
|
||||
<object class="NSNibBindingConnector" key="connector">
|
||||
<reference key="NSSource" ref="897618223"/>
|
||||
<reference key="NSDestination" ref="575306214"/>
|
||||
<string key="NSLabel">value: values.AutoStartWebUI</string>
|
||||
<string key="NSBinding">value</string>
|
||||
<string key="NSKeyPath">values.AutoStartWebUI</string>
|
||||
<object class="NSDictionary" key="NSOptions">
|
||||
<string key="NS.key.0">NSValidatesImmediately</string>
|
||||
<boolean value="YES" key="NS.object.0"/>
|
||||
</object>
|
||||
<int key="NSNibBindingConnectorVersion">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<int key="connectionID">34</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<object class="NSArray" key="object" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1001"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1003"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1004"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="1005"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="1006"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">2</int>
|
||||
<reference key="object" ref="1006"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="668723838"/>
|
||||
<reference ref="445769"/>
|
||||
<reference ref="897618223"/>
|
||||
<reference ref="371541245"/>
|
||||
<reference ref="205669972"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1005"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">3</int>
|
||||
<reference key="object" ref="668723838"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="474631304"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="474631304"/>
|
||||
<reference key="parent" ref="668723838"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="445769"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="741315823"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">9</int>
|
||||
<reference key="object" ref="741315823"/>
|
||||
<reference key="parent" ref="445769"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">14</int>
|
||||
<reference key="object" ref="575306214"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">29</int>
|
||||
<reference key="object" ref="897618223"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="395093705"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">30</int>
|
||||
<reference key="object" ref="395093705"/>
|
||||
<reference key="parent" ref="897618223"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">35</int>
|
||||
<reference key="object" ref="205669972"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="15570902"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">36</int>
|
||||
<reference key="object" ref="15570902"/>
|
||||
<reference key="parent" ref="205669972"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">37</int>
|
||||
<reference key="object" ref="371541245"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="833412041"/>
|
||||
</object>
|
||||
<reference key="parent" ref="1006"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">38</int>
|
||||
<reference key="object" ref="833412041"/>
|
||||
<reference key="parent" ref="371541245"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>-3.IBPluginDependency</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>1.IBWindowTemplateEditedContentRect</string>
|
||||
<string>1.NSWindowTemplate.visibleAtLaunch</string>
|
||||
<string>14.IBPluginDependency</string>
|
||||
<string>2.IBPluginDependency</string>
|
||||
<string>2.IBUserGuides</string>
|
||||
<string>29.IBPluginDependency</string>
|
||||
<string>3.IBPluginDependency</string>
|
||||
<string>30.IBPluginDependency</string>
|
||||
<string>35.IBAttributePlaceholdersKey</string>
|
||||
<string>35.IBPluginDependency</string>
|
||||
<string>36.IBPluginDependency</string>
|
||||
<string>37.IBPluginDependency</string>
|
||||
<string>38.IBPluginDependency</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
<string>9.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{322, 782}, {298, 74}}</string>
|
||||
<boolean value="NO"/>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSMutableArray">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSMutableDictionary">
|
||||
<string key="NS.key.0">AccessibilityDescription</string>
|
||||
<object class="IBAccessibilityAttribute" key="NS.object.0">
|
||||
<string key="name">AccessibilityDescription</string>
|
||||
<reference key="object" ref="205669972"/>
|
||||
<string key="accessibilityValue">information</string>
|
||||
</object>
|
||||
</object>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">38</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">PreferencesDialog</string>
|
||||
<string key="superclassName">NSWindowController</string>
|
||||
<object class="NSMutableDictionary" key="actions">
|
||||
<string key="NS.key.0">autostartButtonClicked:</string>
|
||||
<string key="NS.object.0">id</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="actionInfosByName">
|
||||
<string key="NS.key.0">autostartButtonClicked:</string>
|
||||
<object class="IBActionInfo" key="NS.object.0">
|
||||
<string key="name">autostartButtonClicked:</string>
|
||||
<string key="candidateClassName">id</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>appearanceText</string>
|
||||
<string>autoShowWebUI</string>
|
||||
<string>autostartButton</string>
|
||||
<string>generalText</string>
|
||||
<string>showStatusIconButton</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSTextField</string>
|
||||
<string>NSButton</string>
|
||||
<string>NSButton</string>
|
||||
<string>NSTextField</string>
|
||||
<string>NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>appearanceText</string>
|
||||
<string>autoShowWebUI</string>
|
||||
<string>autostartButton</string>
|
||||
<string>generalText</string>
|
||||
<string>showStatusIconButton</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">appearanceText</string>
|
||||
<string key="candidateClassName">NSTextField</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">autoShowWebUI</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">autostartButton</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">generalText</string>
|
||||
<string key="candidateClassName">NSTextField</string>
|
||||
</object>
|
||||
<object class="IBToOneOutletInfo">
|
||||
<string key="name">showStatusIconButton</string>
|
||||
<string key="candidateClassName">NSButton</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/PreferencesDialog.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<real value="1070" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSInfo</string>
|
||||
<string>NSSwitch</string>
|
||||
</object>
|
||||
<object class="NSArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>{32, 32}</string>
|
||||
<string>{15, 15}</string>
|
||||
</object>
|
||||
</object>
|
||||
</data>
|
||||
</archive>
|
||||
38
osx/RPC.h
38
osx/RPC.h
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "WebClient.h"
|
||||
|
||||
@interface RPC : WebClient {
|
||||
}
|
||||
|
||||
- (id)initWithMethod:(NSString*)method
|
||||
receiver:(id)receiver
|
||||
success:(SEL)successCallback
|
||||
failure:(SEL)failureCallback;
|
||||
|
||||
+ (void)setRpcUrl:(NSString*)url;
|
||||
|
||||
@end
|
||||
62
osx/RPC.m
62
osx/RPC.m
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "RPC.h"
|
||||
|
||||
@implementation RPC
|
||||
|
||||
NSString* rpcUrl;
|
||||
|
||||
- (id)initWithMethod:(NSString*)method
|
||||
receiver:(id)receiver
|
||||
success:(SEL)successCallback
|
||||
failure:(SEL)failureCallback {
|
||||
NSString* urlStr = [rpcUrl stringByAppendingString:method];
|
||||
self = [super initWithURLString:urlStr receiver:receiver success:successCallback failure:failureCallback];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)setRpcUrl:(NSString*)url {
|
||||
rpcUrl = url;
|
||||
}
|
||||
|
||||
- (void)success {
|
||||
NSError *error = nil;
|
||||
id dataObj = [NSJSONSerialization
|
||||
JSONObjectWithData:data
|
||||
options:0
|
||||
error:&error];
|
||||
|
||||
if (error || ![dataObj isKindOfClass:[NSDictionary class]]) {
|
||||
/* JSON was malformed, act appropriately here */
|
||||
failureCode = 999;
|
||||
[self failure];
|
||||
}
|
||||
|
||||
id result = [dataObj valueForKey:@"result"];
|
||||
SuppressPerformSelectorLeakWarning([_receiver performSelector:_successCallback withObject:result];);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,17 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
|
||||
{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue255;}
|
||||
\vieww10800\viewh8400\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\sa260\qc
|
||||
|
||||
\f0\fs22 \cf0 Lightweight binary newsgrabber\
|
||||
\pard\pardeftab720\qc
|
||||
\cf0 NZBGet is free software; use it under the\
|
||||
terms of the {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/gpl-2.0.html"}}{\fldrslt GNU General Public License}}.\
|
||||
\
|
||||
The package also includes other software;\
|
||||
see folder "licenses" inside the package.\
|
||||
\
|
||||
\pard\pardeftab720\qc
|
||||
{\field{\*\fldinst{HYPERLINK "http://nzbget.sourceforge.net"}}{\fldrslt \cf2 \ul \ulc2 nzbget.sourceforge.net}}}
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 480 B |
Binary file not shown.
|
Before Width: | Height: | Size: 820 B |
Binary file not shown.
|
Before Width: | Height: | Size: 428 B |
Binary file not shown.
|
Before Width: | Height: | Size: 656 B |
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
"Status.Downloading"="Downloading at %i KB/s";
|
||||
"Status.Post-Processing"="Post-Processing";
|
||||
"Status.Fetching NZBs"="Fetching NZBs";
|
||||
"Status.Fetching Feeds"="Fetching Feeds";
|
||||
"Status.Paused"="Paused";
|
||||
"Status.Idle"="Idle";
|
||||
"Status.Left"="%@ left";
|
||||
"Status.NoConnection"="Downloader Not Responding";
|
||||
"Status.Restarting"="Restarting";
|
||||
|
||||
"Left.Days"="%i days";
|
||||
"Left.Days.Hours"="%id %ih";
|
||||
"Left.Hours"="%i hours";
|
||||
"Left.Hours.Minutes"="%ih %02im";
|
||||
"Left.Minutes"="%im";
|
||||
"Left.Minutes.Seconds"="%im %02is";
|
||||
"Left.Seconds"="%is";
|
||||
|
||||
"Menu.LinkHomePage"="http://nzbget.sourceforge.net";
|
||||
"Menu.LinkDownloads"="http://nzbget.sourceforge.net/Download";
|
||||
"Menu.LinkForum"="http://nzbget.sourceforge.net/forum";
|
||||
|
||||
"ShowWebUINoConnection.MessageText"="Could not establish connection to downloader (background process).";
|
||||
"ShowWebUINoConnection.InformativeText"="Try to restart the program via Troubleshooting-menu.";
|
||||
|
||||
"RestartNoConnection.MessageText"="Could not establish connection to downloader (background process).";
|
||||
"RestartNoConnection.InformativeText"="Try to restart the program in recovery mode via Troubleshooting-menu.";
|
||||
|
||||
"Restarted.MessageText"="The program has been successfully restarted.";
|
||||
"Restarted.InformativeText"="";
|
||||
"Restarted.WebUI"="Show Web-Interface";
|
||||
"Restarted.OK"="OK";
|
||||
|
||||
"RestartedRecoveryMode.MessageText"="The program has been successfully restarted and is now working on address http://127.0.0.1:6789 without password.";
|
||||
"RestartedRecoveryMode.InformativeText"="To access the program via address, port and password defined in settings the program must be restarted in normal mode using Troubleshooting-menu. A soft-restart via web-interface is not sufficient!";
|
||||
|
||||
"FactoryResetted.MessageText"="The program has been reset to factory defaults.";
|
||||
"FactoryResetted.InformativeText"="";
|
||||
|
||||
"FactoryReset.MessageText"="Reset to factory defaults?";
|
||||
"FactoryReset.InformativeText"="All settings will be reset to defaults. The download queue, history, statstics, log-file, default incoming nzb-directory and default ppscripts-directory will be erased. ";
|
||||
"FactoryReset.Cancel"="Cancel";
|
||||
"FactoryReset.Reset"="Erase and Reset";
|
||||
|
||||
"AlreadyRunning.MessageText"="NZBGet is already running.";
|
||||
"AlreadyRunning.InformativeTextWithIcon" = "You can control NZBGet using web-interface or icon in menubar.";
|
||||
"AlreadyRunning.InformativeTextWithoutIcon" = "You can control NZBGet using web-interface. The icon in menubar is currently not displayed because the option 'Show in menubar' was unselected in preferences.";
|
||||
"AlreadyRunning.Quit"="Quit NZBGet";
|
||||
"AlreadyRunning.Preferences"="Open Preferences";
|
||||
"AlreadyRunning.WebUI"="Show Web-Interface";
|
||||
|
||||
"CantShowInFinder.MessageText"="Cannot open %@.";
|
||||
"CantShowInFinder.InformativeTextWithOption"="The path doesn't exist or refers to a volume not mounted at the moment. Check option %@.";
|
||||
"CantShowInFinder.InformativeTextForCategory"="The path doesn't exist or refers to a volume not mounted at the moment. Please also note that destination directories for categories are created upon first use.";
|
||||
@@ -1,23 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
|
||||
{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
|
||||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
|
||||
|
||||
\f0\fs32 \cf0 Welcome!
|
||||
\f1\fs24 \
|
||||
\
|
||||
\pard\pardeftab720\sa260
|
||||
|
||||
\f0\fs26 \cf0 NZBGet is a downloader from binary newsgroups. An account on a news server is needed to use this program.
|
||||
\fs18 \
|
||||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
|
||||
|
||||
\fs26 \cf0 NZBGet works as a background process and can be controlled from a web-browser. An icon in menubar gives a quick access to few important functions.
|
||||
\fs18 \
|
||||
\pard\pardeftab720
|
||||
|
||||
\fs26 \cf0 \
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/gpl-2.0.html"}}{\fldrslt GNU General Public License}}.\
|
||||
\
|
||||
For more information visit {\field{\*\fldinst{HYPERLINK "http://nzbget.sourceforge.net"}}{\fldrslt NZBGet home page}}.}
|
||||
@@ -1,176 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -1,340 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -1,21 +0,0 @@
|
||||
Copyright 2013 jQuery Foundation and other contributors
|
||||
http://jquery.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user