version 9.1

This commit is contained in:
Andrey Prygunkov
2013-03-30 20:43:04 +00:00
parent c46c1a96cd
commit 99bd29f631
73 changed files with 3802 additions and 5553 deletions

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,16 +43,12 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include "nzbget.h"
#include "ScriptController.h"
#include "Log.h"
#include "Util.h"
// System global variable holding environments variables
extern char** environ;
extern Options* g_pOptions;
extern char* (*g_szEnvironmentVariables)[];
extern DownloadQueueHolder* g_pDownloadQueueHolder;
@@ -218,7 +214,7 @@ void ScriptController::SetEnvVar(const char* szName, const char* szValue)
m_environmentStrings.Append(szVar);
}
void ScriptController::PrepareEnvOptions()
void ScriptController::PrepareEnvironmentStrings()
{
Options::OptEntries* pOptEntries = g_pOptions->LockOptEntries();
@@ -231,7 +227,10 @@ void ScriptController::PrepareEnvOptions()
// convert to upper case; replace "." with "_".
for (char* szPtr = szVarname; *szPtr; szPtr++)
{
if (*szPtr == '.') *szPtr = '_';
if (*szPtr == '.')
{
*szPtr = '_';
}
*szPtr = toupper(*szPtr);
}
@@ -242,40 +241,15 @@ void ScriptController::PrepareEnvOptions()
g_pOptions->UnlockOptEntries();
}
void ScriptController::PrepareEnvParameters(NZBInfo* pNZBInfo)
{
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
char szVarname[1024];
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
szVarname[1024-1] = '\0';
// Original name
SetEnvVar(szVarname, pParameter->GetValue());
char szNormVarname[1024];
strncpy(szNormVarname, szVarname, sizeof(szVarname));
szNormVarname[1024-1] = '\0';
// replace ".*:" with "_".
for (char* szPtr = szNormVarname; *szPtr; szPtr++)
{
if (*szPtr == '.' || *szPtr == ':' || *szPtr == '*') *szPtr = '_';
*szPtr = toupper(*szPtr);
}
// Another env var with normalized name (replaced special chars and converted to upper case)
if (strcmp(szVarname, szNormVarname))
{
SetEnvVar(szNormVarname, pParameter->GetValue());
}
}
}
int ScriptController::Execute()
{
PrepareEnvOptions();
if (!Util::FileExists(m_szScript))
{
error("Could not start %s: could not find file %s", m_szInfoName, m_szScript);
return -1;
}
PrepareEnvironmentStrings();
int iExitCode = 0;
int pipein;
@@ -325,7 +299,8 @@ int ScriptController::Execute()
DWORD dwErrCode = GetLastError();
char szErrMsg[255];
szErrMsg[255-1] = '\0';
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, 0, szErrMsg, 255, NULL))
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM || FORMAT_MESSAGE_IGNORE_INSERTS || FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL, dwErrCode, 0, szErrMsg, 255, NULL))
{
error("Could not start %s: %s", m_szInfoName, szErrMsg);
}
@@ -333,10 +308,6 @@ int ScriptController::Execute()
{
error("Could not start %s: error %i", m_szInfoName, dwErrCode);
}
if (!Util::FileExists(m_szScript))
{
error("Could not find file %s", m_szScript);
}
free(szEnvironmentStrings);
return -1;
}
@@ -399,14 +370,10 @@ int ScriptController::Execute()
fflush(stdout);
#endif
chdir(m_szWorkingDir);
environ = pEnvironmentStrings;
execvp(m_szScript, (char* const*)m_szArgs);
// NOTE: the text "[ERROR] Could not start " is checked later,
// by changing adjust the dependent code below.
fprintf(stdout, "[ERROR] Could not start %s: %s", m_szScript, strerror(errno));
execve(m_szScript, (char* const*)m_szArgs, (char* const*)pEnvironmentStrings);
fprintf(stdout, "[ERROR] Could not start script: %s", strerror(errno));
fflush(stdout);
_exit(254);
_exit(-1);
}
// continue the first instance
@@ -440,11 +407,9 @@ int ScriptController::Execute()
char* buf = (char*)malloc(10240);
debug("Entering pipe-loop");
bool bFirstLine = true;
bool bStartError = false;
while (!feof(readpipe) && !m_bTerminated)
{
if (ReadLine(buf, 10240, readpipe))
if (fgets(buf, 10240, readpipe))
{
#ifdef CHILD_WATCHDOG
if (!bChildConfirmed)
@@ -452,15 +417,9 @@ int ScriptController::Execute()
bChildConfirmed = true;
pWatchDog->Stop();
debug("Child confirmed");
continue;
}
#endif
if (bFirstLine && !strncmp(buf, "[ERROR] Could not start ", 24))
{
bStartError = true;
}
ProcessOutput(buf);
bFirstLine = false;
}
}
debug("Exited pipe-loop");
@@ -499,10 +458,6 @@ int ScriptController::Execute()
if (WIFEXITED(iStatus))
{
iExitCode = WEXITSTATUS(iStatus);
if (iExitCode == 254 && bStartError)
{
iExitCode = -1;
}
}
#endif
@@ -548,11 +503,6 @@ void ScriptController::Terminate()
debug("Stopped %s", m_szInfoName);
}
bool ScriptController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
{
return fgets(szBuf, iBufSize, pStream);
}
void ScriptController::ProcessOutput(char* szText)
{
debug("Processing output received from script");
@@ -567,23 +517,23 @@ void ScriptController::ProcessOutput(char* szText)
if (!strncmp(szText, "[INFO] ", 7))
{
AddMessage(Message::mkInfo, false, szText + 7);
AddMessage(Message::mkInfo, false, g_pOptions->GetInfoTarget(), szText + 7);
}
else if (!strncmp(szText, "[WARNING] ", 10))
{
AddMessage(Message::mkWarning, false, szText + 10);
AddMessage(Message::mkWarning, false, g_pOptions->GetWarningTarget(), szText + 10);
}
else if (!strncmp(szText, "[ERROR] ", 8))
{
AddMessage(Message::mkError, false, szText + 8);
AddMessage(Message::mkError, false, g_pOptions->GetErrorTarget(), szText + 8);
}
else if (!strncmp(szText, "[DETAIL] ", 9))
{
AddMessage(Message::mkDetail, false, szText + 9);
AddMessage(Message::mkDetail, false, g_pOptions->GetDetailTarget(), szText + 9);
}
else if (!strncmp(szText, "[DEBUG] ", 8))
{
AddMessage(Message::mkDebug, false, szText + 8);
AddMessage(Message::mkDebug, false, g_pOptions->GetDebugTarget(), szText + 8);
}
else
{
@@ -593,23 +543,23 @@ void ScriptController::ProcessOutput(char* szText)
break;
case Options::slDetail:
AddMessage(Message::mkDetail, true, szText);
AddMessage(Message::mkDetail, true, g_pOptions->GetDetailTarget(), szText);
break;
case Options::slInfo:
AddMessage(Message::mkInfo, true, szText);
AddMessage(Message::mkInfo, true, g_pOptions->GetInfoTarget(), szText);
break;
case Options::slWarning:
AddMessage(Message::mkWarning, true, szText);
AddMessage(Message::mkWarning, true, g_pOptions->GetWarningTarget(), szText);
break;
case Options::slError:
AddMessage(Message::mkError, true, szText);
AddMessage(Message::mkError, true, g_pOptions->GetErrorTarget(), szText);
break;
case Options::slDebug:
AddMessage(Message::mkDebug, true, szText);
AddMessage(Message::mkDebug, true, g_pOptions->GetDebugTarget(), szText);
break;
}
}
@@ -617,7 +567,7 @@ void ScriptController::ProcessOutput(char* szText)
debug("Processing output received from script - completed");
}
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
{
switch (eKind)
{
@@ -643,30 +593,19 @@ void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const
}
}
void ScriptController::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, const char* szScript, bool bNZBFileCompleted, bool bHasFailedParJobs)
{
char tmp2[1024];
info("Executing post-process-script for %s", pPostInfo->GetInfoName());
va_list ap;
va_start(ap, szFormat);
vsnprintf(tmp2, 1024, szFormat, ap);
tmp2[1024-1] = '\0';
va_end(ap);
AddMessage(eKind, false, tmp2);
}
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, bool bNZBFileCompleted, bool bHasFailedParJobs)
{
PostScriptController* pScriptController = new PostScriptController();
pScriptController->m_pPostInfo = pPostInfo;
pScriptController->SetScript(g_pOptions->GetPostProcess());
pScriptController->SetScript(szScript);
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
pScriptController->m_bNZBFileCompleted = bNZBFileCompleted;
pScriptController->m_bHasFailedParJobs = bHasFailedParJobs;
pScriptController->SetAutoDestroy(false);
pPostInfo->SetPostThread(pScriptController);
pPostInfo->SetScriptThread(pScriptController);
pScriptController->Start();
}
@@ -680,16 +619,10 @@ void PostScriptController::Run()
strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
szNZBName[1024-1] = '\0';
int iParStatus[] = { 0, 0, 1, 2, 3 };
char szParStatus[10];
snprintf(szParStatus, 10, "%i", iParStatus[g_pOptions->GetAllowReProcess() ? (int)m_pPostInfo->GetParStatus() : (int)m_pPostInfo->GetNZBInfo()->GetParStatus()]);
snprintf(szParStatus, 10, "%i", m_pPostInfo->GetParStatus());
szParStatus[10-1] = '\0';
int iUnpackStatus[] = { 0, 0, 1, 2 };
char szUnpackStatus[10];
snprintf(szUnpackStatus, 10, "%i", g_pOptions->GetAllowReProcess() ? 0 : iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
szUnpackStatus[10-1] = '\0';
char szCollectionCompleted[10];
snprintf(szCollectionCompleted, 10, "%i", (int)m_bNZBFileCompleted);
szCollectionCompleted[10-1] = '\0';
@@ -715,7 +648,7 @@ void PostScriptController::Run()
szCategory[1024-1] = '\0';
char szInfoName[1024];
snprintf(szInfoName, 1024, "post-process-script for %s", g_pOptions->GetAllowReProcess() ? m_pPostInfo->GetInfoName() : m_pPostInfo->GetNZBInfo()->GetName());
snprintf(szInfoName, 1024, "post-process-script for %s", m_pPostInfo->GetInfoName());
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
@@ -739,30 +672,31 @@ void PostScriptController::Run()
SetEnvVar("NZBPP_NZBFILENAME", szNZBFilename);
SetEnvVar("NZBPP_PARFILENAME", szParFilename);
SetEnvVar("NZBPP_PARSTATUS", szParStatus);
SetEnvVar("NZBPP_UNPACKSTATUS", szUnpackStatus);
SetEnvVar("NZBPP_NZBCOMPLETED", szCollectionCompleted);
SetEnvVar("NZBPP_PARFAILED", szHasFailedParJobs);
SetEnvVar("NZBPP_CATEGORY", szCategory);
PrepareEnvParameters(m_pPostInfo->GetNZBInfo());
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
char szVarname[1024];
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
szVarname[1024-1] = '\0';
SetEnvVar(szVarname, pParameter->GetValue());
}
g_pDownloadQueueHolder->UnlockQueue();
info("Executing post-process-script for %s", g_pOptions->GetAllowReProcess() ? m_pPostInfo->GetInfoName() : szNZBName);
int iResult = Execute();
szInfoName[0] = 'P'; // uppercase
switch (iResult)
{
case POSTPROCESS_SUCCESS:
info("%s successful", szInfoName);
info("%s sucessful", szInfoName);
m_pPostInfo->SetScriptStatus(PostInfo::srSuccess);
break;
case POSTPROCESS_ERROR:
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
info("%s failed", szInfoName);
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
break;
@@ -774,7 +708,7 @@ void PostScriptController::Run()
#ifndef DISABLE_PARCHECK
case POSTPROCESS_PARCHECK_ALL:
if (m_pPostInfo->GetParStatus() > PostInfo::psSkipped)
if (m_pPostInfo->GetParCheck())
{
error("%s requested par-check/repair for all collections, but they were already checked", szInfoName);
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
@@ -793,7 +727,7 @@ void PostScriptController::Run()
break;
case POSTPROCESS_PARCHECK_CURRENT:
if (m_pPostInfo->GetParStatus() > PostInfo::psSkipped)
if (m_pPostInfo->GetParCheck())
{
error("%s requested par-check/repair for current collection, but it was already checked", szInfoName);
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
@@ -821,18 +755,26 @@ void PostScriptController::Run()
m_pPostInfo->SetWorking(false);
}
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
{
if (!strncmp(szText, "[HISTORY] ", 10))
{
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
}
}
else
{
ScriptController::AddMessage(eKind, bDefaultKind, szText);
m_pPostInfo->AppendMessage(eKind, szText);
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
m_pPostInfo->AppendMessage(eKind, szText);
}
}
if (g_pOptions->GetPausePostProcess())
{
time_t tStageTime = m_pPostInfo->GetStageTime();
@@ -912,7 +854,7 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF
delete pScriptController;
}
void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
{
if (!strncmp(szText, "[NZB] ", 6))
{
@@ -948,7 +890,7 @@ void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, co
}
else
{
ScriptController::AddMessage(eKind, bDefaultKind, szText);
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
}
}
@@ -985,7 +927,14 @@ void NZBAddedScriptController::StartScript(DownloadQueue* pDownloadQueue, NZBInf
snprintf(buf, 100, "%i", iMaxPriority);
pScriptController->SetEnvVar("NZBNA_PRIORITY", buf);
pScriptController->PrepareEnvParameters(pNZBInfo);
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
char szVarname[1024];
snprintf(szVarname, sizeof(szVarname), "NZBPR_%s", pParameter->GetName());
szVarname[1024-1] = '\0';
pScriptController->SetEnvVar(szVarname, pParameter->GetValue());
}
pScriptController->SetAutoDestroy(true);