mirror of
https://github.com/nzbget/nzbget.git
synced 2026-02-18 23:03:56 -05:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08b1b79ac2 | ||
|
|
b4211a57e6 | ||
|
|
4a421c705a | ||
|
|
695e3a912c | ||
|
|
af190697c2 | ||
|
|
814ffbd468 | ||
|
|
cb10f39db3 | ||
|
|
c8a496faaa | ||
|
|
7c858007b3 | ||
|
|
3a9e8f1a79 | ||
|
|
dfa839c4e0 | ||
|
|
876fee3bc5 | ||
|
|
22ffd2e0bd | ||
|
|
8cd59b9ab5 | ||
|
|
988714f92a | ||
|
|
789d39bfb2 | ||
|
|
1c333e68c2 | ||
|
|
e9ff2e4fca | ||
|
|
173622fea1 | ||
|
|
9881f2c39e | ||
|
|
0970c0bc52 | ||
|
|
cb2686dc3c | ||
|
|
e0d79a4079 | ||
|
|
2e54a182c9 | ||
|
|
83a405db8b | ||
|
|
cdddecb834 | ||
|
|
faf528a94e | ||
|
|
aff3c978cb | ||
|
|
c09c787507 | ||
|
|
9b82667fb5 | ||
|
|
6a8d341ecc | ||
|
|
743ce9f07c | ||
|
|
fff550ca37 | ||
|
|
3c5c76eec4 | ||
|
|
ea05b09491 | ||
|
|
d6b8993eb3 | ||
|
|
0d61926a7e | ||
|
|
f8acf9278c | ||
|
|
23f6a778a5 | ||
|
|
e6e950e58c | ||
|
|
7162a19982 | ||
|
|
5a77dd8a96 | ||
|
|
4e89546923 | ||
|
|
0429a689a4 | ||
|
|
b7239b611a | ||
|
|
057df4d35c | ||
|
|
886a07896b | ||
|
|
60857b55f1 | ||
|
|
160590149f | ||
|
|
98c6ab5aac | ||
|
|
7c18cd1009 | ||
|
|
27e53bc363 | ||
|
|
f0e5c6efe7 | ||
|
|
cbd86d3810 | ||
|
|
6f9a2dd57f | ||
|
|
7f45bb22f5 | ||
|
|
9137ed6278 | ||
|
|
3cda6109e9 | ||
|
|
0ce6f07064 | ||
|
|
6bbad0a399 | ||
|
|
8c371cf8af | ||
|
|
d74e484752 | ||
|
|
8f315d9311 | ||
|
|
4a63f14c75 | ||
|
|
e42f7426ee | ||
|
|
e96a1d6bde | ||
|
|
d08805dca6 | ||
|
|
1ca268e36a | ||
|
|
865afb2f9a | ||
|
|
44f448493c | ||
|
|
cee5f769b6 | ||
|
|
ea05d5635a | ||
|
|
984f8b2dd9 | ||
|
|
737f9b3d1e | ||
|
|
8b3158de99 | ||
|
|
cf054c401e | ||
|
|
3a34fa7a8f | ||
|
|
9438f91547 | ||
|
|
157b694727 | ||
|
|
3caf2fc62e | ||
|
|
e3b144a374 | ||
|
|
f7987b5c3e |
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ArticleDownloader.h"
|
||||
@@ -54,8 +55,6 @@ extern DownloadSpeedMeter* g_pDownloadSpeedMeter;
|
||||
extern Options* g_pOptions;
|
||||
extern ServerPool* g_pServerPool;
|
||||
|
||||
const char* ArticleDownloader::m_szJobStatus[] = { "WAITING", "RUNNING", "FINISHED", "FAILED", "DECODING", "JOINING", "NOT_FOUND", "FATAL_ERROR" };
|
||||
|
||||
ArticleDownloader::ArticleDownloader()
|
||||
{
|
||||
debug("Creating ArticleDownloader");
|
||||
@@ -68,6 +67,7 @@ ArticleDownloader::ArticleDownloader()
|
||||
m_pConnection = NULL;
|
||||
m_eStatus = adUndefined;
|
||||
m_bDuplicate = false;
|
||||
m_eFormat = Decoder::efUnknown;
|
||||
SetLastUpdateTimeNow();
|
||||
}
|
||||
|
||||
@@ -123,19 +123,17 @@ void ArticleDownloader::Run()
|
||||
|
||||
if (g_pOptions->GetContinuePartial())
|
||||
{
|
||||
struct stat buffer;
|
||||
bool fileExists = !stat(m_szResultFilename, &buffer);
|
||||
if (fileExists)
|
||||
if (Util::FileExists(m_szResultFilename))
|
||||
{
|
||||
// file exists from previous program's start
|
||||
info("Article %s already downloaded, skipping", m_szInfoName);
|
||||
detail("Article %s already downloaded, skipping", m_szInfoName);
|
||||
SetStatus(adFinished);
|
||||
FreeConnection(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info("Downloading %s", m_szInfoName);
|
||||
detail("Downloading %s", m_szInfoName);
|
||||
|
||||
int retry = g_pOptions->GetRetries();
|
||||
|
||||
@@ -172,30 +170,37 @@ void ArticleDownloader::Run()
|
||||
}
|
||||
|
||||
// test connection
|
||||
bool connected = m_pConnection && m_pConnection->Connect() >= 0;
|
||||
if (connected && !IsStopped())
|
||||
bool bConnected = m_pConnection && m_pConnection->Connect() >= 0;
|
||||
if (bConnected && !IsStopped())
|
||||
{
|
||||
// Okay, we got a Connection. Now start downloading!!
|
||||
// Okay, we got a Connection. Now start downloading.
|
||||
Status = Download();
|
||||
}
|
||||
|
||||
bool bAuthError = m_pConnection && m_pConnection->GetAuthError();
|
||||
|
||||
if (connected)
|
||||
if (bConnected)
|
||||
{
|
||||
// freeing connection allows other threads to start.
|
||||
// we doing this only if the problem was with article or group.
|
||||
// if the problem occurs by Connect() we do not free the connection,
|
||||
// to prevent starting of thousands of threads (cause each of them
|
||||
// will also free it's connection after the same connect-error).
|
||||
|
||||
FreeConnection(Status == adFinished);
|
||||
if (Status == adConnectError)
|
||||
{
|
||||
m_pConnection->Disconnect();
|
||||
bConnected = false;
|
||||
Status = adFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// freeing connection allows other threads to start.
|
||||
// we doing this only if the problem was with article or group.
|
||||
// if the problem occurs by connecting or authorization we do not
|
||||
// free the connection, to prevent starting of thousands of threads
|
||||
// (cause each of them will also free it's connection after the
|
||||
// same connect-error).
|
||||
FreeConnection(Status == adFinished);
|
||||
}
|
||||
}
|
||||
|
||||
if ((Status == adFailed || (Status == adCrcError && g_pOptions->GetRetryOnCrcError())) &&
|
||||
((retry > 1) || !connected || bAuthError) && !IsStopped())
|
||||
if (((Status == adFailed) || (Status == adCrcError && g_pOptions->GetRetryOnCrcError())) &&
|
||||
(retry > 1 || !bConnected) && !IsStopped())
|
||||
{
|
||||
info("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
detail("Waiting %i sec to retry", g_pOptions->GetRetryInterval());
|
||||
int msec = 0;
|
||||
while (!IsStopped() && (msec < g_pOptions->GetRetryInterval() * 1000))
|
||||
{
|
||||
@@ -209,7 +214,7 @@ void ArticleDownloader::Run()
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if ((Status == adFinished) || (Status == adFatalError) ||
|
||||
(Status == adCrcError && !g_pOptions->GetRetryOnCrcError()))
|
||||
{
|
||||
@@ -237,7 +242,7 @@ void ArticleDownloader::Run()
|
||||
}
|
||||
|
||||
// do not count connect-errors, only article- and group-errors
|
||||
if (connected && !bAuthError)
|
||||
if (bConnected)
|
||||
{
|
||||
level++;
|
||||
if (level > iMaxLevel)
|
||||
@@ -266,7 +271,7 @@ void ArticleDownloader::Run()
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
info("Download %s cancelled", m_szInfoName);
|
||||
detail("Download %s cancelled", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -281,71 +286,62 @@ void ArticleDownloader::Run()
|
||||
|
||||
ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
{
|
||||
const char* szResponse = NULL;
|
||||
EStatus Status = adRunning;
|
||||
|
||||
// at first, change group
|
||||
bool grpchanged = false;
|
||||
for (FileInfo::Groups::iterator it = m_pFileInfo->GetGroups()->begin(); it != m_pFileInfo->GetGroups()->end(); it++)
|
||||
{
|
||||
grpchanged = m_pConnection->JoinGroup(*it);
|
||||
if (grpchanged)
|
||||
szResponse = m_pConnection->JoinGroup(*it);
|
||||
if (szResponse && !strncmp(szResponse, "2", 1))
|
||||
{
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!grpchanged)
|
||||
Status = CheckResponse(szResponse, "could not join group");
|
||||
if (Status != adFinished)
|
||||
{
|
||||
if (!m_pConnection->GetAuthError() && !IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed: Could not join group", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
}
|
||||
return adFailed;
|
||||
return Status;
|
||||
}
|
||||
|
||||
// now, let's begin!
|
||||
// retrieve article
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "ARTICLE %s\r\n", m_pArticleInfo->GetMessageID());
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
char* answer = NULL;
|
||||
|
||||
for (int retry = 3; retry > 0; retry--)
|
||||
{
|
||||
answer = m_pConnection->Request(tmp);
|
||||
if (answer && !strncmp(answer, "2", 1))
|
||||
szResponse = m_pConnection->Request(tmp);
|
||||
if (szResponse && !strncmp(szResponse, "2", 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!answer)
|
||||
Status = CheckResponse(szResponse, "could not fetch article");
|
||||
if (Status != adFinished)
|
||||
{
|
||||
if (!m_pConnection->GetAuthError() && !IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed: Connection closed by remote host", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
}
|
||||
return adFailed;
|
||||
}
|
||||
|
||||
if (strncmp(answer, "2", 1))
|
||||
{
|
||||
warn("Article %s @ %s failed: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), answer);
|
||||
return (!strncmp(answer, "41", 2) || !strncmp(answer, "42", 2)) ? adNotFound : adFailed;
|
||||
return Status;
|
||||
}
|
||||
|
||||
// positive answer!
|
||||
|
||||
if (g_pOptions->GetDecoder() == Options::dcYenc)
|
||||
if (g_pOptions->GetDecode())
|
||||
{
|
||||
m_YDecoder.Clear();
|
||||
m_YDecoder.SetAutoSeek(g_pOptions->GetDirectWrite());
|
||||
m_YDecoder.SetCrcCheck(g_pOptions->GetCrcCheck());
|
||||
|
||||
m_UDecoder.Clear();
|
||||
}
|
||||
|
||||
m_pOutFile = NULL;
|
||||
EStatus Status = adRunning;
|
||||
bool bBody = false;
|
||||
bool bEnd = false;
|
||||
const int LineBufSize = 1024*10;
|
||||
char* szLineBuf = (char*)malloc(LineBufSize);
|
||||
Status = adRunning;
|
||||
|
||||
while (!IsStopped())
|
||||
{
|
||||
@@ -366,14 +362,18 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
// Have we encountered a timeout?
|
||||
if (!line)
|
||||
{
|
||||
warn("Article %s @ %s failed: Unexpected end of article", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed: Unexpected end of article", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
}
|
||||
Status = adFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
//detect end of article
|
||||
if ((!strcmp(line, ".\r\n")) || (!strcmp(line, ".\n")))
|
||||
if (!strcmp(line, ".\r\n") || !strcmp(line, ".\n"))
|
||||
{
|
||||
bEnd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -383,13 +383,14 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
line++;
|
||||
}
|
||||
|
||||
// check id of returned article
|
||||
if (!bBody)
|
||||
{
|
||||
if ((!strcmp(line, "\r\n")) || (!strcmp(line, "\n")))
|
||||
// detect body of article
|
||||
if (*line == '\r' || *line == '\n')
|
||||
{
|
||||
bBody = true;
|
||||
}
|
||||
// check id of returned article
|
||||
else if (!strncmp(line, "Message-ID: ", 12))
|
||||
{
|
||||
char* p = line + 12;
|
||||
@@ -402,8 +403,13 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_eFormat == Decoder::efUnknown && g_pOptions->GetDecode())
|
||||
{
|
||||
m_eFormat = Decoder::DetectFormat(line, iLen);
|
||||
}
|
||||
|
||||
if (!Write(line, iLen))
|
||||
// write to output file
|
||||
if (((bBody && m_eFormat != Decoder::efUnknown) || !g_pOptions->GetDecode()) && !Write(line, iLen))
|
||||
{
|
||||
Status = adFatalError;
|
||||
break;
|
||||
@@ -417,29 +423,62 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
|
||||
fclose(m_pOutFile);
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
if (!bEnd && Status == adRunning && !IsStopped())
|
||||
{
|
||||
remove(m_szTempFilename);
|
||||
return adFailed;
|
||||
warn("Article %s @ %s failed: article incomplete", m_szInfoName, m_pConnection->GetServer()->GetHost());
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (Status == adFailed)
|
||||
if (IsStopped())
|
||||
{
|
||||
remove(m_szTempFilename);
|
||||
return adFailed;
|
||||
Status = adFailed;
|
||||
}
|
||||
|
||||
if (Status == adRunning)
|
||||
{
|
||||
FreeConnection(true);
|
||||
return Decode();
|
||||
return DecodeCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
remove(m_szTempFilename);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szResponse, const char* szComment)
|
||||
{
|
||||
if (!szResponse)
|
||||
{
|
||||
if (!IsStopped())
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: Connection closed by remote host", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment);
|
||||
}
|
||||
return adConnectError;
|
||||
}
|
||||
else if (m_pConnection->GetAuthError() || !strncmp(szResponse, "400", 3) || !strncmp(szResponse, "499", 3))
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
return adConnectError;
|
||||
}
|
||||
else if (!strncmp(szResponse, "41", 2) || !strncmp(szResponse, "42", 2))
|
||||
{
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
return adNotFound;
|
||||
}
|
||||
else if (!strncmp(szResponse, "2", 1))
|
||||
{
|
||||
// OK
|
||||
return adFinished;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown error, no special handling
|
||||
warn("Article %s @ %s failed, %s: %s", m_szInfoName, m_pConnection->GetServer()->GetHost(), szComment, szResponse);
|
||||
return adFailed;
|
||||
}
|
||||
}
|
||||
|
||||
bool ArticleDownloader::Write(char* szLine, int iLen)
|
||||
{
|
||||
if (!m_pOutFile && !PrepareFile(szLine))
|
||||
@@ -447,9 +486,20 @@ bool ArticleDownloader::Write(char* szLine, int iLen)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_pOptions->GetDecoder() == Options::dcYenc)
|
||||
if (g_pOptions->GetDecode())
|
||||
{
|
||||
return m_YDecoder.Write(szLine, m_pOutFile);
|
||||
if (m_eFormat == Decoder::efYenc)
|
||||
{
|
||||
return m_YDecoder.Write(szLine, iLen, m_pOutFile);
|
||||
}
|
||||
else if (m_eFormat == Decoder::efUx)
|
||||
{
|
||||
return m_UDecoder.Write(szLine, iLen, m_pOutFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -462,19 +512,19 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
bool bOpen = false;
|
||||
|
||||
// prepare file for writing
|
||||
if (g_pOptions->GetDecoder() == Options::dcYenc)
|
||||
if (m_eFormat == Decoder::efYenc)
|
||||
{
|
||||
if (!strncmp(szLine, "=ybegin part=", 13))
|
||||
if (!strncmp(szLine, "=ybegin ", 8))
|
||||
{
|
||||
if (g_pOptions->GetDupeCheck())
|
||||
{
|
||||
m_pFileInfo->LockOutputFile();
|
||||
if (!m_pFileInfo->GetOutputInitialized())
|
||||
{
|
||||
char* pb = strstr(szLine, "name=");
|
||||
char* pb = strstr(szLine, " name=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 5; //=strlen("name=")
|
||||
pb += 6; //=strlen(" name=")
|
||||
char* pe;
|
||||
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
|
||||
if (!m_szArticleFilename)
|
||||
@@ -499,15 +549,15 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
{
|
||||
char* pb = strstr(szLine, "size=");
|
||||
char* pb = strstr(szLine, " size=");
|
||||
if (pb)
|
||||
{
|
||||
m_pFileInfo->LockOutputFile();
|
||||
if (!m_pFileInfo->GetOutputInitialized())
|
||||
{
|
||||
pb += 5; //=strlen("size=")
|
||||
pb += 6; //=strlen(" size=")
|
||||
long iArticleFilesize = atol(pb);
|
||||
if (!SetFileSize(m_szOutputFilename, iArticleFilesize))
|
||||
if (!Util::SetFileSize(m_szOutputFilename, iArticleFilesize))
|
||||
{
|
||||
error("Could not create file %s!", m_szOutputFilename);
|
||||
return false;
|
||||
@@ -531,11 +581,12 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
|
||||
if (bOpen)
|
||||
{
|
||||
const char* szFilename = g_pOptions->GetDirectWrite() ? m_szOutputFilename : m_szTempFilename;
|
||||
m_pOutFile = fopen(szFilename, g_pOptions->GetDirectWrite() ? "r+" : "w");
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
|
||||
const char* szFilename = bDirectWrite ? m_szOutputFilename : m_szTempFilename;
|
||||
m_pOutFile = fopen(szFilename, bDirectWrite ? "r+" : "w");
|
||||
if (!m_pOutFile)
|
||||
{
|
||||
error("Could not %s file %s", g_pOptions->GetDirectWrite() ? "open" : "create", szFilename);
|
||||
error("Could not %s file %s", bDirectWrite ? "open" : "create", szFilename);
|
||||
return false;
|
||||
}
|
||||
if (g_pOptions->GetWriteBufferSize() == -1)
|
||||
@@ -551,43 +602,38 @@ bool ArticleDownloader::PrepareFile(char* szLine)
|
||||
return true;
|
||||
}
|
||||
|
||||
ArticleDownloader::EStatus ArticleDownloader::Decode()
|
||||
ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
|
||||
{
|
||||
if ((g_pOptions->GetDecoder() == Options::dcUulib) ||
|
||||
(g_pOptions->GetDecoder() == Options::dcYenc))
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
|
||||
|
||||
if (g_pOptions->GetDecode())
|
||||
{
|
||||
SetStatus(adDecoding);
|
||||
|
||||
char tmpdestfile[1024];
|
||||
char* szDecoderTempFilename = NULL;
|
||||
Decoder* pDecoder = NULL;
|
||||
|
||||
if (g_pOptions->GetDecoder() == Options::dcYenc)
|
||||
if (m_eFormat == Decoder::efYenc)
|
||||
{
|
||||
pDecoder = &m_YDecoder;
|
||||
szDecoderTempFilename = m_szTempFilename;
|
||||
}
|
||||
else if (g_pOptions->GetDecoder() == Options::dcUulib)
|
||||
else if (m_eFormat == Decoder::efUx)
|
||||
{
|
||||
pDecoder = new UULibDecoder();
|
||||
pDecoder->SetSrcFilename(m_szTempFilename);
|
||||
snprintf(tmpdestfile, 1024, "%s.dec", m_szResultFilename);
|
||||
tmpdestfile[1024-1] = '\0';
|
||||
szDecoderTempFilename = tmpdestfile;
|
||||
pDecoder->SetDestFilename(szDecoderTempFilename);
|
||||
pDecoder = &m_UDecoder;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Decoding %s failed: no binary data or unsupported encoding format", m_szInfoName);
|
||||
return adFatalError;
|
||||
}
|
||||
|
||||
bool bOK = pDecoder->Execute();
|
||||
Decoder::EStatus eStatus = pDecoder->Check();
|
||||
bool bOK = eStatus == Decoder::eFinished;
|
||||
|
||||
if (!g_pOptions->GetDirectWrite())
|
||||
if (!bDirectWrite && bOK)
|
||||
{
|
||||
if (bOK)
|
||||
if (!Util::MoveFile(m_szTempFilename, m_szResultFilename))
|
||||
{
|
||||
rename(szDecoderTempFilename, m_szResultFilename);
|
||||
}
|
||||
else if (g_pOptions->GetDecoder() == Options::dcUulib)
|
||||
{
|
||||
remove(szDecoderTempFilename);
|
||||
error("Could not rename file %s to %s! Errcode: %i", m_szTempFilename, m_szResultFilename, errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,17 +643,12 @@ ArticleDownloader::EStatus ArticleDownloader::Decode()
|
||||
}
|
||||
|
||||
remove(m_szTempFilename);
|
||||
bool bCrcError = pDecoder->GetCrcError();
|
||||
if (pDecoder != &m_YDecoder)
|
||||
{
|
||||
delete pDecoder;
|
||||
}
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
info("Successfully downloaded %s", m_szInfoName);
|
||||
detail("Successfully downloaded %s", m_szInfoName);
|
||||
|
||||
if (g_pOptions->GetDirectWrite() && g_pOptions->GetContinuePartial())
|
||||
if (bDirectWrite && g_pOptions->GetContinuePartial())
|
||||
{
|
||||
// create empty flag-file to indicate that the artcile was downloaded
|
||||
FILE* flagfile = fopen(m_szResultFilename, "w");
|
||||
@@ -624,11 +665,26 @@ ArticleDownloader::EStatus ArticleDownloader::Decode()
|
||||
else
|
||||
{
|
||||
remove(m_szResultFilename);
|
||||
if (bCrcError)
|
||||
if (eStatus == Decoder::eCrcError)
|
||||
{
|
||||
warn("Decoding %s failed: CRC-Error", m_szInfoName);
|
||||
return adCrcError;
|
||||
}
|
||||
else if (eStatus == Decoder::eArticleIncomplete)
|
||||
{
|
||||
warn("Decoding %s failed: article incomplete", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else if (eStatus == Decoder::eInvalidSize)
|
||||
{
|
||||
warn("Decoding %s failed: size mismatch", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else if (eStatus == Decoder::eNoBinaryData)
|
||||
{
|
||||
warn("Decoding %s failed: no binary data found", m_szInfoName);
|
||||
return adFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Decoding %s failed", m_szInfoName);
|
||||
@@ -636,19 +692,19 @@ ArticleDownloader::EStatus ArticleDownloader::Decode()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g_pOptions->GetDecoder() == Options::dcNone)
|
||||
else
|
||||
{
|
||||
// rawmode
|
||||
rename(m_szTempFilename, m_szResultFilename);
|
||||
info("Article %s successfully downloaded", m_szInfoName);
|
||||
if (Util::MoveFile(m_szTempFilename, m_szResultFilename))
|
||||
{
|
||||
detail("Article %s successfully downloaded", m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not move file %s to %s! Errcode: %i", m_szTempFilename, m_szResultFilename, errno);
|
||||
}
|
||||
return adFinished;
|
||||
}
|
||||
else
|
||||
{
|
||||
// should not occur
|
||||
error("Internal error: Decoding %s failed", m_szInfoName);
|
||||
return adFatalError;
|
||||
}
|
||||
}
|
||||
|
||||
void ArticleDownloader::LogDebugInfo()
|
||||
@@ -660,7 +716,7 @@ void ArticleDownloader::LogDebugInfo()
|
||||
ctime_r(&m_tLastUpdateTime, szTime);
|
||||
#endif
|
||||
|
||||
debug(" Download: status=%s, LastUpdateTime=%s, filename=%s", GetStatusText(), szTime, BaseFileName(GetTempFilename()));
|
||||
debug(" Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(GetTempFilename()));
|
||||
}
|
||||
|
||||
void ArticleDownloader::Stop()
|
||||
@@ -713,40 +769,46 @@ void ArticleDownloader::CompleteFileParts()
|
||||
|
||||
SetStatus(adJoining);
|
||||
|
||||
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_pFileInfo->GetOutputInitialized();
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
m_pFileInfo->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
m_pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
|
||||
char InfoFilename[1024];
|
||||
snprintf(InfoFilename, 1024, "%s%c%s", szNZBNiceName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
InfoFilename[1024-1] = '\0';
|
||||
|
||||
if (g_pOptions->GetDecoder() == Options::dcNone)
|
||||
if (!g_pOptions->GetDecode())
|
||||
{
|
||||
info("Moving articles for %s", InfoFilename);
|
||||
detail("Moving articles for %s", InfoFilename);
|
||||
}
|
||||
else if (g_pOptions->GetDirectWrite())
|
||||
else if (bDirectWrite)
|
||||
{
|
||||
info("Checking articles for %s", InfoFilename);
|
||||
detail("Checking articles for %s", InfoFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Joining articles for %s", InfoFilename);
|
||||
detail("Joining articles for %s", InfoFilename);
|
||||
}
|
||||
|
||||
char ofn[1024];
|
||||
snprintf(ofn, 1024, "%s%c%s", m_pFileInfo->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
snprintf(ofn, 1024, "%s%c%s", m_pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
|
||||
ofn[1024-1] = '\0';
|
||||
|
||||
// Ensure the DstDir is created
|
||||
mkdir(m_pFileInfo->GetDestDir(), S_DIRMODE);
|
||||
if (!Util::CreateDirectory(m_pFileInfo->GetNZBInfo()->GetDestDir()))
|
||||
{
|
||||
error("Could not create directory %s! Errcode: %i", m_pFileInfo->GetNZBInfo()->GetDestDir(), errno);
|
||||
SetStatus(adJoined);
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent overwriting existing files
|
||||
struct stat statbuf;
|
||||
int dupcount = 0;
|
||||
while (!stat(ofn, &statbuf))
|
||||
while (Util::FileExists(ofn))
|
||||
{
|
||||
dupcount++;
|
||||
snprintf(ofn, 1024, "%s%c%s_duplicate%d", m_pFileInfo->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetFilename(), dupcount);
|
||||
snprintf(ofn, 1024, "%s%c%s_duplicate%d", m_pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetFilename(), dupcount);
|
||||
ofn[1024-1] = '\0';
|
||||
}
|
||||
|
||||
@@ -755,16 +817,14 @@ void ArticleDownloader::CompleteFileParts()
|
||||
snprintf(tmpdestfile, 1024, "%s.tmp", ofn);
|
||||
tmpdestfile[1024-1] = '\0';
|
||||
|
||||
if (((g_pOptions->GetDecoder() == Options::dcUulib) ||
|
||||
(g_pOptions->GetDecoder() == Options::dcYenc)) &&
|
||||
!g_pOptions->GetDirectWrite())
|
||||
if (g_pOptions->GetDecode() && !bDirectWrite)
|
||||
{
|
||||
remove(tmpdestfile);
|
||||
outfile = fopen(tmpdestfile, "w+");
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s!", tmpdestfile);
|
||||
SetStatus(adFinished);
|
||||
SetStatus(adJoined);
|
||||
return;
|
||||
}
|
||||
if (g_pOptions->GetWriteBufferSize() == -1 && (*m_pFileInfo->GetArticles())[0])
|
||||
@@ -776,10 +836,15 @@ void ArticleDownloader::CompleteFileParts()
|
||||
setvbuf(outfile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
|
||||
}
|
||||
}
|
||||
else if (g_pOptions->GetDecoder() == Options::dcNone)
|
||||
else if (!g_pOptions->GetDecode())
|
||||
{
|
||||
remove(tmpdestfile);
|
||||
mkdir(ofn, S_DIRMODE);
|
||||
if (!Util::CreateDirectory(ofn))
|
||||
{
|
||||
error("Could not create directory %s! Errcode: %i", ofn, errno);
|
||||
SetStatus(adJoined);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool complete = true;
|
||||
@@ -787,9 +852,7 @@ void ArticleDownloader::CompleteFileParts()
|
||||
static const int BUFFER_SIZE = 1024 * 50;
|
||||
char* buffer = NULL;
|
||||
|
||||
if (((g_pOptions->GetDecoder() == Options::dcUulib) ||
|
||||
(g_pOptions->GetDecoder() == Options::dcYenc)) &&
|
||||
!g_pOptions->GetDirectWrite())
|
||||
if (g_pOptions->GetDecode() && !bDirectWrite)
|
||||
{
|
||||
buffer = (char*)malloc(BUFFER_SIZE);
|
||||
}
|
||||
@@ -802,9 +865,7 @@ void ArticleDownloader::CompleteFileParts()
|
||||
iBrokenCount++;
|
||||
complete = false;
|
||||
}
|
||||
else if (((g_pOptions->GetDecoder() == Options::dcUulib) ||
|
||||
(g_pOptions->GetDecoder() == Options::dcYenc)) &&
|
||||
!g_pOptions->GetDirectWrite())
|
||||
else if (g_pOptions->GetDecode() && !bDirectWrite)
|
||||
{
|
||||
FILE* infile;
|
||||
const char* fn = pa->GetResultFilename();
|
||||
@@ -827,16 +888,19 @@ void ArticleDownloader::CompleteFileParts()
|
||||
{
|
||||
complete = false;
|
||||
iBrokenCount++;
|
||||
info("Could not find file %s. Status is broken", fn);
|
||||
detail("Could not find file %s. Status is broken", fn);
|
||||
}
|
||||
}
|
||||
else if (g_pOptions->GetDecoder() == Options::dcNone)
|
||||
else if (!g_pOptions->GetDecode())
|
||||
{
|
||||
const char* fn = pa->GetResultFilename();
|
||||
char dstFileName[1024];
|
||||
snprintf(dstFileName, 1024, "%s%c%03i", ofn, (int)PATH_SEPARATOR, pa->GetPartNumber());
|
||||
dstFileName[1024-1] = '\0';
|
||||
rename(fn, dstFileName);
|
||||
if (!Util::MoveFile(fn, dstFileName))
|
||||
{
|
||||
error("Could not move file %s to %s! Errcode: %i", fn, dstFileName, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,15 +912,21 @@ void ArticleDownloader::CompleteFileParts()
|
||||
if (outfile)
|
||||
{
|
||||
fclose(outfile);
|
||||
rename(tmpdestfile, ofn);
|
||||
if (!Util::MoveFile(tmpdestfile, ofn))
|
||||
{
|
||||
error("Could not move file %s to %s! Errcode: %i", tmpdestfile, ofn, errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_pOptions->GetDirectWrite())
|
||||
if (bDirectWrite)
|
||||
{
|
||||
rename(m_szOutputFilename, ofn);
|
||||
if (!Util::MoveFile(m_szOutputFilename, ofn))
|
||||
{
|
||||
error("Could not move file %s to %s! Errcode: %i", m_szOutputFilename, ofn, errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_pOptions->GetDirectWrite() || g_pOptions->GetContinuePartial())
|
||||
if (!bDirectWrite || g_pOptions->GetContinuePartial())
|
||||
{
|
||||
for (FileInfo::Articles::iterator it = m_pFileInfo->GetArticles()->begin(); it != m_pFileInfo->GetArticles()->end(); it++)
|
||||
{
|
||||
@@ -878,10 +948,9 @@ void ArticleDownloader::CompleteFileParts()
|
||||
char brokenfn[1024];
|
||||
snprintf(brokenfn, 1024, "%s_broken", ofn);
|
||||
brokenfn[1024-1] = '\0';
|
||||
bool OK = rename(ofn, brokenfn) == 0;
|
||||
if (OK)
|
||||
if (Util::MoveFile(ofn, brokenfn))
|
||||
{
|
||||
info("Renaming broken file from %s to %s", ofn, brokenfn);
|
||||
detail("Renaming broken file from %s to %s", ofn, brokenfn);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -890,21 +959,19 @@ void ArticleDownloader::CompleteFileParts()
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Not renaming broken file %s", ofn);
|
||||
detail("Not renaming broken file %s", ofn);
|
||||
}
|
||||
|
||||
if (g_pOptions->GetCreateBrokenLog())
|
||||
{
|
||||
char szBrokenLogName[1024];
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", m_pFileInfo->GetDestDir(), (int)PATH_SEPARATOR);
|
||||
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", m_pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR);
|
||||
szBrokenLogName[1024-1] = '\0';
|
||||
FILE* file = fopen(szBrokenLogName, "a");
|
||||
fprintf(file, "%s (%i/%i)\n", m_pFileInfo->GetFilename(), m_pFileInfo->GetArticles()->size() - iBrokenCount, m_pFileInfo->GetArticles()->size());
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
warn("%s is incomplete!", InfoFilename);
|
||||
}
|
||||
|
||||
SetStatus(adFinished);
|
||||
SetStatus(adJoined);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -51,7 +51,9 @@ public:
|
||||
adCrcError,
|
||||
adDecoding,
|
||||
adJoining,
|
||||
adJoined,
|
||||
adNotFound,
|
||||
adConnectError,
|
||||
adFatalError
|
||||
};
|
||||
|
||||
@@ -67,16 +69,18 @@ private:
|
||||
char* m_szInfoName;
|
||||
char* m_szOutputFilename;
|
||||
time_t m_tLastUpdateTime;
|
||||
static const char* m_szJobStatus[];
|
||||
Decoder::EFormat m_eFormat;
|
||||
YDecoder m_YDecoder;
|
||||
UDecoder m_UDecoder;
|
||||
FILE* m_pOutFile;
|
||||
bool m_bDuplicate;
|
||||
|
||||
EStatus Download();
|
||||
bool Write(char* szLine, int iLen);
|
||||
bool PrepareFile(char* szLine);
|
||||
EStatus Decode();
|
||||
EStatus DecodeCheck();
|
||||
void FreeConnection(bool bKeepConnected);
|
||||
EStatus CheckResponse(const char* szResponse, const char* szComment);
|
||||
|
||||
public:
|
||||
ArticleDownloader();
|
||||
@@ -87,7 +91,6 @@ public:
|
||||
ArticleInfo* GetArticleInfo() { return m_pArticleInfo; }
|
||||
void SetStatus(EStatus eStatus);
|
||||
EStatus GetStatus() { return m_eStatus; }
|
||||
const char* GetStatusText() { return m_szJobStatus[m_eStatus]; }
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
bool Terminate();
|
||||
|
||||
772
BinRpc.cpp
Normal file
772
BinRpc.cpp
Normal file
@@ -0,0 +1,772 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "BinRpc.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "QueueEditor.h"
|
||||
#include "PrePostProcessor.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern PrePostProcessor* g_pPrePostProcessor;
|
||||
extern void ExitProc();
|
||||
|
||||
const char* g_szMessageRequestNames[] =
|
||||
{ "N/A", "Download", "Pause/Unpause", "List", "Set download rate", "Dump debug",
|
||||
"Edit queue", "Log", "Quit", "Version", "Post-queue" };
|
||||
|
||||
const unsigned int g_iMessageRequestSizes[] =
|
||||
{ 0,
|
||||
sizeof(SNZBDownloadRequest),
|
||||
sizeof(SNZBPauseUnpauseRequest),
|
||||
sizeof(SNZBListRequest),
|
||||
sizeof(SNZBSetDownloadRateRequest),
|
||||
sizeof(SNZBDumpDebugRequest),
|
||||
sizeof(SNZBEditQueueRequest),
|
||||
sizeof(SNZBLogRequest),
|
||||
sizeof(SNZBShutdownRequest),
|
||||
sizeof(SNZBVersionRequest),
|
||||
sizeof(SNZBPostQueueRequest),
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// BinProcessor
|
||||
|
||||
void BinRpcProcessor::Execute()
|
||||
{
|
||||
// Read the first package which needs to be a request
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)&m_MessageBase) + sizeof(m_MessageBase.m_iSignature), sizeof(m_MessageBase) - sizeof(m_MessageBase.m_iSignature), 0);
|
||||
if (iBytesReceived < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure this is a nzbget request from a client
|
||||
if ((int)ntohl(m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetServerPort(), m_szClientIP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetServerPassword()))
|
||||
{
|
||||
warn("nzbget request received on port %i from %s, but password invalid", g_pOptions->GetServerPort(), m_szClientIP);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], m_szClientIP);
|
||||
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
void BinRpcProcessor::Dispatch()
|
||||
{
|
||||
if (ntohl(m_MessageBase.m_iType) >= (int)eRemoteRequestDownload &&
|
||||
ntohl(m_MessageBase.m_iType) <= (int)eRemoteRequestPostQueue &&
|
||||
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)] != ntohl(m_MessageBase.m_iStructSize))
|
||||
{
|
||||
error("Invalid size of request: needed %i Bytes, but received %i Bytes",
|
||||
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)], ntohl(m_MessageBase.m_iStructSize));
|
||||
return;
|
||||
}
|
||||
|
||||
BinCommand* command = NULL;
|
||||
|
||||
switch (ntohl(m_MessageBase.m_iType))
|
||||
{
|
||||
case eRemoteRequestDownload:
|
||||
{
|
||||
command = new DownloadBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestList:
|
||||
{
|
||||
command = new ListBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestLog:
|
||||
{
|
||||
command = new LogBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestPauseUnpause:
|
||||
{
|
||||
command = new PauseUnpauseBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestEditQueue:
|
||||
{
|
||||
command = new EditQueueBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestSetDownloadRate:
|
||||
{
|
||||
command = new SetDownloadRateBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestDumpDebug:
|
||||
{
|
||||
command = new DumpDebugBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestShutdown:
|
||||
{
|
||||
command = new ShutdownBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestVersion:
|
||||
{
|
||||
command = new VersionBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestPostQueue:
|
||||
{
|
||||
command = new PostQueueBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestWriteLog:
|
||||
{
|
||||
command = new WriteLogBinCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
|
||||
break;
|
||||
}
|
||||
|
||||
if (command)
|
||||
{
|
||||
command->SetSocket(m_iSocket);
|
||||
command->SetMessageBase(&m_MessageBase);
|
||||
command->Execute();
|
||||
delete command;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************
|
||||
// Commands
|
||||
|
||||
void BinCommand::SendBoolResponse(bool bSuccess, const char* szText)
|
||||
{
|
||||
// all bool-responses have the same format of structure, we use SNZBDownloadResponse here
|
||||
SNZBDownloadResponse BoolResponse;
|
||||
memset(&BoolResponse, 0, sizeof(BoolResponse));
|
||||
BoolResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
BoolResponse.m_MessageBase.m_iStructSize = htonl(sizeof(BoolResponse));
|
||||
BoolResponse.m_bSuccess = htonl(bSuccess);
|
||||
int iTextLen = strlen(szText) + 1;
|
||||
BoolResponse.m_iTrailingDataLength = htonl(iTextLen);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &BoolResponse, sizeof(BoolResponse), 0);
|
||||
send(m_iSocket, (char*)szText, iTextLen, 0);
|
||||
}
|
||||
|
||||
bool BinCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
{
|
||||
memcpy(pBuffer, m_pMessageBase, sizeof(SNZBRequestBase));
|
||||
iSize -= sizeof(SNZBRequestBase);
|
||||
if (iSize > 0)
|
||||
{
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)pBuffer) + sizeof(SNZBRequestBase), iSize, 0);
|
||||
if (iBytesReceived != iSize)
|
||||
{
|
||||
error("invalid request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PauseUnpauseBinCommand::Execute()
|
||||
{
|
||||
SNZBPauseUnpauseRequest PauseUnpauseRequest;
|
||||
if (!ReceiveRequest(&PauseUnpauseRequest, sizeof(PauseUnpauseRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetPause(ntohl(PauseUnpauseRequest.m_bPause));
|
||||
SendBoolResponse(true, "Pause-/Unpause-Command completed successfully");
|
||||
}
|
||||
|
||||
void SetDownloadRateBinCommand::Execute()
|
||||
{
|
||||
SNZBSetDownloadRateRequest SetDownloadRequest;
|
||||
if (!ReceiveRequest(&SetDownloadRequest, sizeof(SetDownloadRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate) / 1024.0f);
|
||||
SendBoolResponse(true, "Rate-Command completed successfully");
|
||||
}
|
||||
|
||||
void DumpDebugBinCommand::Execute()
|
||||
{
|
||||
SNZBDumpDebugRequest DumpDebugRequest;
|
||||
if (!ReceiveRequest(&DumpDebugRequest, sizeof(DumpDebugRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->LogDebugInfo();
|
||||
SendBoolResponse(true, "Debug-Command completed successfully");
|
||||
}
|
||||
|
||||
void ShutdownBinCommand::Execute()
|
||||
{
|
||||
SNZBShutdownRequest ShutdownRequest;
|
||||
if (!ReceiveRequest(&ShutdownRequest, sizeof(ShutdownRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendBoolResponse(true, "Stopping server");
|
||||
ExitProc();
|
||||
}
|
||||
|
||||
void VersionBinCommand::Execute()
|
||||
{
|
||||
SNZBVersionRequest VersionRequest;
|
||||
if (!ReceiveRequest(&VersionRequest, sizeof(VersionRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendBoolResponse(true, VERSION);
|
||||
}
|
||||
|
||||
void DownloadBinCommand::Execute()
|
||||
{
|
||||
SNZBDownloadRequest DownloadRequest;
|
||||
if (!ReceiveRequest(&DownloadRequest, sizeof(DownloadRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(DownloadRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
||||
|
||||
if (pNZBFile)
|
||||
{
|
||||
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, ntohl(DownloadRequest.m_bAddFirst));
|
||||
delete pNZBFile;
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Collection %s added to queue", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Download Request failed for %s", Util::BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(false, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
|
||||
void ListBinCommand::Execute()
|
||||
{
|
||||
SNZBListRequest ListRequest;
|
||||
if (!ReceiveRequest(&ListRequest, sizeof(ListRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SNZBListResponse ListResponse;
|
||||
memset(&ListResponse, 0, sizeof(ListResponse));
|
||||
ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse));
|
||||
ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseEntry));
|
||||
|
||||
char* buf = NULL;
|
||||
int bufsize = 0;
|
||||
|
||||
if (ntohl(ListRequest.m_bFileList))
|
||||
{
|
||||
// Make a data structure and copy all the elements of the list into it
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
int NrEntries = pDownloadQueue->size();
|
||||
|
||||
// calculate required buffer size
|
||||
bufsize = NrEntries * sizeof(SNZBListResponseEntry);
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
bufsize += strlen(pFileInfo->GetNZBInfo()->GetFilename()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetSubject()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetFilename()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetNZBInfo()->GetDestDir()) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
|
||||
buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
FileInfo* pFileInfo = *it;
|
||||
SNZBListResponseEntry* pListAnswer = (SNZBListResponseEntry*) bufptr;
|
||||
pListAnswer->m_iID = htonl(pFileInfo->GetID());
|
||||
Util::SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
|
||||
Util::SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed());
|
||||
pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused());
|
||||
pListAnswer->m_iNZBFilenameLen = htonl(strlen(pFileInfo->GetNZBInfo()->GetFilename()) + 1);
|
||||
pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
|
||||
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
|
||||
pListAnswer->m_iDestDirLen = htonl(strlen(pFileInfo->GetNZBInfo()->GetDestDir()) + 1);
|
||||
bufptr += sizeof(SNZBListResponseEntry);
|
||||
strcpy(bufptr, pFileInfo->GetNZBInfo()->GetFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iNZBFilenameLen);
|
||||
strcpy(bufptr, pFileInfo->GetSubject());
|
||||
bufptr += ntohl(pListAnswer->m_iSubjectLen);
|
||||
strcpy(bufptr, pFileInfo->GetFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iFilenameLen);
|
||||
strcpy(bufptr, pFileInfo->GetNZBInfo()->GetDestDir());
|
||||
bufptr += ntohl(pListAnswer->m_iDestDirLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pListAnswer->m_iDestDirLen = htonl(ntohl(pListAnswer->m_iDestDirLen) + 4 - (size_t)bufptr % 4);
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
ListResponse.m_iNrTrailingEntries = htonl(NrEntries);
|
||||
ListResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
}
|
||||
|
||||
if (htonl(ListRequest.m_bServerState))
|
||||
{
|
||||
unsigned long iSizeHi, iSizeLo;
|
||||
ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024));
|
||||
Util::SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024));
|
||||
ListResponse.m_bServerPaused = htonl(g_pOptions->GetPause());
|
||||
ListResponse.m_iThreadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself
|
||||
PostQueue* pPostQueue = g_pPrePostProcessor->LockPostQueue();
|
||||
ListResponse.m_iPostJobCount = htonl(pPostQueue->size());
|
||||
g_pPrePostProcessor->UnlockPostQueue();
|
||||
|
||||
int iUpTimeSec, iDnTimeSec;
|
||||
long long iAllBytes;
|
||||
bool bStandBy;
|
||||
g_pQueueCoordinator->CalcStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy);
|
||||
ListResponse.m_iUpTimeSec = htonl(iUpTimeSec);
|
||||
ListResponse.m_iDownloadTimeSec = htonl(iDnTimeSec);
|
||||
ListResponse.m_bServerStandBy = htonl(bStandBy);
|
||||
Util::SplitInt64(iAllBytes, &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iDownloadedBytesHi = htonl(iSizeHi);
|
||||
ListResponse.m_iDownloadedBytesLo = htonl(iSizeLo);
|
||||
}
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void LogBinCommand::Execute()
|
||||
{
|
||||
SNZBLogRequest LogRequest;
|
||||
if (!ReceiveRequest(&LogRequest, sizeof(LogRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log::Messages* pMessages = g_pLog->LockMessages();
|
||||
|
||||
int iNrEntries = ntohl(LogRequest.m_iLines);
|
||||
unsigned int iIDFrom = ntohl(LogRequest.m_iIDFrom);
|
||||
int iStart = pMessages->size();
|
||||
if (iNrEntries > 0)
|
||||
{
|
||||
if (iNrEntries > (int)pMessages->size())
|
||||
{
|
||||
iNrEntries = pMessages->size();
|
||||
}
|
||||
iStart = pMessages->size() - iNrEntries;
|
||||
}
|
||||
if (iIDFrom > 0 && !pMessages->empty())
|
||||
{
|
||||
iStart = iIDFrom - pMessages->front()->GetID();
|
||||
if (iStart < 0)
|
||||
{
|
||||
iStart = 0;
|
||||
}
|
||||
iNrEntries = pMessages->size() - iStart;
|
||||
if (iNrEntries < 0)
|
||||
{
|
||||
iNrEntries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate required buffer size
|
||||
int bufsize = iNrEntries * sizeof(SNZBLogResponseEntry);
|
||||
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
||||
{
|
||||
Message* pMessage = (*pMessages)[i];
|
||||
bufsize += strlen(pMessage->GetText()) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
|
||||
char* buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
||||
{
|
||||
Message* pMessage = (*pMessages)[i];
|
||||
SNZBLogResponseEntry* pLogAnswer = (SNZBLogResponseEntry*) bufptr;
|
||||
pLogAnswer->m_iID = htonl(pMessage->GetID());
|
||||
pLogAnswer->m_iKind = htonl(pMessage->GetKind());
|
||||
pLogAnswer->m_tTime = htonl((int)pMessage->GetTime());
|
||||
pLogAnswer->m_iTextLen = htonl(strlen(pMessage->GetText()) + 1);
|
||||
bufptr += sizeof(SNZBLogResponseEntry);
|
||||
strcpy(bufptr, pMessage->GetText());
|
||||
bufptr += ntohl(pLogAnswer->m_iTextLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pLogAnswer->m_iTextLen = htonl(ntohl(pLogAnswer->m_iTextLen) + 4 - (size_t)bufptr % 4);
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
}
|
||||
|
||||
g_pLog->UnlockMessages();
|
||||
|
||||
SNZBLogResponse LogResponse;
|
||||
LogResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
LogResponse.m_MessageBase.m_iStructSize = htonl(sizeof(LogResponse));
|
||||
LogResponse.m_iEntrySize = htonl(sizeof(SNZBLogResponseEntry));
|
||||
LogResponse.m_iNrTrailingEntries = htonl(iNrEntries);
|
||||
LogResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &LogResponse, sizeof(LogResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void EditQueueBinCommand::Execute()
|
||||
{
|
||||
SNZBEditQueueRequest EditQueueRequest;
|
||||
if (!ReceiveRequest(&EditQueueRequest, sizeof(EditQueueRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iNrEntries = ntohl(EditQueueRequest.m_iNrTrailingEntries);
|
||||
int iAction = ntohl(EditQueueRequest.m_iAction);
|
||||
int iOffset = ntohl(EditQueueRequest.m_iOffset);
|
||||
bool bSmartOrder = ntohl(EditQueueRequest.m_bSmartOrder);
|
||||
unsigned int iBufLength = ntohl(EditQueueRequest.m_iTrailingDataLength);
|
||||
|
||||
if (iNrEntries * sizeof(int32_t) != iBufLength)
|
||||
{
|
||||
error("Invalid struct size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (iNrEntries <= 0)
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed: no IDs specified");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t* pIDs = (int32_t*)malloc(iBufLength);
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
char* pBufPtr = (char*)pIDs;
|
||||
int NeedBytes = iBufLength;
|
||||
int iResult = 0;
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
QueueEditor::IDList cIDList;
|
||||
cIDList.reserve(iNrEntries);
|
||||
for (int i = 0; i < iNrEntries; i++)
|
||||
{
|
||||
cIDList.push_back(ntohl(pIDs[i]));
|
||||
}
|
||||
|
||||
free(pIDs);
|
||||
|
||||
bool bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(&cIDList, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset);
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
SendBoolResponse(true, "Edit-Command completed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed");
|
||||
}
|
||||
}
|
||||
|
||||
void PostQueueBinCommand::Execute()
|
||||
{
|
||||
SNZBPostQueueRequest PostQueueRequest;
|
||||
if (!ReceiveRequest(&PostQueueRequest, sizeof(PostQueueRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SNZBPostQueueResponse PostQueueResponse;
|
||||
memset(&PostQueueResponse, 0, sizeof(PostQueueResponse));
|
||||
PostQueueResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
PostQueueResponse.m_MessageBase.m_iStructSize = htonl(sizeof(PostQueueResponse));
|
||||
PostQueueResponse.m_iEntrySize = htonl(sizeof(SNZBPostQueueResponseEntry));
|
||||
|
||||
char* buf = NULL;
|
||||
int bufsize = 0;
|
||||
|
||||
// Make a data structure and copy all the elements of the list into it
|
||||
PostQueue* pPostQueue = g_pPrePostProcessor->LockPostQueue();
|
||||
|
||||
int NrEntries = pPostQueue->size();
|
||||
|
||||
// calculate required buffer size
|
||||
bufsize = NrEntries * sizeof(SNZBPostQueueResponseEntry);
|
||||
for (PostQueue::iterator it = pPostQueue->begin(); it != pPostQueue->end(); it++)
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
bufsize += strlen(pPostInfo->GetNZBFilename()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetParFilename()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetInfoName()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetDestDir()) + 1;
|
||||
bufsize += strlen(pPostInfo->GetProgressLabel()) + 1;
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
bufsize += bufsize % 4 > 0 ? 4 - bufsize % 4 : 0;
|
||||
}
|
||||
|
||||
time_t tCurTime = time(NULL);
|
||||
buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
|
||||
for (PostQueue::iterator it = pPostQueue->begin(); it != pPostQueue->end(); it++)
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
SNZBPostQueueResponseEntry* pPostQueueAnswer = (SNZBPostQueueResponseEntry*) bufptr;
|
||||
pPostQueueAnswer->m_iID = htonl(pPostInfo->GetID());
|
||||
pPostQueueAnswer->m_iStage = htonl(pPostInfo->GetStage());
|
||||
pPostQueueAnswer->m_iStageProgress = htonl(pPostInfo->GetStageProgress());
|
||||
pPostQueueAnswer->m_iFileProgress = htonl(pPostInfo->GetFileProgress());
|
||||
pPostQueueAnswer->m_iTotalTimeSec = htonl((int)(pPostInfo->GetStartTime() ? tCurTime - pPostInfo->GetStartTime() : 0));
|
||||
pPostQueueAnswer->m_iStageTimeSec = htonl((int)(pPostInfo->GetStageTime() ? tCurTime - pPostInfo->GetStageTime() : 0));
|
||||
pPostQueueAnswer->m_iNZBFilenameLen = htonl(strlen(pPostInfo->GetNZBFilename()) + 1);
|
||||
pPostQueueAnswer->m_iParFilename = htonl(strlen(pPostInfo->GetParFilename()) + 1);
|
||||
pPostQueueAnswer->m_iInfoNameLen = htonl(strlen(pPostInfo->GetInfoName()) + 1);
|
||||
pPostQueueAnswer->m_iDestDirLen = htonl(strlen(pPostInfo->GetDestDir()) + 1);
|
||||
pPostQueueAnswer->m_iProgressLabelLen = htonl(strlen(pPostInfo->GetProgressLabel()) + 1);
|
||||
bufptr += sizeof(SNZBPostQueueResponseEntry);
|
||||
strcpy(bufptr, pPostInfo->GetNZBFilename());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iNZBFilenameLen);
|
||||
strcpy(bufptr, pPostInfo->GetParFilename());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iParFilename);
|
||||
strcpy(bufptr, pPostInfo->GetInfoName());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iInfoNameLen);
|
||||
strcpy(bufptr, pPostInfo->GetDestDir());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iDestDirLen);
|
||||
strcpy(bufptr, pPostInfo->GetProgressLabel());
|
||||
bufptr += ntohl(pPostQueueAnswer->m_iProgressLabelLen);
|
||||
// align struct to 4-bytes, needed by ARM-processor (and may be others)
|
||||
if ((size_t)bufptr % 4 > 0)
|
||||
{
|
||||
pPostQueueAnswer->m_iProgressLabelLen = htonl(ntohl(pPostQueueAnswer->m_iProgressLabelLen) + 4 - (size_t)bufptr % 4);
|
||||
bufptr += 4 - (size_t)bufptr % 4;
|
||||
}
|
||||
}
|
||||
|
||||
g_pPrePostProcessor->UnlockPostQueue();
|
||||
|
||||
PostQueueResponse.m_iNrTrailingEntries = htonl(NrEntries);
|
||||
PostQueueResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &PostQueueResponse, sizeof(PostQueueResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteLogBinCommand::Execute()
|
||||
{
|
||||
SNZBWriteLogRequest WriteLogRequest;
|
||||
if (!ReceiveRequest(&WriteLogRequest, sizeof(WriteLogRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(WriteLogRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(WriteLogRequest.m_iTrailingDataLength);
|
||||
pRecvBuffer[NeedBytes] = '\0';
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
bool OK = true;
|
||||
switch ((Message::EKind)ntohl(WriteLogRequest.m_iKind))
|
||||
{
|
||||
case Message::mkDetail:
|
||||
detail(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkInfo:
|
||||
info(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkWarning:
|
||||
warn(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkError:
|
||||
error(pRecvBuffer);
|
||||
break;
|
||||
case Message::mkDebug:
|
||||
debug(pRecvBuffer);
|
||||
break;
|
||||
default:
|
||||
OK = false;
|
||||
}
|
||||
SendBoolResponse(OK, OK ? "Message added to log" : "Invalid message-kind");
|
||||
}
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
131
BinRpc.h
Normal file
131
BinRpc.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BINRPC_H
|
||||
#define BINRPC_H
|
||||
|
||||
#include "Connection.h"
|
||||
#include "MessageBase.h"
|
||||
|
||||
class BinRpcProcessor
|
||||
{
|
||||
private:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase m_MessageBase;
|
||||
const char* m_szClientIP;
|
||||
|
||||
void Dispatch();
|
||||
|
||||
public:
|
||||
void Execute();
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetSignature(int iSignature) { m_MessageBase.m_iSignature = iSignature; }
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
};
|
||||
|
||||
class BinCommand
|
||||
{
|
||||
protected:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
void SendBoolResponse(bool bSuccess, const char* szText);
|
||||
|
||||
public:
|
||||
virtual ~BinCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; }
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; }
|
||||
};
|
||||
|
||||
class DownloadBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PauseUnpauseBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class EditQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SetDownloadRateBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DumpDebugBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PostQueueBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class WriteLogBinCommand: public BinCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
63
ChangeLog
63
ChangeLog
@@ -1,3 +1,64 @@
|
||||
nzbget-0.4.0:
|
||||
- added the support for XML-RPC and JSON-RPC to easier control the server
|
||||
from other applications;
|
||||
- added web-interface - it is available for download from NZBGet-project's
|
||||
home page as a separate package "web-interface";
|
||||
- added the automatic cleaning up of the download queue (deletion of unneeded
|
||||
paused par-files) after successful par-check/repair - new
|
||||
option <ParCleanupQueue>;
|
||||
- added option <DetailTarget> to allow to filter the (not so important)
|
||||
log-messages from articles' downloads (they have now the type <detail>
|
||||
instead of <info>);
|
||||
- added the gathering of progress-information during par-check; it is
|
||||
available via XML-RPC or JSON-RPC; it is also showed in web-interface;
|
||||
- improvements in internal decoder: added support for yEnc-files without
|
||||
ypart-statement (sometimes used for small files); added support for
|
||||
UU-format;
|
||||
- removed support for uulib-decoder (it did not work well anyway);
|
||||
- replaced the option <decoder (yenc, uulib, none)> with the option
|
||||
<decode (yes, no)>;
|
||||
- added detection of errors <server busy> and <remote server not available>
|
||||
(special case for NNTPCache-server) to consider them as connect-errors
|
||||
(and therefore not count as retries);
|
||||
- added check for incomplete articles (also mostly for NNTPCache-server) to
|
||||
differ such errors from CrcErrors (better error reporting);
|
||||
- improved error-reporting on moving of completed files from tmp- to
|
||||
dst-directory and added code to move files across drives if renaming fails;
|
||||
- improved handling of nzb-files with multiple collections in par-checker;
|
||||
- improved the parchecker: added the detection and processing of files
|
||||
splitted after parring;
|
||||
- added the queueing of post-process-scripts and waiting for script's
|
||||
completion before starting of a next job in postprocessor (par-job or
|
||||
script) to provide more balanced cpu utilization;
|
||||
- added the redirecting of post-process-script's output to log; new option
|
||||
<PostLogKind> to specify the default message-kind for unformatted
|
||||
log-messages;
|
||||
- added the returning of script-output by command <postqueue> via XML-RPC
|
||||
and JSON-RPC; the script-output is also showed in web-interface;
|
||||
- added the saving and restoring of the post-processor-queue (if server was
|
||||
stopped before all items were processed); new option <ReloadPostQueue>;
|
||||
- added new parameter to postprocess-script to indicate if any of par-jobs
|
||||
for the same nzb-file failed;
|
||||
- added remote command (switch O/--post) to request the post-processor-queue
|
||||
from server;
|
||||
- added remote command (switch -W/--write) to write messages to server's log;
|
||||
- added option <DiskSpace> to automatically pause the download on low disk
|
||||
space;
|
||||
- fixed few incompatibility-issues with unslung-platform on nslu2 (ARM);
|
||||
- fixed: articles with trailing text after binary data caused the decode
|
||||
failures and the reporting of CRC-errors;
|
||||
- fixed: dupecheck could cause seg.faults when all articles for a file failed;
|
||||
- fixed: by dupe-checking of files contained in nzb-file the files with the
|
||||
same size were ignored (not deleted from queue);
|
||||
- updated libpar2-patch for msvc to fix a segfault in libpar2 (windows only);
|
||||
- fixed: by registering the service on windows the fullpath to nzbget.exe
|
||||
was not always added to service's exename, making the registered service
|
||||
unusable;
|
||||
- fixed: the pausing of a group could cause the start of post-processing for
|
||||
that group;
|
||||
- fixed: too many info-messages <Need more N blocks> could be printed during
|
||||
par-check (appeared on posix only);
|
||||
|
||||
nzbget-0.3.1:
|
||||
- Greatly reduced the memory consumption by keeping articles' info on disk
|
||||
until the file download starts;
|
||||
@@ -25,7 +86,7 @@ nzbget-0.3.1:
|
||||
and relaunched for download (option "RetryOnCrcError"), it is useful if
|
||||
multiple servers are available;
|
||||
- Improved error-check for downloaded articles (crc-check and check for
|
||||
received message-id) decrease the number of broken files;
|
||||
received message-id) decreases the number of broken files;
|
||||
- Extensions in curses-outputmode: added group-view-mode (key "G") to show
|
||||
items in download queue as groups, where one group represents all files
|
||||
from the same nzb-file; the editing of queue works also in group-mode
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ColoredFrontend.h"
|
||||
#include "Util.h"
|
||||
|
||||
ColoredFrontend::ColoredFrontend()
|
||||
{
|
||||
@@ -77,10 +78,10 @@ void ColoredFrontend::PrintStatus()
|
||||
|
||||
if (fCurrentDownloadSpeed > 0.0 && !m_bPause)
|
||||
{
|
||||
long long remain_sec = m_lRemainingSize / ((long long int)(fCurrentDownloadSpeed * 1024));
|
||||
int h = remain_sec / 3600;
|
||||
int m = (remain_sec % 3600) / 60;
|
||||
int s = remain_sec % 60;
|
||||
long long remain_sec = m_lRemainingSize / ((long long)(fCurrentDownloadSpeed * 1024));
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
sprintf(timeString, " (~ %.2d:%.2d:%.2d)", h, m, s);
|
||||
}
|
||||
|
||||
@@ -94,14 +95,14 @@ void ColoredFrontend::PrintStatus()
|
||||
szDownloadLimit[0] = 0;
|
||||
}
|
||||
|
||||
char szParStatus[128];
|
||||
if (m_iParJobCount > 0)
|
||||
char szPostStatus[128];
|
||||
if (m_iPostJobCount > 0)
|
||||
{
|
||||
sprintf(szParStatus, ", %i par", m_iParJobCount);
|
||||
sprintf(szPostStatus, ", %i post-job%s", m_iPostJobCount, m_iPostJobCount > 1 ? "s" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
szParStatus[0] = 0;
|
||||
szPostStatus[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -112,8 +113,8 @@ void ColoredFrontend::PrintStatus()
|
||||
#endif
|
||||
|
||||
snprintf(tmp, 1024, " %d threads, %.0f KB/s, %.2f MB remaining%s%s%s%s%s\n",
|
||||
m_iThreadCount, fCurrentDownloadSpeed, (float)(m_lRemainingSize / 1024.0 / 1024.0),
|
||||
timeString, szParStatus, m_bPause ? (m_bStandBy ? ", Paused" : ", Pausing") : "", szDownloadLimit, szControlSeq);
|
||||
m_iThreadCount, fCurrentDownloadSpeed, (float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0),
|
||||
timeString, szPostStatus, m_bPause ? (m_bStandBy ? ", Paused" : ", Pausing") : "", szDownloadLimit, szControlSeq);
|
||||
tmp[1024-1] = '\0';
|
||||
printf("%s", tmp);
|
||||
m_bNeedGoBack = true;
|
||||
@@ -140,6 +141,10 @@ void ColoredFrontend::PrintMessage(Message * pMessage)
|
||||
SetConsoleTextAttribute(m_hConsole, 2);
|
||||
printf("[INFO]");
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
SetConsoleTextAttribute(m_hConsole, 2);
|
||||
printf("[DETAIL]");
|
||||
break;
|
||||
}
|
||||
SetConsoleTextAttribute(m_hConsole, 7);
|
||||
char* msg = strdup(pMessage->GetText());
|
||||
@@ -162,6 +167,9 @@ void ColoredFrontend::PrintMessage(Message * pMessage)
|
||||
case Message::mkInfo:
|
||||
printf("\033[32m[INFO]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
printf("\033[32m[DETAIL]\033[39m %s\033[K\n", msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -91,13 +91,28 @@ Connection::Connection(NetAddress* pNetAddress)
|
||||
m_iTimeout = 60;
|
||||
m_bSuppressErrors = true;
|
||||
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
|
||||
m_bAutoClose = true;
|
||||
}
|
||||
|
||||
Connection::Connection(SOCKET iSocket, bool bAutoClose)
|
||||
{
|
||||
debug("Creating Connection");
|
||||
|
||||
m_pNetAddress = NULL;
|
||||
m_eStatus = csConnected;
|
||||
m_iSocket = iSocket;
|
||||
m_iBufAvail = 0;
|
||||
m_iTimeout = 60;
|
||||
m_bSuppressErrors = true;
|
||||
m_szReadBuf = (char*)malloc(CONNECTION_READBUFFER_SIZE + 1);
|
||||
m_bAutoClose = bAutoClose;
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
debug("Destroying Connection");
|
||||
|
||||
if (m_eStatus == csConnected)
|
||||
if (m_eStatus == csConnected && m_bAutoClose)
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
@@ -156,7 +171,7 @@ int Connection::Bind()
|
||||
return iRes;
|
||||
}
|
||||
|
||||
int Connection::WriteLine(char* line)
|
||||
int Connection::WriteLine(const char* pBuffer)
|
||||
{
|
||||
//debug("Connection::write(char* line)");
|
||||
|
||||
@@ -165,12 +180,12 @@ int Connection::WriteLine(char* line)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int iRes = DoWriteLine(line);
|
||||
int iRes = DoWriteLine(pBuffer);
|
||||
|
||||
return iRes;
|
||||
}
|
||||
|
||||
int Connection::Send(char* pBuffer, int iSize)
|
||||
int Connection::Send(const char* pBuffer, int iSize)
|
||||
{
|
||||
debug("Sending data");
|
||||
|
||||
@@ -234,6 +249,17 @@ bool Connection::RecvAll(char * pBuffer, int iSize)
|
||||
|
||||
char* pBufPtr = (char*)pBuffer;
|
||||
int NeedBytes = iSize;
|
||||
|
||||
if (m_iBufAvail > 0)
|
||||
{
|
||||
int len = iSize > m_iBufAvail ? m_iBufAvail : iSize;
|
||||
memcpy(pBufPtr, m_szBufPtr, len);
|
||||
pBufPtr += len;
|
||||
m_szBufPtr += len;
|
||||
m_iBufAvail -= len;
|
||||
NeedBytes -= len;
|
||||
}
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
@@ -352,10 +378,10 @@ int Connection::DoDisconnect()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Connection::DoWriteLine(char* szText)
|
||||
int Connection::DoWriteLine(const char* pBuffer)
|
||||
{
|
||||
//debug("Connection::doWrite()");
|
||||
return send(m_iSocket, szText, strlen(szText), 0);
|
||||
return send(m_iSocket, pBuffer, strlen(pBuffer), 0);
|
||||
}
|
||||
|
||||
char* Connection::DoReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
@@ -388,7 +414,7 @@ char* Connection::DoReadLine(char* pBuffer, int iSize, int* pBytesRead)
|
||||
char* p = (char*)memchr(szBufPtr, '\n', iBufAvail);
|
||||
if (p)
|
||||
{
|
||||
len = p - szBufPtr + 1;
|
||||
len = (int)(p - szBufPtr + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -49,29 +49,31 @@ protected:
|
||||
EStatus m_eStatus;
|
||||
int m_iTimeout;
|
||||
bool m_bSuppressErrors;
|
||||
bool m_bAutoClose;
|
||||
|
||||
unsigned int ResolveHostAddr(const char* szHost);
|
||||
void ReportError(const char* szMsgPrefix, const char* szMsgArg, int ErrCode);
|
||||
virtual int DoConnect();
|
||||
virtual int DoDisconnect();
|
||||
int DoBind();
|
||||
int DoWriteLine(char* text);
|
||||
int DoWriteLine(const char* pBuffer);
|
||||
char* DoReadLine(char* pBuffer, int iSize, int* pBytesRead);
|
||||
SOCKET DoAccept();
|
||||
|
||||
public:
|
||||
Connection(NetAddress* pNetAddress);
|
||||
Connection(SOCKET iSocket, bool bAutoClose);
|
||||
virtual ~Connection();
|
||||
static void Init();
|
||||
static void Final();
|
||||
int Connect();
|
||||
int Disconnect();
|
||||
int Bind();
|
||||
int Send(char* pBuffer, int iSize);
|
||||
int Send(const char* pBuffer, int iSize);
|
||||
int Recv(char* pBuffer, int iSize);
|
||||
bool RecvAll(char* pBuffer, int iSize);
|
||||
char* ReadLine(char* pBuffer, int iSize, int* pBytesRead);
|
||||
int WriteLine(char* text);
|
||||
int WriteLine(const char* pBuffer);
|
||||
SOCKET Accept();
|
||||
void Cancel();
|
||||
NetAddress* GetServer() { return m_pNetAddress; }
|
||||
|
||||
354
Decoder.cpp
354
Decoder.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -40,19 +40,11 @@
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
|
||||
#ifdef ENABLE_UULIB
|
||||
#ifndef PROTOTYPES
|
||||
#define PROTOTYPES
|
||||
#endif
|
||||
#include <uudeview.h>
|
||||
#endif
|
||||
|
||||
#include "Decoder.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
Mutex UULibDecoder::m_mutexDecoder;
|
||||
const char* Decoder::FormatNames[] = { "Unknown", "yEnc", "UU" };
|
||||
unsigned int YDecoder::crc_tab[256];
|
||||
|
||||
Decoder::Decoder()
|
||||
@@ -62,7 +54,6 @@ Decoder::Decoder()
|
||||
m_szSrcFilename = NULL;
|
||||
m_szDestFilename = NULL;
|
||||
m_szArticleFilename = NULL;
|
||||
m_bCrcError = false;
|
||||
}
|
||||
|
||||
Decoder::~ Decoder()
|
||||
@@ -75,93 +66,51 @@ Decoder::~ Decoder()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* UULibDecoder
|
||||
*/
|
||||
|
||||
bool UULibDecoder::Execute()
|
||||
void Decoder::Clear()
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
#ifndef ENABLE_UULIB
|
||||
error("Program was compiled without option ENABLE_UULIB defined. uulib-Decoder is not available.");
|
||||
#else
|
||||
|
||||
m_mutexDecoder.Lock();
|
||||
|
||||
UUInitialize();
|
||||
|
||||
UUSetOption(UUOPT_DESPERATE, 1, NULL);
|
||||
// UUSetOption(UUOPT_DUMBNESS,1,NULL);
|
||||
// UUSetOption( UUOPT_SAVEPATH, 1, szDestDir );
|
||||
|
||||
UULoadFile((char*) m_szSrcFilename, NULL, 0);
|
||||
|
||||
// choose right attachment
|
||||
|
||||
uulist* attachment = NULL;
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
uulist* att_tmp = UUGetFileListItem(i);
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = NULL;
|
||||
}
|
||||
|
||||
if (!att_tmp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len)
|
||||
{
|
||||
if (!strncmp(buffer, "=ybegin ", 8))
|
||||
{
|
||||
return efYenc;
|
||||
}
|
||||
|
||||
if ((len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
|
||||
{
|
||||
return efUx;
|
||||
}
|
||||
|
||||
if ((att_tmp) && (att_tmp->haveparts))
|
||||
if (!strncmp(buffer, "begin ", 6))
|
||||
{
|
||||
bool bOK = true;
|
||||
buffer += 6; //strlen("begin ")
|
||||
while (*buffer && *buffer != ' ')
|
||||
{
|
||||
if (!attachment)
|
||||
char ch = *buffer++;
|
||||
if (ch < '0' || ch > '7')
|
||||
{
|
||||
attachment = att_tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//f**k, multiple attachments!? Can't handle this.
|
||||
attachment = NULL;
|
||||
bOK = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment)
|
||||
{
|
||||
// okay, we got only one attachment, perfect!
|
||||
if ((attachment->haveparts) && (attachment->haveparts[0])) // && (!attachment->haveparts[1])) FUCK UULIB
|
||||
if (bOK)
|
||||
{
|
||||
int r = UUDecodeFile(attachment, (char*)m_szDestFilename);
|
||||
|
||||
if (r == UURET_OK)
|
||||
{
|
||||
// we did it!
|
||||
res = true;
|
||||
m_szArticleFilename = strdup(attachment->filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("[ERROR] Wrong number of parts!\n");
|
||||
return efUx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("[ERROR] Wrong number of attachments!\n");
|
||||
}
|
||||
|
||||
UUCleanUp();
|
||||
|
||||
m_mutexDecoder.Unlock();
|
||||
|
||||
#endif // ENABLE_UULIB
|
||||
|
||||
return res;
|
||||
return efUnknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* YDecoder
|
||||
* Very primitive (but fast) implementation of yEnc-Decoder
|
||||
* YDecoder: fast implementation of yEnc-Decoder
|
||||
*/
|
||||
|
||||
void YDecoder::Init()
|
||||
@@ -182,20 +131,22 @@ YDecoder::YDecoder()
|
||||
|
||||
void YDecoder::Clear()
|
||||
{
|
||||
Decoder::Clear();
|
||||
|
||||
m_bBody = false;
|
||||
m_bBegin = false;
|
||||
m_bPart = false;
|
||||
m_bEnd = false;
|
||||
m_bCrc = false;
|
||||
m_lExpectedCRC = 0;
|
||||
m_lCalculatedCRC = 0xFFFFFFFF;
|
||||
m_iBegin = 0;
|
||||
m_iEnd = 0;
|
||||
m_iSize = 0;
|
||||
m_iEndSize = 0;
|
||||
m_bAutoSeek = false;
|
||||
m_bNeedSetPos = false;
|
||||
m_bCrcCheck = false;
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = NULL;
|
||||
}
|
||||
|
||||
/* from crc32.c (http://www.koders.com/c/fid699AFE0A656F0022C9D6B9D1743E697B69CE5815.aspx)
|
||||
@@ -254,16 +205,23 @@ unsigned long YDecoder::crc32m(unsigned long startCrc, unsigned char *block, uns
|
||||
|
||||
unsigned int YDecoder::DecodeBuffer(char* buffer)
|
||||
{
|
||||
if (m_bBody)
|
||||
if (m_bBody && !m_bEnd)
|
||||
{
|
||||
if (!strncmp(buffer, "=yend size=", 11))
|
||||
if (!strncmp(buffer, "=yend ", 6))
|
||||
{
|
||||
m_bEnd = true;
|
||||
char* pc = strstr(buffer, "pcrc32=");
|
||||
if (pc)
|
||||
char* pb = strstr(buffer, m_bPart ? " pcrc32=" : " crc32=");
|
||||
if (pb)
|
||||
{
|
||||
pc += 7; //=strlen("pcrc32=")
|
||||
m_lExpectedCRC = strtoul(pc, NULL, 16);
|
||||
m_bCrc = true;
|
||||
pb += 7 + (int)m_bPart; //=strlen(" crc32=") or strlen(" pcrc32=")
|
||||
m_lExpectedCRC = strtoul(pb, NULL, 16);
|
||||
}
|
||||
pb = strstr(buffer, " size=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 6; //=strlen(" size=")
|
||||
m_iEndSize = (int)atoi(pb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -295,34 +253,19 @@ BreakLoop:
|
||||
|
||||
if (m_bCrcCheck)
|
||||
{
|
||||
m_lCalculatedCRC = crc32m(m_lCalculatedCRC, (unsigned char *)buffer, optr - buffer);
|
||||
m_lCalculatedCRC = crc32m(m_lCalculatedCRC, (unsigned char *)buffer, (unsigned int)(optr - buffer));
|
||||
}
|
||||
return optr - buffer;
|
||||
return (unsigned int)(optr - buffer);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (!strncmp(buffer, "=ypart begin=", 13))
|
||||
if (!m_bPart && !strncmp(buffer, "=ybegin ", 8))
|
||||
{
|
||||
m_bBody = true;
|
||||
char* pb = strstr(buffer, "begin=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 6; //=strlen("begin=")
|
||||
m_iBegin = (int)atoi(pb);
|
||||
}
|
||||
pb = strstr(buffer, "end=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 4; //=strlen("end=")
|
||||
m_iEnd = (int)atoi(pb);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(buffer, "=ybegin part=", 13))
|
||||
{
|
||||
char* pb = strstr(buffer, "name=");
|
||||
m_bBegin = true;
|
||||
char* pb = strstr(buffer, " name=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 5; //=strlen("name=")
|
||||
pb += 6; //=strlen(" name=")
|
||||
char* pe;
|
||||
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
|
||||
if (m_szArticleFilename)
|
||||
@@ -333,13 +276,43 @@ BreakLoop:
|
||||
strncpy(m_szArticleFilename, pb, pe - pb);
|
||||
m_szArticleFilename[pe - pb] = '\0';
|
||||
}
|
||||
pb = strstr(buffer, " size=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 6; //=strlen(" size=")
|
||||
m_iSize = (int)atoi(pb);
|
||||
}
|
||||
m_bPart = strstr(buffer, " part=");
|
||||
if (!m_bPart)
|
||||
{
|
||||
m_bBody = true;
|
||||
m_iBegin = 1;
|
||||
m_iEnd = m_iSize;
|
||||
}
|
||||
}
|
||||
else if (m_bPart && !strncmp(buffer, "=ypart ", 7))
|
||||
{
|
||||
m_bPart = true;
|
||||
m_bBody = true;
|
||||
char* pb = strstr(buffer, " begin=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 7; //=strlen(" begin=")
|
||||
m_iBegin = (int)atoi(pb);
|
||||
}
|
||||
pb = strstr(buffer, " end=");
|
||||
if (pb)
|
||||
{
|
||||
pb += 5; //=strlen(" end=")
|
||||
m_iEnd = (int)atoi(pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool YDecoder::Write(char* buffer, FILE* outfile)
|
||||
bool YDecoder::Write(char* buffer, int len, FILE* outfile)
|
||||
{
|
||||
unsigned int wcnt = DecodeBuffer(buffer);
|
||||
if (wcnt > 0)
|
||||
@@ -361,13 +334,152 @@ bool YDecoder::Write(char* buffer, FILE* outfile)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YDecoder::Execute()
|
||||
Decoder::EStatus YDecoder::Check()
|
||||
{
|
||||
m_lCalculatedCRC ^= 0xFFFFFFFF;
|
||||
|
||||
debug("Expected pcrc32=%x", m_lExpectedCRC);
|
||||
debug("Calculated pcrc32=%x", m_lCalculatedCRC);
|
||||
m_bCrcError = m_bCrcCheck && (m_lExpectedCRC != m_lCalculatedCRC);
|
||||
debug("Expected crc32=%x", m_lExpectedCRC);
|
||||
debug("Calculated crc32=%x", m_lCalculatedCRC);
|
||||
|
||||
return m_bBody && m_bEnd && !m_bCrcError;
|
||||
if (!m_bBegin)
|
||||
{
|
||||
return eNoBinaryData;
|
||||
}
|
||||
else if (!m_bEnd)
|
||||
{
|
||||
return eArticleIncomplete;
|
||||
}
|
||||
else if (!m_bPart && m_iSize != m_iEndSize)
|
||||
{
|
||||
return eInvalidSize;
|
||||
}
|
||||
else if (m_bCrcCheck && m_bCrc && (m_lExpectedCRC != m_lCalculatedCRC))
|
||||
{
|
||||
return eCrcError;
|
||||
}
|
||||
|
||||
return eFinished;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* UDecoder: supports UU encoding formats
|
||||
*/
|
||||
|
||||
UDecoder::UDecoder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UDecoder::Clear()
|
||||
{
|
||||
Decoder::Clear();
|
||||
|
||||
m_bBody = false;
|
||||
m_bEnd = false;
|
||||
}
|
||||
|
||||
/* DecodeBuffer-function uses portions of code from tool UUDECODE by Clem Dye
|
||||
* UUDECODE.c (http://www.bastet.com/uue.zip)
|
||||
* Copyright (C) 1998 Clem Dye
|
||||
*
|
||||
* Released under GPL (thanks)
|
||||
*/
|
||||
|
||||
#define UU_DECODE_CHAR(c) (c == '`' ? 0 : (((c) - ' ') & 077))
|
||||
|
||||
unsigned int UDecoder::DecodeBuffer(char* buffer, int len)
|
||||
{
|
||||
if (!m_bBody)
|
||||
{
|
||||
if (!strncmp(buffer, "begin ", 6))
|
||||
{
|
||||
char* pb = buffer;
|
||||
pb += 6; //strlen("begin ")
|
||||
|
||||
// skip file-permissions
|
||||
for (; *pb != ' ' && *pb != '\0' && *pb != '\n' && *pb != '\r'; pb++) ;
|
||||
pb++;
|
||||
|
||||
// extracting filename
|
||||
char* pe;
|
||||
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
|
||||
if (m_szArticleFilename)
|
||||
{
|
||||
free(m_szArticleFilename);
|
||||
}
|
||||
m_szArticleFilename = (char*)malloc(pe - pb + 1);
|
||||
strncpy(m_szArticleFilename, pb, pe - pb);
|
||||
m_szArticleFilename[pe - pb] = '\0';
|
||||
|
||||
m_bBody = true;
|
||||
return 0;
|
||||
}
|
||||
else if ((len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
|
||||
{
|
||||
m_bBody = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bBody && (!strncmp(buffer, "end ", 4) || *buffer == '`'))
|
||||
{
|
||||
m_bEnd = true;
|
||||
}
|
||||
|
||||
if (m_bBody && !m_bEnd)
|
||||
{
|
||||
int iEffLen = UU_DECODE_CHAR(buffer[0]);
|
||||
if (iEffLen > len)
|
||||
{
|
||||
// error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* iptr = buffer;
|
||||
char* optr = buffer;
|
||||
for (++iptr; iEffLen > 0; iptr += 4, iEffLen -= 3)
|
||||
{
|
||||
if (iEffLen >= 3)
|
||||
{
|
||||
*optr++ = UU_DECODE_CHAR (iptr[0]) << 2 | UU_DECODE_CHAR (iptr[1]) >> 4;
|
||||
*optr++ = UU_DECODE_CHAR (iptr[1]) << 4 | UU_DECODE_CHAR (iptr[2]) >> 2;
|
||||
*optr++ = UU_DECODE_CHAR (iptr[2]) << 6 | UU_DECODE_CHAR (iptr[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iEffLen >= 1)
|
||||
{
|
||||
*optr++ = UU_DECODE_CHAR (iptr[0]) << 2 | UU_DECODE_CHAR (iptr[1]) >> 4;
|
||||
}
|
||||
if (iEffLen >= 2)
|
||||
{
|
||||
*optr++ = UU_DECODE_CHAR (iptr[1]) << 4 | UU_DECODE_CHAR (iptr[2]) >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (unsigned int)(optr - buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool UDecoder::Write(char* buffer, int len, FILE* outfile)
|
||||
{
|
||||
unsigned int wcnt = DecodeBuffer(buffer, len);
|
||||
if (wcnt > 0)
|
||||
{
|
||||
fwrite(buffer, 1, wcnt, outfile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Decoder::EStatus UDecoder::Check()
|
||||
{
|
||||
if (!m_bBody)
|
||||
{
|
||||
return eNoBinaryData;
|
||||
}
|
||||
|
||||
return eFinished;
|
||||
}
|
||||
|
||||
64
Decoder.h
64
Decoder.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -31,41 +31,58 @@
|
||||
|
||||
class Decoder
|
||||
{
|
||||
public:
|
||||
enum EStatus
|
||||
{
|
||||
eUnknownError,
|
||||
eFinished,
|
||||
eArticleIncomplete,
|
||||
eCrcError,
|
||||
eInvalidSize,
|
||||
eNoBinaryData
|
||||
};
|
||||
|
||||
enum EFormat
|
||||
{
|
||||
efUnknown,
|
||||
efYenc,
|
||||
efUx,
|
||||
};
|
||||
|
||||
static const char* FormatNames[];
|
||||
|
||||
protected:
|
||||
const char* m_szSrcFilename;
|
||||
const char* m_szDestFilename;
|
||||
char* m_szArticleFilename;
|
||||
bool m_bCrcError;
|
||||
|
||||
public:
|
||||
Decoder();
|
||||
virtual ~Decoder();
|
||||
virtual bool Execute() = 0;
|
||||
virtual EStatus Check() = 0;
|
||||
virtual void Clear();
|
||||
virtual bool Write(char* buffer, int len, FILE* outfile) = 0;
|
||||
void SetSrcFilename(const char* szSrcFilename) { m_szSrcFilename = szSrcFilename; }
|
||||
void SetDestFilename(const char* szDestFilename) { m_szDestFilename = szDestFilename; }
|
||||
const char* GetArticleFilename() { return m_szArticleFilename; }
|
||||
bool GetCrcError() { return m_bCrcError; }
|
||||
};
|
||||
|
||||
class UULibDecoder: public Decoder
|
||||
{
|
||||
private:
|
||||
static Mutex m_mutexDecoder;
|
||||
|
||||
public:
|
||||
virtual bool Execute();
|
||||
static EFormat DetectFormat(const char* buffer, int len);
|
||||
};
|
||||
|
||||
class YDecoder: public Decoder
|
||||
{
|
||||
protected:
|
||||
static unsigned int crc_tab[256];
|
||||
bool m_bBegin;
|
||||
bool m_bPart;
|
||||
bool m_bBody;
|
||||
bool m_bEnd;
|
||||
bool m_bCrc;
|
||||
unsigned long m_lExpectedCRC;
|
||||
unsigned long m_lCalculatedCRC;
|
||||
unsigned long m_iBegin;
|
||||
unsigned long m_iEnd;
|
||||
unsigned long m_iSize;
|
||||
unsigned long m_iEndSize;
|
||||
bool m_bAutoSeek;
|
||||
bool m_bNeedSetPos;
|
||||
bool m_bCrcCheck;
|
||||
@@ -76,9 +93,9 @@ protected:
|
||||
|
||||
public:
|
||||
YDecoder();
|
||||
virtual bool Execute();
|
||||
void Clear();
|
||||
bool Write(char* buffer, FILE* outfile);
|
||||
virtual EStatus Check();
|
||||
virtual void Clear();
|
||||
virtual bool Write(char* buffer, int len, FILE* outfile);
|
||||
void SetAutoSeek(bool bAutoSeek) { m_bAutoSeek = m_bNeedSetPos = bAutoSeek; }
|
||||
void SetCrcCheck(bool bCrcCheck) { m_bCrcCheck = bCrcCheck; }
|
||||
|
||||
@@ -86,4 +103,19 @@ public:
|
||||
static void Final();
|
||||
};
|
||||
|
||||
class UDecoder: public Decoder
|
||||
{
|
||||
private:
|
||||
bool m_bBody;
|
||||
bool m_bEnd;
|
||||
|
||||
unsigned int DecodeBuffer(char* buffer, int len);
|
||||
|
||||
public:
|
||||
UDecoder();
|
||||
virtual EStatus Check();
|
||||
virtual void Clear();
|
||||
virtual bool Write(char* buffer, int len, FILE* outfile);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
389
DiskState.cpp
389
DiskState.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -44,15 +44,42 @@
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
static const char* FORMATVERSION_SIGNATURE = "nzbget diskstate file version 3\n";
|
||||
|
||||
/* Save Download Queue to Disk.
|
||||
* The Disk State consists of file "queue", which contains the order of files
|
||||
* and of one diskstate-file for each file in download queue.
|
||||
* This function saves only file "queue".
|
||||
* This function saves file "queue" and files with NZB-info. It does not
|
||||
* save file-infos.
|
||||
*/
|
||||
bool DiskState::Save(DownloadQueue* pDownloadQueue)
|
||||
bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
{
|
||||
debug("Saving queue to disk");
|
||||
|
||||
// prepare list of nzb-infos
|
||||
|
||||
typedef std::deque<NZBInfo*> NZBList;
|
||||
NZBList cNZBList;
|
||||
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
bool inlist = false;
|
||||
for (NZBList::iterator it = cNZBList.begin(); it != cNZBList.end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
if (pNZBInfo == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
inlist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inlist)
|
||||
{
|
||||
cNZBList.push_back(pFileInfo->GetNZBInfo());
|
||||
}
|
||||
}
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
|
||||
fileName[1024-1] = '\0';
|
||||
@@ -66,21 +93,45 @@ bool DiskState::Save(DownloadQueue* pDownloadQueue)
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "nzbget diskstate file version 1\n");
|
||||
fprintf(outfile, FORMATVERSION_SIGNATURE);
|
||||
|
||||
int cnt = 0;
|
||||
// save nzb-infos
|
||||
fprintf(outfile, "%i\n", cNZBList.size());
|
||||
for (NZBList::iterator it = cNZBList.begin(); it != cNZBList.end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = *it;
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetFilename());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetDestDir());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetFileCount());
|
||||
unsigned long High, Low;
|
||||
Util::SplitInt64(pNZBInfo->GetSize(), &High, &Low);
|
||||
fprintf(outfile, "%lu,%lu\n", High, Low);
|
||||
}
|
||||
|
||||
// save file-infos
|
||||
fprintf(outfile, "%i\n", pDownloadQueue->size());
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (!pFileInfo->GetDeleted())
|
||||
{
|
||||
fprintf(outfile, "%i,%i\n", pFileInfo->GetID(), (int)pFileInfo->GetPaused());
|
||||
cnt++;
|
||||
// find index of nzb-info
|
||||
int iNZBIndex = 0;
|
||||
for (unsigned int i = 0; i < cNZBList.size(); i++)
|
||||
{
|
||||
iNZBIndex++;
|
||||
if (cNZBList[i] == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile, "%i,%i,%i\n", pFileInfo->GetID(), iNZBIndex, (int)pFileInfo->GetPaused());
|
||||
}
|
||||
}
|
||||
fclose(outfile);
|
||||
|
||||
if (cnt == 0)
|
||||
if (pDownloadQueue->empty())
|
||||
{
|
||||
remove(fileName);
|
||||
}
|
||||
@@ -88,18 +139,13 @@ bool DiskState::Save(DownloadQueue* pDownloadQueue)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskState::SaveFile(FileInfo* pFileInfo)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
|
||||
fileName[1024-1] = '\0';
|
||||
return SaveFileInfo(pFileInfo, fileName);
|
||||
}
|
||||
|
||||
bool DiskState::Load(DownloadQueue* pDownloadQueue)
|
||||
bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
{
|
||||
debug("Loading queue from disk");
|
||||
|
||||
typedef std::deque<NZBInfo*> NZBList;
|
||||
NZBList cNZBList;
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
|
||||
fileName[1024-1] = '\0';
|
||||
@@ -112,50 +158,84 @@ bool DiskState::Load(DownloadQueue* pDownloadQueue)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
if (!strcmp(FileSignatur, "nzbget diskstate file version 1\n"))
|
||||
{
|
||||
int id, paused;
|
||||
while (fscanf(infile, "%i,%i\n", &id, &paused) != EOF)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
fileName[1024-1] = '\0';
|
||||
FileInfo* pFileInfo = new FileInfo();
|
||||
bool res = LoadFileInfo(pFileInfo, fileName, true, false);
|
||||
if (res)
|
||||
{
|
||||
pFileInfo->SetID(id);
|
||||
pFileInfo->SetPaused(paused);
|
||||
pDownloadQueue->push_back(pFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Could not load diskstate for file %s", fileName);
|
||||
delete pFileInfo;
|
||||
}
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
else
|
||||
if (strcmp(FileSignatur, FORMATVERSION_SIGNATURE))
|
||||
{
|
||||
error("Could not load diskstate due file version mismatch");
|
||||
res = false;
|
||||
fclose(infile);
|
||||
return false;
|
||||
}
|
||||
|
||||
int size;
|
||||
char buf[1024];
|
||||
|
||||
// load nzb-infos
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
NZBInfo* pNZBInfo = new NZBInfo();
|
||||
cNZBList.push_back(pNZBInfo);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pNZBInfo->SetFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pNZBInfo->SetDestDir(buf);
|
||||
|
||||
int iFileCount;
|
||||
if (fscanf(infile, "%i\n", &iFileCount) != 1) goto error;
|
||||
pNZBInfo->SetFileCount(iFileCount);
|
||||
|
||||
unsigned long High, Low;
|
||||
if (fscanf(infile, "%lu,%lu\n", &High, &Low) != 2) goto error;
|
||||
pNZBInfo->SetSize(Util::JoinInt64(High, Low));
|
||||
}
|
||||
|
||||
// load file-infos
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
unsigned int id, iNZBIndex, paused;
|
||||
if (fscanf(infile, "%i,%i,%i\n", &id, &iNZBIndex, &paused) != 3) goto error;
|
||||
if (iNZBIndex < 0 || iNZBIndex > cNZBList.size()) goto error;
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
fileName[1024-1] = '\0';
|
||||
FileInfo* pFileInfo = new FileInfo();
|
||||
bool res = LoadFileInfo(pFileInfo, fileName, true, false);
|
||||
if (res)
|
||||
{
|
||||
pFileInfo->SetID(id);
|
||||
pFileInfo->SetPaused(paused);
|
||||
pFileInfo->SetNZBInfo(cNZBList[iNZBIndex - 1]);
|
||||
pDownloadQueue->push_back(pFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Could not load diskstate for file %s", fileName);
|
||||
delete pFileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
return true;
|
||||
|
||||
return res;
|
||||
error:
|
||||
fclose(infile);
|
||||
error("Error reading diskstate for file %s", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DiskState::LoadArticles(FileInfo* pFileInfo)
|
||||
bool DiskState::SaveFile(FileInfo* pFileInfo)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
|
||||
fileName[1024-1] = '\0';
|
||||
return LoadFileInfo(pFileInfo, fileName, false, true);
|
||||
return SaveFileInfo(pFileInfo, fileName);
|
||||
}
|
||||
|
||||
bool DiskState::SaveFileInfo(FileInfo* pFileInfo, const char* szFilename)
|
||||
@@ -170,13 +250,12 @@ bool DiskState::SaveFileInfo(FileInfo* pFileInfo, const char* szFilename)
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%s\n", pFileInfo->GetNZBFilename());
|
||||
fprintf(outfile, "%s\n", pFileInfo->GetSubject());
|
||||
fprintf(outfile, "%s\n", pFileInfo->GetDestDir());
|
||||
fprintf(outfile, "%s\n", pFileInfo->GetFilename());
|
||||
fprintf(outfile, "%i\n", pFileInfo->GetFilenameConfirmed());
|
||||
|
||||
fprintf(outfile, "%lu,%lu\n", (unsigned long)(pFileInfo->GetSize() >> 32), (unsigned long)(pFileInfo->GetSize()));
|
||||
unsigned long High, Low;
|
||||
Util::SplitInt64(pFileInfo->GetSize(), &High, &Low);
|
||||
fprintf(outfile, "%lu,%lu\n", High, Low);
|
||||
|
||||
fprintf(outfile, "%i\n", pFileInfo->GetGroups()->size());
|
||||
for (FileInfo::Groups::iterator it = pFileInfo->GetGroups()->begin(); it != pFileInfo->GetGroups()->end(); it++)
|
||||
@@ -196,6 +275,14 @@ bool DiskState::SaveFileInfo(FileInfo* pFileInfo, const char* szFilename)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskState::LoadArticles(FileInfo* pFileInfo)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
|
||||
fileName[1024-1] = '\0';
|
||||
return LoadFileInfo(pFileInfo, fileName, false, true);
|
||||
}
|
||||
|
||||
bool DiskState::LoadFileInfo(FileInfo* pFileInfo, const char * szFilename, bool bFileSummary, bool bArticles)
|
||||
{
|
||||
debug("Loading FileInfo from disk");
|
||||
@@ -210,18 +297,10 @@ bool DiskState::LoadFileInfo(FileInfo* pFileInfo, const char * szFilename, bool
|
||||
|
||||
char buf[1024];
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (bFileSummary) pFileInfo->SetNZBFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (bFileSummary) pFileInfo->SetSubject(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (bFileSummary) pFileInfo->SetDestDir(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
if (bFileSummary) pFileInfo->SetFilename(buf);
|
||||
@@ -232,7 +311,7 @@ bool DiskState::LoadFileInfo(FileInfo* pFileInfo, const char * szFilename, bool
|
||||
|
||||
unsigned long High, Low;
|
||||
if (fscanf(infile, "%lu,%lu\n", &High, &Low) != 2) goto error;
|
||||
if (bFileSummary) pFileInfo->SetSize((((unsigned long long)High) << 32) + Low);
|
||||
if (bFileSummary) pFileInfo->SetSize(Util::JoinInt64(High, Low));
|
||||
if (bFileSummary) pFileInfo->SetRemainingSize(pFileInfo->GetSize());
|
||||
|
||||
int size;
|
||||
@@ -272,11 +351,128 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DiskState::SavePostQueue(PostQueue* pPostQueue, bool bCompleted)
|
||||
{
|
||||
debug("Saving post-queue to disk");
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), bCompleted ? "postc" : "postq");
|
||||
fileName[1024-1] = '\0';
|
||||
|
||||
FILE* outfile = fopen(fileName, "w");
|
||||
|
||||
if (!outfile)
|
||||
{
|
||||
error("Could not create file %s", fileName);
|
||||
perror(fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, FORMATVERSION_SIGNATURE);
|
||||
|
||||
fprintf(outfile, "%i\n", pPostQueue->size());
|
||||
for (PostQueue::iterator it = pPostQueue->begin(); it != pPostQueue->end(); it++)
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetNZBFilename());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetDestDir());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetParFilename());
|
||||
fprintf(outfile, "%s\n", pPostInfo->GetInfoName());
|
||||
fprintf(outfile, "%i\n", (int)pPostInfo->GetParCheck());
|
||||
fprintf(outfile, "%i\n", (int)pPostInfo->GetParStatus());
|
||||
fprintf(outfile, "%i\n", (int)pPostInfo->GetParFailed());
|
||||
fprintf(outfile, "%i\n", (int)pPostInfo->GetStage());
|
||||
}
|
||||
fclose(outfile);
|
||||
|
||||
if (pPostQueue->empty())
|
||||
{
|
||||
remove(fileName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskState::LoadPostQueue(PostQueue* pPostQueue, bool bCompleted)
|
||||
{
|
||||
debug("Loading post-queue from disk");
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), bCompleted ? "postc" : "postq");
|
||||
fileName[1024-1] = '\0';
|
||||
|
||||
FILE* infile = fopen(fileName, "r");
|
||||
|
||||
if (!infile)
|
||||
{
|
||||
error("Could not open file %s", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
if (strcmp(FileSignatur, FORMATVERSION_SIGNATURE))
|
||||
{
|
||||
error("Could not load diskstate due file version mismatch");
|
||||
fclose(infile);
|
||||
return false;
|
||||
}
|
||||
|
||||
int size;
|
||||
char buf[1024];
|
||||
int iIntValue;
|
||||
|
||||
// load file-infos
|
||||
if (fscanf(infile, "%i\n", &size) != 1) goto error;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
PostInfo* pPostInfo = new PostInfo();
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pPostInfo->SetNZBFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pPostInfo->SetDestDir(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pPostInfo->SetParFilename(buf);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), infile)) goto error;
|
||||
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
|
||||
pPostInfo->SetInfoName(buf);
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParCheck(iIntValue);
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParStatus(iIntValue);
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetParFailed(iIntValue);
|
||||
|
||||
if (fscanf(infile, "%i\n", &iIntValue) != 1) goto error;
|
||||
pPostInfo->SetStage((PostInfo::EStage)iIntValue);
|
||||
|
||||
pPostQueue->push_back(pPostInfo);
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
return true;
|
||||
|
||||
error:
|
||||
fclose(infile);
|
||||
error("Error reading diskstate for file %s", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all files from Queue.
|
||||
* Returns true if successful, false if not
|
||||
*/
|
||||
bool DiskState::Discard()
|
||||
bool DiskState::DiscardDownloadQueue()
|
||||
{
|
||||
debug("Discarding queue");
|
||||
|
||||
@@ -295,15 +491,31 @@ bool DiskState::Discard()
|
||||
bool res = false;
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
if (!strcmp(FileSignatur, "nzbget diskstate file version 1\n"))
|
||||
if (!strcmp(FileSignatur, FORMATVERSION_SIGNATURE))
|
||||
{
|
||||
int id, paused;
|
||||
while (fscanf(infile, "%i,%i\n", &id, &paused) == 2)
|
||||
// skip nzb-infos
|
||||
int size = 0;
|
||||
char buf[1024];
|
||||
fscanf(infile, "%i\n", &size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
if (!fgets(buf, sizeof(buf), infile)) break;
|
||||
}
|
||||
|
||||
fscanf(infile, "%i\n", &size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
int id, group, paused;
|
||||
if (fscanf(infile, "%i,%i,%i\n", &id, &group, &paused) == 3)
|
||||
{
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), id);
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
}
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
@@ -322,27 +534,56 @@ bool DiskState::Discard()
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DiskState::Exists()
|
||||
/*
|
||||
* Delete all files from Queue.
|
||||
* Returns true if successful, false if not
|
||||
*/
|
||||
bool DiskState::DiscardPostQueue()
|
||||
{
|
||||
debug("Discarding post-queue");
|
||||
|
||||
char fileName[1024];
|
||||
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "postq");
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "postc");
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskState::DownloadQueueExists()
|
||||
{
|
||||
debug("Checking if a saved queue exists on disk");
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), "queue");
|
||||
fileName[1024-1] = '\0';
|
||||
struct stat buffer;
|
||||
bool fileExists = !stat(fileName, &buffer);
|
||||
return fileExists;
|
||||
return Util::FileExists(fileName);
|
||||
}
|
||||
|
||||
bool DiskState::PostQueueExists(bool bCompleted)
|
||||
{
|
||||
debug("Checking if a saved queue exists on disk");
|
||||
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%s", g_pOptions->GetQueueDir(), bCompleted ? "postc" : "postq");
|
||||
fileName[1024-1] = '\0';
|
||||
return Util::FileExists(fileName);
|
||||
}
|
||||
|
||||
bool DiskState::DiscardFile(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo)
|
||||
{
|
||||
// delete diskstate-file
|
||||
// delete diskstate-file for file-info
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
|
||||
fileName[1024-1] = '\0';
|
||||
remove(fileName);
|
||||
|
||||
return !pDownloadQueue || Save(pDownloadQueue);
|
||||
return !pDownloadQueue || SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
void DiskState::CleanupTempDir(DownloadQueue* pDownloadQueue)
|
||||
|
||||
15
DiskState.h
15
DiskState.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -27,6 +27,7 @@
|
||||
#define DISKSTATE_H
|
||||
|
||||
#include "DownloadInfo.h"
|
||||
#include "PostInfo.h"
|
||||
|
||||
class DiskState
|
||||
{
|
||||
@@ -35,12 +36,16 @@ private:
|
||||
bool LoadFileInfo(FileInfo* pFileInfo, const char* szFilename, bool bFileSummary, bool bArticles);
|
||||
|
||||
public:
|
||||
bool Exists();
|
||||
bool Save(DownloadQueue* pDownloadQueue);
|
||||
bool Load(DownloadQueue* pDownloadQueue);
|
||||
bool DownloadQueueExists();
|
||||
bool PostQueueExists(bool bCompleted);
|
||||
bool SaveDownloadQueue(DownloadQueue* pDownloadQueue);
|
||||
bool LoadDownloadQueue(DownloadQueue* pDownloadQueue);
|
||||
bool SaveFile(FileInfo* pFileInfo);
|
||||
bool LoadArticles(FileInfo* pFileInfo);
|
||||
bool Discard();
|
||||
bool SavePostQueue(PostQueue* pPostQueue, bool bCompleted);
|
||||
bool LoadPostQueue(PostQueue* pPostQueue, bool bCompleted);
|
||||
bool DiscardDownloadQueue();
|
||||
bool DiscardPostQueue();
|
||||
bool DiscardFile(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo);
|
||||
void CleanupTempDir(DownloadQueue* pDownloadQueue);
|
||||
};
|
||||
|
||||
263
DownloadInfo.cpp
263
DownloadInfo.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -43,6 +43,105 @@
|
||||
|
||||
int FileInfo::m_iIDGen = 0;
|
||||
|
||||
NZBInfo::NZBInfo()
|
||||
{
|
||||
debug("Creating NZBInfo");
|
||||
|
||||
m_szFilename = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_iFileCount = 0;
|
||||
m_lSize = 0;
|
||||
m_iRefCount = 0;
|
||||
}
|
||||
|
||||
NZBInfo::~NZBInfo()
|
||||
{
|
||||
debug("Destroying NZBInfo");
|
||||
|
||||
if (m_szFilename)
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::AddReference()
|
||||
{
|
||||
m_iRefCount++;
|
||||
}
|
||||
|
||||
void NZBInfo::Release()
|
||||
{
|
||||
m_iRefCount--;
|
||||
if (m_iRefCount <= 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void NZBInfo::SetDestDir(const char* szDestDir)
|
||||
{
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void NZBInfo::SetFilename(const char * szFilename)
|
||||
{
|
||||
m_szFilename = strdup(szFilename);
|
||||
}
|
||||
|
||||
void NZBInfo::GetNiceNZBName(char* szBuffer, int iSize)
|
||||
{
|
||||
MakeNiceNZBName(m_szFilename, szBuffer, iSize);
|
||||
}
|
||||
|
||||
void NZBInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize)
|
||||
{
|
||||
char postname[1024];
|
||||
const char* szBaseName = Util::BaseFileName(szNZBFilename);
|
||||
|
||||
// if .nzb file has a certain structure, try to strip out certain elements
|
||||
if (sscanf(szBaseName, "msgid_%*d_%1023s", postname) == 1)
|
||||
{
|
||||
// OK, using stripped name
|
||||
}
|
||||
else
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
}
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
|
||||
Util::MakeValidFilename(postname, '_');
|
||||
|
||||
// if the resulting name is empty, use basename without cleaning up "msgid_"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
|
||||
Util::MakeValidFilename(postname, '_');
|
||||
|
||||
// if the resulting name is STILL empty, use "noname"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
strncpy(postname, "noname", 1024);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(szBuffer, postname, iSize);
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
|
||||
ArticleInfo::ArticleInfo()
|
||||
{
|
||||
//debug("Creating ArticleInfo");
|
||||
@@ -86,8 +185,6 @@ FileInfo::FileInfo()
|
||||
m_szSubject = NULL;
|
||||
m_szFilename = NULL;
|
||||
m_bFilenameConfirmed = false;
|
||||
m_szDestDir = NULL;
|
||||
m_szNZBFilename = NULL;
|
||||
m_lSize = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_bPaused = false;
|
||||
@@ -110,14 +207,6 @@ FileInfo::~ FileInfo()
|
||||
{
|
||||
free(m_szFilename);
|
||||
}
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
|
||||
for (Groups::iterator it = m_Groups.begin(); it != m_Groups.end() ;it++)
|
||||
{
|
||||
@@ -126,6 +215,11 @@ FileInfo::~ FileInfo()
|
||||
m_Groups.clear();
|
||||
|
||||
ClearArticles();
|
||||
|
||||
if (m_pNZBInfo)
|
||||
{
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfo::ClearArticles()
|
||||
@@ -146,71 +240,17 @@ void FileInfo::SetID(int s)
|
||||
}
|
||||
}
|
||||
|
||||
void FileInfo::SetNZBInfo(NZBInfo* pNZBInfo)
|
||||
{
|
||||
m_pNZBInfo = pNZBInfo;
|
||||
m_pNZBInfo->AddReference();
|
||||
}
|
||||
|
||||
void FileInfo::SetSubject(const char* szSubject)
|
||||
{
|
||||
m_szSubject = strdup(szSubject);
|
||||
}
|
||||
|
||||
void FileInfo::SetDestDir(const char* szDestDir)
|
||||
{
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void FileInfo::SetNZBFilename(const char * szNZBFilename)
|
||||
{
|
||||
m_szNZBFilename = strdup(szNZBFilename);
|
||||
}
|
||||
|
||||
void FileInfo::GetNiceNZBName(char* szBuffer, int iSize)
|
||||
{
|
||||
MakeNiceNZBName(m_szNZBFilename, szBuffer, iSize);
|
||||
}
|
||||
|
||||
void FileInfo::MakeNiceNZBName(const char * szNZBFilename, char * szBuffer, int iSize)
|
||||
{
|
||||
char postname[1024];
|
||||
const char* szBaseName = BaseFileName(szNZBFilename);
|
||||
|
||||
// if .nzb file has a certain structure, try to strip out certain elements
|
||||
if (sscanf(szBaseName, "msgid_%*d_%1023s", postname) == 1)
|
||||
{
|
||||
// OK, using stripped name
|
||||
}
|
||||
else
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
}
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
|
||||
::MakeValidFilename(postname, '_');
|
||||
|
||||
// if the resulting name is empty, use basename without cleaing up "msgid_"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
// using complete filename
|
||||
strncpy(postname, szBaseName, 1024);
|
||||
postname[1024-1] = '\0';
|
||||
|
||||
// wipe out ".nzb"
|
||||
if (char* p = strrchr(postname, '.')) *p = '\0';
|
||||
|
||||
::MakeValidFilename(postname, '_');
|
||||
|
||||
// if the resulting name is STILL empty, use "noname"
|
||||
if (strlen(postname) == 0)
|
||||
{
|
||||
strncpy(postname, "noname", 1024);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(szBuffer, postname, iSize);
|
||||
szBuffer[iSize-1] = '\0';
|
||||
}
|
||||
|
||||
void FileInfo::SetFilename(const char* szFilename)
|
||||
{
|
||||
if (m_szFilename)
|
||||
@@ -222,7 +262,7 @@ void FileInfo::SetFilename(const char* szFilename)
|
||||
|
||||
void FileInfo::MakeValidFilename()
|
||||
{
|
||||
::MakeValidFilename(m_szFilename, '_');
|
||||
Util::MakeValidFilename(m_szFilename, '_');
|
||||
}
|
||||
|
||||
void FileInfo::LockOutputFile()
|
||||
@@ -237,22 +277,87 @@ void FileInfo::UnlockOutputFile()
|
||||
|
||||
bool FileInfo::IsDupe(const char* szFilename)
|
||||
{
|
||||
struct stat buffer;
|
||||
char fileName[1024];
|
||||
snprintf(fileName, 1024, "%s%c%s", m_szDestDir, (int)PATH_SEPARATOR, szFilename);
|
||||
snprintf(fileName, 1024, "%s%c%s", m_pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, szFilename);
|
||||
fileName[1024-1] = '\0';
|
||||
bool exists = !stat(fileName, &buffer);
|
||||
if (exists)
|
||||
if (Util::FileExists(fileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
snprintf(fileName, 1024, "%s%c%s_broken", m_szDestDir, (int)PATH_SEPARATOR, szFilename);
|
||||
snprintf(fileName, 1024, "%s%c%s_broken", m_pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, szFilename);
|
||||
fileName[1024-1] = '\0';
|
||||
exists = !stat(fileName, &buffer);
|
||||
if (exists)
|
||||
if (Util::FileExists(fileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GroupInfo::GroupInfo()
|
||||
{
|
||||
m_iFirstID = 0;
|
||||
m_iLastID = 0;
|
||||
m_iRemainingFileCount = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_lPausedSize = 0;
|
||||
m_iRemainingParCount = 0;
|
||||
}
|
||||
|
||||
GroupInfo::~GroupInfo()
|
||||
{
|
||||
if (m_pNZBInfo)
|
||||
{
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupInfo::BuildGroups(DownloadQueue* pDownloadQueue, GroupQueue* pGroupQueue)
|
||||
{
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
GroupInfo* pGroupInfo = NULL;
|
||||
for (GroupQueue::iterator itg = pGroupQueue->begin(); itg != pGroupQueue->end(); itg++)
|
||||
{
|
||||
GroupInfo* pGroupInfo1 = *itg;
|
||||
if (pGroupInfo1->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
pGroupInfo = pGroupInfo1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pGroupInfo)
|
||||
{
|
||||
pGroupInfo = new GroupInfo();
|
||||
pGroupInfo->m_pNZBInfo = pFileInfo->GetNZBInfo();
|
||||
pGroupInfo->m_pNZBInfo->AddReference();
|
||||
pGroupInfo->m_iFirstID = pFileInfo->GetID();
|
||||
pGroupInfo->m_iLastID = pFileInfo->GetID();
|
||||
pGroupQueue->push_back(pGroupInfo);
|
||||
}
|
||||
if (pFileInfo->GetID() < pGroupInfo->GetFirstID())
|
||||
{
|
||||
pGroupInfo->m_iFirstID = pFileInfo->GetID();
|
||||
}
|
||||
if (pFileInfo->GetID() > pGroupInfo->GetLastID())
|
||||
{
|
||||
pGroupInfo->m_iLastID = pFileInfo->GetID();
|
||||
}
|
||||
pGroupInfo->m_iRemainingFileCount++;
|
||||
pGroupInfo->m_lRemainingSize += pFileInfo->GetRemainingSize();
|
||||
if (pFileInfo->GetPaused())
|
||||
{
|
||||
pGroupInfo->m_lPausedSize += pFileInfo->GetRemainingSize();
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
pGroupInfo->m_iRemainingParCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -32,6 +32,32 @@
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
class NZBInfo
|
||||
{
|
||||
private:
|
||||
int m_iRefCount;
|
||||
char* m_szFilename;
|
||||
char* m_szDestDir;
|
||||
int m_iFileCount;
|
||||
long long m_lSize;
|
||||
|
||||
public:
|
||||
NZBInfo();
|
||||
~NZBInfo();
|
||||
void AddReference();
|
||||
void Release();
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
void SetFilename(const char* szFilename);
|
||||
void GetNiceNZBName(char* szBuffer, int iSize);
|
||||
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize);
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
void SetDestDir(const char* szDestDir);
|
||||
long long GetSize() { return m_lSize; }
|
||||
void SetSize(long long s) { m_lSize = s; }
|
||||
int GetFileCount() { return m_iFileCount; }
|
||||
void SetFileCount(int s) { m_iFileCount = s; }
|
||||
};
|
||||
|
||||
class ArticleInfo
|
||||
{
|
||||
public:
|
||||
@@ -73,12 +99,11 @@ public:
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
NZBInfo* m_pNZBInfo;
|
||||
Articles m_Articles;
|
||||
Groups m_Groups;
|
||||
char* m_szNZBFilename;
|
||||
char* m_szSubject;
|
||||
char* m_szFilename;
|
||||
char* m_szDestDir;
|
||||
long long m_lSize;
|
||||
long long m_lRemainingSize;
|
||||
bool m_bPaused;
|
||||
@@ -95,12 +120,10 @@ public:
|
||||
~FileInfo();
|
||||
int GetID() { return m_iID; }
|
||||
void SetID(int s);
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
void SetNZBInfo(NZBInfo* pNZBInfo);
|
||||
Articles* GetArticles() { return &m_Articles; }
|
||||
Groups* GetGroups() { return &m_Groups; }
|
||||
const char* GetNZBFilename() { return m_szNZBFilename; }
|
||||
void SetNZBFilename(const char* szNZBFilename);
|
||||
void GetNiceNZBName(char* szBuffer, int iSize);
|
||||
static void MakeNiceNZBName(const char* szNZBFilename, char* szBuffer, int iSize);
|
||||
const char* GetSubject() { return m_szSubject; }
|
||||
void SetSubject(const char* szSubject);
|
||||
const char* GetFilename() { return m_szFilename; }
|
||||
@@ -116,8 +139,6 @@ public:
|
||||
void SetPaused(bool Paused) { m_bPaused = Paused; }
|
||||
bool GetDeleted() { return m_bDeleted; }
|
||||
void SetDeleted(bool Deleted) { m_bDeleted = Deleted; }
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
void SetDestDir(const char* szDestDir);
|
||||
int GetCompleted() { return m_iCompleted; }
|
||||
void SetCompleted(int s) { m_iCompleted = s; }
|
||||
void ClearArticles();
|
||||
@@ -130,4 +151,32 @@ public:
|
||||
|
||||
typedef std::deque<FileInfo*> DownloadQueue;
|
||||
|
||||
class GroupInfo;
|
||||
typedef std::deque<GroupInfo*> GroupQueue;
|
||||
|
||||
class GroupInfo
|
||||
{
|
||||
private:
|
||||
NZBInfo* m_pNZBInfo;
|
||||
int m_iFirstID;
|
||||
int m_iLastID;
|
||||
int m_iRemainingFileCount;
|
||||
long long m_lRemainingSize;
|
||||
long long m_lPausedSize;
|
||||
int m_iRemainingParCount;
|
||||
|
||||
public:
|
||||
GroupInfo();
|
||||
~GroupInfo();
|
||||
NZBInfo* GetNZBInfo() { return m_pNZBInfo; }
|
||||
int GetFirstID() { return m_iFirstID; }
|
||||
int GetLastID() { return m_iLastID; }
|
||||
long long GetRemainingSize() { return m_lRemainingSize; }
|
||||
long long GetPausedSize() { return m_lPausedSize; }
|
||||
int GetRemainingFileCount() { return m_iRemainingFileCount; }
|
||||
int GetRemainingParCount() { return m_iRemainingParCount; }
|
||||
|
||||
static void BuildGroups(DownloadQueue* pDownloadQueue, GroupQueue* pGroupQueue);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
50
Frontend.cpp
50
Frontend.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -68,7 +68,7 @@ Frontend::Frontend()
|
||||
m_bPause = false;
|
||||
m_fDownloadLimit = 0;
|
||||
m_iThreadCount = 0;
|
||||
m_iParJobCount = 0;
|
||||
m_iPostJobCount = 0;
|
||||
m_iUpTimeSec = 0;
|
||||
m_iDnTimeSec = 0;
|
||||
m_iAllBytes = 0;
|
||||
@@ -102,9 +102,9 @@ bool Frontend::PrepareData()
|
||||
m_bPause = g_pOptions->GetPause();
|
||||
m_fDownloadLimit = g_pOptions->GetDownloadRate();
|
||||
m_iThreadCount = Thread::GetThreadCount();
|
||||
PrePostProcessor::ParQueue* pParQueue = g_pPrePostProcessor->LockParQueue();
|
||||
m_iParJobCount = pParQueue->size();
|
||||
g_pPrePostProcessor->UnlockParQueue();
|
||||
PostQueue* pPostQueue = g_pPrePostProcessor->LockPostQueue();
|
||||
m_iPostJobCount = pPostQueue->size();
|
||||
g_pPrePostProcessor->UnlockPostQueue();
|
||||
g_pQueueCoordinator->CalcStat(&m_iUpTimeSec, &m_iDnTimeSec, &m_iAllBytes, &m_bStandBy);
|
||||
}
|
||||
}
|
||||
@@ -351,19 +351,22 @@ bool Frontend::RequestFileList()
|
||||
if (m_bSummary)
|
||||
{
|
||||
m_bPause = ntohl(ListResponse.m_bServerPaused);
|
||||
m_lRemainingSize = JoinInt64(ntohl(ListResponse.m_iRemainingSizeHi), ntohl(ListResponse.m_iRemainingSizeLo));
|
||||
m_fCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate) / 1024.0;
|
||||
m_fDownloadLimit = ntohl(ListResponse.m_iDownloadLimit) / 1024.0;
|
||||
m_lRemainingSize = Util::JoinInt64(ntohl(ListResponse.m_iRemainingSizeHi), ntohl(ListResponse.m_iRemainingSizeLo));
|
||||
m_fCurrentDownloadSpeed = ntohl(ListResponse.m_iDownloadRate) / 1024.0f;
|
||||
m_fDownloadLimit = ntohl(ListResponse.m_iDownloadLimit) / 1024.0f;
|
||||
m_iThreadCount = ntohl(ListResponse.m_iThreadCount);
|
||||
m_iParJobCount = ntohl(ListResponse.m_iParJobCount);
|
||||
m_iPostJobCount = ntohl(ListResponse.m_iPostJobCount);
|
||||
m_iUpTimeSec = ntohl(ListResponse.m_iUpTimeSec);
|
||||
m_iDnTimeSec = ntohl(ListResponse.m_iDownloadTimeSec);
|
||||
m_bStandBy = ntohl(ListResponse.m_bServerStandBy);
|
||||
m_iAllBytes = JoinInt64(ntohl(ListResponse.m_iDownloadedBytesHi), ntohl(ListResponse.m_iDownloadedBytesLo));
|
||||
m_iAllBytes = Util::JoinInt64(ntohl(ListResponse.m_iDownloadedBytesHi), ntohl(ListResponse.m_iDownloadedBytesLo));
|
||||
}
|
||||
|
||||
if (m_bFileList && ntohl(ListResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
typedef std::deque<NZBInfo*> NZBList;
|
||||
NZBList cNZBList;
|
||||
|
||||
char* pBufPtr = (char*)pBuf;
|
||||
for (unsigned int i = 0; i < ntohl(ListResponse.m_iNrTrailingEntries); i++)
|
||||
{
|
||||
@@ -376,14 +379,33 @@ bool Frontend::RequestFileList()
|
||||
|
||||
FileInfo* pFileInfo = new FileInfo();
|
||||
pFileInfo->SetID(ntohl(pListAnswer->m_iID));
|
||||
pFileInfo->SetSize(JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo)));
|
||||
pFileInfo->SetRemainingSize(JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
|
||||
pFileInfo->SetSize(Util::JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo)));
|
||||
pFileInfo->SetRemainingSize(Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
|
||||
pFileInfo->SetPaused(ntohl(pListAnswer->m_bPaused));
|
||||
pFileInfo->SetNZBFilename(szNZBFilename);
|
||||
pFileInfo->SetSubject(szSubject);
|
||||
pFileInfo->SetFilename(szFileName);
|
||||
pFileInfo->SetFilenameConfirmed(ntohl(pListAnswer->m_bFilenameConfirmed));
|
||||
pFileInfo->SetDestDir(szDestDir);
|
||||
|
||||
// find nzb-info or create new
|
||||
NZBInfo* pNZBInfo = NULL;
|
||||
for (NZBList::iterator it = cNZBList.begin(); it != cNZBList.end(); it++)
|
||||
{
|
||||
NZBInfo* pNZBInfo2 = *it;
|
||||
if (!strcmp(pNZBInfo2->GetFilename(), szNZBFilename))
|
||||
{
|
||||
pNZBInfo = pNZBInfo2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pNZBInfo)
|
||||
{
|
||||
pNZBInfo = new NZBInfo();
|
||||
pNZBInfo->SetFilename(szNZBFilename);
|
||||
pNZBInfo->SetDestDir(szDestDir);
|
||||
cNZBList.push_back(pNZBInfo);
|
||||
}
|
||||
|
||||
pFileInfo->SetNZBInfo(pNZBInfo);
|
||||
|
||||
m_RemoteQueue.push_back(pFileInfo);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -55,7 +55,7 @@ protected:
|
||||
bool m_bPause;
|
||||
float m_fDownloadLimit;
|
||||
int m_iThreadCount;
|
||||
int m_iParJobCount;
|
||||
int m_iPostJobCount;
|
||||
int m_iUpTimeSec;
|
||||
int m_iDnTimeSec;
|
||||
long long m_iAllBytes;
|
||||
|
||||
34
Log.cpp
34
Log.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -50,8 +50,7 @@ Log::Log()
|
||||
m_iIDGen = 0;
|
||||
m_szLogFilename = NULL;
|
||||
#ifdef DEBUG
|
||||
struct stat buffer;
|
||||
m_bExtraDebug = !stat("extradebug", &buffer);
|
||||
m_bExtraDebug = Util::FileExists("extradebug");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -144,11 +143,11 @@ void debug(const char* msg, ...)
|
||||
#ifdef HAVE_VARIADIC_MACROS
|
||||
if (szFuncname)
|
||||
{
|
||||
snprintf(tmp2, 1024, "%s (%s:%i:%s)", tmp1, BaseFileName(szFilename), iLineNr, szFuncname);
|
||||
snprintf(tmp2, 1024, "%s (%s:%i:%s)", tmp1, Util::BaseFileName(szFilename), iLineNr, szFuncname);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(tmp2, 1024, "%s (%s:%i)", tmp1, BaseFileName(szFilename), iLineNr);
|
||||
snprintf(tmp2, 1024, "%s (%s:%i)", tmp1, Util::BaseFileName(szFilename), iLineNr);
|
||||
}
|
||||
#else
|
||||
snprintf(tmp2, 1024, "%s", tmp1);
|
||||
@@ -257,6 +256,31 @@ void info(const char* msg, ...)
|
||||
g_pLog->m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void detail(const char* msg, ...)
|
||||
{
|
||||
char tmp2[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vsnprintf(tmp2, 1024, msg, ap);
|
||||
tmp2[1024-1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
g_pLog->m_mutexLog.Lock();
|
||||
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetDetailTarget();
|
||||
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->Filelog("DETAIL\t%s", tmp2);
|
||||
}
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
g_pLog->AppendMessage(Message::mkDetail, tmp2);
|
||||
}
|
||||
|
||||
g_pLog->m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void abort(const char* msg, ...)
|
||||
{
|
||||
char tmp2[1024];
|
||||
|
||||
7
Log.h
7
Log.h
@@ -35,6 +35,7 @@
|
||||
void error(const char* msg, ...);
|
||||
void warn(const char* msg, ...);
|
||||
void info(const char* msg, ...);
|
||||
void detail(const char* msg, ...);
|
||||
void abort(const char* msg, ...);
|
||||
|
||||
#ifdef HAVE_VARIADIC_MACROS
|
||||
@@ -49,10 +50,11 @@ class Message
|
||||
public:
|
||||
enum EKind
|
||||
{
|
||||
mkInfo,
|
||||
mkInfo,
|
||||
mkWarning,
|
||||
mkError,
|
||||
mkDebug
|
||||
mkDebug,
|
||||
mkDetail
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -91,6 +93,7 @@ private:
|
||||
friend void warn(const char* msg, ...);
|
||||
friend void info(const char* msg, ...);
|
||||
friend void abort(const char* msg, ...);
|
||||
friend void detail(const char* msg, ...);
|
||||
#ifdef HAVE_VARIADIC_MACROS
|
||||
friend void debug(const char* szFilename, const char* szFuncname, int iLineNr, const char* msg, ...);
|
||||
#else
|
||||
|
||||
@@ -126,6 +126,9 @@ void LoggableFrontend::PrintMessage(Message * pMessage)
|
||||
case Message::mkInfo:
|
||||
printf("[INFO] %s\n", msg);
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
printf("[DETAIL] %s\n", msg);
|
||||
break;
|
||||
}
|
||||
#ifdef WIN32
|
||||
free(msg);
|
||||
|
||||
@@ -8,7 +8,8 @@ nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h ColoredFrontend.cpp \
|
||||
ParChecker.cpp ParChecker.h PrePostProcessor.cpp PrePostProcessor.h \
|
||||
QueueCoordinator.cpp QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp \
|
||||
RemoteClient.h RemoteServer.cpp RemoteServer.h ServerPool.cpp ServerPool.h Thread.cpp \
|
||||
Thread.h Util.cpp Util.h nzbget.cpp nzbget.h
|
||||
Thread.h Util.cpp Util.h nzbget.cpp nzbget.h BinRpc.cpp BinRpc.h XmlRpc.cpp XmlRpc.h \
|
||||
PostInfo.cpp PostInfo.h ScriptController.cpp ScriptController.h
|
||||
|
||||
EXTRA_DIST = nzbget.conf.example \
|
||||
win32.h NTService.cpp NTService.h \
|
||||
|
||||
10
Makefile.in
10
Makefile.in
@@ -60,7 +60,8 @@ am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) \
|
||||
PrePostProcessor.$(OBJEXT) QueueCoordinator.$(OBJEXT) \
|
||||
QueueEditor.$(OBJEXT) RemoteClient.$(OBJEXT) \
|
||||
RemoteServer.$(OBJEXT) ServerPool.$(OBJEXT) Thread.$(OBJEXT) \
|
||||
Util.$(OBJEXT) nzbget.$(OBJEXT)
|
||||
Util.$(OBJEXT) nzbget.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
XmlRpc.$(OBJEXT) PostInfo.$(OBJEXT) ScriptController.$(OBJEXT)
|
||||
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
|
||||
nzbget_LDADD = $(LDADD)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
@@ -208,7 +209,8 @@ nzbget_SOURCES = ArticleDownloader.cpp ArticleDownloader.h ColoredFrontend.cpp \
|
||||
ParChecker.cpp ParChecker.h PrePostProcessor.cpp PrePostProcessor.h \
|
||||
QueueCoordinator.cpp QueueCoordinator.h QueueEditor.cpp QueueEditor.h RemoteClient.cpp \
|
||||
RemoteClient.h RemoteServer.cpp RemoteServer.h ServerPool.cpp ServerPool.h Thread.cpp \
|
||||
Thread.h Util.cpp Util.h nzbget.cpp nzbget.h
|
||||
Thread.h Util.cpp Util.h nzbget.cpp nzbget.h BinRpc.cpp BinRpc.h XmlRpc.cpp XmlRpc.h \
|
||||
PostInfo.cpp PostInfo.h ScriptController.cpp ScriptController.h
|
||||
|
||||
EXTRA_DIST = nzbget.conf.example \
|
||||
win32.h NTService.cpp NTService.h \
|
||||
@@ -304,6 +306,7 @@ distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArticleDownloader.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BinRpc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColoredFrontend.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Connection.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Decoder.Po@am__quote@
|
||||
@@ -320,14 +323,17 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Observer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Options.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParChecker.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PostInfo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PrePostProcessor.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueEditor.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RemoteClient.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RemoteServer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ScriptController.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nzbget.Po@am__quote@
|
||||
|
||||
.cpp.o:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -36,16 +36,9 @@ static const int NZBREQUESTPASSWORDSIZE = 32;
|
||||
* Integer values are passed using network byte order (Big-Endian).
|
||||
* Use function "htonl" and "ntohl" to convert integers to/from machine
|
||||
' (host) byte order.
|
||||
* All char-strings must end with NULL-char.
|
||||
* All char-strings ends with NULL-char.
|
||||
*/
|
||||
|
||||
// The pack-directive prevents aligning of structs.
|
||||
// This makes them more portable and allows to use together servers and clients
|
||||
// compiled on different cpu architectures
|
||||
#ifdef HAVE_PRAGMA_PACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
// Possible values for field "m_iType" of struct "SNZBRequestBase":
|
||||
enum eRemoteRequest
|
||||
{
|
||||
@@ -57,7 +50,9 @@ enum eRemoteRequest
|
||||
eRemoteRequestEditQueue,
|
||||
eRemoteRequestLog,
|
||||
eRemoteRequestShutdown,
|
||||
eRemoteRequestVersion
|
||||
eRemoteRequestVersion,
|
||||
eRemoteRequestPostQueue,
|
||||
eRemoteRequestWriteLog
|
||||
};
|
||||
|
||||
// Possible values for field "m_iAction" of struct "SNZBEditQueueRequest":
|
||||
@@ -137,7 +132,7 @@ struct SNZBListResponse
|
||||
int32_t m_iDownloadLimit; // Current download limit, in Bytes pro Second
|
||||
int32_t m_bServerPaused; // 1 - server is currently in paused-state
|
||||
int32_t m_iThreadCount; // Number of threads running
|
||||
int32_t m_iParJobCount; // Number of ParJobs in Par-Checker queue (including current file)
|
||||
int32_t m_iPostJobCount; // Number of jobs in post-processor queue (including current job)
|
||||
int32_t m_iUpTimeSec; // Server up time in seconds
|
||||
int32_t m_iDownloadTimeSec; // Server download time in seconds (up_time - standby_time)
|
||||
int32_t m_iDownloadedBytesLo; // Amount of data downloaded since server start, Low 32-bits of 64-bit value
|
||||
@@ -295,8 +290,59 @@ struct SNZBVersionResponse
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
#ifdef HAVE_PRAGMA_PACK
|
||||
#pragma pack()
|
||||
#endif
|
||||
// PostQueue request
|
||||
struct SNZBPostQueueRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
};
|
||||
|
||||
// A PostQueue response
|
||||
struct SNZBPostQueueResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_iEntrySize; // Size of the SNZBPostQueueResponseEntry-struct
|
||||
int32_t m_iNrTrailingEntries; // Number of PostQueue-entries, following to this structure
|
||||
int32_t m_iTrailingDataLength; // Length of all PostQueue-entries, following to this structure
|
||||
// SNZBPostQueueResponseEntry m_Entries[m_iNrTrailingEntries] // variable sized
|
||||
};
|
||||
|
||||
// A PostQueue response entry
|
||||
struct SNZBPostQueueResponseEntry
|
||||
{
|
||||
int32_t m_iID; // ID of Post-entry
|
||||
int32_t m_iStage; // See PrePostProcessor::EPostJobStage
|
||||
int32_t m_iStageProgress; // Progress of current stage, value in range 0..1000
|
||||
int32_t m_iFileProgress; // Progress of current file, value in range 0..1000
|
||||
int32_t m_iTotalTimeSec; // Number of seconds this post-job is beeing processed (after it first changed the state from QUEUED).
|
||||
int32_t m_iStageTimeSec; // Number of seconds the current stage is beeing processed.
|
||||
int32_t m_iNZBFilenameLen; // Length of NZBFileName-string (m_szNZBFilename), following to this record
|
||||
int32_t m_iParFilename; // Length of ParFilename-string (m_szParFilename), following to this record
|
||||
int32_t m_iInfoNameLen; // Length of Filename-string (m_szFilename), following to this record
|
||||
int32_t m_iDestDirLen; // Length of DestDir-string (m_szDestDir), following to this record
|
||||
int32_t m_iProgressLabelLen; // Length of ProgressLabel-string (m_szProgressLabel), following to this record
|
||||
//char m_szNZBFilename[m_iNZBFilenameLen]; // variable sized, may contain full path (local path on client) or only filename
|
||||
//char m_szParFilename[m_iParFilename]; // variable sized
|
||||
//char m_szInfoName[m_iInfoNameLen]; // variable sized
|
||||
//char m_szDestDir[m_iDestDirLen]; // variable sized
|
||||
//char m_szProgressLabel[m_iProgressLabelLen]; // variable sized
|
||||
};
|
||||
|
||||
// Write log request
|
||||
struct SNZBWriteLogRequest
|
||||
{
|
||||
SNZBRequestBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_iKind; // see Message::Kind in "Log.h"
|
||||
int32_t m_iTrailingDataLength; // Length of nzb-file in bytes
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
// Write log response
|
||||
struct SNZBWriteLogResponse
|
||||
{
|
||||
SNZBResponseBase m_MessageBase; // Must be the first in the struct
|
||||
int32_t m_bSuccess; // 0 - command failed, 1 - command executed successfully
|
||||
int32_t m_iTrailingDataLength; // Length of Text-string (m_szText), following to this record
|
||||
//char m_szText[m_iTrailingDataLength]; // variable sized
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "nzbget.h"
|
||||
#include "NCursesFrontend.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
#ifdef HAVE_CURSES_H
|
||||
// curses.h header must be included last to avoid problems on Solaris
|
||||
@@ -67,11 +68,12 @@ static const int NCURSES_COLORPAIR_INFO = 2;
|
||||
static const int NCURSES_COLORPAIR_WARNING = 3;
|
||||
static const int NCURSES_COLORPAIR_ERROR = 4;
|
||||
static const int NCURSES_COLORPAIR_DEBUG = 5;
|
||||
static const int NCURSES_COLORPAIR_STATUS = 6;
|
||||
static const int NCURSES_COLORPAIR_KEYBAR = 7;
|
||||
static const int NCURSES_COLORPAIR_INFOLINE = 8;
|
||||
static const int NCURSES_COLORPAIR_TEXTHIGHL = 9;
|
||||
static const int NCURSES_COLORPAIR_CURSOR = 10;
|
||||
static const int NCURSES_COLORPAIR_DETAIL = 6;
|
||||
static const int NCURSES_COLORPAIR_STATUS = 7;
|
||||
static const int NCURSES_COLORPAIR_KEYBAR = 8;
|
||||
static const int NCURSES_COLORPAIR_INFOLINE = 9;
|
||||
static const int NCURSES_COLORPAIR_TEXTHIGHL = 10;
|
||||
static const int NCURSES_COLORPAIR_CURSOR = 11;
|
||||
|
||||
static const int MAX_SCREEN_WIDTH = 512;
|
||||
|
||||
@@ -101,25 +103,6 @@ static const int READKEY_EMPTY = ERR;
|
||||
|
||||
#endif
|
||||
|
||||
NCursesFrontend::GroupInfo::GroupInfo(int iID, const char* szNZBFilename)
|
||||
{
|
||||
m_iID = iID;
|
||||
m_szNZBFilename = strdup(szNZBFilename);
|
||||
m_iFileCount = 0;
|
||||
m_lSize = 0;
|
||||
m_lRemainingSize = 0;
|
||||
m_lPausedSize = 0;
|
||||
m_iParCount = 0;
|
||||
}
|
||||
|
||||
NCursesFrontend::GroupInfo::~GroupInfo()
|
||||
{
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
}
|
||||
|
||||
NCursesFrontend::NCursesFrontend()
|
||||
{
|
||||
m_iScreenHeight = 0;
|
||||
@@ -193,6 +176,7 @@ NCursesFrontend::NCursesFrontend()
|
||||
init_pair(NCURSES_COLORPAIR_WARNING, COLOR_MAGENTA, COLOR_BLACK);
|
||||
init_pair(NCURSES_COLORPAIR_ERROR, COLOR_RED, COLOR_BLACK);
|
||||
init_pair(NCURSES_COLORPAIR_DEBUG, COLOR_WHITE, COLOR_BLACK);
|
||||
init_pair(NCURSES_COLORPAIR_DETAIL, COLOR_GREEN, COLOR_BLACK);
|
||||
init_pair(NCURSES_COLORPAIR_STATUS, COLOR_BLUE, COLOR_WHITE);
|
||||
init_pair(NCURSES_COLORPAIR_KEYBAR, COLOR_WHITE, COLOR_BLUE);
|
||||
init_pair(NCURSES_COLORPAIR_INFOLINE, COLOR_WHITE, COLOR_BLUE);
|
||||
@@ -240,7 +224,7 @@ void NCursesFrontend::Run()
|
||||
{
|
||||
// The data (queue and log) is updated each m_iUpdateInterval msec,
|
||||
// but the window is updated more often for better reaction on user's input
|
||||
if (iScreenUpdatePos <= 0)
|
||||
if (iScreenUpdatePos <= 0 || m_iDataUpdatePos <= 0)
|
||||
{
|
||||
iScreenUpdatePos = iScreenUpdateInterval;
|
||||
Update();
|
||||
@@ -335,9 +319,9 @@ void NCursesFrontend::CalcWindowSizes()
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_iScreenBufferSize = iNrRows * iNrColumns * sizeof(CHAR_INFO);
|
||||
m_pScreenBuffer = (CHAR_INFO*)malloc(m_iScreenBufferSize);
|
||||
m_pScreenBuffer = (CHAR_INFO*)realloc(m_pScreenBuffer, m_iScreenBufferSize);
|
||||
memset(m_pScreenBuffer, 0, m_iScreenBufferSize);
|
||||
m_pOldScreenBuffer = (CHAR_INFO*)malloc(m_iScreenBufferSize);
|
||||
m_pOldScreenBuffer = (CHAR_INFO*)realloc(m_pOldScreenBuffer, m_iScreenBufferSize);
|
||||
memset(m_pOldScreenBuffer, 0, m_iScreenBufferSize);
|
||||
#else
|
||||
clear();
|
||||
@@ -517,9 +501,9 @@ void NCursesFrontend::PrintMessages()
|
||||
|
||||
int NCursesFrontend::PrintMessage(Message* Msg, int iRow, int iMaxLines)
|
||||
{
|
||||
char* szMessageType[] = { "INFO ", "WARNING ", "ERROR ", "DEBUG "};
|
||||
char* szMessageType[] = { "INFO ", "WARNING ", "ERROR ", "DEBUG ", "DETAIL "};
|
||||
const int iMessageTypeColor[] = { NCURSES_COLORPAIR_INFO, NCURSES_COLORPAIR_WARNING,
|
||||
NCURSES_COLORPAIR_ERROR, NCURSES_COLORPAIR_DEBUG };
|
||||
NCURSES_COLORPAIR_ERROR, NCURSES_COLORPAIR_DEBUG, NCURSES_COLORPAIR_DETAIL };
|
||||
|
||||
char* szText = (char*)Msg->GetText();
|
||||
|
||||
@@ -546,10 +530,10 @@ int NCursesFrontend::PrintMessage(Message* Msg, int iRow, int iMaxLines)
|
||||
szText = strdup(szText);
|
||||
}
|
||||
|
||||
// replace CR and LF characters with spaces
|
||||
// replace some special characters with spaces
|
||||
for (char* p = szText; *p; p++)
|
||||
{
|
||||
if (*p == '\n' || *p == '\r')
|
||||
if (*p == '\n' || *p == '\r' || *p == '\b')
|
||||
{
|
||||
*p = ' ';
|
||||
}
|
||||
@@ -596,9 +580,9 @@ void NCursesFrontend::PrintStatus()
|
||||
if (fCurrentDownloadSpeed > 0.0 && !m_bPause)
|
||||
{
|
||||
long long remain_sec = (long long)(m_lRemainingSize / (fCurrentDownloadSpeed * 1024));
|
||||
int h = remain_sec / 3600;
|
||||
int m = (remain_sec % 3600) / 60;
|
||||
int s = remain_sec % 60;
|
||||
int h = (int)(remain_sec / 3600);
|
||||
int m = (int)((remain_sec % 3600) / 60);
|
||||
int s = (int)(remain_sec % 60);
|
||||
sprintf(timeString, " (~ %.2d:%.2d:%.2d)", h, m, s);
|
||||
}
|
||||
|
||||
@@ -612,21 +596,21 @@ void NCursesFrontend::PrintStatus()
|
||||
szDownloadLimit[0] = 0;
|
||||
}
|
||||
|
||||
char szParStatus[128];
|
||||
if (m_iParJobCount > 0)
|
||||
char szPostStatus[128];
|
||||
if (m_iPostJobCount > 0)
|
||||
{
|
||||
sprintf(szParStatus, ", %i par%s", m_iParJobCount, m_iParJobCount > 1 ? "s" : "");
|
||||
sprintf(szPostStatus, ", %i post-job%s", m_iPostJobCount, m_iPostJobCount > 1 ? "s" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
szParStatus[0] = 0;
|
||||
szPostStatus[0] = 0;
|
||||
}
|
||||
|
||||
float fAverageSpeed = m_iDnTimeSec > 0 ? m_iAllBytes / m_iDnTimeSec / 1024 : 0;
|
||||
float fAverageSpeed = Util::Int64ToFloat(m_iDnTimeSec > 0 ? m_iAllBytes / m_iDnTimeSec / 1024 : 0);
|
||||
|
||||
snprintf(tmp, MAX_SCREEN_WIDTH, " %d threads, %.0f KB/s, %.2f MB remaining%s%s%s%s, Avg. %.0f KB/s",
|
||||
m_iThreadCount, fCurrentDownloadSpeed, (float)(m_lRemainingSize / 1024.0 / 1024.0), timeString,
|
||||
szParStatus, m_bPause ? (m_bStandBy ? ", Paused" : ", Pausing") : "", szDownloadLimit, fAverageSpeed);
|
||||
m_iThreadCount, fCurrentDownloadSpeed, (float)(Util::Int64ToFloat(m_lRemainingSize) / 1024.0 / 1024.0), timeString,
|
||||
szPostStatus, m_bPause ? (m_bStandBy ? ", Paused" : ", Pausing") : "", szDownloadLimit, fAverageSpeed);
|
||||
tmp[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
PlotLine(tmp, iStatusRow, 0, NCURSES_COLORPAIR_STATUS);
|
||||
}
|
||||
@@ -769,13 +753,13 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
|
||||
szCompleted[0] = '\0';
|
||||
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
|
||||
{
|
||||
sprintf(szCompleted, ", %i%%", (int)(100 - pFileInfo->GetRemainingSize() * 100.0 / pFileInfo->GetSize()));
|
||||
sprintf(szCompleted, ", %i%%", (int)(100 - Util::Int64ToFloat(pFileInfo->GetRemainingSize()) * 100.0 / Util::Int64ToFloat(pFileInfo->GetSize())));
|
||||
}
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
if (m_bShowNZBname)
|
||||
{
|
||||
pFileInfo->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
int len = strlen(szNZBNiceName);
|
||||
szNZBNiceName[len] = PATH_SEPARATOR;
|
||||
szNZBNiceName[len + 1] = '\0';
|
||||
@@ -786,7 +770,9 @@ void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelect
|
||||
}
|
||||
|
||||
char szBuffer[MAX_SCREEN_WIDTH];
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(), Brace2, szNZBNiceName, pFileInfo->GetFilename(), pFileInfo->GetSize() / 1024.0 / 1024.0, szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(),
|
||||
Brace2, szNZBNiceName, pFileInfo->GetFilename(), (float)(Util::Int64ToFloat(pFileInfo->GetSize()) / 1024.0 / 1024.0),
|
||||
szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
|
||||
PlotLine(szBuffer, iRow, 0, color);
|
||||
@@ -796,15 +782,15 @@ void NCursesFrontend::FormatFileSize(char * szBuffer, int iBufLen, long long lFi
|
||||
{
|
||||
if (lFileSize > 1024 * 1024 * 1024)
|
||||
{
|
||||
snprintf(szBuffer, iBufLen, "%.2f GB", (float)lFileSize / 1024 / 1024 / 1024);
|
||||
snprintf(szBuffer, iBufLen, "%.2f GB", (float)(Util::Int64ToFloat(lFileSize) / 1024 / 1024 / 1024));
|
||||
}
|
||||
else if (lFileSize > 1024 * 1024)
|
||||
{
|
||||
snprintf(szBuffer, iBufLen, "%.2f MB", (float)lFileSize / 1024 / 1024);
|
||||
snprintf(szBuffer, iBufLen, "%.2f MB", (float)(Util::Int64ToFloat(lFileSize) / 1024 / 1024));
|
||||
}
|
||||
else if (lFileSize > 1024)
|
||||
{
|
||||
snprintf(szBuffer, iBufLen, "%.2f KB", (float)lFileSize / 1024);
|
||||
snprintf(szBuffer, iBufLen, "%.2f KB", (float)(Util::Int64ToFloat(lFileSize) / 1024));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -953,11 +939,11 @@ void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSel
|
||||
}
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
FileInfo::MakeNiceNZBName(pGroupInfo->GetNZBFilename(), szNZBNiceName, 1023);
|
||||
pGroupInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1023);
|
||||
|
||||
char szBuffer[MAX_SCREEN_WIDTH];
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s (%i file%s, %s%s)", Brace1, pGroupInfo->GetID(), Brace2, szNZBNiceName,
|
||||
pGroupInfo->m_iFileCount, pGroupInfo->m_iFileCount > 1 ? "s" : "", szRemaining, szPaused);
|
||||
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i-%i%s %s (%i file%s, %s%s)", Brace1, pGroupInfo->GetFirstID(), pGroupInfo->GetLastID(), Brace2, szNZBNiceName,
|
||||
pGroupInfo->GetRemainingFileCount(), pGroupInfo->GetRemainingFileCount() > 1 ? "s" : "", szRemaining, szPaused);
|
||||
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
||||
|
||||
PlotLine(szBuffer, iRow, 0, color);
|
||||
@@ -968,41 +954,7 @@ void NCursesFrontend::PrepareGroupQueue()
|
||||
m_groupQueue.clear();
|
||||
|
||||
DownloadQueue* pDownloadQueue = LockQueue();
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
GroupInfo* pGroupInfo = NULL;
|
||||
for (GroupQueue::iterator itg = m_groupQueue.begin(); itg != m_groupQueue.end(); itg++)
|
||||
{
|
||||
GroupInfo* pGroupInfo1 = *itg;
|
||||
if (!strcmp(pGroupInfo1->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
{
|
||||
pGroupInfo = pGroupInfo1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pGroupInfo)
|
||||
{
|
||||
pGroupInfo = new GroupInfo(pFileInfo->GetID(), pFileInfo->GetNZBFilename());
|
||||
m_groupQueue.push_back(pGroupInfo);
|
||||
}
|
||||
pGroupInfo->m_iFileCount++;
|
||||
pGroupInfo->m_lSize += pFileInfo->GetSize();
|
||||
pGroupInfo->m_lRemainingSize += pFileInfo->GetRemainingSize();
|
||||
if (pFileInfo->GetPaused())
|
||||
{
|
||||
pGroupInfo->m_lPausedSize += pFileInfo->GetRemainingSize();
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
pGroupInfo->m_iParCount++;
|
||||
}
|
||||
}
|
||||
GroupInfo::BuildGroups(pDownloadQueue, &m_groupQueue);
|
||||
UnlockQueue();
|
||||
}
|
||||
|
||||
@@ -1024,14 +976,14 @@ bool NCursesFrontend::EditQueue(QueueEditor::EEditAction eAction, int iOffset)
|
||||
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)m_groupQueue.size())
|
||||
{
|
||||
GroupInfo* pGroupInfo = m_groupQueue[m_iSelectedQueueEntry];
|
||||
ID = pGroupInfo->GetID();
|
||||
ID = pGroupInfo->GetLastID();
|
||||
if (eAction == QueueEditor::eaFilePause)
|
||||
{
|
||||
if (pGroupInfo->GetRemainingSize() == pGroupInfo->GetPausedSize())
|
||||
{
|
||||
eAction = QueueEditor::eaFileResume;
|
||||
}
|
||||
else if (pGroupInfo->GetPausedSize() == 0 && (pGroupInfo->m_iParCount > 0) &&
|
||||
else if (pGroupInfo->GetPausedSize() == 0 && (pGroupInfo->GetRemainingParCount() > 0) &&
|
||||
!(m_bLastPausePars && m_iLastEditEntry == m_iSelectedQueueEntry))
|
||||
{
|
||||
eAction = QueueEditor::eaFilePauseExtraPars;
|
||||
@@ -1075,6 +1027,8 @@ bool NCursesFrontend::EditQueue(QueueEditor::EEditAction eAction, int iOffset)
|
||||
|
||||
m_iLastEditEntry = m_iSelectedQueueEntry;
|
||||
|
||||
NeedUpdateData();
|
||||
|
||||
if (ID != 0)
|
||||
{
|
||||
return ServerEditQueue(eAction, iOffset, ID);
|
||||
|
||||
@@ -46,31 +46,6 @@ private:
|
||||
eDownloadRate
|
||||
};
|
||||
|
||||
class GroupInfo
|
||||
{
|
||||
private:
|
||||
int m_iID;
|
||||
char* m_szNZBFilename;
|
||||
|
||||
public:
|
||||
int m_iFileCount;
|
||||
long long m_lSize;
|
||||
long long m_lRemainingSize;
|
||||
long long m_lPausedSize;
|
||||
int m_iParCount;
|
||||
|
||||
public:
|
||||
GroupInfo(int iID, const char* szNZBFilename);
|
||||
~GroupInfo();
|
||||
int GetID() { return m_iID; }
|
||||
const char* GetNZBFilename() { return m_szNZBFilename; }
|
||||
long long GetSize() { return m_lSize; }
|
||||
long long GetRemainingSize() { return m_lRemainingSize; }
|
||||
long long GetPausedSize() { return m_lPausedSize; }
|
||||
};
|
||||
|
||||
typedef std::deque<GroupInfo*> GroupQueue;
|
||||
|
||||
bool m_bUseColor;
|
||||
int m_iDataUpdatePos;
|
||||
int m_iScreenHeight;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -60,7 +60,7 @@ NNTPConnection::~NNTPConnection()
|
||||
free(m_szLineBuf);
|
||||
}
|
||||
|
||||
char* NNTPConnection::Request(char* req)
|
||||
const char* NNTPConnection::Request(char* req)
|
||||
{
|
||||
if (!req)
|
||||
{
|
||||
@@ -190,25 +190,26 @@ bool NNTPConnection::AuthInfoPass(int iRecur)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NNTPConnection::JoinGroup(char* grp)
|
||||
const char* NNTPConnection::JoinGroup(const char* grp)
|
||||
{
|
||||
if ((m_szActiveGroup) && (!strcmp(m_szActiveGroup, grp)))
|
||||
if (m_szActiveGroup && !strcmp(m_szActiveGroup, grp))
|
||||
{
|
||||
// already in group
|
||||
return true;
|
||||
strcpy(m_szLineBuf, "211 ");
|
||||
return m_szLineBuf;
|
||||
}
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "GROUP %s\r\n", grp);
|
||||
tmp[1024-1] = '\0';
|
||||
|
||||
char* answer = Request(tmp);
|
||||
const char* answer = Request(tmp);
|
||||
if (m_bAuthError)
|
||||
{
|
||||
return false;
|
||||
return answer;
|
||||
}
|
||||
|
||||
if ((answer) && (!strncmp(answer, "2", 1)))
|
||||
if (answer && !strncmp(answer, "2", 1))
|
||||
{
|
||||
debug("Changed group to %s on %s", grp, GetServer()->GetHost());
|
||||
|
||||
@@ -217,24 +218,14 @@ bool NNTPConnection::JoinGroup(char* grp)
|
||||
free(m_szActiveGroup);
|
||||
}
|
||||
m_szActiveGroup = strdup(grp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetStatus() != csCancelled)
|
||||
else
|
||||
{
|
||||
if (!answer)
|
||||
{
|
||||
warn("Error changing group on %s: Connection closed by remote host.",
|
||||
GetServer()->GetHost());
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Error changing group on %s to %s: Answer was \"%s\".",
|
||||
GetServer()->GetHost(), grp, answer);
|
||||
}
|
||||
debug("Error changing group on %s to %s: %s.",
|
||||
GetServer()->GetHost(), grp, answer);
|
||||
}
|
||||
|
||||
return false;
|
||||
return answer;
|
||||
}
|
||||
|
||||
int NNTPConnection::DoConnect()
|
||||
@@ -254,7 +245,6 @@ int NNTPConnection::DoConnect()
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (strncmp(answer, "2", 1))
|
||||
{
|
||||
error("Connection to %s failed. Answer: ", m_pNetAddress->GetHost(), answer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -45,11 +45,11 @@ public:
|
||||
NNTPConnection(NewsServer* server);
|
||||
~NNTPConnection();
|
||||
NewsServer* GetNewsServer() { return(NewsServer*)m_pNetAddress; }
|
||||
char* Request(char* req);
|
||||
const char* Request(char* req);
|
||||
bool Authenticate();
|
||||
bool AuthInfoUser(int iRecur = 0);
|
||||
bool AuthInfoPass(int iRecur = 0);
|
||||
bool JoinGroup(char* grp);
|
||||
const char* JoinGroup(const char* grp);
|
||||
bool GetAuthError() { return m_bAuthError; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -133,8 +133,12 @@ void InstallService(int argc, char *argv[])
|
||||
return;
|
||||
}
|
||||
|
||||
char szExeName[1024];
|
||||
GetModuleFileName(NULL, szExeName, 1024);
|
||||
szExeName[1024-1] = '\0';
|
||||
|
||||
char szCmdLine[1024];
|
||||
snprintf(szCmdLine, 1024, "%s -D", argv[0]);
|
||||
snprintf(szCmdLine, 1024, "%s -D", szExeName);
|
||||
szCmdLine[1024-1] = '\0';
|
||||
|
||||
SC_HANDLE hService = CreateService(scm, strServiceName,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
|
||||
26
NZBFile.cpp
26
NZBFile.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -59,6 +59,10 @@ NZBFile::NZBFile(const char* szFileName)
|
||||
debug("Creating NZBFile");
|
||||
|
||||
m_szFileName = strdup(szFileName);
|
||||
m_pNZBInfo = new NZBInfo();
|
||||
m_pNZBInfo->AddReference();
|
||||
m_pNZBInfo->SetFilename(szFileName);
|
||||
BuildDestDirName();
|
||||
|
||||
m_FileInfos.clear();
|
||||
}
|
||||
@@ -78,6 +82,11 @@ NZBFile::~NZBFile()
|
||||
delete *it;
|
||||
}
|
||||
m_FileInfos.clear();
|
||||
|
||||
if (m_pNZBInfo)
|
||||
{
|
||||
m_pNZBInfo->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void NZBFile::LogDebugInfo()
|
||||
@@ -131,8 +140,10 @@ void NZBFile::AddFileInfo(FileInfo* pFileInfo)
|
||||
if (!pArticles->empty())
|
||||
{
|
||||
ParseSubject(pFileInfo);
|
||||
BuildDestDirName(pFileInfo);
|
||||
m_FileInfos.push_back(pFileInfo);
|
||||
pFileInfo->SetNZBInfo(m_pNZBInfo);
|
||||
m_pNZBInfo->SetSize(m_pNZBInfo->GetSize() + pFileInfo->GetSize());
|
||||
m_pNZBInfo->SetFileCount(m_pNZBInfo->GetFileCount() + 1);
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
@@ -167,7 +178,7 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo)
|
||||
if (sep)
|
||||
{
|
||||
// end of token
|
||||
int len = p - start;
|
||||
int len = (int)(p - start);
|
||||
if (len > 0)
|
||||
{
|
||||
char* token = (char*)malloc(len + 1);
|
||||
@@ -234,14 +245,14 @@ void NZBFile::ParseSubject(FileInfo* pFileInfo)
|
||||
pFileInfo->MakeValidFilename();
|
||||
}
|
||||
|
||||
void NZBFile::BuildDestDirName(FileInfo* pFileInfo)
|
||||
void NZBFile::BuildDestDirName()
|
||||
{
|
||||
char szBuffer[1024];
|
||||
|
||||
if (g_pOptions->GetAppendNZBDir())
|
||||
{
|
||||
char szNiceNZBName[1024];
|
||||
pFileInfo->GetNiceNZBName(szNiceNZBName, 1024);
|
||||
m_pNZBInfo->GetNiceNZBName(szNiceNZBName, 1024);
|
||||
snprintf(szBuffer, 1024, "%s%s", g_pOptions->GetDestDir(), szNiceNZBName);
|
||||
szBuffer[1024-1] = '\0';
|
||||
}
|
||||
@@ -251,7 +262,7 @@ void NZBFile::BuildDestDirName(FileInfo* pFileInfo)
|
||||
szBuffer[1024-1] = '\0'; // trim the last slash, always returned by GetDestDir()
|
||||
}
|
||||
|
||||
pFileInfo->SetDestDir(szBuffer);
|
||||
m_pNZBInfo->SetDestDir(szBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,7 +399,6 @@ bool NZBFile::ParseNZB(IUnknown* nzb)
|
||||
if (!attribute) return false;
|
||||
_bstr_t subject(attribute->Gettext());
|
||||
FileInfo* pFileInfo = new FileInfo();
|
||||
pFileInfo->SetNZBFilename(m_szFileName);
|
||||
pFileInfo->SetSubject(subject);
|
||||
|
||||
MSXML::IXMLDOMNodeListPtr groupList = node->selectNodes("groups/group");
|
||||
@@ -493,7 +503,7 @@ bool NZBFile::ParseNZB(void* nzb)
|
||||
if (!strcmp("file", (char*)name))
|
||||
{
|
||||
pFileInfo = new FileInfo();
|
||||
pFileInfo->SetNZBFilename(m_szFileName);
|
||||
pFileInfo->SetFilename(m_szFileName);
|
||||
|
||||
while (xmlTextReaderMoveToNextAttribute(node))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -38,13 +38,14 @@ public:
|
||||
|
||||
private:
|
||||
FileInfos m_FileInfos;
|
||||
NZBInfo* m_pNZBInfo;
|
||||
char* m_szFileName;
|
||||
|
||||
NZBFile(const char* szFileName);
|
||||
void AddArticle(FileInfo* pFileInfo, ArticleInfo* pArticleInfo);
|
||||
void AddFileInfo(FileInfo* pFileInfo);
|
||||
void ParseSubject(FileInfo* pFileInfo);
|
||||
void BuildDestDirName(FileInfo* pFileInfo);
|
||||
void BuildDestDirName();
|
||||
void CheckFilenames();
|
||||
#ifdef WIN32
|
||||
bool ParseNZB(IUnknown* nzb);
|
||||
|
||||
135
Options.cpp
135
Options.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -51,7 +51,6 @@
|
||||
#include "NewsServer.h"
|
||||
#include "MessageBase.h"
|
||||
|
||||
extern float g_fDownloadRate;
|
||||
extern ServerPool* g_pServerPool;
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
@@ -77,11 +76,13 @@ static struct option long_options[] =
|
||||
{"edit", required_argument, 0, 'E'},
|
||||
{"connect", no_argument, 0, 'C'},
|
||||
{"quit", no_argument, 0, 'Q'},
|
||||
{"post", no_argument, 0, 'O'},
|
||||
{"write", required_argument, 0, 'W'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
static char short_options[] = "c:hno:psvABDCG:LPUR:TE:QV";
|
||||
static char short_options[] = "c:hno:psvABDCE:G:LOPR:TUQVW:";
|
||||
|
||||
// Program options
|
||||
static const char* OPTION_DESTDIR = "DestDir";
|
||||
@@ -103,9 +104,10 @@ static const char* OPTION_SERVERPASSWORD = "ServerPassword";
|
||||
static const char* OPTION_CONNECTIONTIMEOUT = "ConnectionTimeout";
|
||||
static const char* OPTION_SAVEQUEUE = "SaveQueue";
|
||||
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
|
||||
static const char* OPTION_RELOADPOSTQUEUE = "ReloadPostQueue";
|
||||
static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog";
|
||||
static const char* OPTION_RESETLOG = "ResetLog";
|
||||
static const char* OPTION_DECODER = "Decoder";
|
||||
static const char* OPTION_DECODE = "Decode";
|
||||
static const char* OPTION_RETRIES = "Retries";
|
||||
static const char* OPTION_RETRYINTERVAL = "RetryInterval";
|
||||
static const char* OPTION_TERMINATETIMEOUT = "TerminateTimeout";
|
||||
@@ -115,6 +117,7 @@ static const char* OPTION_INFOTARGET = "InfoTarget";
|
||||
static const char* OPTION_WARNINGTARGET = "WarningTarget";
|
||||
static const char* OPTION_ERRORTARGET = "ErrorTarget";
|
||||
static const char* OPTION_DEBUGTARGET = "DebugTarget";
|
||||
static const char* OPTION_DETAILTARGET = "DetailTarget";
|
||||
static const char* OPTION_LOADPARS = "LoadPars";
|
||||
static const char* OPTION_PARCHECK = "ParCheck";
|
||||
static const char* OPTION_PARREPAIR = "ParRepair";
|
||||
@@ -132,6 +135,9 @@ static const char* OPTION_DIRECTWRITE = "DirectWrite";
|
||||
static const char* OPTION_WRITEBUFFERSIZE = "WriteBufferSize";
|
||||
static const char* OPTION_NZBDIRINTERVAL = "NzbDirInterval";
|
||||
static const char* OPTION_NZBDIRFILEAGE = "NzbDirFileAge";
|
||||
static const char* OPTION_PARCLEANUPQUEUE = "ParCleanupQueue";
|
||||
static const char* OPTION_DISKSPACE = "DiskSpace";
|
||||
static const char* OPTION_POSTLOGKIND = "PostLogKind";
|
||||
|
||||
#ifndef WIN32
|
||||
const char* PossibleConfigLocations[] =
|
||||
@@ -159,7 +165,8 @@ Options::Options(int argc, char* argv[])
|
||||
m_eWarningTarget = mtScreen;
|
||||
m_eErrorTarget = mtScreen;
|
||||
m_eDebugTarget = mtScreen;
|
||||
m_eDecoder = dcUulib;
|
||||
m_eDetailTarget = mtScreen;
|
||||
m_bDecode = true;
|
||||
m_bPause = false;
|
||||
m_bCreateBrokenLog = false;
|
||||
m_bResetLog = false;
|
||||
@@ -169,6 +176,7 @@ Options::Options(int argc, char* argv[])
|
||||
m_iEditQueueIDCount = 0;
|
||||
m_iEditQueueOffset = 0;
|
||||
m_szArgFilename = NULL;
|
||||
m_szLastArg = NULL;
|
||||
m_iConnectionTimeout = 0;
|
||||
m_iTerminateTimeout = 0;
|
||||
m_bServerMode = false;
|
||||
@@ -190,11 +198,13 @@ Options::Options(int argc, char* argv[])
|
||||
m_szDaemonUserName = NULL;
|
||||
m_eOutputMode = omLoggable;
|
||||
m_bReloadQueue = false;
|
||||
m_bReloadPostQueue = false;
|
||||
m_iLogBufferSize = 0;
|
||||
m_iLogLines = 0;
|
||||
m_iWriteLogKind = 0;
|
||||
m_bCreateLog = false;
|
||||
m_szLogFile = NULL;
|
||||
m_eLoadPars = plAll;
|
||||
m_eLoadPars = lpAll;
|
||||
m_bParCheck = false;
|
||||
m_bParRepair = false;
|
||||
m_szPostProcess = NULL;
|
||||
@@ -212,6 +222,9 @@ Options::Options(int argc, char* argv[])
|
||||
m_iWriteBufferSize = 0;
|
||||
m_iNzbDirInterval = 0;
|
||||
m_iNzbDirFileAge = 0;
|
||||
m_bParCleanupQueue = false;
|
||||
m_iDiskSpace = 0;
|
||||
m_ePostLogKind = plNone;
|
||||
|
||||
char szFilename[MAX_PATH + 1];
|
||||
#ifdef WIN32
|
||||
@@ -220,7 +233,7 @@ Options::Options(int argc, char* argv[])
|
||||
strncpy(szFilename, argv[0], MAX_PATH + 1);
|
||||
#endif
|
||||
szFilename[MAX_PATH] = '\0';
|
||||
NormalizePathSeparators(szFilename);
|
||||
Util::NormalizePathSeparators(szFilename);
|
||||
char* end = strrchr(szFilename, PATH_SEPARATOR);
|
||||
if (end) *end = '\0';
|
||||
SetOption("APPDIR", szFilename);
|
||||
@@ -295,6 +308,10 @@ Options::~Options()
|
||||
{
|
||||
free(m_szArgFilename);
|
||||
}
|
||||
if (m_szLastArg)
|
||||
{
|
||||
free(m_szLastArg);
|
||||
}
|
||||
if (m_szServerIP)
|
||||
{
|
||||
free(m_szServerIP);
|
||||
@@ -372,10 +389,11 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_SERVERPORT, "6789");
|
||||
SetOption(OPTION_CONNECTIONTIMEOUT, "60");
|
||||
SetOption(OPTION_SAVEQUEUE, "yes");
|
||||
SetOption(OPTION_RELOADQUEUE, "ask");
|
||||
SetOption(OPTION_RELOADQUEUE, "yes");
|
||||
SetOption(OPTION_RELOADPOSTQUEUE, "yes");
|
||||
SetOption(OPTION_CREATEBROKENLOG, "no");
|
||||
SetOption(OPTION_RESETLOG, "no");
|
||||
SetOption(OPTION_DECODER, "yEnc");
|
||||
SetOption(OPTION_DECODE, "yes");
|
||||
SetOption(OPTION_RETRIES, "5");
|
||||
SetOption(OPTION_RETRYINTERVAL, "10");
|
||||
SetOption(OPTION_TERMINATETIMEOUT, "600");
|
||||
@@ -385,6 +403,7 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_WARNINGTARGET, "both");
|
||||
SetOption(OPTION_ERRORTARGET, "both");
|
||||
SetOption(OPTION_DEBUGTARGET, "none");
|
||||
SetOption(OPTION_DETAILTARGET, "both");
|
||||
SetOption(OPTION_LOADPARS, "all");
|
||||
SetOption(OPTION_PARCHECK, "no");
|
||||
SetOption(OPTION_PARREPAIR, "no");
|
||||
@@ -403,6 +422,9 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_WRITEBUFFERSIZE, "0");
|
||||
SetOption(OPTION_NZBDIRINTERVAL, "5");
|
||||
SetOption(OPTION_NZBDIRFILEAGE, "60");
|
||||
SetOption(OPTION_PARCLEANUPQUEUE, "no");
|
||||
SetOption(OPTION_DISKSPACE, "0");
|
||||
SetOption(OPTION_POSTLOGKIND, "none");
|
||||
}
|
||||
|
||||
void Options::InitOptFile()
|
||||
@@ -419,13 +441,12 @@ void Options::InitOptFile()
|
||||
char szFilename[MAX_PATH + 1];
|
||||
GetModuleFileName(NULL, szFilename, MAX_PATH + 1);
|
||||
szFilename[MAX_PATH] = '\0';
|
||||
NormalizePathSeparators(szFilename);
|
||||
Util::NormalizePathSeparators(szFilename);
|
||||
char* end = strrchr(szFilename, PATH_SEPARATOR);
|
||||
if (end) end[1] = '\0';
|
||||
strcat(szFilename, "nzbget.conf");
|
||||
|
||||
struct stat buffer;
|
||||
if (!stat(szFilename, &buffer) && S_ISREG(buffer.st_mode))
|
||||
if (Util::FileExists(szFilename))
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
}
|
||||
@@ -437,8 +458,7 @@ void Options::InitOptFile()
|
||||
SetOption("$CONFIGFILENAME", szFilename);
|
||||
szFilename = GetOption("$CONFIGFILENAME");
|
||||
|
||||
struct stat buffer;
|
||||
if (!stat(szFilename, &buffer) && S_ISREG(buffer.st_mode))
|
||||
if (Util::FileExists(szFilename))
|
||||
{
|
||||
m_szConfigFilename = strdup(szFilename);
|
||||
DelOption("$CONFIGFILENAME");
|
||||
@@ -476,14 +496,14 @@ void Options::CheckDir(char** dir, const char* szOptionName)
|
||||
usedir[len] = PATH_SEPARATOR;
|
||||
usedir[len + 1] = '\0';
|
||||
}
|
||||
NormalizePathSeparators(usedir);
|
||||
Util::NormalizePathSeparators(usedir);
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Wrong value for option \"%s\"\n", szOptionName);
|
||||
}
|
||||
// Ensure the dir is created
|
||||
if (!ForceDirectories(usedir))
|
||||
if (!Util::ForceDirectories(usedir))
|
||||
{
|
||||
abort("FATAL ERROR: Directory \"%s\" (option \"%s\") does not exist and could not be created\n", usedir, szOptionName);
|
||||
}
|
||||
@@ -516,15 +536,16 @@ void Options::InitOptions()
|
||||
m_iWriteBufferSize = atoi(GetOption(OPTION_WRITEBUFFERSIZE));
|
||||
m_iNzbDirInterval = atoi(GetOption(OPTION_NZBDIRINTERVAL));
|
||||
m_iNzbDirFileAge = atoi(GetOption(OPTION_NZBDIRFILEAGE));
|
||||
m_iDiskSpace = atoi(GetOption(OPTION_DISKSPACE));
|
||||
|
||||
if (m_iNzbDirInterval > 0)
|
||||
{
|
||||
CheckDir(&m_szNzbDir, OPTION_NZBDIR);
|
||||
}
|
||||
|
||||
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable" };
|
||||
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||
const int BoolCount = 10;
|
||||
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable", "enabled", "disabled" };
|
||||
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||
const int BoolCount = 12;
|
||||
m_bCreateBrokenLog = (bool)ParseOptionValue(OPTION_CREATEBROKENLOG, BoolCount, BoolNames, BoolValues);
|
||||
m_bResetLog = (bool)ParseOptionValue(OPTION_RESETLOG, BoolCount, BoolNames, BoolValues);
|
||||
m_bAppendNZBDir = (bool)ParseOptionValue(OPTION_APPENDNZBDIR, BoolCount, BoolNames, BoolValues);
|
||||
@@ -537,25 +558,23 @@ void Options::InitOptions()
|
||||
m_bParRepair = (bool)ParseOptionValue(OPTION_PARREPAIR, BoolCount, BoolNames, BoolValues);
|
||||
m_bStrictParName = (bool)ParseOptionValue(OPTION_STRICTPARNAME, BoolCount, BoolNames, BoolValues);
|
||||
m_bReloadQueue = (bool)ParseOptionValue(OPTION_RELOADQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
m_bReloadPostQueue = (bool)ParseOptionValue(OPTION_RELOADPOSTQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
m_bCursesNZBName = (bool)ParseOptionValue(OPTION_CURSESNZBNAME, BoolCount, BoolNames, BoolValues);
|
||||
m_bCursesTime = (bool)ParseOptionValue(OPTION_CURSESTIME, BoolCount, BoolNames, BoolValues);
|
||||
m_bCursesGroup = (bool)ParseOptionValue(OPTION_CURSESGROUP, BoolCount, BoolNames, BoolValues);
|
||||
m_bCrcCheck = (bool)ParseOptionValue(OPTION_CRCCHECK, BoolCount, BoolNames, BoolValues);
|
||||
m_bRetryOnCrcError = (bool)ParseOptionValue(OPTION_RETRYONCRCERROR, BoolCount, BoolNames, BoolValues);
|
||||
m_bDirectWrite = (bool)ParseOptionValue(OPTION_DIRECTWRITE, BoolCount, BoolNames, BoolValues);
|
||||
m_bParCleanupQueue = (bool)ParseOptionValue(OPTION_PARCLEANUPQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
m_bDecode = (bool)ParseOptionValue(OPTION_DECODE, BoolCount, BoolNames, BoolValues);
|
||||
|
||||
const char* OutputModeNames[] = { "loggable", "logable", "log", "colored", "color", "ncurses", "curses" };
|
||||
const int OutputModeValues[] = { omLoggable, omLoggable, omLoggable, omColored, omColored, omNCurses, omNCurses };
|
||||
const int OutputModeCount = 7;
|
||||
m_eOutputMode = (EOutputMode)ParseOptionValue(OPTION_OUTPUTMODE, OutputModeCount, OutputModeNames, OutputModeValues);
|
||||
|
||||
const char* DecoderNames[] = { "uulib", "yenc", "none", "ydec", "ydecoder" };
|
||||
const int DecoderValues[] = { dcUulib, dcYenc, dcNone, dcYenc, dcYenc };
|
||||
const int DecoderCount = 5;
|
||||
m_eDecoder = (EDecoder)ParseOptionValue(OPTION_DECODER, DecoderCount, DecoderNames, DecoderValues);
|
||||
|
||||
const char* LoadParsNames[] = { "none", "one", "all", "1", "0" };
|
||||
const int LoadParsValues[] = { plNone, plOne, plAll, plOne, plNone };
|
||||
const int LoadParsValues[] = { lpNone, lpOne, lpAll, lpOne, lpNone };
|
||||
const int LoadParsCount = 4;
|
||||
m_eLoadPars = (ELoadPars)ParseOptionValue(OPTION_LOADPARS, LoadParsCount, LoadParsNames, LoadParsValues);
|
||||
|
||||
@@ -566,6 +585,12 @@ void Options::InitOptions()
|
||||
m_eWarningTarget = (EMessageTarget)ParseOptionValue(OPTION_WARNINGTARGET, TargetCount, TargetNames, TargetValues);
|
||||
m_eErrorTarget = (EMessageTarget)ParseOptionValue(OPTION_ERRORTARGET, TargetCount, TargetNames, TargetValues);
|
||||
m_eDebugTarget = (EMessageTarget)ParseOptionValue(OPTION_DEBUGTARGET, TargetCount, TargetNames, TargetValues);
|
||||
m_eDetailTarget = (EMessageTarget)ParseOptionValue(OPTION_DETAILTARGET, TargetCount, TargetNames, TargetValues);
|
||||
|
||||
const char* PostLogKindNames[] = { "none", "detail", "info", "warning", "error", "debug" };
|
||||
const int PostLogKindValues[] = { plNone, plDetail, plInfo, plWarning, plError, plDebug };
|
||||
const int PostLogKindCount = 6;
|
||||
m_ePostLogKind = (EPostLogKind)ParseOptionValue(OPTION_POSTLOGKIND, PostLogKindCount, PostLogKindNames, PostLogKindValues);
|
||||
}
|
||||
|
||||
int Options::ParseOptionValue(const char * OptName, int argc, const char * argn[], const int argv[])
|
||||
@@ -734,6 +759,31 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
case 'V':
|
||||
m_eClientOperation = opClientRequestVersion;
|
||||
break;
|
||||
case 'O':
|
||||
m_eClientOperation = opClientRequestPostQueue;
|
||||
break;
|
||||
case 'W':
|
||||
m_eClientOperation = opClientRequestWriteLog;
|
||||
if (!strcmp(optarg, "I")) {
|
||||
m_iWriteLogKind = (int)Message::mkInfo;
|
||||
}
|
||||
else if (!strcmp(optarg, "W")) {
|
||||
m_iWriteLogKind = (int)Message::mkWarning;
|
||||
}
|
||||
else if (!strcmp(optarg, "E")) {
|
||||
m_iWriteLogKind = (int)Message::mkError;
|
||||
}
|
||||
else if (!strcmp(optarg, "D")) {
|
||||
m_iWriteLogKind = (int)Message::mkDetail;
|
||||
}
|
||||
else if (!strcmp(optarg, "G")) {
|
||||
m_iWriteLogKind = (int)Message::mkDebug;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("FATAL ERROR: Could not parse value of option 'W'\n");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
exit(-1);
|
||||
break;
|
||||
@@ -746,7 +796,7 @@ void Options::InitCommandLine(int argc, char* argv[])
|
||||
void Options::PrintUsage(char* com)
|
||||
{
|
||||
printf("Usage:\n"
|
||||
" %s [switches] [<nzb-file>]\n\n"
|
||||
" %s [switches]\n\n"
|
||||
"Switches:\n"
|
||||
" -h, --help Print this help-message\n"
|
||||
" -v, --version Print version and exit\n"
|
||||
@@ -761,7 +811,7 @@ void Options::PrintUsage(char* com)
|
||||
#endif
|
||||
" -V, --serverversion Print server's version and exit\n"
|
||||
" -Q, --quit Shutdown the server\n"
|
||||
" -A, --append Send file to the server's download queue\n"
|
||||
" -A, --append <nzb-file> Send file to the server's download queue\n"
|
||||
" -C, --connect Attach client to server\n"
|
||||
" -L, --list Request list of downloads from the server\n"
|
||||
" -P, --pause Pause downloading on the server\n"
|
||||
@@ -770,6 +820,8 @@ void Options::PrintUsage(char* com)
|
||||
" -T, --top Add file to the top (begining) of queue\n"
|
||||
" (should be used with switch --append)\n"
|
||||
" -G, --log <lines> Request last <lines> lines from server's screen-log\n"
|
||||
" -W, --write <D|I|W|E|G> \"Text\" Send text to server's log\n"
|
||||
" -O, --post Request post-processor-queue from server\n"
|
||||
" -E, --edit [G] <action> <IDs> Edit queue on the server\n"
|
||||
" <G> Affect all files in the group (same nzb-file)\n"
|
||||
" <action> is one of:\n"
|
||||
@@ -784,7 +836,7 @@ void Options::PrintUsage(char* com)
|
||||
" D Delete file(s)\n"
|
||||
" <IDs> Comma-separated list of file-ids or ranges\n"
|
||||
" of file-ids, e. g.: 1-5,3,10-22\n",
|
||||
BaseFileName(com));
|
||||
Util::BaseFileName(com));
|
||||
}
|
||||
|
||||
void Options::InitFileArg(int argc, char* argv[])
|
||||
@@ -794,9 +846,17 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
// no nzb-file passed
|
||||
if (!m_bServerMode && !m_bRemoteClientMode &&
|
||||
(m_eClientOperation == opClientNoOperation ||
|
||||
m_eClientOperation == opClientRequestDownload))
|
||||
m_eClientOperation == opClientRequestDownload ||
|
||||
m_eClientOperation == opClientRequestWriteLog))
|
||||
{
|
||||
printf("nzb-file not specified\n");
|
||||
if (m_eClientOperation == opClientRequestWriteLog)
|
||||
{
|
||||
printf("Log-text not specified\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Nzb-file not specified\n");
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -806,6 +866,8 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
m_szLastArg = strdup(argv[optind]);
|
||||
|
||||
// Check if the file-name is a relative path or an absolute path
|
||||
// If the path starts with '/' its an absolute, else relative
|
||||
const char* szFileName = argv[optind];
|
||||
@@ -829,10 +891,11 @@ void Options::InitFileArg(int argc, char* argv[])
|
||||
#endif
|
||||
|
||||
if (m_bServerMode || m_bRemoteClientMode ||
|
||||
!((m_eClientOperation == opClientRequestDownload)
|
||||
|| (m_eClientOperation == opClientNoOperation)))
|
||||
!(m_eClientOperation == opClientNoOperation ||
|
||||
m_eClientOperation == opClientRequestDownload ||
|
||||
m_eClientOperation == opClientRequestWriteLog))
|
||||
{
|
||||
printf("nzb-file not needed for this command\n");
|
||||
printf("Too many arguments\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1112,7 @@ bool Options::SetOptionString(const char * option)
|
||||
{
|
||||
char optname[1001];
|
||||
char optvalue[1001];
|
||||
int maxlen = eq - option < 1000 ? eq - option : 1000;
|
||||
int maxlen = (int)(eq - option < 1000 ? eq - option : 1000);
|
||||
strncpy(optname, option, maxlen);
|
||||
optname[maxlen] = '\0';
|
||||
strncpy(optvalue, eq + 1, 1000);
|
||||
@@ -1122,7 +1185,7 @@ void Options::CheckOptions()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_eDecoder != dcYenc)
|
||||
if (!m_bDecode)
|
||||
{
|
||||
m_bDirectWrite = false;
|
||||
}
|
||||
@@ -1146,7 +1209,7 @@ void Options::ParseFileIDList(int argc, char* argv[], int optind)
|
||||
if (p)
|
||||
{
|
||||
char buf[101];
|
||||
int maxlen = p - optarg < 100 ? p - optarg : 100;
|
||||
int maxlen = (int)(p - optarg < 100 ? p - optarg : 100);
|
||||
strncpy(buf, optarg, maxlen);
|
||||
buf[maxlen] = '\0';
|
||||
iEditQueueIDFrom = atoi(buf);
|
||||
|
||||
82
Options.h
82
Options.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -34,42 +34,48 @@ class Options
|
||||
public:
|
||||
enum EClientOperation
|
||||
{
|
||||
opClientNoOperation,
|
||||
opClientRequestDownload,
|
||||
opClientRequestList,
|
||||
opClientRequestPause,
|
||||
opClientRequestUnpause,
|
||||
opClientRequestSetRate,
|
||||
opClientRequestDumpDebug,
|
||||
opClientRequestEditQueue,
|
||||
opClientRequestLog,
|
||||
opClientRequestShutdown,
|
||||
opClientRequestVersion
|
||||
opClientNoOperation,
|
||||
opClientRequestDownload,
|
||||
opClientRequestList,
|
||||
opClientRequestPause,
|
||||
opClientRequestUnpause,
|
||||
opClientRequestSetRate,
|
||||
opClientRequestDumpDebug,
|
||||
opClientRequestEditQueue,
|
||||
opClientRequestLog,
|
||||
opClientRequestShutdown,
|
||||
opClientRequestVersion,
|
||||
opClientRequestPostQueue,
|
||||
opClientRequestWriteLog
|
||||
};
|
||||
enum EMessageTarget
|
||||
{
|
||||
mtNone,
|
||||
mtScreen,
|
||||
mtLog,
|
||||
mtBoth
|
||||
};
|
||||
enum EDecoder
|
||||
{
|
||||
dcNone,
|
||||
dcUulib,
|
||||
dcYenc
|
||||
mtNone,
|
||||
mtScreen,
|
||||
mtLog,
|
||||
mtBoth
|
||||
};
|
||||
enum EOutputMode
|
||||
{
|
||||
omLoggable,
|
||||
omColored,
|
||||
omNCurses
|
||||
omLoggable,
|
||||
omColored,
|
||||
omNCurses
|
||||
};
|
||||
enum ELoadPars
|
||||
{
|
||||
plNone,
|
||||
plOne,
|
||||
plAll
|
||||
lpNone,
|
||||
lpOne,
|
||||
lpAll
|
||||
};
|
||||
|
||||
enum EPostLogKind
|
||||
{
|
||||
plNone,
|
||||
plDetail,
|
||||
plInfo,
|
||||
plWarning,
|
||||
plError,
|
||||
plDebug
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -93,7 +99,8 @@ private:
|
||||
EMessageTarget m_eWarningTarget;
|
||||
EMessageTarget m_eErrorTarget;
|
||||
EMessageTarget m_eDebugTarget;
|
||||
EDecoder m_eDecoder;
|
||||
EMessageTarget m_eDetailTarget;
|
||||
bool m_bDecode;
|
||||
bool m_bCreateBrokenLog;
|
||||
bool m_bResetLog;
|
||||
int m_iConnectionTimeout;
|
||||
@@ -112,6 +119,7 @@ private:
|
||||
char* m_szDaemonUserName;
|
||||
EOutputMode m_eOutputMode;
|
||||
bool m_bReloadQueue;
|
||||
bool m_bReloadPostQueue;
|
||||
int m_iLogBufferSize;
|
||||
bool m_bCreateLog;
|
||||
char* m_szLogFile;
|
||||
@@ -133,6 +141,9 @@ private:
|
||||
int m_iWriteBufferSize;
|
||||
int m_iNzbDirInterval;
|
||||
int m_iNzbDirFileAge;
|
||||
bool m_bParCleanupQueue;
|
||||
int m_iDiskSpace;
|
||||
EPostLogKind m_ePostLogKind;
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool m_bServerMode;
|
||||
@@ -143,10 +154,12 @@ private:
|
||||
int* m_pEditQueueIDList;
|
||||
int m_iEditQueueIDCount;
|
||||
char* m_szArgFilename;
|
||||
char* m_szLastArg;
|
||||
bool m_bPrintOptions;
|
||||
bool m_bAddTop;
|
||||
float m_fSetRate;
|
||||
int m_iLogLines;
|
||||
int m_iWriteLogKind;
|
||||
|
||||
// Current state
|
||||
bool m_bPause;
|
||||
@@ -187,9 +200,10 @@ public:
|
||||
EMessageTarget GetWarningTarget() const { return m_eWarningTarget; }
|
||||
EMessageTarget GetErrorTarget() const { return m_eErrorTarget; }
|
||||
EMessageTarget GetDebugTarget() const { return m_eDebugTarget; }
|
||||
EMessageTarget GetDetailTarget() const { return m_eDetailTarget; }
|
||||
int GetConnectionTimeout() { return m_iConnectionTimeout; }
|
||||
int GetTerminateTimeout() { return m_iTerminateTimeout; }
|
||||
EDecoder GetDecoder() { return m_eDecoder; };
|
||||
bool GetDecode() { return m_bDecode; };
|
||||
bool GetAppendNZBDir() { return m_bAppendNZBDir; }
|
||||
bool GetContinuePartial() { return m_bContinuePartial; }
|
||||
bool GetRenameBroken() { return m_bRenameBroken; }
|
||||
@@ -204,6 +218,7 @@ public:
|
||||
char* GetDaemonUserName() { return m_szDaemonUserName; }
|
||||
EOutputMode GetOutputMode() { return m_eOutputMode; }
|
||||
bool GetReloadQueue() { return m_bReloadQueue; }
|
||||
bool GetReloadPostQueue() { return m_bReloadPostQueue; }
|
||||
int GetLogBufferSize() { return m_iLogBufferSize; }
|
||||
bool GetCreateLog() { return m_bCreateLog; }
|
||||
char* GetLogFile() { return m_szLogFile; }
|
||||
@@ -224,20 +239,25 @@ public:
|
||||
int GetWriteBufferSize() { return m_iWriteBufferSize; }
|
||||
int GetNzbDirInterval() { return m_iNzbDirInterval; }
|
||||
int GetNzbDirFileAge() { return m_iNzbDirFileAge; }
|
||||
bool GetParCleanupQueue() { return m_bParCleanupQueue; }
|
||||
int GetDiskSpace() { return m_iDiskSpace; }
|
||||
EPostLogKind GetPostLogKind() { return m_ePostLogKind; }
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool GetServerMode() { return m_bServerMode; }
|
||||
bool GetDaemonMode() { return m_bDaemonMode; }
|
||||
bool GetRemoteClientMode() { return m_bRemoteClientMode; }
|
||||
EClientOperation GetClientOperation() { return m_eClientOperation; }
|
||||
EClientOperation GetClientOperation() { return m_eClientOperation; }
|
||||
int GetEditQueueAction() { return m_iEditQueueAction; }
|
||||
int GetEditQueueOffset() { return m_iEditQueueOffset; }
|
||||
int* GetEditQueueIDList() { return m_pEditQueueIDList; }
|
||||
int GetEditQueueIDCount() { return m_iEditQueueIDCount; }
|
||||
const char* GetArgFilename() { return m_szArgFilename; }
|
||||
const char* GetLastArg() { return m_szLastArg; }
|
||||
bool GetAddTop() { return m_bAddTop; }
|
||||
float GetSetRate() { return m_fSetRate; }
|
||||
int GetLogLines() { return m_iLogLines; }
|
||||
int GetWriteLogKind() { return m_iWriteLogKind; }
|
||||
|
||||
// Current state
|
||||
void SetPause(bool bOnOff) { m_bPause = bOnOff; }
|
||||
|
||||
485
ParChecker.cpp
485
ParChecker.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -47,11 +47,9 @@
|
||||
#include "nzbget.h"
|
||||
#include "ParChecker.h"
|
||||
#include "Log.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "Options.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern Options* g_pOptions;
|
||||
|
||||
const char* Par2CmdLineErrStr[] = { "OK",
|
||||
@@ -64,11 +62,13 @@ const char* Par2CmdLineErrStr[] = { "OK",
|
||||
"internal error occurred",
|
||||
"out of memory" };
|
||||
|
||||
|
||||
class Repairer : public Par2Repairer
|
||||
{
|
||||
friend class ParChecker;
|
||||
};
|
||||
|
||||
|
||||
ParChecker::ParChecker()
|
||||
{
|
||||
debug("Creating ParChecker");
|
||||
@@ -78,6 +78,12 @@ ParChecker::ParChecker()
|
||||
m_szNZBFilename = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_szErrMsg = NULL;
|
||||
m_szProgressLabel = (char*)malloc(1024);
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_iExtraFiles = 0;
|
||||
m_bVerifyingExtraFiles = false;
|
||||
m_eStage = ptLoadingPars;
|
||||
m_QueuedParFiles.clear();
|
||||
}
|
||||
|
||||
@@ -101,6 +107,7 @@ ParChecker::~ParChecker()
|
||||
{
|
||||
free(m_szErrMsg);
|
||||
}
|
||||
free(m_szProgressLabel);
|
||||
|
||||
for (QueuedParFiles::iterator it = m_QueuedParFiles.begin(); it != m_QueuedParFiles.end() ;it++)
|
||||
{
|
||||
@@ -144,12 +151,24 @@ void ParChecker::SetStatus(EStatus eStatus)
|
||||
|
||||
void ParChecker::Run()
|
||||
{
|
||||
info("Verifying %s", m_szInfoName);
|
||||
m_bRepairNotNeeded = false;
|
||||
m_eStage = ptLoadingPars;
|
||||
m_iProcessedFiles = 0;
|
||||
m_iExtraFiles = 0;
|
||||
m_bVerifyingExtraFiles = false;
|
||||
|
||||
info("Verifying %s", m_szInfoName);
|
||||
SetStatus(psWorking);
|
||||
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "Verifying %s", m_szInfoName);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
UpdateProgress();
|
||||
|
||||
debug("par: %s", m_szParFilename);
|
||||
CommandLine commandLine;
|
||||
const char* argv[] = { "par2", "r", "-q", "-q", m_szParFilename };
|
||||
const char* argv[] = { "par2", "r", "-v", "-v", m_szParFilename };
|
||||
if (!commandLine.Parse(5, (char**)argv))
|
||||
{
|
||||
error("Could not start par-check for %s. Par-file: %s", m_szInfoName, m_szParFilename);
|
||||
@@ -158,17 +177,23 @@ void ParChecker::Run()
|
||||
}
|
||||
|
||||
Result res;
|
||||
Repairer* repairer = new Repairer();
|
||||
repairer->sig_filename.connect(sigc::mem_fun(*this, &ParChecker::signal_filename));
|
||||
|
||||
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 = repairer->PreProcess(commandLine);
|
||||
res = pRepairer->PreProcess(commandLine);
|
||||
debug("ParChecker: PreProcess-result=%i", res);
|
||||
|
||||
if (res != eSuccess || IsStopped())
|
||||
{
|
||||
error("Could not verify %s: ", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
|
||||
error("Could not verify %s: %s", m_szInfoName, IsStopped() ? "due stopping" : "par2-file could not be processed");
|
||||
m_szErrMsg = strdup("par2-file could not be processed");
|
||||
SetStatus(psFailed);
|
||||
delete repairer;
|
||||
delete pRepairer;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,15 +205,25 @@ void ParChecker::Run()
|
||||
}
|
||||
m_szErrMsg = NULL;
|
||||
|
||||
m_bRepairNotNeeded = false;
|
||||
m_bRepairing = false;
|
||||
res = repairer->Process(commandLine, false);
|
||||
m_eStage = ptVerifyingSources;
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
|
||||
|
||||
if (!IsStopped() && res == eRepairNotPossible && CheckSplittedFragments())
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
|
||||
bool bMoreFilesLoaded = true;
|
||||
while (!IsStopped() && res == eRepairNotPossible)
|
||||
{
|
||||
int missingblockcount = repairer->missingblockcount - repairer->recoverypacketmap.size();
|
||||
info("Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
int missingblockcount = pRepairer->missingblockcount - pRepairer->recoverypacketmap.size();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
info("Need more %i par-block(s) for %s", missingblockcount, m_szInfoName);
|
||||
}
|
||||
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
bool hasMorePars = !m_QueuedParFiles.empty();
|
||||
@@ -198,6 +233,13 @@ void ParChecker::Run()
|
||||
{
|
||||
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();
|
||||
@@ -222,18 +264,19 @@ void ParChecker::Run()
|
||||
break;
|
||||
}
|
||||
|
||||
LoadMorePars(repairer);
|
||||
repairer->UpdateVerificationResults();
|
||||
|
||||
m_bRepairing = false;
|
||||
res = repairer->Process(commandLine, false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
bMoreFilesLoaded = LoadMorePars();
|
||||
if (bMoreFilesLoaded)
|
||||
{
|
||||
pRepairer->UpdateVerificationResults();
|
||||
res = pRepairer->Process(commandLine, false);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
SetStatus(psFailed);
|
||||
delete repairer;
|
||||
delete pRepairer;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -247,8 +290,17 @@ void ParChecker::Run()
|
||||
if (g_pOptions->GetParRepair())
|
||||
{
|
||||
info("Repairing %s", m_szInfoName);
|
||||
m_bRepairing = true;
|
||||
res = repairer->Process(commandLine, true);
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "Repairing %s", m_szInfoName);
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_iProcessedFiles = 0;
|
||||
m_eStage = ptRepairing;
|
||||
m_iFilesToRepair = pRepairer->damagedfilecount + pRepairer->missingfilecount;
|
||||
UpdateProgress();
|
||||
|
||||
res = pRepairer->Process(commandLine, true);
|
||||
debug("ParChecker: Process-result=%i", res);
|
||||
if (res == eSuccess)
|
||||
{
|
||||
@@ -276,214 +328,10 @@ void ParChecker::Run()
|
||||
SetStatus(psFailed);
|
||||
}
|
||||
|
||||
delete repairer;
|
||||
delete pRepairer;
|
||||
}
|
||||
|
||||
bool ParChecker::ParseParFilename(const char * szParFilename, int* iBaseNameLen, int* iBlocks)
|
||||
{
|
||||
char szFilename[1024];
|
||||
strncpy(szFilename, szParFilename, 1024);
|
||||
szFilename[1024-1] = '\0';
|
||||
for (char* p = szFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
int iLen = strlen(szFilename);
|
||||
if (iLen < 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// find last occurence of ".par2" and trim filename after it
|
||||
char* szEnd = szFilename;
|
||||
while (char* p = strstr(szEnd, ".par2")) szEnd = p + 5;
|
||||
*szEnd = '\0';
|
||||
iLen = strlen(szFilename);
|
||||
|
||||
if (strcasecmp(szFilename + iLen - 5, ".par2"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*(szFilename + iLen - 5) = '\0';
|
||||
|
||||
int blockcnt = 0;
|
||||
char* p = strrchr(szFilename, '.');
|
||||
if (p && !strncasecmp(p, ".vol", 4))
|
||||
{
|
||||
char* b = strchr(p, '+');
|
||||
if (!b)
|
||||
{
|
||||
b = strchr(p, '-');
|
||||
}
|
||||
if (b)
|
||||
{
|
||||
blockcnt = atoi(b+1);
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (iBaseNameLen)
|
||||
{
|
||||
*iBaseNameLen = strlen(szFilename);
|
||||
}
|
||||
if (iBlocks)
|
||||
{
|
||||
*iBlocks = blockcnt;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpause par2-files
|
||||
* returns true, if the files with required number of blocks were unpaused,
|
||||
* or false if there are no more files in queue for this collection or not enough blocks
|
||||
*/
|
||||
bool ParChecker::RequestMorePars(int iBlockNeeded, int* pBlockFound)
|
||||
{
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
Blocks blocks;
|
||||
blocks.clear();
|
||||
int iBlockFound = 0;
|
||||
|
||||
FindPars(pDownloadQueue, &blocks, true, &iBlockFound);
|
||||
if (iBlockFound == 0 && !g_pOptions->GetStrictParName())
|
||||
{
|
||||
FindPars(pDownloadQueue, &blocks, false, &iBlockFound);
|
||||
}
|
||||
|
||||
if (iBlockFound >= iBlockNeeded)
|
||||
{
|
||||
char szNZBNiceName[1024];
|
||||
FileInfo::MakeNiceNZBName(m_szNZBFilename, szNZBNiceName, 1024);
|
||||
|
||||
// 1. first unpause all files with par-blocks less or equal iBlockNeeded
|
||||
// starting from the file with max block count.
|
||||
// if par-collection was built exponentially and all par-files present,
|
||||
// this step selects par-files with exact number of blocks we need.
|
||||
while (iBlockNeeded > 0)
|
||||
{
|
||||
BlockInfo* pBestBlockInfo = NULL;
|
||||
for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
|
||||
{
|
||||
BlockInfo* pBlockInfo = *it;
|
||||
if (pBlockInfo->m_iBlockCount <= iBlockNeeded &&
|
||||
(!pBestBlockInfo || pBestBlockInfo->m_iBlockCount < pBlockInfo->m_iBlockCount))
|
||||
{
|
||||
pBestBlockInfo = pBlockInfo;
|
||||
}
|
||||
}
|
||||
if (pBestBlockInfo)
|
||||
{
|
||||
if (pBestBlockInfo->m_pFileInfo->GetPaused())
|
||||
{
|
||||
info("Unpausing %s%c%s for par-recovery", szNZBNiceName, (int)PATH_SEPARATOR, pBestBlockInfo->m_pFileInfo->GetFilename());
|
||||
pBestBlockInfo->m_pFileInfo->SetPaused(false);
|
||||
}
|
||||
iBlockNeeded -= pBestBlockInfo->m_iBlockCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. then unpause other files
|
||||
// this step only needed if the par-collection was built not exponentially
|
||||
// or not all par-files present (or some of them were corrupted)
|
||||
// this step is not optimal, but we hope, that the first step will work good
|
||||
// in most cases and we will not need the second step often
|
||||
while (iBlockNeeded > 0)
|
||||
{
|
||||
BlockInfo* pBlockInfo = blocks.front();
|
||||
if (pBlockInfo->m_pFileInfo->GetPaused())
|
||||
{
|
||||
info("Unpausing %s%c%s for par-recovery", szNZBNiceName, (int)PATH_SEPARATOR, pBlockInfo->m_pFileInfo->GetFilename());
|
||||
pBlockInfo->m_pFileInfo->SetPaused(false);
|
||||
}
|
||||
iBlockNeeded -= pBlockInfo->m_iBlockCount;
|
||||
}
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (pBlockFound)
|
||||
{
|
||||
*pBlockFound = iBlockFound;
|
||||
}
|
||||
|
||||
for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
blocks.clear();
|
||||
|
||||
return iBlockNeeded <= 0;
|
||||
}
|
||||
|
||||
void ParChecker::FindPars(DownloadQueue * pDownloadQueue, Blocks * pBlocks, bool bStrictParName, int* pBlockFound)
|
||||
{
|
||||
*pBlockFound = 0;
|
||||
|
||||
// extract base name from m_szParFilename (trim .par2-extension and possible .vol-part)
|
||||
char* szBaseParFilename = BaseFileName(m_szParFilename);
|
||||
char szMainBaseFilename[1024];
|
||||
int iMainBaseLen = 0;
|
||||
if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
|
||||
{
|
||||
// should not happen
|
||||
error("Internal error: could not parse filename %s", szBaseParFilename);
|
||||
return;
|
||||
}
|
||||
int maxlen = iMainBaseLen < 1024 ? iMainBaseLen : 1024 - 1;
|
||||
strncpy(szMainBaseFilename, szBaseParFilename, maxlen);
|
||||
szMainBaseFilename[maxlen] = '\0';
|
||||
for (char* p = szMainBaseFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
int iBlocks = 0;
|
||||
if (!strcmp(pFileInfo->GetNZBFilename(), m_szNZBFilename) &&
|
||||
ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
|
||||
iBlocks > 0)
|
||||
{
|
||||
if (bStrictParName)
|
||||
{
|
||||
// the pFileInfo->GetFilename() may be not confirmed and may contain
|
||||
// additional texts if Subject could not be parsed correctly
|
||||
|
||||
char szLoFileName[1024];
|
||||
strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
|
||||
szLoFileName[1024-1] = '\0';
|
||||
for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
|
||||
|
||||
char szCandidateFileName[1024];
|
||||
snprintf(szCandidateFileName, 1024, "%s.par2", szMainBaseFilename);
|
||||
szCandidateFileName[1024-1] = '\0';
|
||||
if (!strstr(szLoFileName, szCandidateFileName))
|
||||
{
|
||||
snprintf(szCandidateFileName, 1024, "%s.vol", szMainBaseFilename);
|
||||
szCandidateFileName[1024-1] = '\0';
|
||||
if (!strstr(szLoFileName, szCandidateFileName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it is a par2-file with blocks and it was from the same NZB-request
|
||||
// and it belongs to the same file collection (same base name),
|
||||
// then OK, we can use it
|
||||
BlockInfo* pBlockInfo = new BlockInfo();
|
||||
pBlockInfo->m_pFileInfo = pFileInfo;
|
||||
pBlockInfo->m_iBlockCount = iBlocks;
|
||||
pBlocks->push_back(pBlockInfo);
|
||||
*pBlockFound += iBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParChecker::LoadMorePars(void* repairer)
|
||||
bool ParChecker::LoadMorePars()
|
||||
{
|
||||
m_mutexQueuedParFiles.Lock();
|
||||
QueuedParFiles moreFiles;
|
||||
@@ -494,17 +342,19 @@ void ParChecker::LoadMorePars(void* repairer)
|
||||
for (QueuedParFiles::iterator it = moreFiles.begin(); it != moreFiles.end() ;it++)
|
||||
{
|
||||
char* szParFilename = *it;
|
||||
bool loadedOK = ((Repairer*)repairer)->LoadPacketsFromFile(szParFilename);
|
||||
bool loadedOK = ((Repairer*)m_pRepairer)->LoadPacketsFromFile(szParFilename);
|
||||
if (loadedOK)
|
||||
{
|
||||
info("File %s successfully loaded for par-check", BaseFileName(szParFilename), m_szInfoName);
|
||||
info("File %s successfully loaded for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("Could not load file %s for par-check", BaseFileName(szParFilename), m_szInfoName);
|
||||
info("Could not load file %s for par-check", Util::BaseFileName(szParFilename), m_szInfoName);
|
||||
}
|
||||
free(szParFilename);
|
||||
}
|
||||
|
||||
return !moreFiles.empty();
|
||||
}
|
||||
|
||||
void ParChecker::AddParFile(const char * szParFilename)
|
||||
@@ -522,9 +372,172 @@ void ParChecker::QueueChanged()
|
||||
m_mutexQueuedParFiles.Unlock();
|
||||
}
|
||||
|
||||
bool ParChecker::CheckSplittedFragments()
|
||||
{
|
||||
bool bFragmentsAdded = false;
|
||||
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
if (!sourcefile->GetTargetExists() && AddSplittedFragments(sourcefile->TargetFileName().c_str()))
|
||||
{
|
||||
bFragmentsAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bFragmentsAdded;
|
||||
}
|
||||
|
||||
bool ParChecker::AddSplittedFragments(const char* szFilename)
|
||||
{
|
||||
char szDirectory[1024];
|
||||
strncpy(szDirectory, szFilename, 1024);
|
||||
szDirectory[1024-1] = '\0';
|
||||
|
||||
char* szBasename = Util::BaseFileName(szDirectory);
|
||||
if (szBasename == szDirectory)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
szBasename[-1] = '\0';
|
||||
int iBaseLen = strlen(szBasename);
|
||||
|
||||
list<CommandLine::ExtraFile> extrafiles;
|
||||
|
||||
DirBrowser dir(szDirectory);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (!strncasecmp(filename, szBasename, iBaseLen))
|
||||
{
|
||||
const char* p = filename + iBaseLen;
|
||||
if (*p == '.')
|
||||
{
|
||||
for (p++; *p && strchr("0123456789", *p); p++) ;
|
||||
if (!*p)
|
||||
{
|
||||
debug("Found splitted fragment %s", filename);
|
||||
|
||||
char fullfilename[1024];
|
||||
snprintf(fullfilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
|
||||
fullfilename[1024-1] = '\0';
|
||||
|
||||
CommandLine::ExtraFile extrafile(fullfilename, Util::FileSize(fullfilename));
|
||||
extrafiles.push_back(extrafile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bFragmentsAdded = false;
|
||||
|
||||
if (!extrafiles.empty())
|
||||
{
|
||||
m_iExtraFiles = extrafiles.size();
|
||||
m_bVerifyingExtraFiles = true;
|
||||
bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles);
|
||||
m_bVerifyingExtraFiles = false;
|
||||
}
|
||||
|
||||
return bFragmentsAdded;
|
||||
}
|
||||
|
||||
void ParChecker::signal_filename(std::string str)
|
||||
{
|
||||
info("%s file %s", m_bRepairing ? "Repairing" : "Verifying", str.c_str());
|
||||
char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
|
||||
|
||||
if (m_eStage == ptRepairing)
|
||||
{
|
||||
m_eStage = ptVerifyingRepaired;
|
||||
}
|
||||
|
||||
info("%s %s", szStageMessage[m_eStage], str.c_str());
|
||||
|
||||
snprintf(m_szProgressLabel, 1024, "%s %s", szStageMessage[m_eStage], str.c_str());
|
||||
m_szProgressLabel[1024-1] = '\0';
|
||||
m_iFileProgress = 0;
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
void ParChecker::signal_progress(double progress)
|
||||
{
|
||||
m_iFileProgress = (int)progress;
|
||||
|
||||
if (m_eStage == ptRepairing)
|
||||
{
|
||||
// calculating repair-data for all files
|
||||
m_iStageProgress = m_iFileProgress;
|
||||
}
|
||||
else
|
||||
{
|
||||
// processing individual files
|
||||
|
||||
int iTotalFiles = 0;
|
||||
if (m_eStage == ptVerifyingRepaired)
|
||||
{
|
||||
// repairing individual files
|
||||
iTotalFiles = m_iFilesToRepair;
|
||||
}
|
||||
else
|
||||
{
|
||||
// verifying individual files
|
||||
iTotalFiles = ((Repairer*)m_pRepairer)->sourcefiles.size() + m_iExtraFiles;
|
||||
}
|
||||
|
||||
if (iTotalFiles > 0)
|
||||
{
|
||||
if (m_iFileProgress < 1000)
|
||||
{
|
||||
m_iStageProgress = (m_iProcessedFiles * 1000 + m_iFileProgress) / iTotalFiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iStageProgress = m_iProcessedFiles * 1000 / iTotalFiles;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iStageProgress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
debug("Current-progres: %i, Total-progress: %i", m_iFileProgress, m_iStageProgress);
|
||||
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
void ParChecker::signal_done(std::string str, int available, int total)
|
||||
{
|
||||
m_iProcessedFiles++;
|
||||
|
||||
if (m_eStage == ptVerifyingSources)
|
||||
{
|
||||
if (available < total && !m_bVerifyingExtraFiles)
|
||||
{
|
||||
bool bFileExists = true;
|
||||
|
||||
for (vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
|
||||
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
|
||||
{
|
||||
Par2RepairerSourceFile *sourcefile = *it;
|
||||
if (sourcefile && !strcmp(str.c_str(), Util::BaseFileName(sourcefile->TargetFileName().c_str())) &&
|
||||
!sourcefile->GetTargetExists())
|
||||
{
|
||||
bFileExists = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFileExists)
|
||||
{
|
||||
warn("File %s has %i bad block(s) of total %i block(s)", str.c_str(), total - available, total);
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("File %s with %i block(s) is missing", str.c_str(), total);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
48
ParChecker.h
48
ParChecker.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -44,32 +44,57 @@ public:
|
||||
psFailed,
|
||||
psFinished
|
||||
};
|
||||
struct BlockInfo
|
||||
|
||||
enum EStage
|
||||
{
|
||||
FileInfo* m_pFileInfo;
|
||||
int m_iBlockCount;
|
||||
ptLoadingPars,
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
};
|
||||
|
||||
|
||||
typedef std::deque<char*> QueuedParFiles;
|
||||
typedef std::deque<BlockInfo*> Blocks;
|
||||
|
||||
private:
|
||||
char* m_szInfoName;
|
||||
char* m_szNZBFilename;
|
||||
char* m_szParFilename;
|
||||
EStatus m_eStatus;
|
||||
EStage m_eStage;
|
||||
void* m_pRepairer; // declared as void* to prevent the including of libpar2-headers into this header-file
|
||||
char* m_szErrMsg;
|
||||
bool m_bRepairNotNeeded;
|
||||
QueuedParFiles m_QueuedParFiles;
|
||||
Mutex m_mutexQueuedParFiles;
|
||||
Semaphore m_semNeedMoreFiles;
|
||||
bool m_bRepairing;
|
||||
int m_iProcessedFiles;
|
||||
int m_iFilesToRepair;
|
||||
int m_iExtraFiles;
|
||||
bool m_bVerifyingExtraFiles;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
int m_iStageProgress;
|
||||
|
||||
bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
void FindPars(DownloadQueue* pDownloadQueue, Blocks* pBlocks, bool bStrictParName, int* pBlockFound);
|
||||
void LoadMorePars(void* repairer);
|
||||
bool LoadMorePars();
|
||||
bool CheckSplittedFragments();
|
||||
bool AddSplittedFragments(const char* szFilename);
|
||||
void signal_filename(std::string str);
|
||||
|
||||
void signal_progress(double progress);
|
||||
void signal_done(std::string str, int available, int total);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Unpause par2-files
|
||||
* returns true, if the files with required number of blocks were unpaused,
|
||||
* or false if there are no more files in queue for this collection or not enough blocks
|
||||
*/
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound) = 0;
|
||||
virtual void UpdateProgress() {}
|
||||
EStage GetStage() { return m_eStage; }
|
||||
const char* GetProgressLabel() { return m_szProgressLabel; }
|
||||
int GetFileProgress() { return m_iFileProgress; }
|
||||
int GetStageProgress() { return m_iStageProgress; }
|
||||
|
||||
public:
|
||||
ParChecker();
|
||||
virtual ~ParChecker();
|
||||
@@ -86,7 +111,6 @@ public:
|
||||
bool GetRepairNotNeeded() { return m_bRepairNotNeeded; }
|
||||
void AddParFile(const char* szParFilename);
|
||||
void QueueChanged();
|
||||
static bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
154
PostInfo.cpp
Normal file
154
PostInfo.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "PostInfo.h"
|
||||
#include "Options.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
int PostInfo::m_iIDGen = 0;
|
||||
|
||||
PostInfo::PostInfo()
|
||||
{
|
||||
debug("Creating PostInfo");
|
||||
|
||||
m_szNZBFilename = NULL;
|
||||
m_szDestDir = NULL;
|
||||
m_szParFilename = NULL;
|
||||
m_szInfoName = NULL;
|
||||
m_bWorking = false;
|
||||
m_bParCheck = false;
|
||||
m_iParStatus = 0;
|
||||
m_bParFailed = false;
|
||||
m_szProgressLabel = strdup("");
|
||||
m_iFileProgress = 0;
|
||||
m_iStageProgress = 0;
|
||||
m_tStartTime = 0;
|
||||
m_tStageTime = 0;
|
||||
m_eStage = ptQueued;
|
||||
m_pScriptThread = NULL;
|
||||
m_Messages.clear();
|
||||
m_iIDGen++;
|
||||
m_iID = m_iIDGen;
|
||||
}
|
||||
|
||||
PostInfo::~ PostInfo()
|
||||
{
|
||||
debug("Destroying PostInfo");
|
||||
|
||||
if (m_szNZBFilename)
|
||||
{
|
||||
free(m_szNZBFilename);
|
||||
}
|
||||
if (m_szDestDir)
|
||||
{
|
||||
free(m_szDestDir);
|
||||
}
|
||||
if (m_szParFilename)
|
||||
{
|
||||
free(m_szParFilename);
|
||||
}
|
||||
if (m_szInfoName)
|
||||
{
|
||||
free(m_szInfoName);
|
||||
}
|
||||
if (m_szProgressLabel)
|
||||
{
|
||||
free(m_szProgressLabel);
|
||||
}
|
||||
for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Messages.clear();
|
||||
}
|
||||
|
||||
void PostInfo::SetNZBFilename(const char* szNZBFilename)
|
||||
{
|
||||
m_szNZBFilename = strdup(szNZBFilename);
|
||||
}
|
||||
|
||||
void PostInfo::SetDestDir(const char* szDestDir)
|
||||
{
|
||||
m_szDestDir = strdup(szDestDir);
|
||||
}
|
||||
|
||||
void PostInfo::SetParFilename(const char* szParFilename)
|
||||
{
|
||||
m_szParFilename = strdup(szParFilename);
|
||||
}
|
||||
|
||||
void PostInfo::SetInfoName(const char* szInfoName)
|
||||
{
|
||||
m_szInfoName = strdup(szInfoName);
|
||||
}
|
||||
|
||||
void PostInfo::SetProgressLabel(const char* szProgressLabel)
|
||||
{
|
||||
if (m_szProgressLabel)
|
||||
{
|
||||
free(m_szProgressLabel);
|
||||
}
|
||||
m_szProgressLabel = strdup(szProgressLabel);
|
||||
}
|
||||
|
||||
PostInfo::Messages* PostInfo::LockMessages()
|
||||
{
|
||||
m_mutexLog.Lock();
|
||||
return &m_Messages;
|
||||
}
|
||||
|
||||
void PostInfo::UnlockMessages()
|
||||
{
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
|
||||
void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
Message* pMessage = new Message(++m_iIDGen, eKind, time(NULL), szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
{
|
||||
Message* pMessage = m_Messages.front();
|
||||
delete pMessage;
|
||||
m_Messages.pop_front();
|
||||
}
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
113
PostInfo.h
Normal file
113
PostInfo.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef POSTINFO_H
|
||||
#define POSTINFO_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
|
||||
class PostInfo
|
||||
{
|
||||
public:
|
||||
enum EStage
|
||||
{
|
||||
ptQueued,
|
||||
ptLoadingPars,
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
ptExecutingScript,
|
||||
ptFinished
|
||||
};
|
||||
|
||||
typedef std::deque<Message*> Messages;
|
||||
|
||||
private:
|
||||
int m_iID;
|
||||
char* m_szNZBFilename;
|
||||
char* m_szDestDir;
|
||||
char* m_szParFilename;
|
||||
char* m_szInfoName;
|
||||
bool m_bWorking;
|
||||
bool m_bParCheck;
|
||||
int m_iParStatus;
|
||||
bool m_bParFailed;
|
||||
EStage m_eStage;
|
||||
char* m_szProgressLabel;
|
||||
int m_iFileProgress;
|
||||
int m_iStageProgress;
|
||||
time_t m_tStartTime;
|
||||
time_t m_tStageTime;
|
||||
Thread* m_pScriptThread;
|
||||
|
||||
Mutex m_mutexLog;
|
||||
Messages m_Messages;
|
||||
static int m_iIDGen;
|
||||
|
||||
public:
|
||||
PostInfo();
|
||||
~PostInfo();
|
||||
int GetID() { return m_iID; }
|
||||
const char* GetNZBFilename() { return m_szNZBFilename; }
|
||||
void SetNZBFilename(const char* szNZBFilename);
|
||||
const char* GetDestDir() { return m_szDestDir; }
|
||||
void SetDestDir(const char* szDestDir);
|
||||
const char* GetParFilename() { return m_szParFilename; }
|
||||
void SetParFilename(const char* szParFilename);
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
void SetInfoName(const char* szInfoName);
|
||||
EStage GetStage() { return m_eStage; }
|
||||
void SetStage(EStage eStage) { m_eStage = eStage; }
|
||||
void SetProgressLabel(const char* szProgressLabel);
|
||||
const char* GetProgressLabel() { return m_szProgressLabel; }
|
||||
int GetFileProgress() { return m_iFileProgress; }
|
||||
void SetFileProgress(int iFileProgress) { m_iFileProgress = iFileProgress; }
|
||||
int GetStageProgress() { return m_iStageProgress; }
|
||||
void SetStageProgress(int iStageProgress) { m_iStageProgress = iStageProgress; }
|
||||
time_t GetStartTime() { return m_tStartTime; }
|
||||
void SetStartTime(time_t tStartTime) { m_tStartTime = tStartTime; }
|
||||
time_t GetStageTime() { return m_tStageTime; }
|
||||
void SetStageTime(time_t tStageTime) { m_tStageTime = tStageTime; }
|
||||
bool GetWorking() { return m_bWorking; }
|
||||
void SetWorking(bool bWorking) { m_bWorking = bWorking; }
|
||||
bool GetParCheck() { return m_bParCheck; }
|
||||
void SetParCheck(bool bParCheck) { m_bParCheck = bParCheck; }
|
||||
int GetParStatus() { return m_iParStatus; }
|
||||
void SetParStatus(int iParStatus) { m_iParStatus = iParStatus; }
|
||||
bool GetParFailed() { return m_bParFailed; }
|
||||
void SetParFailed(bool bParFailed) { m_bParFailed = bParFailed; }
|
||||
void AppendMessage(Message::EKind eKind, const char* szText);
|
||||
Thread* GetScriptThread() { return m_pScriptThread; }
|
||||
void SetScriptThread(Thread* pScriptThread) { m_pScriptThread = pScriptThread; }
|
||||
Messages* LockMessages();
|
||||
void UnlockMessages();
|
||||
};
|
||||
|
||||
typedef std::deque<PostInfo*> PostQueue;
|
||||
|
||||
#endif
|
||||
1048
PrePostProcessor.cpp
1048
PrePostProcessor.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Thread.h"
|
||||
#include "Observer.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "PostInfo.h"
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include "ParChecker.h"
|
||||
@@ -38,24 +39,6 @@
|
||||
|
||||
class PrePostProcessor : public Thread
|
||||
{
|
||||
public:
|
||||
class ParJob
|
||||
{
|
||||
private:
|
||||
char* m_szNZBFilename;
|
||||
char* m_szParFilename;
|
||||
char* m_szInfoName;
|
||||
|
||||
public:
|
||||
ParJob(const char* szNZBFilename, const char* szParFilename, const char* szInfoName);
|
||||
~ParJob();
|
||||
const char* GetNZBFilename() { return m_szNZBFilename; }
|
||||
const char* GetParFilename() { return m_szParFilename; }
|
||||
const char* GetInfoName() { return m_szInfoName; }
|
||||
};
|
||||
|
||||
typedef std::deque<ParJob*> ParQueue;
|
||||
|
||||
private:
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
@@ -73,31 +56,68 @@ private:
|
||||
PrePostProcessor* owner;
|
||||
virtual void Update(Subject* Caller, void* Aspect) { owner->ParCheckerUpdate(Caller, Aspect); }
|
||||
};
|
||||
|
||||
class PostParChecker: public ParChecker
|
||||
{
|
||||
private:
|
||||
PrePostProcessor* m_Owner;
|
||||
protected:
|
||||
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
|
||||
virtual void UpdateProgress();
|
||||
|
||||
friend class PrePostProcessor;
|
||||
};
|
||||
|
||||
struct BlockInfo
|
||||
{
|
||||
FileInfo* m_pFileInfo;
|
||||
int m_iBlockCount;
|
||||
};
|
||||
|
||||
typedef std::deque<BlockInfo*> Blocks;
|
||||
#endif
|
||||
|
||||
private:
|
||||
QueueCoordinatorObserver m_QueueCoordinatorObserver;
|
||||
bool m_bHasMoreJobs;
|
||||
bool m_bPostScript;
|
||||
|
||||
void PausePars(DownloadQueue* pDownloadQueue, const char* szNZBFilename);
|
||||
void CheckIncomingNZBs();
|
||||
bool WasLastInCollection(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, bool bIgnorePaused);
|
||||
void ExecPostScript(const char* szPath, const char* szNZBFilename, const char * szParFilename, int iParStatus);
|
||||
bool IsNZBFileCompleted(DownloadQueue* pDownloadQueue, const char* szNZBFilename,
|
||||
bool bIgnoreFirstInPostQueue, bool bIgnorePaused, bool bCheckPostQueue);
|
||||
bool CheckScript(FileInfo* pFileInfo);
|
||||
bool JobExists(PostQueue* pPostQueue, const char* szNZBFilename);
|
||||
bool ClearCompletedJobs(const char* szNZBFilename);
|
||||
void CheckPostQueue();
|
||||
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartScriptJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void SavePostQueue();
|
||||
void SanitisePostQueue();
|
||||
void CheckDiskSpace();
|
||||
|
||||
|
||||
Mutex m_mutexParChecker;
|
||||
ParQueue m_ParQueue;
|
||||
Mutex m_mutexQueue;
|
||||
PostQueue m_PostQueue;
|
||||
PostQueue m_CompletedJobs;
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
ParChecker m_ParChecker;
|
||||
PostParChecker m_ParChecker;
|
||||
ParCheckerObserver m_ParCheckerObserver;
|
||||
|
||||
void ParCheckerUpdate(Subject* Caller, void* Aspect);
|
||||
void CheckParQueue();
|
||||
void CheckPars(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo);
|
||||
bool CheckPars(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo);
|
||||
bool AddPar(FileInfo* pFileInfo, bool bDeleted);
|
||||
bool SameParCollection(const char* szFilename1, const char* szFilename2);
|
||||
bool FindMainPars(const char* szPath, FileList* pFileList);
|
||||
int GetParCleanupQueueGroup(DownloadQueue* pDownloadQueue, const char* szNZBFilename);
|
||||
bool HasFailedParJobs(const char* szNZBFilename);
|
||||
bool ParJobExists(PostQueue* pPostQueue, const char* szParFilename);
|
||||
bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
|
||||
bool RequestMorePars(const char* szNZBFilename, const char* szParFilename, int iBlockNeeded, int* pBlockFound);
|
||||
void FindPars(DownloadQueue* pDownloadQueue, const char* szNZBFilename, const char* szParFilename,
|
||||
Blocks* pBlocks, bool bStrictParName, bool bExactParName, int* pBlockFound);
|
||||
void UpdateParProgress();
|
||||
void StartParJob(PostInfo* pPostInfo);
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -107,8 +127,8 @@ public:
|
||||
virtual void Stop();
|
||||
void QueueCoordinatorUpdate(Subject* Caller, void* Aspect);
|
||||
bool HasMoreJobs() { return m_bHasMoreJobs; }
|
||||
ParQueue* LockParQueue();
|
||||
void UnlockParQueue();
|
||||
PostQueue* LockPostQueue();
|
||||
void UnlockPostQueue();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -107,15 +107,15 @@ void QueueCoordinator::Run()
|
||||
|
||||
m_mutexDownloadQueue.Lock();
|
||||
|
||||
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pDiskState->Exists())
|
||||
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pDiskState->DownloadQueueExists())
|
||||
{
|
||||
if (g_pOptions->GetReloadQueue())
|
||||
{
|
||||
g_pDiskState->Load(&m_DownloadQueue);
|
||||
g_pDiskState->LoadDownloadQueue(&m_DownloadQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pDiskState->Discard();
|
||||
g_pDiskState->DiscardDownloadQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +212,10 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
DownloadQueue DupeList;
|
||||
DupeList.clear();
|
||||
|
||||
int index1 = 0;
|
||||
for (NZBFile::FileInfos::iterator it = pNZBFile->GetFileInfos()->begin(); it != pNZBFile->GetFileInfos()->end(); it++)
|
||||
{
|
||||
index1++;
|
||||
FileInfo* pFileInfo = *it;
|
||||
|
||||
if (g_pOptions->GetDupeCheck())
|
||||
@@ -224,11 +226,15 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
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++)
|
||||
{
|
||||
index2++;
|
||||
FileInfo* pFileInfo2 = *it2;
|
||||
if (!strcmp(pFileInfo->GetFilename(), pFileInfo2->GetFilename()) &&
|
||||
(pFileInfo->GetSize() < pFileInfo2->GetSize()))
|
||||
if (pFileInfo != pFileInfo2 &&
|
||||
!strcmp(pFileInfo->GetFilename(), pFileInfo2->GetFilename()) &&
|
||||
(pFileInfo->GetSize() < pFileInfo2->GetSize() ||
|
||||
(pFileInfo->GetSize() == pFileInfo2->GetSize() && index2 < index1)))
|
||||
{
|
||||
warn("File \"%s\" appears twice in nzb-request, adding only the biggest file", pFileInfo->GetFilename());
|
||||
dupe = true;
|
||||
@@ -267,7 +273,10 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
for (DownloadQueue::iterator it = DupeList.begin(); it != DupeList.end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
g_pDiskState->DiscardFile(NULL, pFileInfo);
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->DiscardFile(NULL, pFileInfo);
|
||||
}
|
||||
delete pFileInfo;
|
||||
}
|
||||
|
||||
@@ -278,7 +287,7 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst)
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->Save(&m_DownloadQueue);
|
||||
g_pDiskState->SaveDownloadQueue(&m_DownloadQueue);
|
||||
}
|
||||
|
||||
m_mutexDownloadQueue.Unlock();
|
||||
@@ -315,7 +324,7 @@ float QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
iTotal += m_iSpeedBytes[i];
|
||||
}
|
||||
|
||||
float fSpeed = iTotal / 1024.0 / SPEEDMETER_SECONDS;
|
||||
float fSpeed = iTotal / 1024.0f / SPEEDMETER_SECONDS;
|
||||
|
||||
return fSpeed;
|
||||
}
|
||||
@@ -331,7 +340,7 @@ float QueueCoordinator::CalcCurrentDownloadSpeed()
|
||||
*/
|
||||
void QueueCoordinator::AddSpeedReading(int iBytes)
|
||||
{
|
||||
int iIndex = time(NULL);
|
||||
int iIndex = (int)time(NULL);
|
||||
|
||||
if (iIndex - m_iSpeedBytesIndex > SPEEDMETER_SECONDS)
|
||||
{
|
||||
@@ -475,7 +484,7 @@ void QueueCoordinator::BuildArticleFilename(ArticleDownloader* pArticleDownloade
|
||||
pArticleDownloader->SetTempFilename(tmpname);
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
pFileInfo->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
pFileInfo->GetNZBInfo()->GetNiceNZBName(szNZBNiceName, 1024);
|
||||
|
||||
snprintf(name, 1024, "%s%c%s [%i/%i]", szNZBNiceName, (int)PATH_SEPARATOR, pFileInfo->GetFilename(), pArticleInfo->GetPartNumber(), pFileInfo->GetArticles()->size());
|
||||
name[1024-1] = '\0';
|
||||
@@ -588,10 +597,11 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
|
||||
}
|
||||
if (deleteFileObj)
|
||||
{
|
||||
bool fileDeleted = pFileInfo->GetDeleted();
|
||||
// delete File from Queue
|
||||
pFileInfo->SetDeleted(true);
|
||||
|
||||
Aspect aspect = { fileCompleted ? eaFileCompleted : eaFileDeleted, pFileInfo, &m_DownloadQueue, NULL };
|
||||
Aspect aspect = { fileCompleted && !fileDeleted ? eaFileCompleted : eaFileDeleted, pFileInfo, &m_DownloadQueue, NULL };
|
||||
Notify(&aspect);
|
||||
|
||||
DeleteFileInfo(pFileInfo, fileCompleted);
|
||||
@@ -659,7 +669,7 @@ bool QueueCoordinator::IsDupe(FileInfo* pFileInfo)
|
||||
for (DownloadQueue::iterator it = m_DownloadQueue.begin(); it != m_DownloadQueue.end(); it++)
|
||||
{
|
||||
FileInfo* pQueueEntry = *it;
|
||||
if (!strcmp(pFileInfo->GetDestDir(), pQueueEntry->GetDestDir()) &&
|
||||
if (!strcmp(pFileInfo->GetNZBInfo()->GetDestDir(), pQueueEntry->GetNZBInfo()->GetDestDir()) &&
|
||||
!strcmp(pFileInfo->GetFilename(), pQueueEntry->GetFilename()) &&
|
||||
pFileInfo != pQueueEntry)
|
||||
{
|
||||
@@ -719,7 +729,7 @@ void QueueCoordinator::ResetHangingDownloads()
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not terminate hanging download %s", BaseFileName(pArticleInfo->GetResultFilename()));
|
||||
error("Could not terminate hanging download %s", Util::BaseFileName(pArticleInfo->GetResultFilename()));
|
||||
}
|
||||
m_ActiveDownloads.erase(it);
|
||||
// it's not safe to destroy pArticleDownloader, because the state of object is unknown
|
||||
@@ -761,7 +771,7 @@ void QueueCoordinator::CalcStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAl
|
||||
m_mutexStat.Lock();
|
||||
if (m_tStartServer > 0)
|
||||
{
|
||||
*iUpTimeSec = time(NULL) - m_tStartServer;
|
||||
*iUpTimeSec = (int)(time(NULL) - m_tStartServer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -770,11 +780,11 @@ void QueueCoordinator::CalcStat(int* iUpTimeSec, int* iDnTimeSec, long long* iAl
|
||||
*bStandBy = m_bStandBy;
|
||||
if (m_bStandBy)
|
||||
{
|
||||
*iDnTimeSec = m_tPausedFrom - m_tStartDownload;
|
||||
*iDnTimeSec = (int)(m_tPausedFrom - m_tStartDownload);
|
||||
}
|
||||
else
|
||||
{
|
||||
*iDnTimeSec = time(NULL) - m_tStartDownload;
|
||||
*iDnTimeSec = (int)(time(NULL) - m_tStartDownload);
|
||||
}
|
||||
*iAllBytes = m_iAllBytes;
|
||||
m_mutexStat.Unlock();
|
||||
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
void AddNZBFileToQueue(NZBFile* pNZBQueue, bool bAddFirst);
|
||||
bool AddFileToQueue(const char* szFileName);
|
||||
bool HasMoreJobs() { return m_bHasMoreJobs; }
|
||||
bool GetStandBy() { return m_bStandBy; }
|
||||
bool DeleteQueueEntry(FileInfo* pFileInfo);
|
||||
QueueEditor* GetQueueEditor() { return &m_QueueEditor; }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -169,7 +169,7 @@ bool QueueEditor::EditList(IDList* pIDList, bool bSmartOrder, EEditAction eActio
|
||||
|
||||
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
|
||||
{
|
||||
g_pDiskState->Save(pDownloadQueue);
|
||||
g_pDiskState->SaveDownloadQueue(pDownloadQueue);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
@@ -353,7 +353,7 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo2 = *it;
|
||||
if (!strcmp(pFileInfo2->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
if (pFileInfo2->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
cIDList.push_back(pFileInfo2->GetID());
|
||||
}
|
||||
@@ -368,7 +368,7 @@ bool QueueEditor::EditGroup(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo,
|
||||
for (FileList::iterator it = cGroupList.begin(); it != cGroupList.end(); it++, iNum++)
|
||||
{
|
||||
FileInfo* pGroupInfo = *it;
|
||||
if (!strcmp(pGroupInfo->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
if (pGroupInfo->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -421,7 +421,7 @@ void QueueEditor::BuildGroupList(DownloadQueue* pDownloadQueue, FileList* pGroup
|
||||
for (FileList::iterator itg = pGroupList->begin(); itg != pGroupList->end(); itg++)
|
||||
{
|
||||
FileInfo* pGroupInfo1 = *itg;
|
||||
if (!strcmp(pGroupInfo1->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
if (pGroupInfo1->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
pGroupInfo = pGroupInfo1;
|
||||
break;
|
||||
@@ -465,7 +465,7 @@ void QueueEditor::AlignAffectedGroups(DownloadQueue* pDownloadQueue, IDList* pID
|
||||
for (FileList::iterator it = cGroupList.begin(); it != cGroupList.end(); it++, iNum++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
if (!strcmp(pItem->m_pFileInfo->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
if (pItem->m_pFileInfo->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
if (!ItemExists(&cAffectedGroupList, pFileInfo))
|
||||
{
|
||||
@@ -519,7 +519,7 @@ void QueueEditor::AlignGroup(DownloadQueue* pDownloadQueue, FileInfo* pFirstFile
|
||||
while (iNum < pDownloadQueue->size())
|
||||
{
|
||||
FileInfo* pFileInfo = (*pDownloadQueue)[iNum];
|
||||
if (!strcmp(pFirstFileInfo->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
||||
if (pFirstFileInfo->GetNZBInfo() == pFileInfo->GetNZBInfo())
|
||||
{
|
||||
if (pLastFileInfo && iNum - iLastNum > 1)
|
||||
{
|
||||
@@ -549,7 +549,7 @@ void QueueEditor::PauseParsInGroups(ItemList* pItemList, bool bExtraParsOnly)
|
||||
{
|
||||
EditItem* pItem = *it;
|
||||
if (!pFirstFileInfo ||
|
||||
!strcmp(pFirstFileInfo->GetNZBFilename(), pItem->m_pFileInfo->GetNZBFilename()))
|
||||
(pFirstFileInfo->GetNZBInfo() == pItem->m_pFileInfo->GetNZBInfo()))
|
||||
{
|
||||
GroupFileList.push_back(pItem->m_pFileInfo);
|
||||
if (!pFirstFileInfo)
|
||||
|
||||
75
README
75
README
@@ -41,7 +41,7 @@ NZBGet is written in C++ and was initialy developed on Linux.
|
||||
It was ported to Windows later and tested for compatibility with
|
||||
several POSIX-OS'es.
|
||||
|
||||
The current version (0.3.1) should run at least on:
|
||||
The current version (0.4.0) should run at least on:
|
||||
- Linux Debian 4.0 on x86;
|
||||
- Linux BusyBox with uClibc on MIPSEL;
|
||||
- PC-BSD 1.4 (based on FreeBSD 6.2) on x86;
|
||||
@@ -87,9 +87,6 @@ And the following libraries are optional:
|
||||
- libpar2 (http://parchive.sourceforge.net)
|
||||
- libsigc++ (http://libsigc.sourceforge.net)
|
||||
|
||||
- for support of encoding-formats other than yEnc (disabled by default):
|
||||
- libuu (http://www.fpx.de/fp/Software/UUDeview)
|
||||
|
||||
All these libraries are included in modern Linux distributions and
|
||||
should be available as installable packages. Please note that you also
|
||||
need the developer packages for these libraries too, they package names
|
||||
@@ -110,11 +107,10 @@ Well, the usual stuff:
|
||||
- configure it via
|
||||
./configure
|
||||
(maybe you have to tell configure, where to find some libraries.
|
||||
./configure --help is your friend! ;-)
|
||||
./configure --help is your friend!)
|
||||
also see "Configure-options" later.)
|
||||
- compile it via
|
||||
make
|
||||
(you may get some warnings concerning 'mktemp', simply ignore them!)
|
||||
- become root via
|
||||
su
|
||||
- install it via
|
||||
@@ -124,10 +120,6 @@ Configure-options
|
||||
-----------------
|
||||
You may run configure with additional arguments:
|
||||
|
||||
--enable-uulib - to make with uulib-library, in a case you want it
|
||||
(see later section "Optional package: uulib"). This option is not
|
||||
enabled by default.
|
||||
|
||||
--disable-curses - to make without curses-support. Use this option
|
||||
if you can not use curses/ncurses.
|
||||
|
||||
@@ -136,63 +128,18 @@ You may run configure with additional arguments:
|
||||
|
||||
--enable-debug - to build in debug-mode, if you want to see and log
|
||||
debug-messages.
|
||||
|
||||
Optional package: uulib
|
||||
-----------------------
|
||||
uulib is not required to compile and run nzbget, because nzbget includes
|
||||
internal decoder for yEnc-format. However, uulib supports many other formats,
|
||||
you may possibly want to have support for. In this case you can build the
|
||||
program with uulib-support enabled.
|
||||
|
||||
NOTE: enabling uulib does not disable internal decoder. The program built with
|
||||
uulib-support can use both decoders (internal and uulib), depending on option
|
||||
"decoder" in program's configuration file.
|
||||
|
||||
To build with uulib use option "--enable-uulib" while running configure:
|
||||
|
||||
./configure --enable-uulib
|
||||
|
||||
The uulib must be installed on your system. On most linux distributions
|
||||
the package uulib-dev is available. So you only need to install this package
|
||||
and run configure with parameter "--enable-uulib".
|
||||
If you do not have this package you can compile uulib yourself:
|
||||
|
||||
- download source code of uudeview from
|
||||
http://www.fpx.de/fp/Software/UUDeview;
|
||||
- build uudeview as usually:
|
||||
/.confugure
|
||||
make
|
||||
- start nzbget's configure-script with following parameters:
|
||||
./configure --enable-uulib \
|
||||
--with-uulib-includes=<path to uudeview>/uulib \
|
||||
--with-uulib-libraries=<path to uudeview>/uulib
|
||||
for example:
|
||||
./configure --enable-uulib \
|
||||
--with-uulib-includes=/home/user/uudeview-0.5.20/uulib \
|
||||
--with-uulib-libraries=/home/user/uudeview-0.5.20/uulib
|
||||
- now you can compile nzbget.
|
||||
|
||||
NOTE: after nzbget is compiled, the code of uulib-library is built into
|
||||
nzbget's executable. You do not need to have uulib on target system
|
||||
to run nzbget.
|
||||
|
||||
|
||||
Optional package: par-check
|
||||
---------------------------
|
||||
NZBGet can check and repair downloaded files for you. For this purpose
|
||||
it uses library par2 (libpar2), which needs sigc++ on its part.
|
||||
|
||||
To build with par-check use option "--enable-parcheck" while running
|
||||
configure:
|
||||
|
||||
./configure --enable-parcheck
|
||||
|
||||
The libpar2 and libsigc++ (version 2 or later) must be installed on your
|
||||
system. On most linux distributions these libraries are available as packages.
|
||||
So you only need to install theme and run configure with parameter
|
||||
"--enable-parcheck".
|
||||
If you do not have these package you can compile them yourself. Please
|
||||
refer to section "Optional package: uulib" for an example on how to
|
||||
compile additional library. Following configure-parameters may be usefull:
|
||||
If you do not have these packages you can compile them yourself.
|
||||
Following configure-parameters may be usefull:
|
||||
|
||||
--with-libpar2-includes
|
||||
--with-libpar2-libraries
|
||||
@@ -201,12 +148,17 @@ compile additional library. Following configure-parameters may be usefull:
|
||||
|
||||
The library libsigc++ must be installed first, since libpar2 requires it.
|
||||
|
||||
If you are not able to use libpar2 or libsigc++ or do not want them you can
|
||||
make the program without support for par-check using option
|
||||
"--disable-parcheck":
|
||||
|
||||
./configure --disable-parcheck
|
||||
|
||||
Optional package: curses
|
||||
-------------------------
|
||||
For curses-outputmode you need ncurses or curses on your system.
|
||||
If you do not have one of them you can download and compile ncurses yourself.
|
||||
Please refer to section "Optional package: uulib" for an example on how to
|
||||
compile additional library. Following configure-parameters may be usefull:
|
||||
Following configure-parameters may be usefull:
|
||||
|
||||
--with-libcurses-includes
|
||||
--with-libcurses-libraries
|
||||
@@ -311,8 +263,7 @@ mode, not to daemon mode).
|
||||
|
||||
When the server is running it is possible to queue up downloads. This can be
|
||||
done either in terminal with "nzbget -A <nzb-file>" or by uploading
|
||||
a nzb-file into server's monitor-directory (<MAINDIR>/nzb by default, the
|
||||
directory must exist on server's start; otherwise it will not be monitored).
|
||||
a nzb-file into server's monitor-directory (<MAINDIR>/nzb by default).
|
||||
|
||||
To check the status of server start client and connect it to server:
|
||||
|
||||
|
||||
185
RemoteClient.cpp
185
RemoteClient.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -131,7 +131,7 @@ void RemoteClient::InitMessageBase(SNZBRequestBase* pMessageBase, int iRequest,
|
||||
|
||||
bool RemoteClient::ReceiveBoolResponse()
|
||||
{
|
||||
printf("request sent\n");
|
||||
printf("Request sent\n");
|
||||
|
||||
// all bool-responses have the same format of structure, we use SNZBDownloadResponse here
|
||||
SNZBDownloadResponse BoolResponse;
|
||||
@@ -142,7 +142,14 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
(int)ntohl(BoolResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(BoolResponse.m_MessageBase.m_iStructSize) != sizeof(BoolResponse))
|
||||
{
|
||||
printf("invaid response received: either not nzbget-server or wrong server version\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,7 +158,14 @@ bool RemoteClient::ReceiveBoolResponse()
|
||||
iResponseLen = m_pConnection->Recv(buf, iTextLen);
|
||||
if (iResponseLen != iTextLen)
|
||||
{
|
||||
printf("invaid response received: either not nzbget-server or wrong server version\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -168,7 +182,7 @@ bool RemoteClient::RequestServerDownload(const char* szName, bool bAddFirst)
|
||||
// Read the file into the buffer
|
||||
char* szBuffer = NULL;
|
||||
int iLength = 0;
|
||||
if (!LoadFileIntoBuffer(szName, &szBuffer, &iLength))
|
||||
if (!Util::LoadFileIntoBuffer(szName, &szBuffer, &iLength))
|
||||
{
|
||||
printf("Could not load file %s\n", szName);
|
||||
return false;
|
||||
@@ -222,6 +236,8 @@ bool RemoteClient::RequestServerList()
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Request sent\n");
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBListResponse ListResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &ListResponse, sizeof(ListResponse));
|
||||
@@ -229,7 +245,14 @@ bool RemoteClient::RequestServerList()
|
||||
(int)ntohl(ListResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(ListResponse.m_MessageBase.m_iStructSize) != sizeof(ListResponse))
|
||||
{
|
||||
printf("invaid response received: either not nzbget-server or wrong server version\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -262,14 +285,14 @@ bool RemoteClient::RequestServerList()
|
||||
{
|
||||
SNZBListResponseEntry* pListAnswer = (SNZBListResponseEntry*) pBufPtr;
|
||||
|
||||
long long lFileSize = JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo));
|
||||
long long lRemainingSize = JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo));
|
||||
long long lFileSize = Util::JoinInt64(ntohl(pListAnswer->m_iFileSizeHi), ntohl(pListAnswer->m_iFileSizeLo));
|
||||
long long lRemainingSize = Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo));
|
||||
|
||||
char szCompleted[100];
|
||||
szCompleted[0] = '\0';
|
||||
if (lRemainingSize < lFileSize)
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(100 - lRemainingSize * 100.0 / lFileSize), "%");
|
||||
sprintf(szCompleted, ", %i%s", (int)(100 - Util::Int64ToFloat(lRemainingSize) * 100.0 / Util::Int64ToFloat(lFileSize)), "%");
|
||||
}
|
||||
char szStatus[100];
|
||||
if (ntohl(pListAnswer->m_bPaused))
|
||||
@@ -286,9 +309,10 @@ bool RemoteClient::RequestServerList()
|
||||
char* szFilename = pBufPtr + sizeof(SNZBListResponseEntry) + ntohl(pListAnswer->m_iNZBFilenameLen) + ntohl(pListAnswer->m_iSubjectLen);
|
||||
|
||||
char szNZBNiceName[1024];
|
||||
FileInfo::MakeNiceNZBName(szNZBFilename, szNZBNiceName, 1024);
|
||||
NZBInfo::MakeNiceNZBName(szNZBFilename, szNZBNiceName, 1024);
|
||||
|
||||
printf("[%i] %s%c%s (%.2f MB%s)%s\n", ntohl(pListAnswer->m_iID), szNZBNiceName, (int)PATH_SEPARATOR, szFilename, lFileSize / 1024.0 / 1024.0, szCompleted, szStatus);
|
||||
printf("[%i] %s%c%s (%.2f MB%s)%s\n", ntohl(pListAnswer->m_iID), szNZBNiceName, (int)PATH_SEPARATOR, szFilename,
|
||||
(float)(Util::Int64ToFloat(lFileSize) / 1024.0 / 1024.0), szCompleted, szStatus);
|
||||
|
||||
pBufPtr += sizeof(SNZBListResponseEntry) + ntohl(pListAnswer->m_iNZBFilenameLen) +
|
||||
ntohl(pListAnswer->m_iSubjectLen) + ntohl(pListAnswer->m_iFilenameLen) + ntohl(pListAnswer->m_iDestDirLen);
|
||||
@@ -298,19 +322,20 @@ bool RemoteClient::RequestServerList()
|
||||
printf("Files: %i\n", ntohl(ListResponse.m_iNrTrailingEntries));
|
||||
if (lPaused > 0)
|
||||
{
|
||||
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", lRemaining / 1024.0 / 1024.0, lPaused / 1024.0 / 1024.0);
|
||||
printf("Remaining size: %.2f MB (+%.2f MB paused)\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0),
|
||||
(float)(Util::Int64ToFloat(lPaused) / 1024.0 / 1024.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Remaining size: %.2f MB\n", lRemaining / 1024.0 / 1024.0);
|
||||
printf("Remaining size: %.2f MB\n", (float)(Util::Int64ToFloat(lRemaining) / 1024.0 / 1024.0));
|
||||
}
|
||||
printf("Current download rate: %.1f KB/s\n", (float)(ntohl(ListResponse.m_iDownloadRate) / 1024.0));
|
||||
|
||||
free(pBuf);
|
||||
}
|
||||
|
||||
long long iAllBytes = JoinInt64(ntohl(ListResponse.m_iDownloadedBytesHi), ntohl(ListResponse.m_iDownloadedBytesLo));
|
||||
float fAverageSpeed = ntohl(ListResponse.m_iDownloadTimeSec) > 0 ? iAllBytes / ntohl(ListResponse.m_iDownloadTimeSec) : 0;
|
||||
long long iAllBytes = Util::JoinInt64(ntohl(ListResponse.m_iDownloadedBytesHi), ntohl(ListResponse.m_iDownloadedBytesLo));
|
||||
float fAverageSpeed = Util::Int64ToFloat(ntohl(ListResponse.m_iDownloadTimeSec) > 0 ? iAllBytes / ntohl(ListResponse.m_iDownloadTimeSec) : 0);
|
||||
printf("Session download rate: %.1f KB/s\n", (float)(fAverageSpeed / 1024.0));
|
||||
|
||||
if (ntohl(ListResponse.m_iDownloadLimit) > 0)
|
||||
@@ -330,13 +355,13 @@ bool RemoteClient::RequestServerList()
|
||||
s = sec % 60;
|
||||
printf("Download time: %.2d:%.2d:%.2d\n", h, m, s);
|
||||
|
||||
printf("Downloaded: %.2f MB\n", iAllBytes / 1024.0 / 1024.0);
|
||||
printf("Downloaded: %.2f MB\n", (float)(Util::Int64ToFloat(iAllBytes) / 1024.0 / 1024.0));
|
||||
|
||||
printf("Threads running: %i\n", ntohl(ListResponse.m_iThreadCount));
|
||||
|
||||
if (ntohl(ListResponse.m_iParJobCount) > 0)
|
||||
if (ntohl(ListResponse.m_iPostJobCount) > 0)
|
||||
{
|
||||
printf("Par-jobs: %i\n", (int)ntohl(ListResponse.m_iParJobCount));
|
||||
printf("Post-jobs: %i\n", (int)ntohl(ListResponse.m_iPostJobCount));
|
||||
}
|
||||
|
||||
if (ntohl(ListResponse.m_bServerStandBy))
|
||||
@@ -366,6 +391,8 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Request sent\n");
|
||||
|
||||
// Now listen for the returned log
|
||||
SNZBLogResponse LogResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &LogResponse, sizeof(LogResponse));
|
||||
@@ -373,7 +400,14 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
(int)ntohl(LogResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(LogResponse.m_MessageBase.m_iStructSize) != sizeof(LogResponse))
|
||||
{
|
||||
printf("invaid response received: either not nzbget-server or wrong server version\n");
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -419,6 +453,9 @@ bool RemoteClient::RequestServerLog(int iLines)
|
||||
case Message::mkInfo:
|
||||
printf("[INFO] %s\n", szText);
|
||||
break;
|
||||
case Message::mkDetail:
|
||||
printf("[DETAIL] %s\n", szText);
|
||||
break;
|
||||
}
|
||||
|
||||
pBufPtr += sizeof(SNZBLogResponseEntry) + ntohl(pLogAnswer->m_iTextLen);
|
||||
@@ -580,3 +617,113 @@ bool RemoteClient::RequestServerVersion()
|
||||
m_pConnection->Disconnect();
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestPostQueue()
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBPostQueueRequest PostQueueRequest;
|
||||
InitMessageBase(&PostQueueRequest.m_MessageBase, eRemoteRequestPostQueue, sizeof(PostQueueRequest));
|
||||
|
||||
if (m_pConnection->Send((char*)(&PostQueueRequest), sizeof(PostQueueRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Request sent\n");
|
||||
|
||||
// Now listen for the returned list
|
||||
SNZBPostQueueResponse PostQueueResponse;
|
||||
int iResponseLen = m_pConnection->Recv((char*) &PostQueueResponse, sizeof(PostQueueResponse));
|
||||
if (iResponseLen != sizeof(PostQueueResponse) ||
|
||||
(int)ntohl(PostQueueResponse.m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE ||
|
||||
ntohl(PostQueueResponse.m_MessageBase.m_iStructSize) != sizeof(PostQueueResponse))
|
||||
{
|
||||
if (iResponseLen < 0)
|
||||
{
|
||||
printf("No response received (timeout)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid response received: either not nzbget-server or wrong server version\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char* pBuf = NULL;
|
||||
if (ntohl(PostQueueResponse.m_iTrailingDataLength) > 0)
|
||||
{
|
||||
pBuf = (char*)malloc(ntohl(PostQueueResponse.m_iTrailingDataLength));
|
||||
if (!m_pConnection->RecvAll(pBuf, ntohl(PostQueueResponse.m_iTrailingDataLength)))
|
||||
{
|
||||
free(pBuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_pConnection->Disconnect();
|
||||
|
||||
if (ntohl(PostQueueResponse.m_iTrailingDataLength) == 0)
|
||||
{
|
||||
printf("Server has no files queued for post-processing\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Post-Processing List\n");
|
||||
printf("-----------------------------------\n");
|
||||
|
||||
char* pBufPtr = (char*)pBuf;
|
||||
for (unsigned int i = 0; i < ntohl(PostQueueResponse.m_iNrTrailingEntries); i++)
|
||||
{
|
||||
SNZBPostQueueResponseEntry* pPostQueueAnswer = (SNZBPostQueueResponseEntry*) pBufPtr;
|
||||
|
||||
int iStageProgress = ntohl(pPostQueueAnswer->m_iStageProgress);
|
||||
|
||||
static const int EXECUTING_SCRIPT = 5;
|
||||
char szCompleted[100];
|
||||
szCompleted[0] = '\0';
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != EXECUTING_SCRIPT)
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(iStageProgress / 10), "%");
|
||||
}
|
||||
|
||||
char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Executing postprocess-script", "" };
|
||||
char* szInfoName = pBufPtr + sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen) + ntohl(pPostQueueAnswer->m_iParFilename);
|
||||
|
||||
printf("[%i] %s%s%s\n", ntohl(pPostQueueAnswer->m_iID), szInfoName, szPostStageName[ntohl(pPostQueueAnswer->m_iStage)], szCompleted);
|
||||
|
||||
pBufPtr += sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen) +
|
||||
ntohl(pPostQueueAnswer->m_iParFilename) + ntohl(pPostQueueAnswer->m_iInfoNameLen) +
|
||||
ntohl(pPostQueueAnswer->m_iDestDirLen) + ntohl(pPostQueueAnswer->m_iProgressLabelLen);
|
||||
}
|
||||
|
||||
free(pBuf);
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteClient::RequestWriteLog(int iKind, const char* szText)
|
||||
{
|
||||
if (!InitConnection()) return false;
|
||||
|
||||
SNZBWriteLogRequest WriteLogRequest;
|
||||
InitMessageBase(&WriteLogRequest.m_MessageBase, eRemoteRequestWriteLog, sizeof(WriteLogRequest));
|
||||
WriteLogRequest.m_iKind = htonl(iKind);
|
||||
int iLength = strlen(szText) + 1;
|
||||
WriteLogRequest.m_iTrailingDataLength = htonl(iLength);
|
||||
|
||||
if (m_pConnection->Send((char*)(&WriteLogRequest), sizeof(WriteLogRequest)) < 0)
|
||||
{
|
||||
perror("m_pConnection->Send");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pConnection->Send(szText, iLength);
|
||||
bool OK = ReceiveBoolResponse();
|
||||
m_pConnection->Disconnect();
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
bool RequestServerLog(int iLines);
|
||||
bool RequestServerShutdown();
|
||||
bool RequestServerVersion();
|
||||
bool RequestPostQueue();
|
||||
bool RequestWriteLog(int iKind, const char* szText);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
619
RemoteServer.cpp
619
RemoteServer.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -43,34 +43,12 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "RemoteServer.h"
|
||||
#include "BinRpc.h"
|
||||
#include "XmlRpc.h"
|
||||
#include "Log.h"
|
||||
#include "Options.h"
|
||||
#include "QueueCoordinator.h"
|
||||
#include "QueueEditor.h"
|
||||
#include "PrePostProcessor.h"
|
||||
#include "Util.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern PrePostProcessor* g_pPrePostProcessor;
|
||||
extern void ExitProc();
|
||||
|
||||
const char* g_szMessageRequestNames[] =
|
||||
{ "N/A", "Download", "Pause/Unpause", "List",
|
||||
"Set download rate", "Dump debug", "Edit queue", "Log", "Quit"
|
||||
};
|
||||
|
||||
const unsigned int g_iMessageRequestSizes[] =
|
||||
{ 0,
|
||||
sizeof(SNZBDownloadRequest),
|
||||
sizeof(SNZBPauseUnpauseRequest),
|
||||
sizeof(SNZBListRequest),
|
||||
sizeof(SNZBSetDownloadRateRequest),
|
||||
sizeof(SNZBDumpDebugRequest),
|
||||
sizeof(SNZBEditQueueRequest),
|
||||
sizeof(SNZBLogRequest),
|
||||
sizeof(SNZBRequestBase)
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// RemoteServer
|
||||
@@ -160,546 +138,89 @@ void RemoteServer::Stop()
|
||||
|
||||
void RequestProcessor::Run()
|
||||
{
|
||||
int iBytesReceived = 0;
|
||||
|
||||
// Read the first package which needs to be a request
|
||||
|
||||
iBytesReceived = recv(m_iSocket, (char*) & m_MessageBase, sizeof(m_MessageBase), 0);
|
||||
// Read the first 4 bytes to determine request type
|
||||
bool bOK = false;
|
||||
int iSignature = 0;
|
||||
int iBytesReceived = recv(m_iSocket, (char*)&iSignature, sizeof(iSignature), 0);
|
||||
if (iBytesReceived < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure this is a nzbget request from a client
|
||||
if ((int)ntohl(m_MessageBase.m_iSignature) != (int)NZBMESSAGE_SIGNATURE)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i", g_pOptions->GetServerPort());
|
||||
|
||||
if (m_iSocket > -1)
|
||||
{
|
||||
closesocket(m_iSocket);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(m_MessageBase.m_szPassword, g_pOptions->GetServerPassword()))
|
||||
{
|
||||
warn("nzbget request received on port %i, but password invalid", g_pOptions->GetServerPort());
|
||||
|
||||
if (m_iSocket > -1)
|
||||
{
|
||||
closesocket(m_iSocket);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Info - connection received
|
||||
#ifdef WIN32
|
||||
char* ip = NULL;
|
||||
#else
|
||||
char ip[20];
|
||||
#endif
|
||||
struct sockaddr_in PeerName;
|
||||
int iPeerNameLength = sizeof(PeerName);
|
||||
if (getpeername(m_iSocket, (struct sockaddr*)&PeerName, (socklen_t*) &iPeerNameLength) >= 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char* ip = inet_ntoa(PeerName.sin_addr);
|
||||
ip = inet_ntoa(PeerName.sin_addr);
|
||||
#else
|
||||
char ip[20];
|
||||
inet_ntop(AF_INET, &PeerName.sin_addr, ip, sizeof(ip));
|
||||
#endif
|
||||
debug("%s request received from %s", g_szMessageRequestNames[ntohl(m_MessageBase.m_iType)], ip);
|
||||
}
|
||||
|
||||
Dispatch();
|
||||
if ((int)ntohl(iSignature) == (int)NZBMESSAGE_SIGNATURE)
|
||||
{
|
||||
// binary request received
|
||||
bOK = true;
|
||||
BinRpcProcessor processor;
|
||||
processor.SetSocket(m_iSocket);
|
||||
processor.SetSignature(iSignature);
|
||||
processor.SetClientIP(ip);
|
||||
processor.Execute();
|
||||
}
|
||||
else if (!strncmp((char*)&iSignature, "POST", 4) || !strncmp((char*)&iSignature, "GET ", 4))
|
||||
{
|
||||
// XML-RPC or JSON-RPC request received
|
||||
Connection con(m_iSocket, false);
|
||||
char szBuffer[1024];
|
||||
if (con.ReadLine(szBuffer, sizeof(szBuffer), NULL))
|
||||
{
|
||||
XmlRpcProcessor::EHttpMethod eHttpMethod = XmlRpcProcessor::hmGet;
|
||||
char* szUrl = szBuffer;
|
||||
if (!strncmp((char*)&iSignature, "POST", 4))
|
||||
{
|
||||
eHttpMethod = XmlRpcProcessor::hmPost;
|
||||
szUrl++;
|
||||
}
|
||||
if (char* p = strchr(szUrl, ' '))
|
||||
{
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
XmlRpcProcessor::ERpcProtocol eProtocol = XmlRpcProcessor::rpUndefined;
|
||||
if (!strcmp(szUrl, "/xmlrpc") || !strncmp(szUrl, "/xmlrpc/", 8))
|
||||
{
|
||||
eProtocol = XmlRpcProcessor::rpXmlRpc;
|
||||
}
|
||||
else if (!strcmp(szUrl, "/jsonrpc") || !strncmp(szUrl, "/jsonrpc/", 9))
|
||||
{
|
||||
eProtocol = XmlRpcProcessor::rpJsonRpc;
|
||||
}
|
||||
|
||||
if (eProtocol != XmlRpcProcessor::rpUndefined)
|
||||
{
|
||||
XmlRpcProcessor processor;
|
||||
processor.SetConnection(&con);
|
||||
processor.SetClientIP(ip);
|
||||
processor.SetProtocol(eProtocol);
|
||||
processor.SetHttpMethod(eHttpMethod);
|
||||
processor.SetUrl(szUrl);
|
||||
processor.Execute();
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bOK)
|
||||
{
|
||||
warn("Non-nzbget request received on port %i from %s", g_pOptions->GetServerPort(), ip);
|
||||
}
|
||||
|
||||
// Close the socket
|
||||
closesocket(m_iSocket);
|
||||
}
|
||||
|
||||
void RequestProcessor::Dispatch()
|
||||
{
|
||||
if (ntohl(m_MessageBase.m_iType) >= (int)eRemoteRequestDownload &&
|
||||
ntohl(m_MessageBase.m_iType) <= (int)eRemoteRequestShutdown &&
|
||||
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)] != ntohl(m_MessageBase.m_iStructSize))
|
||||
{
|
||||
error("Invalid size of request: needed %i Bytes, but received %i Bytes",
|
||||
g_iMessageRequestSizes[ntohl(m_MessageBase.m_iType)], ntohl(m_MessageBase.m_iStructSize));
|
||||
return;
|
||||
}
|
||||
|
||||
MessageCommand* command = NULL;
|
||||
|
||||
switch (ntohl(m_MessageBase.m_iType))
|
||||
{
|
||||
case eRemoteRequestDownload:
|
||||
{
|
||||
command = new DownloadCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestList:
|
||||
{
|
||||
command = new ListCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestLog:
|
||||
{
|
||||
command = new LogCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestPauseUnpause:
|
||||
{
|
||||
command = new PauseUnpauseCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestEditQueue:
|
||||
{
|
||||
command = new EditQueueCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestSetDownloadRate:
|
||||
{
|
||||
command = new SetDownloadRateCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestDumpDebug:
|
||||
{
|
||||
command = new DumpDebugCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestShutdown:
|
||||
{
|
||||
command = new ShutdownCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
case eRemoteRequestVersion:
|
||||
{
|
||||
command = new VersionCommand();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("Received unsupported request %i", ntohl(m_MessageBase.m_iType));
|
||||
break;
|
||||
}
|
||||
|
||||
if (command)
|
||||
{
|
||||
command->SetSocket(m_iSocket);
|
||||
command->SetMessageBase(&m_MessageBase);
|
||||
command->Execute();
|
||||
delete command;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************
|
||||
// Commands
|
||||
|
||||
void MessageCommand::SendBoolResponse(bool bSuccess, const char* szText)
|
||||
{
|
||||
// all bool-responses have the same format of structure, we use SNZBDownloadResponse here
|
||||
SNZBDownloadResponse BoolResponse;
|
||||
memset(&BoolResponse, 0, sizeof(BoolResponse));
|
||||
BoolResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
BoolResponse.m_MessageBase.m_iStructSize = htonl(sizeof(BoolResponse));
|
||||
BoolResponse.m_bSuccess = htonl(bSuccess);
|
||||
int iTextLen = strlen(szText) + 1;
|
||||
BoolResponse.m_iTrailingDataLength = htonl(iTextLen);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &BoolResponse, sizeof(BoolResponse), 0);
|
||||
send(m_iSocket, (char*)szText, iTextLen, 0);
|
||||
}
|
||||
|
||||
bool MessageCommand::ReceiveRequest(void* pBuffer, int iSize)
|
||||
{
|
||||
memcpy(pBuffer, m_pMessageBase, sizeof(SNZBRequestBase));
|
||||
iSize -= sizeof(SNZBRequestBase);
|
||||
if (iSize > 0)
|
||||
{
|
||||
int iBytesReceived = recv(m_iSocket, ((char*)pBuffer) + sizeof(SNZBRequestBase), iSize, 0);
|
||||
if (iBytesReceived != iSize)
|
||||
{
|
||||
error("invalid request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PauseUnpauseCommand::Execute()
|
||||
{
|
||||
SNZBPauseUnpauseRequest PauseUnpauseRequest;
|
||||
if (!ReceiveRequest(&PauseUnpauseRequest, sizeof(PauseUnpauseRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetPause(ntohl(PauseUnpauseRequest.m_bPause));
|
||||
SendBoolResponse(true, "Pause-/Unpause-Command completed successfully");
|
||||
}
|
||||
|
||||
void SetDownloadRateCommand::Execute()
|
||||
{
|
||||
SNZBSetDownloadRateRequest SetDownloadRequest;
|
||||
if (!ReceiveRequest(&SetDownloadRequest, sizeof(SetDownloadRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pOptions->SetDownloadRate(ntohl(SetDownloadRequest.m_iDownloadRate) / 1024.0);
|
||||
SendBoolResponse(true, "Rate-Command completed successfully");
|
||||
}
|
||||
|
||||
void DumpDebugCommand::Execute()
|
||||
{
|
||||
SNZBDumpDebugRequest DumpDebugRequest;
|
||||
if (!ReceiveRequest(&DumpDebugRequest, sizeof(DumpDebugRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->LogDebugInfo();
|
||||
SendBoolResponse(true, "Debug-Command completed successfully");
|
||||
}
|
||||
|
||||
void ShutdownCommand::Execute()
|
||||
{
|
||||
SNZBShutdownRequest ShutdownRequest;
|
||||
if (!ReceiveRequest(&ShutdownRequest, sizeof(ShutdownRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendBoolResponse(true, "Stopping server");
|
||||
ExitProc();
|
||||
}
|
||||
|
||||
void VersionCommand::Execute()
|
||||
{
|
||||
SNZBVersionRequest VersionRequest;
|
||||
if (!ReceiveRequest(&VersionRequest, sizeof(VersionRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendBoolResponse(true, VERSION);
|
||||
}
|
||||
|
||||
void DownloadCommand::Execute()
|
||||
{
|
||||
SNZBDownloadRequest DownloadRequest;
|
||||
if (!ReceiveRequest(&DownloadRequest, sizeof(DownloadRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* pRecvBuffer = (char*)malloc(ntohl(DownloadRequest.m_iTrailingDataLength) + 1);
|
||||
char* pBufPtr = pRecvBuffer;
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
int iResult = 0;
|
||||
int NeedBytes = ntohl(DownloadRequest.m_iTrailingDataLength);
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
if (NeedBytes == 0)
|
||||
{
|
||||
NZBFile* pNZBFile = NZBFile::CreateFromBuffer(DownloadRequest.m_szFilename, pRecvBuffer, ntohl(DownloadRequest.m_iTrailingDataLength));
|
||||
|
||||
if (pNZBFile)
|
||||
{
|
||||
info("Request: Queue collection %s", DownloadRequest.m_szFilename);
|
||||
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, ntohl(DownloadRequest.m_bAddFirst));
|
||||
delete pNZBFile;
|
||||
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Collection %s added to queue", BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(true, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp[1024];
|
||||
snprintf(tmp, 1024, "Download Request failed for %s", BaseFileName(DownloadRequest.m_szFilename));
|
||||
tmp[1024-1] = '\0';
|
||||
SendBoolResponse(false, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
free(pRecvBuffer);
|
||||
}
|
||||
|
||||
void ListCommand::Execute()
|
||||
{
|
||||
SNZBListRequest ListRequest;
|
||||
if (!ReceiveRequest(&ListRequest, sizeof(ListRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SNZBListResponse ListResponse;
|
||||
memset(&ListResponse, 0, sizeof(ListResponse));
|
||||
ListResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
ListResponse.m_MessageBase.m_iStructSize = htonl(sizeof(ListResponse));
|
||||
ListResponse.m_iEntrySize = htonl(sizeof(SNZBListResponseEntry));
|
||||
|
||||
char* buf = NULL;
|
||||
int bufsize = 0;
|
||||
|
||||
if (ntohl(ListRequest.m_bFileList))
|
||||
{
|
||||
// Make a data structure and copy all the elements of the list into it
|
||||
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
|
||||
|
||||
int NrEntries = pDownloadQueue->size();
|
||||
|
||||
// calculate required buffer size
|
||||
bufsize = NrEntries * sizeof(SNZBListResponseEntry);
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
FileInfo* pFileInfo = *it;
|
||||
bufsize += strlen(pFileInfo->GetNZBFilename()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetSubject()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetFilename()) + 1;
|
||||
bufsize += strlen(pFileInfo->GetDestDir()) + 1;
|
||||
}
|
||||
|
||||
buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
||||
{
|
||||
unsigned int iSizeHi, iSizeLo;
|
||||
FileInfo* pFileInfo = *it;
|
||||
SNZBListResponseEntry* pListAnswer = (SNZBListResponseEntry*) bufptr;
|
||||
pListAnswer->m_iID = htonl(pFileInfo->GetID());
|
||||
SplitInt64(pFileInfo->GetSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iFileSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iFileSizeHi = htonl(iSizeHi);
|
||||
SplitInt64(pFileInfo->GetRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
pListAnswer->m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
pListAnswer->m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
pListAnswer->m_bFilenameConfirmed = htonl(pFileInfo->GetFilenameConfirmed());
|
||||
pListAnswer->m_bPaused = htonl(pFileInfo->GetPaused());
|
||||
pListAnswer->m_iNZBFilenameLen = htonl(strlen(pFileInfo->GetNZBFilename()) + 1);
|
||||
pListAnswer->m_iSubjectLen = htonl(strlen(pFileInfo->GetSubject()) + 1);
|
||||
pListAnswer->m_iFilenameLen = htonl(strlen(pFileInfo->GetFilename()) + 1);
|
||||
pListAnswer->m_iDestDirLen = htonl(strlen(pFileInfo->GetDestDir()) + 1);
|
||||
bufptr += sizeof(SNZBListResponseEntry);
|
||||
strcpy(bufptr, pFileInfo->GetNZBFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iNZBFilenameLen);
|
||||
strcpy(bufptr, pFileInfo->GetSubject());
|
||||
bufptr += ntohl(pListAnswer->m_iSubjectLen);
|
||||
strcpy(bufptr, pFileInfo->GetFilename());
|
||||
bufptr += ntohl(pListAnswer->m_iFilenameLen);
|
||||
strcpy(bufptr, pFileInfo->GetDestDir());
|
||||
bufptr += ntohl(pListAnswer->m_iDestDirLen);
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
ListResponse.m_iNrTrailingEntries = htonl(NrEntries);
|
||||
ListResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
}
|
||||
|
||||
if (htonl(ListRequest.m_bServerState))
|
||||
{
|
||||
unsigned int iSizeHi, iSizeLo;
|
||||
ListResponse.m_iDownloadRate = htonl((int)(g_pQueueCoordinator->CalcCurrentDownloadSpeed() * 1024));
|
||||
SplitInt64(g_pQueueCoordinator->CalcRemainingSize(), &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iRemainingSizeHi = htonl(iSizeHi);
|
||||
ListResponse.m_iRemainingSizeLo = htonl(iSizeLo);
|
||||
ListResponse.m_iDownloadLimit = htonl((int)(g_pOptions->GetDownloadRate() * 1024));
|
||||
ListResponse.m_bServerPaused = htonl(g_pOptions->GetPause());
|
||||
ListResponse.m_iThreadCount = htonl(Thread::GetThreadCount() - 1); // not counting itself
|
||||
PrePostProcessor::ParQueue* pParQueue = g_pPrePostProcessor->LockParQueue();
|
||||
ListResponse.m_iParJobCount = htonl(pParQueue->size());
|
||||
g_pPrePostProcessor->UnlockParQueue();
|
||||
|
||||
int iUpTimeSec, iDnTimeSec;
|
||||
long long iAllBytes;
|
||||
bool bStandBy;
|
||||
g_pQueueCoordinator->CalcStat(&iUpTimeSec, &iDnTimeSec, &iAllBytes, &bStandBy);
|
||||
ListResponse.m_iUpTimeSec = htonl(iUpTimeSec);
|
||||
ListResponse.m_iDownloadTimeSec = htonl(iDnTimeSec);
|
||||
ListResponse.m_bServerStandBy = htonl(bStandBy);
|
||||
SplitInt64(iAllBytes, &iSizeHi, &iSizeLo);
|
||||
ListResponse.m_iDownloadedBytesHi = htonl(iSizeHi);
|
||||
ListResponse.m_iDownloadedBytesLo = htonl(iSizeLo);
|
||||
}
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &ListResponse, sizeof(ListResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void LogCommand::Execute()
|
||||
{
|
||||
SNZBLogRequest LogRequest;
|
||||
if (!ReceiveRequest(&LogRequest, sizeof(LogRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log::Messages* pMessages = g_pLog->LockMessages();
|
||||
|
||||
int iNrEntries = ntohl(LogRequest.m_iLines);
|
||||
unsigned int iIDFrom = ntohl(LogRequest.m_iIDFrom);
|
||||
int iStart = pMessages->size();
|
||||
if (iNrEntries > 0)
|
||||
{
|
||||
if (iNrEntries > (int)pMessages->size())
|
||||
{
|
||||
iNrEntries = pMessages->size();
|
||||
}
|
||||
iStart = pMessages->size() - iNrEntries;
|
||||
}
|
||||
if (iIDFrom > 0 && !pMessages->empty())
|
||||
{
|
||||
iStart = iIDFrom - pMessages->front()->GetID();
|
||||
if (iStart < 0)
|
||||
{
|
||||
iStart = 0;
|
||||
}
|
||||
iNrEntries = pMessages->size() - iStart;
|
||||
if (iNrEntries < 0)
|
||||
{
|
||||
iNrEntries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate required buffer size
|
||||
int bufsize = iNrEntries * sizeof(SNZBLogResponseEntry);
|
||||
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
||||
{
|
||||
Message* pMessage = (*pMessages)[i];
|
||||
bufsize += strlen(pMessage->GetText()) + 1;
|
||||
}
|
||||
|
||||
char* buf = (char*) malloc(bufsize);
|
||||
char* bufptr = buf;
|
||||
for (unsigned int i = (unsigned int)iStart; i < pMessages->size(); i++)
|
||||
{
|
||||
Message* pMessage = (*pMessages)[i];
|
||||
SNZBLogResponseEntry* pLogAnswer = (SNZBLogResponseEntry*) bufptr;
|
||||
pLogAnswer->m_iID = htonl(pMessage->GetID());
|
||||
pLogAnswer->m_iKind = htonl(pMessage->GetKind());
|
||||
pLogAnswer->m_tTime = htonl(pMessage->GetTime());
|
||||
pLogAnswer->m_iTextLen = htonl(strlen(pMessage->GetText()) + 1);
|
||||
bufptr += sizeof(SNZBLogResponseEntry);
|
||||
strcpy(bufptr, pMessage->GetText());
|
||||
bufptr += ntohl(pLogAnswer->m_iTextLen);
|
||||
}
|
||||
|
||||
g_pLog->UnlockMessages();
|
||||
|
||||
SNZBLogResponse LogResponse;
|
||||
LogResponse.m_MessageBase.m_iSignature = htonl(NZBMESSAGE_SIGNATURE);
|
||||
LogResponse.m_MessageBase.m_iStructSize = htonl(sizeof(LogResponse));
|
||||
LogResponse.m_iEntrySize = htonl(sizeof(SNZBLogResponseEntry));
|
||||
LogResponse.m_iNrTrailingEntries = htonl(iNrEntries);
|
||||
LogResponse.m_iTrailingDataLength = htonl(bufsize);
|
||||
|
||||
// Send the request answer
|
||||
send(m_iSocket, (char*) &LogResponse, sizeof(LogResponse), 0);
|
||||
|
||||
// Send the data
|
||||
if (bufsize > 0)
|
||||
{
|
||||
send(m_iSocket, buf, bufsize, 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void EditQueueCommand::Execute()
|
||||
{
|
||||
SNZBEditQueueRequest EditQueueRequest;
|
||||
if (!ReceiveRequest(&EditQueueRequest, sizeof(EditQueueRequest)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iNrEntries = ntohl(EditQueueRequest.m_iNrTrailingEntries);
|
||||
int iAction = ntohl(EditQueueRequest.m_iAction);
|
||||
int iOffset = ntohl(EditQueueRequest.m_iOffset);
|
||||
bool bSmartOrder = ntohl(EditQueueRequest.m_bSmartOrder);
|
||||
unsigned int iBufLength = ntohl(EditQueueRequest.m_iTrailingDataLength);
|
||||
|
||||
if (iNrEntries * sizeof(int32_t) != iBufLength)
|
||||
{
|
||||
error("Invalid struct size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (iNrEntries <= 0)
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed: no IDs specified");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t* pIDs = (int32_t*)malloc(iBufLength);
|
||||
|
||||
// Read from the socket until nothing remains
|
||||
char* pBufPtr = (char*)pIDs;
|
||||
int NeedBytes = iBufLength;
|
||||
int iResult = 0;
|
||||
while (NeedBytes > 0)
|
||||
{
|
||||
iResult = recv(m_iSocket, pBufPtr, NeedBytes, 0);
|
||||
// Did the recv succeed?
|
||||
if (iResult <= 0)
|
||||
{
|
||||
error("invalid request");
|
||||
break;
|
||||
}
|
||||
pBufPtr += iResult;
|
||||
NeedBytes -= iResult;
|
||||
}
|
||||
|
||||
QueueEditor::IDList cIDList;
|
||||
cIDList.reserve(iNrEntries);
|
||||
for (int i = 0; i < iNrEntries; i++)
|
||||
{
|
||||
cIDList.push_back(ntohl(pIDs[i]));
|
||||
}
|
||||
|
||||
bool bOK = g_pQueueCoordinator->GetQueueEditor()->EditList(&cIDList, bSmartOrder, (QueueEditor::EEditAction)iAction, iOffset);
|
||||
|
||||
free(pIDs);
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
SendBoolResponse(true, "Edit-Command completed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendBoolResponse(false, "Edit-Command failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -27,12 +27,9 @@
|
||||
#ifndef REMOTESERVER_H
|
||||
#define REMOTESERVER_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Thread.h"
|
||||
#include "NetAddress.h"
|
||||
#include "Connection.h"
|
||||
#include "MessageBase.h"
|
||||
|
||||
class RemoteServer : public Thread
|
||||
{
|
||||
@@ -51,83 +48,10 @@ class RequestProcessor : public Thread
|
||||
{
|
||||
private:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase m_MessageBase;
|
||||
|
||||
void Dispatch();
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; };
|
||||
};
|
||||
|
||||
class MessageCommand
|
||||
{
|
||||
protected:
|
||||
SOCKET m_iSocket;
|
||||
SNZBRequestBase* m_pMessageBase;
|
||||
|
||||
bool ReceiveRequest(void* pBuffer, int iSize);
|
||||
void SendBoolResponse(bool bSuccess, const char* szText);
|
||||
|
||||
public:
|
||||
virtual ~MessageCommand() {};
|
||||
virtual void Execute() = 0;
|
||||
void SetSocket(SOCKET iSocket) { m_iSocket = iSocket; };
|
||||
void SetMessageBase(SNZBRequestBase* pMessageBase) { m_pMessageBase = pMessageBase; };
|
||||
};
|
||||
|
||||
class DownloadCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ListCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class LogCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class PauseUnpauseCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class EditQueueCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class SetDownloadRateCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class DumpDebugCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class VersionCommand: public MessageCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
390
ScriptController.cpp
Normal file
390
ScriptController.cpp
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ScriptController.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "Options.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
|
||||
void ScriptController::StartScriptJob(PostInfo* pPostInfo, const char* szScript, bool bNZBFileCompleted, bool bHasFailedParJobs)
|
||||
{
|
||||
if (!Util::FileExists(szScript))
|
||||
{
|
||||
error("Could not start post-process-script: could not find file %s", szScript);
|
||||
pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
info("Executing post-process-script for %s", pPostInfo->GetInfoName());
|
||||
|
||||
ScriptController* pScriptController = new ScriptController();
|
||||
pScriptController->m_pPostInfo = pPostInfo;
|
||||
pScriptController->m_szScript = szScript;
|
||||
pScriptController->m_bNZBFileCompleted = bNZBFileCompleted;
|
||||
pScriptController->m_bHasFailedParJobs = bHasFailedParJobs;
|
||||
pScriptController->SetAutoDestroy(false);
|
||||
|
||||
pPostInfo->SetScriptThread(pScriptController);
|
||||
|
||||
pScriptController->Start();
|
||||
}
|
||||
|
||||
void ScriptController::Run()
|
||||
{
|
||||
char szParStatus[10];
|
||||
snprintf(szParStatus, 10, "%i", m_pPostInfo->GetParStatus());
|
||||
szParStatus[10-1] = '\0';
|
||||
|
||||
char szCollectionCompleted[10];
|
||||
snprintf(szCollectionCompleted, 10, "%i", (int)m_bNZBFileCompleted);
|
||||
szCollectionCompleted[10-1] = '\0';
|
||||
|
||||
char szHasFailedParJobs[10];
|
||||
snprintf(szHasFailedParJobs, 10, "%i", (int)m_bHasFailedParJobs);
|
||||
szHasFailedParJobs[10-1] = '\0';
|
||||
|
||||
int pipein;
|
||||
|
||||
#ifdef WIN32
|
||||
char szCmdLine[2048];
|
||||
snprintf(szCmdLine, 2048, "\"%s\" \"%s\" \"%s\" \"%s\" %s %s %s", m_szScript, m_pPostInfo->GetDestDir(),
|
||||
m_pPostInfo->GetNZBFilename(), m_pPostInfo->GetParFilename(), szParStatus, szCollectionCompleted, szHasFailedParJobs);
|
||||
szCmdLine[2048-1] = '\0';
|
||||
|
||||
// create pipes to write and read data
|
||||
HANDLE hReadPipe, hWritePipe;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
memset(&SecurityAttributes, 0, sizeof(SecurityAttributes));
|
||||
SecurityAttributes.nLength = sizeof(SecurityAttributes);
|
||||
SecurityAttributes.bInheritHandle = TRUE;
|
||||
|
||||
CreatePipe(&hReadPipe, &hWritePipe, &SecurityAttributes, 0);
|
||||
|
||||
STARTUPINFO StartupInfo;
|
||||
memset(&StartupInfo, 0, sizeof(StartupInfo));
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
StartupInfo.hStdInput = 0;
|
||||
StartupInfo.hStdOutput = hWritePipe;
|
||||
StartupInfo.hStdError = hWritePipe;
|
||||
|
||||
PROCESS_INFORMATION ProcessInfo;
|
||||
memset(&ProcessInfo, 0, sizeof(ProcessInfo));
|
||||
|
||||
BOOL bOK = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, m_pPostInfo->GetDestDir(), &StartupInfo, &ProcessInfo);
|
||||
if (!bOK)
|
||||
{
|
||||
DWORD dwErrCode = GetLastError();
|
||||
char szErrMsg[255];
|
||||
szErrMsg[255-1] = '\0';
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM || FORMAT_MESSAGE_IGNORE_INSERTS || FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
{
|
||||
error("Could not start post-process-script: %s", szErrMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not start post-process-script: error %i", dwErrCode);
|
||||
}
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Child Process-ID: %i", (int)ProcessInfo.dwProcessId);
|
||||
|
||||
m_hProcess = ProcessInfo.hProcess;
|
||||
|
||||
// close unused "write" end
|
||||
CloseHandle(hWritePipe);
|
||||
|
||||
pipein = _open_osfhandle((intptr_t)hReadPipe, _O_RDONLY);
|
||||
|
||||
#else
|
||||
|
||||
char szDestDir[1024];
|
||||
strncpy(szDestDir, m_pPostInfo->GetDestDir(), 1024);
|
||||
szDestDir[1024-1] = '\0';
|
||||
|
||||
char szNZBFilename[1024];
|
||||
strncpy(szNZBFilename, m_pPostInfo->GetNZBFilename(), 1024);
|
||||
szNZBFilename[1024-1] = '\0';
|
||||
|
||||
char szParFilename[1024];
|
||||
strncpy(szParFilename, m_pPostInfo->GetParFilename(), 1024);
|
||||
szParFilename[1024-1] = '\0';
|
||||
|
||||
int p[2];
|
||||
int pipeout;
|
||||
|
||||
// create the pipe
|
||||
if (pipe(p))
|
||||
{
|
||||
error("Could not open pipe: errno %i", errno);
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
pipein = p[0];
|
||||
pipeout = p[1];
|
||||
|
||||
debug("forking");
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
error("Could not start post-process-script: errno %i", errno);
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
// here goes the second instance
|
||||
|
||||
// close up the "read" end
|
||||
close(pipein);
|
||||
|
||||
// make the pipeout to be the same as stdout and stderr
|
||||
dup2(pipeout, 1);
|
||||
dup2(pipeout, 2);
|
||||
|
||||
close(pipeout);
|
||||
|
||||
execlp(m_szScript, m_szScript, szDestDir, szNZBFilename, szParFilename,
|
||||
szParStatus, szCollectionCompleted, szHasFailedParJobs, NULL);
|
||||
fprintf(stdout, "[ERROR] Could not start post-process-script: %s", strerror(errno));
|
||||
fflush(stdout);
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
// continue the first instance
|
||||
debug("forked");
|
||||
debug("Child Process-ID: %i", (int)pid);
|
||||
|
||||
m_hProcess = pid;
|
||||
|
||||
// close unused "write" end
|
||||
close(pipeout);
|
||||
#endif
|
||||
|
||||
// open the read end
|
||||
FILE* readpipe = fdopen(pipein, "r");
|
||||
if (!readpipe)
|
||||
{
|
||||
error("Could not open pipe to post-process-script");
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
char* buf = (char*)malloc(10240);
|
||||
|
||||
debug("Entering pipe-loop");
|
||||
while (!feof(readpipe) && !IsStopped())
|
||||
{
|
||||
if (fgets(buf, 10240, readpipe))
|
||||
{
|
||||
AddMessage(buf);
|
||||
}
|
||||
}
|
||||
debug("Exited pipe-loop");
|
||||
|
||||
free(buf);
|
||||
fclose(readpipe);
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
warn("Interrupted post-process-script for %s", m_pPostInfo->GetInfoName());
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
WaitForSingleObject(m_hProcess, INFINITE);
|
||||
#else
|
||||
waitpid(m_hProcess, NULL, 0);
|
||||
#endif
|
||||
|
||||
if (!IsStopped())
|
||||
{
|
||||
info("Completed post-process-script for %s", m_pPostInfo->GetInfoName());
|
||||
}
|
||||
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void ScriptController::AddMessage(char* szText)
|
||||
{
|
||||
debug("Adding message received from post-process-script");
|
||||
|
||||
for (char* pend = szText + strlen(szText) - 1; pend >= szText && (*pend == '\n' || *pend == '\r' || *pend == ' '); pend--) *pend = '\0';
|
||||
|
||||
if (strlen(szText) == 0)
|
||||
{
|
||||
// skip empty lines
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(szText, "[INFO] ", 7))
|
||||
{
|
||||
info(szText + 7);
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetInfoTarget();
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(Message::mkInfo, szText + 7);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(szText, "[WARNING] ", 10))
|
||||
{
|
||||
warn(szText + 10);
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetWarningTarget();
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(Message::mkWarning, szText + 10);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(szText, "[ERROR] ", 8))
|
||||
{
|
||||
error(szText + 8);
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetErrorTarget();
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(Message::mkError, szText + 8);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(szText, "[DETAIL] ", 9))
|
||||
{
|
||||
detail(szText + 9);
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetDetailTarget();
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(Message::mkDetail, szText + 9);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(szText, "[DEBUG] ", 8))
|
||||
{
|
||||
debug(szText + 8);
|
||||
Options::EMessageTarget eMessageTarget = g_pOptions->GetDebugTarget();
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(Message::mkDebug, szText + 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Options::EMessageTarget eMessageTarget = Options::mtNone;
|
||||
Message::EKind eKind = Message::mkDebug;
|
||||
switch (g_pOptions->GetPostLogKind())
|
||||
{
|
||||
case Options::plNone:
|
||||
break;
|
||||
|
||||
case Options::plDetail:
|
||||
detail("Post-Process: %s", szText);
|
||||
eMessageTarget = g_pOptions->GetDetailTarget();
|
||||
eKind = Message::mkDetail;
|
||||
break;
|
||||
|
||||
case Options::plInfo:
|
||||
info("Post-Process: %s", szText);
|
||||
eMessageTarget = g_pOptions->GetInfoTarget();
|
||||
eKind = Message::mkInfo;
|
||||
break;
|
||||
|
||||
case Options::plWarning:
|
||||
warn("Post-Process: %s", szText);
|
||||
eMessageTarget = g_pOptions->GetWarningTarget();
|
||||
eKind = Message::mkWarning;
|
||||
break;
|
||||
|
||||
case Options::plError:
|
||||
error("Post-Process: %s", szText);
|
||||
eMessageTarget = g_pOptions->GetErrorTarget();
|
||||
eKind = Message::mkError;
|
||||
break;
|
||||
|
||||
case Options::plDebug:
|
||||
debug("Post-Process: %s", szText);
|
||||
eMessageTarget = g_pOptions->GetDebugTarget();
|
||||
eKind = Message::mkDebug;
|
||||
break;
|
||||
}
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
}
|
||||
}
|
||||
|
||||
debug("Adding message received from post-process-script - completed");
|
||||
}
|
||||
|
||||
void ScriptController::Stop()
|
||||
{
|
||||
debug("Stopping post-process-script");
|
||||
Thread::Stop();
|
||||
|
||||
#ifdef WIN32
|
||||
BOOL bOK = TerminateProcess(m_hProcess, -1);
|
||||
#else
|
||||
bool bOK = kill(m_hProcess, 9) == 0;
|
||||
#endif
|
||||
|
||||
if (bOK)
|
||||
{
|
||||
debug("Terminated post-process-script");
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Could not terminate post-process-script");
|
||||
}
|
||||
|
||||
debug("Post-process-script stopped");
|
||||
}
|
||||
54
ScriptController.h
Normal file
54
ScriptController.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SCRIPTCONTROLLER_H
|
||||
#define SCRIPTCONTROLLER_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "PostInfo.h"
|
||||
|
||||
class ScriptController : public Thread
|
||||
{
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
const char* m_szScript;
|
||||
bool m_bNZBFileCompleted;
|
||||
bool m_bHasFailedParJobs;
|
||||
#ifdef WIN32
|
||||
HANDLE m_hProcess;
|
||||
#else
|
||||
pid_t m_hProcess;
|
||||
#endif
|
||||
|
||||
void AddMessage(char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartScriptJob(PostInfo* pPostInfo, const char* szScript,
|
||||
bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -211,7 +211,7 @@ void ServerPool::CloseUnusedConnections()
|
||||
PooledConnection* pConnection = *it;
|
||||
if (!pConnection->GetInUse() && pConnection->GetStatus() == Connection::csConnected)
|
||||
{
|
||||
int tdiff = curtime - pConnection->GetFreeTime();
|
||||
int tdiff = (int)(curtime - pConnection->GetFreeTime());
|
||||
if (tdiff > CONNECTION_HOLD_SECODNS)
|
||||
{
|
||||
debug("Closing unused connection to %s", pConnection->GetNewsServer()->GetHost());
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include "Log.h"
|
||||
@@ -299,4 +299,3 @@ int Thread::GetThreadCount()
|
||||
m_mutexThread.Unlock();
|
||||
return iThreadCount;
|
||||
}
|
||||
|
||||
|
||||
664
Util.cpp
664
Util.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -35,36 +35,17 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Util.h"
|
||||
|
||||
char* BaseFileName(const char* filename)
|
||||
{
|
||||
char* p = (char*)strrchr(filename, PATH_SEPARATOR);
|
||||
char* p1 = (char*)strrchr(filename, ALT_PATH_SEPARATOR);
|
||||
if (p1)
|
||||
{
|
||||
if ((p && p < p1) || !p)
|
||||
{
|
||||
p = p1;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
return p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (char*)filename;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
// getopt for WIN32:
|
||||
@@ -217,7 +198,28 @@ const char* DirBrowser::Next()
|
||||
|
||||
#endif
|
||||
|
||||
void NormalizePathSeparators(char* szPath)
|
||||
char* Util::BaseFileName(const char* filename)
|
||||
{
|
||||
char* p = (char*)strrchr(filename, PATH_SEPARATOR);
|
||||
char* p1 = (char*)strrchr(filename, ALT_PATH_SEPARATOR);
|
||||
if (p1)
|
||||
{
|
||||
if ((p && p < p1) || !p)
|
||||
{
|
||||
p = p1;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
return p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (char*)filename;
|
||||
}
|
||||
}
|
||||
|
||||
void Util::NormalizePathSeparators(char* szPath)
|
||||
{
|
||||
for (char* p = szPath; *p; p++)
|
||||
{
|
||||
@@ -228,7 +230,7 @@ void NormalizePathSeparators(char* szPath)
|
||||
}
|
||||
}
|
||||
|
||||
bool ForceDirectories(const char* szPath)
|
||||
bool Util::ForceDirectories(const char* szPath)
|
||||
{
|
||||
char* szNormPath = strdup(szPath);
|
||||
NormalizePathSeparators(szNormPath);
|
||||
@@ -281,7 +283,7 @@ bool ForceDirectories(const char* szPath)
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength)
|
||||
bool Util::LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength)
|
||||
{
|
||||
FILE* pFile = fopen(szFileName, "r");
|
||||
if (!pFile)
|
||||
@@ -313,7 +315,7 @@ bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLeng
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetFileSize(const char* szFilename, int iSize)
|
||||
bool Util::SetFileSize(const char* szFilename, int iSize)
|
||||
{
|
||||
bool bOK = false;
|
||||
#ifdef WIN32
|
||||
@@ -330,7 +332,7 @@ bool SetFileSize(const char* szFilename, int iSize)
|
||||
{
|
||||
fclose(pFile);
|
||||
}
|
||||
// there no reliable function to expand file on POSIX, so we must try different approaches,
|
||||
// there are no reliable function to expand file on POSIX, so we must try different approaches,
|
||||
// starting with the fastest one and hoping it will work
|
||||
// 1) set file size using function "truncate" (it is fast, if works)
|
||||
truncate(szFilename, iSize);
|
||||
@@ -357,7 +359,7 @@ bool SetFileSize(const char* szFilename, int iSize)
|
||||
}
|
||||
|
||||
//replace bad chars in filename
|
||||
void MakeValidFilename(char* szFilename, char cReplaceChar)
|
||||
void Util::MakeValidFilename(char* szFilename, char cReplaceChar)
|
||||
{
|
||||
char* p = szFilename;
|
||||
while (*p)
|
||||
@@ -377,18 +379,25 @@ void MakeValidFilename(char* szFilename, char cReplaceChar)
|
||||
}
|
||||
}
|
||||
|
||||
long long JoinInt64(unsigned int Hi, unsigned int Lo)
|
||||
long long Util::JoinInt64(unsigned long Hi, unsigned long Lo)
|
||||
{
|
||||
return (((long long)Hi) << 32) + Lo;
|
||||
}
|
||||
|
||||
void SplitInt64(long long Int64, unsigned int* Hi, unsigned int* Lo)
|
||||
void Util::SplitInt64(long long Int64, unsigned long* Hi, unsigned long* Lo)
|
||||
{
|
||||
*Hi = (unsigned int)(Int64 >> 32);
|
||||
*Lo = (unsigned int)Int64;
|
||||
*Hi = (unsigned long)(Int64 >> 32);
|
||||
*Lo = (unsigned long)Int64;
|
||||
}
|
||||
|
||||
float EqualTime(_timeval* t1, _timeval* t2)
|
||||
float Util::Int64ToFloat(long long Int64)
|
||||
{
|
||||
unsigned long Hi = (unsigned long)(Int64 >> 32);
|
||||
unsigned long Lo = (unsigned long)Int64;
|
||||
return ((unsigned long)(1 << 30)) * 4.0f * Hi + Lo;
|
||||
}
|
||||
|
||||
float Util::EqualTime(_timeval* t1, _timeval* t2)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return t1->time == t2->time && t1->millitm == t2->millitm;
|
||||
@@ -397,7 +406,7 @@ float EqualTime(_timeval* t1, _timeval* t2)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EmptyTime(_timeval* t)
|
||||
bool Util::EmptyTime(_timeval* t)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return t->time == 0 && t->millitm == 0;
|
||||
@@ -406,11 +415,594 @@ bool EmptyTime(_timeval* t)
|
||||
#endif
|
||||
}
|
||||
|
||||
float DiffTime(_timeval* t1, _timeval* t2)
|
||||
float Util::DiffTime(_timeval* t1, _timeval* t2)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return ((t1->time - t2->time) + (t1->millitm - t2->millitm) / 1000.0);
|
||||
return ((t1->time - t2->time) + (t1->millitm - t2->millitm) / 1000.0f);
|
||||
#else
|
||||
return (float)((t1->tv_sec - t2->tv_sec) + (t1->tv_usec - t2->tv_usec) / 1000000.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Base64 decryption is taken from
|
||||
* Article "BASE 64 Decoding and Encoding Class 2003" by Jan Raddatz
|
||||
* http://www.codeguru.com/cpp/cpp/algorithms/article.php/c5099/
|
||||
*/
|
||||
|
||||
const static char BASE64_DEALPHABET [128] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 9
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 - 19
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - 29
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 30 - 39
|
||||
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, // 40 - 49
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 0, 0, // 50 - 59
|
||||
0, 61, 0, 0, 0, 0, 1, 2, 3, 4, // 60 - 69
|
||||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 70 - 79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 80 - 89
|
||||
25, 0, 0, 0, 0, 0, 0, 26, 27, 28, // 90 - 99
|
||||
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100 - 109
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 110 - 119
|
||||
49, 50, 51, 0, 0, 0, 0, 0 // 120 - 127
|
||||
};
|
||||
|
||||
unsigned int DecodeByteQuartet(char* szInputBuffer, char* szOutputBuffer)
|
||||
{
|
||||
unsigned int buffer = 0;
|
||||
|
||||
if (szInputBuffer[3] == '=')
|
||||
{
|
||||
if (szInputBuffer[2] == '=')
|
||||
{
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[0]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[1]]) << 6;
|
||||
buffer = buffer << 14;
|
||||
|
||||
char* temp = (char*) &buffer;
|
||||
szOutputBuffer [0] = temp [3];
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[0]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[1]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[2]]) << 6;
|
||||
buffer = buffer << 8;
|
||||
|
||||
char* temp = (char*) &buffer;
|
||||
szOutputBuffer [0] = temp [3];
|
||||
szOutputBuffer [1] = temp [2];
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[0]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[1]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[2]]) << 6;
|
||||
buffer = (buffer | BASE64_DEALPHABET [(int)szInputBuffer[3]]) << 6;
|
||||
buffer = buffer << 2;
|
||||
|
||||
char* temp = (char*) &buffer;
|
||||
szOutputBuffer [0] = temp [3];
|
||||
szOutputBuffer [1] = temp [2];
|
||||
szOutputBuffer [2] = temp [1];
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Util::DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer)
|
||||
{
|
||||
unsigned int InputBufferIndex = 0;
|
||||
unsigned int OutputBufferIndex = 0;
|
||||
unsigned int InputBufferLength = iInputBufferLength > 0 ? iInputBufferLength : strlen(szInputBuffer);
|
||||
|
||||
char ByteQuartet [4];
|
||||
|
||||
while (InputBufferIndex < InputBufferLength)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ByteQuartet [i] = szInputBuffer[InputBufferIndex];
|
||||
|
||||
// Ignore all characters except the ones in BASE64_ALPHABET
|
||||
if (!((ByteQuartet [i] >= 48 && ByteQuartet [i] <= 57) ||
|
||||
(ByteQuartet [i] >= 65 && ByteQuartet [i] <= 90) ||
|
||||
(ByteQuartet [i] >= 97 && ByteQuartet [i] <= 122) ||
|
||||
ByteQuartet [i] == '+' || ByteQuartet [i] == '/' || ByteQuartet [i] == '='))
|
||||
{
|
||||
// Invalid character
|
||||
i--;
|
||||
}
|
||||
|
||||
InputBufferIndex++;
|
||||
}
|
||||
|
||||
OutputBufferIndex += DecodeByteQuartet(ByteQuartet, szOutputBuffer + OutputBufferIndex);
|
||||
}
|
||||
|
||||
// OutputBufferIndex gives us the next position of the next decoded character
|
||||
// inside our output buffer and thus represents the number of decoded characters
|
||||
// in our buffer.
|
||||
return OutputBufferIndex;
|
||||
}
|
||||
|
||||
/* END - Base64
|
||||
*/
|
||||
|
||||
char* Util::XmlEncode(const char* raw)
|
||||
{
|
||||
// calculate the required outputstring-size based on number of xml-entities and their sizes
|
||||
int iReqSize = strlen(raw);
|
||||
for (const char* p = raw; *p; p++)
|
||||
{
|
||||
unsigned char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
case '>':
|
||||
case '<':
|
||||
iReqSize += 4;
|
||||
break;
|
||||
case '&':
|
||||
iReqSize += 5;
|
||||
break;
|
||||
case '\'':
|
||||
case '\"':
|
||||
iReqSize += 6;
|
||||
break;
|
||||
default:
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
iReqSize += 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* result = (char*)malloc(iReqSize + 1);
|
||||
|
||||
// copy string
|
||||
char* output = result;
|
||||
for (const char* p = raw; ; p++)
|
||||
{
|
||||
unsigned char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
case '\0':
|
||||
goto BreakLoop;
|
||||
case '<':
|
||||
strcpy(output, "<");
|
||||
output += 4;
|
||||
break;
|
||||
case '>':
|
||||
strcpy(output, ">");
|
||||
output += 4;
|
||||
break;
|
||||
case '&':
|
||||
strcpy(output, "&");
|
||||
output += 5;
|
||||
break;
|
||||
case '\'':
|
||||
strcpy(output, "'");
|
||||
output += 6;
|
||||
break;
|
||||
case '\"':
|
||||
strcpy(output, """);
|
||||
output += 6;
|
||||
break;
|
||||
default:
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
sprintf(output, "&#%i;", ch);
|
||||
output += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
*output++ = ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
BreakLoop:
|
||||
|
||||
*output = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Util::XmlDecode(char* raw)
|
||||
{
|
||||
char* output = raw;
|
||||
for (char* p = raw;;)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '\0':
|
||||
goto BreakLoop;
|
||||
case '&':
|
||||
{
|
||||
p++;
|
||||
if (!strncmp(p, "lt;", 3))
|
||||
{
|
||||
*output++ = '<';
|
||||
p += 3;
|
||||
}
|
||||
else if (!strncmp(p, "gt;", 3))
|
||||
{
|
||||
*output++ = '>';
|
||||
p += 3;
|
||||
}
|
||||
else if (!strncmp(p, "amp;", 4))
|
||||
{
|
||||
*output++ = '&';
|
||||
p += 4;
|
||||
}
|
||||
else if (!strncmp(p, "apos;", 5))
|
||||
{
|
||||
*output++ = '\'';
|
||||
p += 5;
|
||||
}
|
||||
else if (!strncmp(p, "quot;", 5))
|
||||
{
|
||||
*output++ = '\"';
|
||||
p += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown entity
|
||||
*output++ = *(p-1);
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*output++ = *p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BreakLoop:
|
||||
|
||||
*output = '\0';
|
||||
}
|
||||
|
||||
const char* Util::XmlFindTag(const char* szXml, const char* szTag, int* pValueLength)
|
||||
{
|
||||
char szOpenTag[100];
|
||||
snprintf(szOpenTag, 100, "<%s>", szTag);
|
||||
szOpenTag[100-1] = '\0';
|
||||
|
||||
char szCloseTag[100];
|
||||
snprintf(szCloseTag, 100, "</%s>", szTag);
|
||||
szCloseTag[100-1] = '\0';
|
||||
|
||||
const char* pstart = strstr(szXml, szOpenTag);
|
||||
if (!pstart) return NULL;
|
||||
|
||||
const char* pend = strstr(pstart, szCloseTag);
|
||||
if (!pend) return NULL;
|
||||
|
||||
int iTagLen = strlen(szOpenTag);
|
||||
*pValueLength = (int)(pend - pstart - iTagLen);
|
||||
|
||||
return pstart + iTagLen;
|
||||
}
|
||||
|
||||
bool Util::XmlParseTagValue(const char* szXml, const char* szTag, char* szValueBuf, int iValueBufSize, const char** pTagEnd)
|
||||
{
|
||||
int iValueLen = 0;
|
||||
const char* szValue = XmlFindTag(szXml, szTag, &iValueLen);
|
||||
if (!szValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int iLen = iValueLen < iValueBufSize ? iValueLen : iValueBufSize - 1;
|
||||
strncpy(szValueBuf, szValue, iLen);
|
||||
szValueBuf[iLen] = '\0';
|
||||
if (pTagEnd)
|
||||
{
|
||||
*pTagEnd = szValue + iValueLen;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Util::MoveFile(const char* szSrcFilename, const char* szDstFilename)
|
||||
{
|
||||
bool bOK = rename(szSrcFilename, szDstFilename) == 0;
|
||||
|
||||
#ifndef WIN32
|
||||
if (!bOK && (errno == EXDEV))
|
||||
{
|
||||
FILE* infile = fopen(szSrcFilename, "r");
|
||||
if (!infile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* outfile = fopen(szDstFilename, "w+");
|
||||
if (!outfile)
|
||||
{
|
||||
fclose(infile);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int BUFFER_SIZE = 1024 * 50;
|
||||
char* buffer = (char*)malloc(BUFFER_SIZE);
|
||||
|
||||
int cnt = BUFFER_SIZE;
|
||||
while (cnt == BUFFER_SIZE)
|
||||
{
|
||||
cnt = (int)fread(buffer, 1, BUFFER_SIZE, infile);
|
||||
fwrite(buffer, 1, cnt, outfile);
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
fclose(outfile);
|
||||
free(buffer);
|
||||
|
||||
bOK = remove(szSrcFilename) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
bool Util::FileExists(const char* szFilename)
|
||||
{
|
||||
struct stat buffer;
|
||||
bool bExists = !stat(szFilename, &buffer) && S_ISREG(buffer.st_mode);
|
||||
return bExists;
|
||||
}
|
||||
|
||||
bool Util::DirectoryExists(const char* szDirFilename)
|
||||
{
|
||||
struct stat buffer;
|
||||
bool bExists = !stat(szDirFilename, &buffer) && S_ISDIR(buffer.st_mode);
|
||||
return bExists;
|
||||
}
|
||||
|
||||
bool Util::CreateDirectory(const char* szDirFilename)
|
||||
{
|
||||
mkdir(szDirFilename, S_DIRMODE);
|
||||
return DirectoryExists(szDirFilename);
|
||||
}
|
||||
|
||||
long long Util::FileSize(const char* szFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
struct _stat32i64 buffer;
|
||||
_stat32i64(szFilename, &buffer);
|
||||
#else
|
||||
#ifdef HAVE_STAT64
|
||||
struct stat64 buffer;
|
||||
stat64(szFilename, &buffer);
|
||||
#else
|
||||
struct stat buffer;
|
||||
stat(szFilename, &buffer);
|
||||
#endif
|
||||
#endif
|
||||
return buffer.st_size;
|
||||
}
|
||||
|
||||
char* Util::JsonEncode(const char* raw)
|
||||
{
|
||||
// calculate the required outputstring-size based on number of escape-entities and their sizes
|
||||
int iReqSize = strlen(raw);
|
||||
for (const char* p = raw; *p; p++)
|
||||
{
|
||||
unsigned char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
case '\"':
|
||||
case '\\':
|
||||
case '/':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
iReqSize += 1;
|
||||
default:
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
iReqSize += 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* result = (char*)malloc(iReqSize + 1);
|
||||
|
||||
// copy string
|
||||
char* output = result;
|
||||
for (const char* p = raw; ; p++)
|
||||
{
|
||||
unsigned char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
case '\0':
|
||||
goto BreakLoop;
|
||||
case '"':
|
||||
strcpy(output, "\\\"");
|
||||
output += 2;
|
||||
break;
|
||||
case '\\':
|
||||
strcpy(output, "\\\\");
|
||||
output += 2;
|
||||
break;
|
||||
case '/':
|
||||
strcpy(output, "\\/");
|
||||
output += 2;
|
||||
break;
|
||||
case '\b':
|
||||
strcpy(output, "\\b");
|
||||
output += 2;
|
||||
break;
|
||||
case '\f':
|
||||
strcpy(output, "\\f");
|
||||
output += 2;
|
||||
break;
|
||||
case '\n':
|
||||
strcpy(output, "\\n");
|
||||
output += 2;
|
||||
break;
|
||||
case '\r':
|
||||
strcpy(output, "\\r");
|
||||
output += 2;
|
||||
break;
|
||||
case '\t':
|
||||
strcpy(output, "\\t");
|
||||
output += 2;
|
||||
break;
|
||||
default:
|
||||
if (ch >= 0x80)
|
||||
{
|
||||
sprintf(output, "\\u%04x", ch);
|
||||
output += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
*output++ = ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
BreakLoop:
|
||||
|
||||
*output = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Util::JsonDecode(char* raw)
|
||||
{
|
||||
char* output = raw;
|
||||
for (char* p = raw;;)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '\0':
|
||||
goto BreakLoop;
|
||||
case '\\':
|
||||
{
|
||||
p++;
|
||||
switch (*p)
|
||||
{
|
||||
case '"':
|
||||
*output++ = '"';
|
||||
break;
|
||||
case '\\':
|
||||
*output++ = '\\';
|
||||
break;
|
||||
case '/':
|
||||
*output++ = '/';
|
||||
break;
|
||||
case 'b':
|
||||
*output++ = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
*output++ = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
*output++ = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
*output++ = '\r';
|
||||
break;
|
||||
case 't':
|
||||
*output++ = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
*output++ = (char)strtol(p + 1, NULL, 16);
|
||||
p += 4;
|
||||
break;
|
||||
default:
|
||||
// unknown escape-sequence, should never occur
|
||||
*output++ = *p;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
default:
|
||||
*output++ = *p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BreakLoop:
|
||||
|
||||
*output = '\0';
|
||||
}
|
||||
|
||||
const char* Util::JsonFindField(const char* szJsonText, const char* szFieldName, int* pValueLength)
|
||||
{
|
||||
char szOpenTag[100];
|
||||
snprintf(szOpenTag, 100, "\"%s\"", szFieldName);
|
||||
szOpenTag[100-1] = '\0';
|
||||
|
||||
const char* pstart = strstr(szJsonText, szOpenTag);
|
||||
if (!pstart) return NULL;
|
||||
|
||||
pstart += strlen(szOpenTag);
|
||||
|
||||
return JsonNextValue(pstart, pValueLength);
|
||||
}
|
||||
|
||||
const char* Util::JsonNextValue(const char* szJsonText, int* pValueLength)
|
||||
{
|
||||
const char* pstart = szJsonText;
|
||||
|
||||
while (*pstart && strchr(" ,[{:\r\n\t\f", *pstart)) pstart++;
|
||||
if (!*pstart) return NULL;
|
||||
|
||||
const char* pend = pstart;
|
||||
|
||||
char ch = *pend;
|
||||
bool bStr = ch == '"';
|
||||
if (bStr)
|
||||
{
|
||||
ch = *++pend;
|
||||
}
|
||||
while (ch)
|
||||
{
|
||||
if (ch == '\\')
|
||||
{
|
||||
if (!*++pend || !*++pend) return NULL;
|
||||
ch = *pend;
|
||||
}
|
||||
if (bStr && ch == '"')
|
||||
{
|
||||
pend++;
|
||||
break;
|
||||
}
|
||||
else if (!bStr && strchr(" ,]}\r\n\t\f", ch))
|
||||
{
|
||||
break;
|
||||
}
|
||||
ch = *++pend;
|
||||
}
|
||||
|
||||
*pValueLength = (int)(pend - pstart);
|
||||
return pstart;
|
||||
}
|
||||
|
||||
long long Util::FreeDiskSize(const char* szPath)
|
||||
{
|
||||
#ifdef WIN32
|
||||
ULARGE_INTEGER lFree, lDummy;
|
||||
if (GetDiskFreeSpaceEx(szPath, &lFree, &lDummy, &lDummy))
|
||||
{
|
||||
return lFree.QuadPart;
|
||||
}
|
||||
#else
|
||||
struct statvfs diskdata;
|
||||
if (!statvfs(szPath, &diskdata))
|
||||
{
|
||||
return (long long)diskdata.f_bsize * (long long)diskdata.f_bavail;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
91
Util.h
91
Util.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -58,18 +58,85 @@ public:
|
||||
const char* Next();
|
||||
};
|
||||
|
||||
char* BaseFileName(const char* filename);
|
||||
void NormalizePathSeparators(char* szPath);
|
||||
bool ForceDirectories(const char* szPath);
|
||||
bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength);
|
||||
bool SetFileSize(const char* szFilename, int iSize);
|
||||
void MakeValidFilename(char* szFilename, char cReplaceChar);
|
||||
class Util
|
||||
{
|
||||
public:
|
||||
|
||||
long long JoinInt64(unsigned int Hi, unsigned int Lo);
|
||||
void SplitInt64(long long Int64, unsigned int* Hi, unsigned int* Lo);
|
||||
static char* BaseFileName(const char* filename);
|
||||
static void NormalizePathSeparators(char* szPath);
|
||||
static bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength);
|
||||
static bool SetFileSize(const char* szFilename, int iSize);
|
||||
static void MakeValidFilename(char* szFilename, char cReplaceChar);
|
||||
static bool MoveFile(const char* szSrcFilename, const char* szDstFilename);
|
||||
static bool FileExists(const char* szFilename);
|
||||
static bool DirectoryExists(const char* szDirFilename);
|
||||
static bool CreateDirectory(const char* szDirFilename);
|
||||
static bool ForceDirectories(const char* szPath);
|
||||
static long long FileSize(const char* szFilename);
|
||||
static long long FreeDiskSize(const char* szPath);
|
||||
|
||||
float EqualTime(_timeval* t1, _timeval* t2);
|
||||
bool EmptyTime(_timeval* t);
|
||||
float DiffTime(_timeval* t1, _timeval* t2);
|
||||
static long long JoinInt64(unsigned long Hi, unsigned long Lo);
|
||||
static void SplitInt64(long long Int64, unsigned long* Hi, unsigned long* Lo);
|
||||
|
||||
/**
|
||||
* Int64ToFloat converts Int64 to float.
|
||||
* Simple (float)Int64 does not work on all compilers,
|
||||
* for example on ARM for NSLU2 (unslung).
|
||||
*/
|
||||
static float Int64ToFloat(long long Int64);
|
||||
|
||||
static float EqualTime(_timeval* t1, _timeval* t2);
|
||||
static bool EmptyTime(_timeval* t);
|
||||
static float DiffTime(_timeval* t1, _timeval* t2);
|
||||
|
||||
static unsigned int DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer);
|
||||
|
||||
/*
|
||||
* Encodes string to be used as content of xml-tag.
|
||||
* Returns new string allocated with malloc, it need to be freed by caller.
|
||||
*/
|
||||
static char* XmlEncode(const char* raw);
|
||||
|
||||
/*
|
||||
* Decodes string from xml.
|
||||
* The string is decoded on the place overwriting the content of raw-data.
|
||||
*/
|
||||
static void XmlDecode(char* raw);
|
||||
|
||||
/*
|
||||
* Returns pointer to tag-content and length of content in iValueLength
|
||||
* The returned pointer points to the part of source-string, no additional strings are allocated.
|
||||
*/
|
||||
static const char* XmlFindTag(const char* szXml, const char* szTag, int* pValueLength);
|
||||
|
||||
/*
|
||||
* Parses tag-content into szValueBuf.
|
||||
*/
|
||||
static bool XmlParseTagValue(const char* szXml, const char* szTag, char* szValueBuf, int iValueBufSize, const char** pTagEnd);
|
||||
|
||||
/*
|
||||
* Creates JSON-string by replace the certain characters with escape-sequences.
|
||||
* Returns new string allocated with malloc, it need to be freed by caller.
|
||||
*/
|
||||
static char* JsonEncode(const char* raw);
|
||||
|
||||
/*
|
||||
* Decodes JSON-string.
|
||||
* The string is decoded on the place overwriting the content of raw-data.
|
||||
*/
|
||||
static void JsonDecode(char* raw);
|
||||
|
||||
/*
|
||||
* Returns pointer to field-content and length of content in iValueLength
|
||||
* The returned pointer points to the part of source-string, no additional strings are allocated.
|
||||
*/
|
||||
static const char* JsonFindField(const char* szJsonText, const char* szFieldName, int* pValueLength);
|
||||
|
||||
/*
|
||||
* Returns pointer to field-content and length of content in iValueLength
|
||||
* The returned pointer points to the part of source-string, no additional strings are allocated.
|
||||
*/
|
||||
static const char* JsonNextValue(const char* szJsonText, int* pValueLength);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
1442
XmlRpc.cpp
Normal file
1442
XmlRpc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
215
XmlRpc.h
Normal file
215
XmlRpc.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XMLRPC_H
|
||||
#define XMLRPC_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Connection.h"
|
||||
|
||||
class StringBuilder
|
||||
{
|
||||
private:
|
||||
char* m_szBuffer;
|
||||
int m_iBufferSize;
|
||||
int m_iUsedSize;
|
||||
public:
|
||||
StringBuilder();
|
||||
~StringBuilder();
|
||||
void Append(const char* szStr);
|
||||
const char* GetBuffer() { return m_szBuffer; }
|
||||
};
|
||||
|
||||
class XmlCommand;
|
||||
|
||||
class XmlRpcProcessor
|
||||
{
|
||||
public:
|
||||
enum ERpcProtocol
|
||||
{
|
||||
rpUndefined,
|
||||
rpXmlRpc,
|
||||
rpJsonRpc
|
||||
};
|
||||
|
||||
enum EHttpMethod
|
||||
{
|
||||
hmPost,
|
||||
hmGet
|
||||
};
|
||||
|
||||
private:
|
||||
Connection* m_pConnection;
|
||||
const char* m_szClientIP;
|
||||
char* m_szRequest;
|
||||
ERpcProtocol m_eProtocol;
|
||||
EHttpMethod m_eHttpMethod;
|
||||
char* m_szUrl;
|
||||
|
||||
void Dispatch();
|
||||
void SendResponse(const char* szResponse, bool bFault);
|
||||
XmlCommand* CreateCommand(const char* szMethodName);
|
||||
void MutliCall();
|
||||
|
||||
public:
|
||||
XmlRpcProcessor();
|
||||
~XmlRpcProcessor();
|
||||
void Execute();
|
||||
void SetConnection(Connection* pConnection) { m_pConnection = pConnection; }
|
||||
void SetProtocol(ERpcProtocol eProtocol) { m_eProtocol = eProtocol; }
|
||||
void SetHttpMethod(EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
void SetUrl(const char* szUrl);
|
||||
void SetClientIP(const char* szClientIP) { m_szClientIP = szClientIP; }
|
||||
};
|
||||
|
||||
class XmlCommand
|
||||
{
|
||||
protected:
|
||||
char* m_szRequest;
|
||||
char* m_szRequestPtr;
|
||||
StringBuilder m_StringBuilder;
|
||||
bool m_bFault;
|
||||
XmlRpcProcessor::ERpcProtocol m_eProtocol;
|
||||
XmlRpcProcessor::EHttpMethod m_eHttpMethod;
|
||||
|
||||
void BuildErrorResponse(int iErrCode, const char* szErrText);
|
||||
void BuildBoolResponse(bool bOK);
|
||||
void AppendResponse(const char* szPart);
|
||||
bool IsJson() { return m_eProtocol == XmlRpcProcessor::rpJsonRpc; }
|
||||
bool NextParamAsInt(int* iValue);
|
||||
bool NextParamAsBool(bool* bValue);
|
||||
bool NextParamAsStr(char** szValueBuf);
|
||||
const char* BoolToStr(bool bValue);
|
||||
char* EncodeStr(const char* szStr);
|
||||
|
||||
public:
|
||||
XmlCommand();
|
||||
virtual ~XmlCommand() {}
|
||||
virtual void Execute() = 0;
|
||||
void PrepareParams();
|
||||
void SetRequest(char* szRequest) { m_szRequest = szRequest; m_szRequestPtr = m_szRequest; }
|
||||
void SetProtocol(XmlRpcProcessor::ERpcProtocol eProtocol) { m_eProtocol = eProtocol; }
|
||||
void SetHttpMethod(XmlRpcProcessor::EHttpMethod eHttpMethod) { m_eHttpMethod = eHttpMethod; }
|
||||
const char* GetResponse() { return m_StringBuilder.GetBuffer(); }
|
||||
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 PauseXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class UnPauseXmlCommand: public XmlCommand
|
||||
{
|
||||
public:
|
||||
virtual void Execute();
|
||||
};
|
||||
|
||||
class ShutdownXmlCommand: 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();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,9 +9,6 @@
|
||||
/* Define to 1 to disable smart par-verification and restoration */
|
||||
#undef DISABLE_PARCHECK
|
||||
|
||||
/* Define to 1 to include support for uulib */
|
||||
#undef ENABLE_UULIB
|
||||
|
||||
/* Define to the name of macro which returns the name of function being
|
||||
compiled */
|
||||
#undef FUNCTION_MACRO_NAME
|
||||
@@ -46,8 +43,8 @@
|
||||
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
|
||||
#undef HAVE_NCURSES_NCURSES_H
|
||||
|
||||
/* Define to 1 to use pragma pack directive in MessageBase.h */
|
||||
#undef HAVE_PRAGMA_PACK
|
||||
/* Define to 1 if stat64 is supported */
|
||||
#undef HAVE_STAT64
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
444
configure
vendored
444
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 0.3.1.
|
||||
# Generated by GNU Autoconf 2.61 for nzbget 0.4.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='0.3.1'
|
||||
PACKAGE_STRING='nzbget 0.3.1'
|
||||
PACKAGE_VERSION='0.4.0'
|
||||
PACKAGE_STRING='nzbget 0.4.0'
|
||||
PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
|
||||
|
||||
ac_unique_file="nzbget.cpp"
|
||||
@@ -1238,7 +1238,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 0.3.1 to adapt to many kinds of systems.
|
||||
\`configure' configures nzbget 0.4.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1308,7 +1308,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of nzbget 0.3.1:";;
|
||||
short | recursive ) echo "Configuration of nzbget 0.4.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1318,7 +1318,6 @@ Optional Features:
|
||||
--disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors
|
||||
--disable-curses do not use curses (removes dependency from curses-library and makes executable smaller)
|
||||
--enable-uulib use uulib for decoding and joining
|
||||
--enable-parcheck include code for par-checking
|
||||
--enable-debug enable debugging
|
||||
|
||||
@@ -1329,8 +1328,6 @@ Optional Packages:
|
||||
--with-libxml2-libraries=DIR libxml2 library directory
|
||||
--with-libcurses-includes=DIR libcurses include directory
|
||||
--with-libcurses-libraries=DIR libcurses library directory
|
||||
--with-uulib-includes=DIR uulib include directory
|
||||
--with-uulib-libraries=DIR uulib library directory
|
||||
--with-libsigc-includes=DIR libsigc++-2.0 include directory
|
||||
--with-libsigc-libraries=DIR libsigc++-2.0 library directory
|
||||
--with-libpar2-includes=DIR libpar2 include directory
|
||||
@@ -1413,7 +1410,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
nzbget configure 0.3.1
|
||||
nzbget configure 0.4.0
|
||||
generated by GNU Autoconf 2.61
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1427,7 +1424,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 0.3.1, which was
|
||||
It was created by nzbget $as_me 0.4.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -2117,7 +2114,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=nzbget
|
||||
VERSION=0.3.1
|
||||
VERSION=0.4.0
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -5566,6 +5563,104 @@ fi
|
||||
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for stat64" >&5
|
||||
echo $ECHO_N "checking for stat64... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_func_stat64+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
/* Define stat64 to an innocuous variant, in case <limits.h> declares stat64.
|
||||
For example, HP-UX 11i <limits.h> declares gettimeofday. */
|
||||
#define stat64 innocuous_stat64
|
||||
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char stat64 (); below.
|
||||
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
|
||||
<limits.h> exists even on freestanding compilers. */
|
||||
|
||||
#ifdef __STDC__
|
||||
# include <limits.h>
|
||||
#else
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#undef stat64
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char stat64 ();
|
||||
/* The GNU C library defines this for functions which it implements
|
||||
to always fail with ENOSYS. Some functions are actually named
|
||||
something starting with __ and the normal name is an alias. */
|
||||
#if defined __stub_stat64 || defined __stub___stat64
|
||||
choke me
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return stat64 ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_func_stat64=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_func_stat64=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_func_stat64" >&5
|
||||
echo "${ECHO_T}$ac_cv_func_stat64" >&6; }
|
||||
if test $ac_cv_func_stat64 = yes; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_STAT64 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
case " $LIBOBJS " in
|
||||
*" stat64.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS stat64.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for ctime_r" >&5
|
||||
echo $ECHO_N "checking for ctime_r... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
@@ -5923,59 +6018,6 @@ _ACEOF
|
||||
fi
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for pragma pack" >&5
|
||||
echo $ECHO_N "checking for pragma pack... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#pragma pack(1)
|
||||
#pragma pack()
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
{ echo "$as_me:$LINENO: result: yes" >&5
|
||||
echo "${ECHO_T}yes" >&6; }
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_PRAGMA_PACK 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
{ echo "$as_me:$LINENO: result: no" >&5
|
||||
echo "${ECHO_T}no" >&6; }
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
|
||||
|
||||
INCVAL="${LIBPREF}/include/libxml2"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
|
||||
@@ -7025,276 +7067,6 @@ _ACEOF
|
||||
fi
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking whether to use uulib for decoding and joining" >&5
|
||||
echo $ECHO_N "checking whether to use uulib for decoding and joining... $ECHO_C" >&6; }
|
||||
# Check whether --enable-uulib was given.
|
||||
if test "${enable_uulib+set}" = set; then
|
||||
enableval=$enable_uulib; ENABLEUULIB=$enableval
|
||||
else
|
||||
ENABLEUULIB=no
|
||||
fi
|
||||
|
||||
{ echo "$as_me:$LINENO: result: $ENABLEUULIB" >&5
|
||||
echo "${ECHO_T}$ENABLEUULIB" >&6; }
|
||||
if test "$ENABLEUULIB" = "yes"; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define ENABLE_UULIB 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
INCVAL="${LIBPREF}/include"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
|
||||
# Check whether --with-uulib_includes was given.
|
||||
if test "${with_uulib_includes+set}" = set; then
|
||||
withval=$with_uulib_includes; INCVAL="$withval"
|
||||
fi
|
||||
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
as_ac_Header=`echo "ac_cv_header_$INCVAL/uudeview.h" | $as_tr_sh`
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
{ echo "$as_me:$LINENO: checking for $INCVAL/uudeview.h" >&5
|
||||
echo $ECHO_N "checking for $INCVAL/uudeview.h... $ECHO_C" >&6; }
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
fi
|
||||
ac_res=`eval echo '${'$as_ac_Header'}'`
|
||||
{ echo "$as_me:$LINENO: result: $ac_res" >&5
|
||||
echo "${ECHO_T}$ac_res" >&6; }
|
||||
else
|
||||
# Is the header compilable?
|
||||
{ echo "$as_me:$LINENO: checking $INCVAL/uudeview.h usability" >&5
|
||||
echo $ECHO_N "checking $INCVAL/uudeview.h usability... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <$INCVAL/uudeview.h>
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_header_compiler=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_compiler=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
|
||||
echo "${ECHO_T}$ac_header_compiler" >&6; }
|
||||
|
||||
# Is the header present?
|
||||
{ echo "$as_me:$LINENO: checking $INCVAL/uudeview.h presence" >&5
|
||||
echo $ECHO_N "checking $INCVAL/uudeview.h presence... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <$INCVAL/uudeview.h>
|
||||
_ACEOF
|
||||
if { (ac_try="$ac_cpp conftest.$ac_ext"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null && {
|
||||
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
}; then
|
||||
ac_header_preproc=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_preproc=no
|
||||
fi
|
||||
|
||||
rm -f conftest.err conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
|
||||
echo "${ECHO_T}$ac_header_preproc" >&6; }
|
||||
|
||||
# So? What about this header?
|
||||
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
|
||||
yes:no: )
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: accepted by the compiler, rejected by the preprocessor!" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: proceeding with the compiler's result" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: proceeding with the compiler's result" >&2;}
|
||||
ac_header_preproc=yes
|
||||
;;
|
||||
no:yes:* )
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: present but cannot be compiled" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: present but cannot be compiled" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: check for missing prerequisite headers?" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: check for missing prerequisite headers?" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: see the Autoconf documentation" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: see the Autoconf documentation" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: section \"Present But Cannot Be Compiled\"" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: proceeding with the preprocessor's result" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: proceeding with the preprocessor's result" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $INCVAL/uudeview.h: in the future, the compiler will take precedence" >&5
|
||||
echo "$as_me: WARNING: $INCVAL/uudeview.h: in the future, the compiler will take precedence" >&2;}
|
||||
( cat <<\_ASBOX
|
||||
## ------------------------------------------- ##
|
||||
## Report this to hugbug@users.sourceforge.net ##
|
||||
## ------------------------------------------- ##
|
||||
_ASBOX
|
||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||
;;
|
||||
esac
|
||||
{ echo "$as_me:$LINENO: checking for $INCVAL/uudeview.h" >&5
|
||||
echo $ECHO_N "checking for $INCVAL/uudeview.h... $ECHO_C" >&6; }
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
eval "$as_ac_Header=\$ac_header_preproc"
|
||||
fi
|
||||
ac_res=`eval echo '${'$as_ac_Header'}'`
|
||||
{ echo "$as_me:$LINENO: result: $ac_res" >&5
|
||||
echo "${ECHO_T}$ac_res" >&6; }
|
||||
|
||||
fi
|
||||
if test `eval echo '${'$as_ac_Header'}'` = yes; then
|
||||
:
|
||||
else
|
||||
{ { echo "$as_me:$LINENO: error: \"uulib header files were not found in $INCVAL.\"" >&5
|
||||
echo "$as_me: error: \"uulib header files were not found in $INCVAL.\"" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --with-uulib_libraries was given.
|
||||
if test "${with_uulib_libraries+set}" = set; then
|
||||
withval=$with_uulib_libraries; LIBVAL="$withval"
|
||||
fi
|
||||
|
||||
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for library containing UUInitialize" >&5
|
||||
echo $ECHO_N "checking for library containing UUInitialize... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_UUInitialize+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char UUInitialize ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return UUInitialize ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' uu; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_search_UUInitialize=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_UUInitialize+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_UUInitialize+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_UUInitialize=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_UUInitialize" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_UUInitialize" >&6; }
|
||||
ac_res=$ac_cv_search_UUInitialize
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
|
||||
else
|
||||
{ { echo "$as_me:$LINENO: error: \"uulib library not found in $LIBVAL.\"" >&5
|
||||
echo "$as_me: error: \"uulib library not found in $LIBVAL.\"" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ echo "$as_me:$LINENO: checking whether to include code for par-checking" >&5
|
||||
echo $ECHO_N "checking whether to include code for par-checking... $ECHO_C" >&6; }
|
||||
# Check whether --enable-parcheck was given.
|
||||
@@ -8386,7 +8158,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 0.3.1, which was
|
||||
This file was extended by nzbget $as_me 0.4.0, which was
|
||||
generated by GNU Autoconf 2.61. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -8439,7 +8211,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
nzbget config.status 0.3.1
|
||||
nzbget config.status 0.4.0
|
||||
configured by $0, generated by GNU Autoconf 2.61,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
59
configure.ac
59
configure.ac
@@ -2,8 +2,8 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(nzbget, 0.3.1, hugbug@users.sourceforge.net)
|
||||
AM_INIT_AUTOMAKE(nzbget, 0.3.1)
|
||||
AC_INIT(nzbget, 0.4.0, hugbug@users.sourceforge.net)
|
||||
AM_INIT_AUTOMAKE(nzbget, 0.4.0)
|
||||
AC_CONFIG_SRCDIR([nzbget.cpp])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
@@ -87,6 +87,14 @@ AC_CHECK_FUNC(getopt_long,
|
||||
[AC_LIBOBJ(getopt) AC_LIBOBJ(getopt1)])
|
||||
|
||||
|
||||
dnl
|
||||
dnl stat64
|
||||
dnl
|
||||
AC_CHECK_FUNC(stat64,
|
||||
[AC_DEFINE([HAVE_STAT64], 1, [Define to 1 if stat64 is supported])],
|
||||
[AC_LIBOBJ(stat64)])
|
||||
|
||||
|
||||
dnl
|
||||
dnl check ctime_r
|
||||
dnl
|
||||
@@ -166,17 +174,6 @@ if test "$HAVE_FUNCTION_MACRO" != "yes"; then
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl check for pragma pack
|
||||
dnl
|
||||
AC_MSG_CHECKING(for pragma pack)
|
||||
AC_TRY_COMPILE([#pragma pack(1)
|
||||
#pragma pack()],,
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_PRAGMA_PACK],1,[Define to 1 to use pragma pack directive in MessageBase.h]),
|
||||
AC_MSG_RESULT([no]))
|
||||
|
||||
|
||||
dnl
|
||||
dnl checks for libxml2 includes and libraries.
|
||||
dnl
|
||||
@@ -245,42 +242,6 @@ else
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl Use uulib. Deafult: no
|
||||
dnl
|
||||
AC_MSG_CHECKING(whether to use uulib for decoding and joining)
|
||||
AC_ARG_ENABLE(uulib,
|
||||
[ --enable-uulib use uulib for decoding and joining],
|
||||
[ ENABLEUULIB=$enableval ],
|
||||
[ ENABLEUULIB=no] )
|
||||
AC_MSG_RESULT($ENABLEUULIB)
|
||||
if test "$ENABLEUULIB" = "yes"; then
|
||||
AC_DEFINE([ENABLE_UULIB],1,[Define to 1 to include support for uulib])
|
||||
|
||||
dnl
|
||||
dnl checks for uulib includes and libraries.
|
||||
dnl
|
||||
INCVAL="${LIBPREF}/include"
|
||||
LIBVAL="${LIBPREF}/lib"
|
||||
AC_ARG_WITH(uulib_includes,
|
||||
[ --with-uulib-includes=DIR uulib include directory],
|
||||
[INCVAL="$withval"])
|
||||
|
||||
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
|
||||
AC_CHECK_HEADER($INCVAL/uudeview.h,,
|
||||
AC_MSG_ERROR("uulib header files were not found in $INCVAL."))
|
||||
|
||||
AC_ARG_WITH(uulib_libraries,
|
||||
[ --with-uulib-libraries=DIR uulib library directory],
|
||||
[LIBVAL="$withval"])
|
||||
|
||||
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
|
||||
|
||||
AC_SEARCH_LIBS([UUInitialize], [uu],,
|
||||
AC_MSG_ERROR("uulib library not found in $LIBVAL."))
|
||||
fi
|
||||
|
||||
|
||||
dnl
|
||||
dnl Use lib2par for par-checking. Deafult: no
|
||||
dnl
|
||||
|
||||
@@ -425,7 +425,7 @@ diff -urN libpar2-0.2-original/par2cmdline.h libpar2-0.2-modified/par2cmdline.h
|
||||
#ifdef HAVE_CONFIG_H
|
||||
diff -urN libpar2-0.2-original/par2repairer.cpp libpar2-0.2-modified/par2repairer.cpp
|
||||
--- libpar2-0.2-original/par2repairer.cpp 2006-01-20 18:25:20.000000000 +0100
|
||||
+++ libpar2-0.2-modified/par2repairer.cpp 2008-01-31 14:35:11.110360000 +0100
|
||||
+++ libpar2-0.2-modified/par2repairer.cpp 2008-02-13 15:37:59.899314300 +0100
|
||||
@@ -78,6 +78,7 @@
|
||||
|
||||
delete mainpacket;
|
||||
@@ -434,3 +434,21 @@ diff -urN libpar2-0.2-original/par2repairer.cpp libpar2-0.2-modified/par2repaire
|
||||
}
|
||||
|
||||
|
||||
@@ -1261,7 +1262,7 @@
|
||||
DiskFile::SplitFilename(filename, path, name);
|
||||
|
||||
cout << "Target: \"" << name << "\" - missing." << endl;
|
||||
- sig_done.emit(name, 0, sourcefile->GetVerificationPacket()->BlockCount());
|
||||
+ sig_done.emit(name, 0, sourcefile && sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1804,7 +1805,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
- sig_done.emit(name,count,sourcefile->GetVerificationPacket()->BlockCount());
|
||||
+ sig_done.emit(name,count, sourcefile && sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0);
|
||||
sig_progress.emit(1000.0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -158,15 +158,12 @@ DupeCheck=no
|
||||
# Do not activate this option if par-check is enabled.
|
||||
RenameBroken=no
|
||||
|
||||
# Determine how the articles should be decoded (yenc, uulib, none)
|
||||
# yenc - use internal yEnc-Decoder. Supports only yEnc-format, but is
|
||||
# very fast and does not create temporary files with articles' text
|
||||
# decoding them on the fly.
|
||||
# uulib - use uulib to decode files. Supports many encoding formats,
|
||||
# but is slow. Not available in Windows-version.
|
||||
# none - the articles will not be decoded and joined. External programs
|
||||
# (like "uudeview") can be used to decode and join downloaded articles.
|
||||
Decoder=yEnc
|
||||
# Decode articles (yes, no)
|
||||
# yes - decode articles using internal decoder (supports yEnc and UU formats).
|
||||
# no - the articles will not be decoded and joined. External programs
|
||||
# (like "uudeview") can be used to decode and join downloaded articles.
|
||||
# Also useful for debugging to look at article's source text.
|
||||
Decode=yes
|
||||
|
||||
# Write decoded articles directly into destination output file (yes, no)
|
||||
# With this option enabled the program at first creates the output
|
||||
@@ -257,6 +254,12 @@ DownloadRate=0
|
||||
# the effect of the option is highly OS-dependend.
|
||||
WriteBufferSize=0
|
||||
|
||||
# Pause if disk space gets below this value, in MegaBytes.
|
||||
# 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
|
||||
|
||||
|
||||
##############################################################################
|
||||
### LOGGING ###
|
||||
@@ -268,11 +271,12 @@ CreateLog=yes
|
||||
ResetLog=no
|
||||
|
||||
# How various messages must be printed (screen, log, both, none)
|
||||
# Debug-messages can be only printed if the programm was compiled in
|
||||
# Debug-messages can be printed only if the programm was compiled in
|
||||
# debug-mode: "./configure --enable-debug"
|
||||
InfoTarget=both
|
||||
WarningTarget=both
|
||||
ErrorTarget=both
|
||||
WarningTarget=both
|
||||
InfoTarget=both
|
||||
DetailTarget=both
|
||||
DebugTarget=both
|
||||
|
||||
# Number of messages stored in buffer and available for remote clients
|
||||
@@ -337,7 +341,12 @@ ServerPassword=tegbzn6789
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PAR CHECK AND REPAIR ###
|
||||
### PAR CHECK/REPAIR AND POSTPROCESSING ###
|
||||
|
||||
# Reload Post-processor-queue on start, if it exists (yes, no)
|
||||
# For this option to work the options "SaveQueue" and "ReloadQueue" must
|
||||
# be also enabled.
|
||||
ReloadPostQueue=yes
|
||||
|
||||
# How many par2-files to load (none, all, one)
|
||||
# none - all added par2-files must be automatically paused
|
||||
@@ -379,38 +388,73 @@ ParRepair=yes
|
||||
# and the option "strictparname" does not change this behavior
|
||||
StrictParName=yes
|
||||
|
||||
# Cleanup download queue after successful check/repair (yes, no)
|
||||
# Enable this option for automatic deletion of unneeded (paused) par-files
|
||||
# from download queue after successful check/repair.
|
||||
# NOTE: before cleaning up the program checks if all paused files are par-files.
|
||||
# If there are paused non-par-files (this means that you have paused them
|
||||
# manually), the cleanup will be skipped for this collection.
|
||||
ParCleanupQueue=yes
|
||||
|
||||
##############################################################################
|
||||
### POSTPROCESSING ###
|
||||
|
||||
# Set path to program, that must be executed after the download of
|
||||
# nzb-file or one collection in nzb-file (if par-check enabled)
|
||||
# Set path to program, that must be executed after the download of nzb-file
|
||||
# or one collection in nzb-file (if par-check enabled and nzb-file contains
|
||||
# multiple collections; see note below for the definition of "collection")
|
||||
# is completed and possibly par-checked/repaired.
|
||||
# Six arguments are being passed to this program:
|
||||
# - path to destination dir, where downloaded files are located;
|
||||
# - name of nzb-file processed;
|
||||
# - name of par-file processed (if par-checked) or empty string (if not);
|
||||
# - result of par-check:
|
||||
# Arguments passed to that program:
|
||||
# 1 - path to destination dir, where downloaded files are located;
|
||||
# 2 - name of nzb-file processed;
|
||||
# 3 - name of par-file processed (if par-checked) or empty string (if not);
|
||||
# 4 - result of par-check:
|
||||
# 0 - not checked: par-check disabled or nzb-file does not contain any
|
||||
# par-files;
|
||||
# 1 - checked and failed to repair;
|
||||
# 2 - checked and sucessfully repaired;
|
||||
# 3 - checked and can be repaired but repair is disabled;
|
||||
# - state of nzb-job:
|
||||
# 5 - state of nzb-job:
|
||||
# 0 - there are more collections in this nzb-file queued;
|
||||
# 1 - this was the last collection in nzb-file;
|
||||
# NOTE: if par-check is enabled and nzb-file contains more than one collection
|
||||
# 6 - indication of failed par-jobs for current nzb-file:
|
||||
# 0 - no failed par-jobs;
|
||||
# 1 - current par-job or any of the previous par-jobs for the
|
||||
# same nzb-files failed;
|
||||
# NOTE: The parameter "state of nzb-job" is very important and MUST be checked
|
||||
# even in the simplest scripts.
|
||||
# If par-check is enabled and nzb-file contains more than one collection
|
||||
# of files the postprocess-program is called after each collection is completed
|
||||
# and par-checked. If you want to clean up the directory (delete par-files,
|
||||
# etc.) there are two possibilities, when you can do this:
|
||||
# and par-checked. If you want to unpack files or clean up the directory
|
||||
# (delete par-files, etc.) there are two possibilities, when you can do this:
|
||||
# 1) you parse the "name of par-file processed" to find out the base name
|
||||
# of collection and clean up only files from this collection;
|
||||
# 2) or you just check the parameter "state of nzb-job" and do clean up,
|
||||
# only if it is equal to "1" (which means, that this was the last
|
||||
# collection in nzb-file and all files are now completed);
|
||||
# NOTE: do not forget to uncomment the next line
|
||||
# of collection and clean up only files from this collection (not reliable,
|
||||
# because par-files sometimes have different names than rar-files);
|
||||
# 2) or you just check the parameters "state of nzb-job" and "indication of
|
||||
# failed par-jobs" and do the processing, only if they are set to "1"
|
||||
# (which means, that this was the last collection in nzb-file and all files
|
||||
# are now completed) and to "0" (no failed par-jobs) respectively;
|
||||
# NOTE 2: if the option "ParCheck" is disabled nzbget calls PostProcess
|
||||
# only once, not after every collection, because the detection of collection
|
||||
# is disabled in this case;
|
||||
# NOTE 3: the term "collection" in the above description actually means
|
||||
# "par-set". To determine what "collections" are present in nzb-file nzbget
|
||||
# looks for par-sets. If any collection of files within nzb-file does
|
||||
# not have any par-files, this collection will not be detected.
|
||||
# For example, for nzb-file containing three collections but only two par-sets,
|
||||
# the postprocess will be called two times - after processing of each par-set.
|
||||
# NOTE 4: do not forget to uncomment the next line
|
||||
#PostProcess=~/myscript.sh
|
||||
|
||||
# Set the default message-kind for output received from postprocess-script
|
||||
# (None, Detail, Info, Warning, Error, Debug).
|
||||
# NZBGet checks if the line written by the script to stdout or stderr starts
|
||||
# with special character-sequence, determining the message-kind, e.g.:
|
||||
# [INFO] bla-bla
|
||||
# [DETAIL] bla-bla
|
||||
# [WARNING] bla-bla
|
||||
# [ERROR] bla-bla
|
||||
# [DEBUG] bla-bla
|
||||
# If the message-kind was detected the text is added to log with detected type.
|
||||
# Otherwise the message becomes the default kind, specified in this option.
|
||||
PostLogKind=Detail
|
||||
|
||||
|
||||
##############################################################################
|
||||
### PERFORMANCE ###
|
||||
|
||||
71
nzbget.cpp
71
nzbget.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
@@ -46,6 +46,9 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef DISABLE_PARCHECK
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ServerPool.h"
|
||||
@@ -74,6 +77,9 @@ void ProcessClientRequest();
|
||||
void InstallSignalHandlers();
|
||||
void Daemonize();
|
||||
#endif
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void DisableCout();
|
||||
#endif
|
||||
|
||||
Thread* g_pFrontend = NULL;
|
||||
Options* g_pOptions = NULL;
|
||||
@@ -91,11 +97,27 @@ DiskState* g_pDiskState = NULL;
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef _DEBUG
|
||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF
|
||||
#ifdef DEBUG_CRTMEMLEAKS
|
||||
| _CRTDBG_CHECK_CRT_DF | _CRTDBG_CHECK_ALWAYS_DF
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
_set_fmode(_O_BINARY);
|
||||
InstallUninstallServiceCheck(argc, argv);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
DisableCout();
|
||||
#endif
|
||||
|
||||
// Init options & get the name of the .nzb file
|
||||
g_pLog = new Log();
|
||||
g_pServerPool = new ServerPool();
|
||||
@@ -137,6 +159,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
Run();
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _DEBUG
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -171,11 +200,10 @@ void Run()
|
||||
g_pRemoteServer->Start();
|
||||
}
|
||||
|
||||
// Starting a thread with the PrePostProcessor
|
||||
// Creating PrePostProcessor
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
g_pPrePostProcessor = new PrePostProcessor();
|
||||
g_pPrePostProcessor->Start();
|
||||
}
|
||||
|
||||
// Create the frontend
|
||||
@@ -203,7 +231,7 @@ void Run()
|
||||
g_pFrontend->Start();
|
||||
}
|
||||
|
||||
// Starting QueueCoordinator
|
||||
// Starting QueueCoordinator and PrePostProcessor
|
||||
if (!g_pOptions->GetRemoteClientMode())
|
||||
{
|
||||
// Standalone-mode
|
||||
@@ -219,6 +247,7 @@ void Run()
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->Start();
|
||||
g_pPrePostProcessor->Start();
|
||||
|
||||
// enter main program-loop
|
||||
while (g_pQueueCoordinator->IsRunning() || g_pPrePostProcessor->IsRunning())
|
||||
@@ -325,6 +354,14 @@ void ProcessClientRequest()
|
||||
{
|
||||
Client->RequestServerVersion();
|
||||
}
|
||||
else if (g_pOptions->GetClientOperation() == Options::opClientRequestPostQueue)
|
||||
{
|
||||
Client->RequestPostQueue();
|
||||
}
|
||||
else if (g_pOptions->GetClientOperation() == Options::opClientRequestWriteLog)
|
||||
{
|
||||
Client->RequestWriteLog(g_pOptions->GetWriteLogKind(), g_pOptions->GetLastArg());
|
||||
}
|
||||
|
||||
delete Client;
|
||||
}
|
||||
@@ -366,19 +403,21 @@ void SignalProc(int iSignal)
|
||||
{
|
||||
case SIGINT:
|
||||
signal(SIGINT, SIG_DFL); // Reset the signal handler
|
||||
debug("SIGINT received");
|
||||
ExitProc();
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
signal(SIGTERM, SIG_DFL); // Reset the signal handler
|
||||
debug("SIGTERM received");
|
||||
ExitProc();
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
case SIGPIPE:
|
||||
debug("SIGPIPE received, ignoring");
|
||||
// ignoring
|
||||
break;
|
||||
|
||||
case SIGCHLD:
|
||||
// ignoring
|
||||
break;
|
||||
|
||||
case SIGSEGV:
|
||||
@@ -387,7 +426,7 @@ void SignalProc(int iSignal)
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Signal %i received", iSignal);
|
||||
// printf("Signal %i received\n", iSignal);
|
||||
if (SignalProcList[iSignal - 1])
|
||||
{
|
||||
SignalProcList[iSignal - 1](iSignal);
|
||||
@@ -531,3 +570,19 @@ void Daemonize()
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
class NullStreamBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
int sputc ( char c ) { return (int) c; }
|
||||
} NullStreamBufInstance;
|
||||
|
||||
void DisableCout()
|
||||
{
|
||||
// libpar2 prints messages to c++ standard output stream (std::cout).
|
||||
// However we do not want these messages to be printed.
|
||||
// Since we do not use std::cout in nzbget we just disable it.
|
||||
std::cout.rdbuf(&NullStreamBufInstance);
|
||||
}
|
||||
#endif
|
||||
|
||||
10
nzbget.h
10
nzbget.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -31,16 +31,18 @@
|
||||
// WIN32
|
||||
|
||||
#define snprintf _snprintf
|
||||
#ifndef strdup
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
#define fdopen _fdopen
|
||||
#define ctime_r(timep, buf, bufsize) ctime_s(buf, bufsize, timep)
|
||||
#define int32_t __int32
|
||||
#define mkdir(dir, flags) _mkdir(dir)
|
||||
#define strcasecmp(a, b) _stricmp(a, b)
|
||||
#define strncasecmp(a, b, c) _strnicmp(a, b, c)
|
||||
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||
|
||||
#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
|
||||
#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
|
||||
|
||||
@@ -175,6 +175,14 @@
|
||||
RelativePath=".\ArticleDownloader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BinRpc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BinRpc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ColoredFrontend.cpp"
|
||||
>
|
||||
@@ -323,6 +331,14 @@
|
||||
RelativePath=".\ParChecker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PostInfo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PostInfo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PrePostProcessor.cpp"
|
||||
>
|
||||
@@ -363,6 +379,14 @@
|
||||
RelativePath=".\RemoteServer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ScriptController.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ScriptController.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ServerPool.cpp"
|
||||
>
|
||||
@@ -391,6 +415,14 @@
|
||||
RelativePath=".\win32.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\XmlRpc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\XmlRpc.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
||||
17
win32.h
17
win32.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file if part of nzbget
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
||||
*
|
||||
@@ -30,9 +30,6 @@
|
||||
/* Define to 1 to disable smart par-verification and restoration */
|
||||
#undef DISABLE_PARCHECK
|
||||
|
||||
/* Define to 1 to include support for uulib */
|
||||
#undef ENABLE_UULIB
|
||||
|
||||
/* Define to the name of macro which returns the name of function being
|
||||
compiled */
|
||||
#define FUNCTION_MACRO_NAME __FUNCTION__
|
||||
@@ -46,13 +43,10 @@
|
||||
/* Define to 1 if getopt_long is supported */
|
||||
#undef HAVE_GETOPT_LONG
|
||||
|
||||
/* Define to 1 to use pragma pack directive in MessageBase.h */
|
||||
#define HAVE_PRAGMA_PACK
|
||||
|
||||
/* Define to 1 if variadic macros are supported */
|
||||
#define HAVE_VARIADIC_MACROS
|
||||
|
||||
#define VERSION "0.3.1"
|
||||
#define VERSION "0.4.0"
|
||||
|
||||
/* Suppress warnings */
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
@@ -62,6 +56,13 @@
|
||||
|
||||
#define _USE_32BIT_TIME_T
|
||||
|
||||
#ifdef _DEBUG
|
||||
// detection of memory leaks
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user