diff --git a/daemon/frontend/Frontend.cpp b/daemon/frontend/Frontend.cpp index bde7562e..c1af0489 100644 --- a/daemon/frontend/Frontend.cpp +++ b/daemon/frontend/Frontend.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -119,11 +119,7 @@ void Frontend::FreeData() { if (IsRemoteMode()) { - for (Log::Messages::iterator it = m_RemoteMessages.begin(); it != m_RemoteMessages.end(); it++) - { - delete *it; - } - m_RemoteMessages.clear(); + m_RemoteMessages.Clear(); DownloadQueue* pDownloadQueue = DownloadQueue::Lock(); pDownloadQueue->GetQueue()->Clear(); @@ -131,7 +127,7 @@ void Frontend::FreeData() } } -Log::Messages* Frontend::LockMessages() +MessageList* Frontend::LockMessages() { if (IsRemoteMode()) { diff --git a/daemon/frontend/Frontend.h b/daemon/frontend/Frontend.h index a0a18bef..85d5e3bf 100644 --- a/daemon/frontend/Frontend.h +++ b/daemon/frontend/Frontend.h @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ class Frontend : public Thread { private: - Log::Messages m_RemoteMessages; + MessageList m_RemoteMessages; bool RequestMessages(); bool RequestFileList(); @@ -62,7 +62,7 @@ protected: bool PrepareData(); void FreeData(); - Log::Messages* LockMessages(); + MessageList* LockMessages(); void UnlockMessages(); DownloadQueue* LockQueue(); void UnlockQueue(); diff --git a/daemon/frontend/LoggableFrontend.cpp b/daemon/frontend/LoggableFrontend.cpp index 8465291f..352da684 100644 --- a/daemon/frontend/LoggableFrontend.cpp +++ b/daemon/frontend/LoggableFrontend.cpp @@ -2,7 +2,7 @@ * This file if part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -79,7 +79,7 @@ void LoggableFrontend::Update() BeforePrint(); - Log::Messages* pMessages = LockMessages(); + MessageList* pMessages = LockMessages(); if (!pMessages->empty()) { Message* pFirstMessage = pMessages->front(); diff --git a/daemon/frontend/NCursesFrontend.cpp b/daemon/frontend/NCursesFrontend.cpp index fac09c94..2f1e47b7 100644 --- a/daemon/frontend/NCursesFrontend.cpp +++ b/daemon/frontend/NCursesFrontend.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -504,7 +504,7 @@ void NCursesFrontend::PrintMessages() int iLine = iLineNr + m_iMessagesWinClientHeight - 1; int iLinesToPrint = m_iMessagesWinClientHeight; - Log::Messages* pMessages = LockMessages(); + MessageList* pMessages = LockMessages(); // print messages from bottom for (int i = (int)pMessages->size() - 1; i >= 0 && iLinesToPrint > 0; i--) diff --git a/daemon/main/Maintenance.cpp b/daemon/main/Maintenance.cpp index 6302a185..98fe5c27 100644 --- a/daemon/main/Maintenance.cpp +++ b/daemon/main/Maintenance.cpp @@ -69,7 +69,7 @@ Maintenance::~Maintenance() } } - ClearMessages(); + m_Messages.Clear(); free(m_szUpdateScript); } @@ -81,16 +81,7 @@ void Maintenance::ResetUpdateController() m_mutexController.Unlock(); } -void Maintenance::ClearMessages() -{ - for (Log::Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++) - { - delete *it; - } - m_Messages.clear(); -} - -Log::Messages* Maintenance::LockMessages() +MessageList* Maintenance::LockMessages() { m_mutexLog.Lock(); return &m_Messages; @@ -101,7 +92,7 @@ void Maintenance::UnlockMessages() m_mutexLog.Unlock(); } -void Maintenance::AppendMessage(Message::EKind eKind, time_t tTime, const char * szText) +void Maintenance::AddMessage(Message::EKind eKind, time_t tTime, const char * szText) { if (tTime == 0) { @@ -137,7 +128,7 @@ bool Maintenance::StartUpdate(EBranch eBranch) return false; } - ClearMessages(); + m_Messages.Clear(); m_UpdateScriptController = new UpdateScriptController(); m_UpdateScriptController->SetScript(m_szUpdateScript); @@ -269,7 +260,7 @@ void UpdateScriptController::AddMessage(Message::EKind eKind, const char* szText { szText = szText + m_iPrefixLen; - g_pMaintenance->AppendMessage(eKind, time(NULL), szText); + g_pMaintenance->AddMessage(eKind, time(NULL), szText); ScriptController::AddMessage(eKind, szText); } diff --git a/daemon/main/Maintenance.h b/daemon/main/Maintenance.h index 58c1e9a7..7c7120ab 100644 --- a/daemon/main/Maintenance.h +++ b/daemon/main/Maintenance.h @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2013-2014 Andrey Prygunkov + * Copyright (C) 2013-2015 Andrey Prygunkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ class UpdateScriptController; class Maintenance { private: - Log::Messages m_Messages; + MessageList m_Messages; Mutex m_mutexLog; Mutex m_mutexController; int m_iIDMessageGen; @@ -54,9 +54,8 @@ public: Maintenance(); ~Maintenance(); - void ClearMessages(); - void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText); - Log::Messages* LockMessages(); + void AddMessage(Message::EKind eKind, time_t tTime, const char* szText); + MessageList* LockMessages(); void UnlockMessages(); bool StartUpdate(EBranch eBranch); void ResetUpdateController(); diff --git a/daemon/main/Options.cpp b/daemon/main/Options.cpp index 2bacca25..b4746e68 100644 --- a/daemon/main/Options.cpp +++ b/daemon/main/Options.cpp @@ -140,6 +140,7 @@ static const char* OPTION_URLTIMEOUT = "UrlTimeout"; static const char* OPTION_SAVEQUEUE = "SaveQueue"; static const char* OPTION_RELOADQUEUE = "ReloadQueue"; static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog"; +static const char* OPTION_NZBLOG = "NzbLog"; static const char* OPTION_DECODE = "Decode"; static const char* OPTION_RETRIES = "Retries"; static const char* OPTION_RETRYINTERVAL = "RetryInterval"; @@ -509,6 +510,7 @@ Options::Options(int argc, char* argv[]) m_bPauseScan = false; m_bTempPauseDownload = false; m_bCreateBrokenLog = false; + m_bNzbLog = false; m_iDownloadRate = 0; m_iEditQueueAction = 0; m_pEditQueueIDList = NULL; @@ -835,6 +837,7 @@ void Options::InitDefault() SetOption(OPTION_SAVEQUEUE, "yes"); SetOption(OPTION_RELOADQUEUE, "yes"); SetOption(OPTION_CREATEBROKENLOG, "yes"); + SetOption(OPTION_NZBLOG, "yes"); SetOption(OPTION_DECODE, "yes"); SetOption(OPTION_RETRIES, "3"); SetOption(OPTION_RETRYINTERVAL, "10"); @@ -1117,6 +1120,7 @@ void Options::InitOptions() CheckDir(&m_szNzbDir, OPTION_NZBDIR, szMainDir, m_iNzbDirInterval == 0, true); m_bCreateBrokenLog = (bool)ParseEnumValue(OPTION_CREATEBROKENLOG, BoolCount, BoolNames, BoolValues); + m_bNzbLog = (bool)ParseEnumValue(OPTION_NZBLOG, BoolCount, BoolNames, BoolValues); m_bAppendCategoryDir = (bool)ParseEnumValue(OPTION_APPENDCATEGORYDIR, BoolCount, BoolNames, BoolValues); m_bContinuePartial = (bool)ParseEnumValue(OPTION_CONTINUEPARTIAL, BoolCount, BoolNames, BoolValues); m_bSaveQueue = (bool)ParseEnumValue(OPTION_SAVEQUEUE, BoolCount, BoolNames, BoolValues); diff --git a/daemon/main/Options.h b/daemon/main/Options.h index e31534de..24dbeabc 100644 --- a/daemon/main/Options.h +++ b/daemon/main/Options.h @@ -265,6 +265,7 @@ private: EMessageTarget m_eDetailTarget; bool m_bDecode; bool m_bCreateBrokenLog; + bool m_bNzbLog; int m_iArticleTimeout; int m_iUrlTimeout; int m_iTerminateTimeout; @@ -444,6 +445,7 @@ public: const char* GetConfigTemplate() { return m_szConfigTemplate; } const char* GetScriptDir() { return m_szScriptDir; } bool GetCreateBrokenLog() const { return m_bCreateBrokenLog; } + bool GetNzbLog() const { return m_bNzbLog; } EMessageTarget GetInfoTarget() const { return m_eInfoTarget; } EMessageTarget GetWarningTarget() const { return m_eWarningTarget; } EMessageTarget GetErrorTarget() const { return m_eErrorTarget; } diff --git a/daemon/nntp/ArticleWriter.cpp b/daemon/nntp/ArticleWriter.cpp index 1f9681b2..a215f4e9 100644 --- a/daemon/nntp/ArticleWriter.cpp +++ b/daemon/nntp/ArticleWriter.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2014 Andrey Prygunkov + * Copyright (C) 2014-2015 Andrey Prygunkov * * 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 @@ -190,7 +190,9 @@ bool ArticleWriter::Start(Decoder::EFormat eFormat, const char* szFilename, long m_pOutFile = fopen(szFilename, bDirectWrite ? FOPEN_RBP : FOPEN_WB); if (!m_pOutFile) { - error("Could not %s file %s: %s", bDirectWrite ? "open" : "create", szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not %s file %s: %s", bDirectWrite ? "open" : "create", szFilename, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); return false; } SetWriteBuffer(m_pOutFile, m_pArticleInfo->GetSize()); @@ -250,7 +252,9 @@ void ArticleWriter::Finish(bool bSuccess) { if (!Util::MoveFile(m_szTempFilename, m_szResultFilename)) { - error("Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } @@ -279,7 +283,9 @@ void ArticleWriter::Finish(bool bSuccess) // rawmode if (!Util::MoveFile(m_szTempFilename, m_szResultFilename)) { - error("Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } } @@ -307,13 +313,15 @@ bool ArticleWriter::CreateOutputFile(long long iSize) if (!Util::ForceDirectories(szDestDir, szErrBuf, sizeof(szErrBuf))) { - error("Could not create directory %s: %s", szDestDir, szErrBuf); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create directory %s: %s", szDestDir, szErrBuf); return false; } if (!Util::CreateSparseFile(m_szOutputFilename, iSize)) { - error("Could not create file %s", m_szOutputFilename); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create file %s", m_szOutputFilename); return false; } @@ -399,7 +407,8 @@ void ArticleWriter::CompleteFileParts() // Ensure the DstDir is created if (!Util::ForceDirectories(szNZBDestDir, szErrBuf, sizeof(szErrBuf))) { - error("Could not create directory %s: %s", szNZBDestDir, szErrBuf); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create directory %s: %s", szNZBDestDir, szErrBuf); return; } @@ -417,7 +426,8 @@ void ArticleWriter::CompleteFileParts() outfile = fopen(tmpdestfile, FOPEN_WBP); if (!outfile) { - error("Could not create file %s: %s", tmpdestfile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create file %s: %s", tmpdestfile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); return; } } @@ -426,7 +436,8 @@ void ArticleWriter::CompleteFileParts() outfile = fopen(m_szOutputFilename, FOPEN_RBP); if (!outfile) { - error("Could not open file %s: %s", m_szOutputFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not open file %s: %s", m_szOutputFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); return; } strncpy(tmpdestfile, m_szOutputFilename, 1024); @@ -437,7 +448,8 @@ void ArticleWriter::CompleteFileParts() remove(tmpdestfile); if (!Util::CreateDirectory(ofn)) { - error("Could not create directory %s: %s", ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create directory %s: %s", ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); return; } } @@ -504,7 +516,8 @@ void ArticleWriter::CompleteFileParts() { m_pFileInfo->SetFailedArticles(m_pFileInfo->GetFailedArticles() + 1); m_pFileInfo->SetSuccessArticles(m_pFileInfo->GetSuccessArticles() - 1); - error("Could not find file %s for %s%c%s [%i/%i]", + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not find file %s for %s%c%s [%i/%i]", pa->GetResultFilename(), szNZBName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename(), pa->GetPartNumber(), (int)m_pFileInfo->GetArticles()->size()); } @@ -516,7 +529,9 @@ void ArticleWriter::CompleteFileParts() dstFileName[1024-1] = '\0'; if (!Util::MoveFile(pa->GetResultFilename(), dstFileName)) { - error("Could not move file %s to %s: %s", pa->GetResultFilename(), dstFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not move file %s to %s: %s", pa->GetResultFilename(), dstFileName, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } @@ -540,7 +555,9 @@ void ArticleWriter::CompleteFileParts() fclose(outfile); if (!bDirectWrite && !Util::MoveFile(tmpdestfile, ofn)) { - error("Could not move file %s to %s: %s", tmpdestfile, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not move file %s to %s: %s", tmpdestfile, ofn, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } @@ -548,7 +565,9 @@ void ArticleWriter::CompleteFileParts() { if (!Util::MoveFile(m_szOutputFilename, ofn)) { - error("Could not move file %s to %s: %s", m_szOutputFilename, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not move file %s to %s: %s", m_szOutputFilename, ofn, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } // if destination directory was changed delete the old directory (if empty) @@ -581,11 +600,13 @@ void ArticleWriter::CompleteFileParts() if (m_pFileInfo->GetMissedArticles() == 0 && m_pFileInfo->GetFailedArticles() == 0) { - info("Successfully downloaded %s", szInfoFilename); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, "Successfully downloaded %s", szInfoFilename); } else { - warn("%i of %i article downloads failed for \"%s\"", m_pFileInfo->GetMissedArticles() + m_pFileInfo->GetFailedArticles(), + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkWarning, + "%i of %i article downloads failed for \"%s\"", + m_pFileInfo->GetMissedArticles() + m_pFileInfo->GetFailedArticles(), m_pFileInfo->GetTotalArticles(), szInfoFilename); if (g_pOptions->GetCreateBrokenLog()) @@ -668,7 +689,9 @@ void ArticleWriter::FlushCache() outfile = fopen(m_pFileInfo->GetOutputFilename(), FOPEN_RBP); if (!outfile) { - error("Could not open file %s: %s", m_pFileInfo->GetOutputFilename(), Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not open file %s: %s", m_pFileInfo->GetOutputFilename(), + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); break; } bNeedBufFile = true; @@ -682,7 +705,9 @@ void ArticleWriter::FlushCache() outfile = fopen(szDestFile, FOPEN_WB); if (!outfile) { - error("Could not create file %s: %s", "create", szDestFile, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not create file %s: %s", "create", szDestFile, + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); break; } bNeedBufFile = true; @@ -713,7 +738,9 @@ void ArticleWriter::FlushCache() if (!Util::MoveFile(szDestFile, pa->GetResultFilename())) { - error("Could not rename file %s to %s: %s", szDestFile, pa->GetResultFilename(), Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + m_pFileInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Could not rename file %s to %s: %s", szDestFile, pa->GetResultFilename(), + Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } } @@ -743,7 +770,7 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD char szErrBuf[1024]; if (!Util::ForceDirectories(pNZBInfo->GetDestDir(), szErrBuf, sizeof(szErrBuf))) { - error("Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf); + pNZBInfo->PrintMessage(Message::mkError, "Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf); return false; } @@ -770,7 +797,8 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD if (!Util::MoveFile(szOldFileName, szNewFileName)) { char szErrBuf[256]; - error("Could not move file %s to %s: %s", szOldFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + pNZBInfo->PrintMessage(Message::mkError, "Could not move file %s to %s: %s", + szOldFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } } @@ -813,13 +841,13 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD } else { - error("Could not open file %s", szOldBrokenLogName); + pNZBInfo->PrintMessage(Message::mkError, "Could not open file %s", szOldBrokenLogName); } fclose(outfile); } else { - error("Could not open file %s", szBrokenLogName); + pNZBInfo->PrintMessage(Message::mkError, "Could not open file %s", szBrokenLogName); } } else @@ -828,7 +856,8 @@ bool ArticleWriter::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestD if (!Util::MoveFile(szOldBrokenLogName, szBrokenLogName)) { char szErrBuf[256]; - error("Could not move file %s to %s: %s", szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + pNZBInfo->PrintMessage(Message::mkError, "Could not move file %s to %s: %s", + szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } } } diff --git a/daemon/postprocess/ParChecker.cpp b/daemon/postprocess/ParChecker.cpp index f7850646..4aa61e63 100644 --- a/daemon/postprocess/ParChecker.cpp +++ b/daemon/postprocess/ParChecker.cpp @@ -961,7 +961,7 @@ bool ParChecker::AddSplittedFragments() { m_iExtraFiles += extrafiles.size(); m_bVerifyingExtraFiles = true; - info("Found %i splitted fragments for %s", (int)extrafiles.size(), m_szInfoName); + PrintMessage(Message::mkInfo, "Found %i splitted fragments for %s", (int)extrafiles.size(), m_szInfoName); bFragmentsAdded = ((Repairer*)m_pRepairer)->VerifyExtraFiles(extrafiles); ((Repairer*)m_pRepairer)->UpdateVerificationResults(); m_bVerifyingExtraFiles = false; @@ -1031,7 +1031,7 @@ bool ParChecker::AddMissingFiles() bool bAdded = iWasMissing > (int)((Repairer*)m_pRepairer)->missingfilecount; if (bAdded) { - info("Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str())); + PrintMessage(Message::mkInfo, "Found missing file %s", Util::BaseFileName(pExtraFile->FileName().c_str())); RegisterParredFile(Util::BaseFileName(pExtraFile->FileName().c_str())); } @@ -1467,7 +1467,8 @@ bool ParChecker::VerifyPartialDataFile(void* pDiskfile, void* pSourcefile, Segme FILE* infile = fopen(szFilename, FOPEN_RB); if (!infile) { - error("Could not open file %s: %s", szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + PrintMessage(Message::mkError, "Could not open file %s: %s", + szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); } // For each sequential range of presumably valid blocks: diff --git a/daemon/postprocess/ParCoordinator.cpp b/daemon/postprocess/ParCoordinator.cpp index 7d31ec3f..a6f67dbe 100644 --- a/daemon/postprocess/ParCoordinator.cpp +++ b/daemon/postprocess/ParCoordinator.cpp @@ -72,7 +72,7 @@ void ParCoordinator::PostParChecker::PrintMessage(Message::EKind eKind, const ch va_end(args); szText[1024-1] = '\0'; - m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText); + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText); } void ParCoordinator::PostParChecker::RegisterParredFile(const char* szFilename) @@ -160,7 +160,7 @@ void ParCoordinator::PostParRenamer::PrintMessage(Message::EKind eKind, const ch va_end(args); szText[1024-1] = '\0'; - m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText); + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText); } void ParCoordinator::PostParRenamer::RegisterParredFile(const char* szFilename) @@ -579,7 +579,7 @@ void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL)) { // should not happen - error("Internal error: could not parse filename %s", szBaseParFilename); + pNZBInfo->PrintMessage(Message::mkError, "Internal error: could not parse filename %s", szBaseParFilename); return; } int maxlen = iMainBaseLen < 1024 ? iMainBaseLen : 1024 - 1; @@ -759,7 +759,7 @@ void ParCoordinator::ParRenameCompleted() if (m_ParRenamer.HasMissedFiles() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped) { - PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName()); + m_ParRenamer.PrintMessage(Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName()); pPostInfo->SetRequestParCheck(true); } @@ -791,39 +791,4 @@ void ParCoordinator::UpdateParRenameProgress() CheckPauseState(pPostInfo); } -void ParCoordinator::PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...) -{ - char szText[1024]; - va_list args; - va_start(args, szFormat); - vsnprintf(szText, 1024, szFormat, args); - va_end(args); - szText[1024-1] = '\0'; - - pPostInfo->AppendMessage(eKind, szText); - - switch (eKind) - { - case Message::mkDetail: - detail("%s", szText); - break; - - case Message::mkInfo: - info("%s", szText); - break; - - case Message::mkWarning: - warn("%s", szText); - break; - - case Message::mkError: - error("%s", szText); - break; - - case Message::mkDebug: - debug("%s", szText); - break; - } -} - #endif diff --git a/daemon/postprocess/ParCoordinator.h b/daemon/postprocess/ParCoordinator.h index c29961b5..64854bf7 100644 --- a/daemon/postprocess/ParCoordinator.h +++ b/daemon/postprocess/ParCoordinator.h @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -114,7 +114,6 @@ protected: void ParRenameCompleted(); void CheckPauseState(PostInfo* pPostInfo); bool RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound); - void PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...); #endif public: diff --git a/daemon/postprocess/ParRenamer.cpp b/daemon/postprocess/ParRenamer.cpp index 7b5e31a0..eb41df12 100644 --- a/daemon/postprocess/ParRenamer.cpp +++ b/daemon/postprocess/ParRenamer.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2013-2014 Andrey Prygunkov + * Copyright (C) 2013-2015 Andrey Prygunkov * * 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 @@ -262,7 +262,7 @@ void ParRenamer::LoadParFile(const char* szParFilename) Par2RepairerSourceFile* sourceFile = (*it).second; if (!sourceFile || !sourceFile->GetDescriptionPacket()) { - warn("Damaged par2-file detected: %s", szParFilename); + PrintMessage(Message::mkWarning, "Damaged par2-file detected: %s", szParFilename); continue; } m_FileHashList.push_back(new FileHash(sourceFile->GetDescriptionPacket()->FileName().c_str(), @@ -315,11 +315,11 @@ void ParRenamer::CheckMissing() if (Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetParIgnoreExt(), ",;") || Util::MatchFileExt(pFileHash->GetFilename(), g_pOptions->GetExtCleanupDisk(), ",;")) { - info("File %s is missing, ignoring", pFileHash->GetFilename()); + PrintMessage(Message::mkInfo, "File %s is missing, ignoring", pFileHash->GetFilename()); } else { - info("File %s is missing", pFileHash->GetFilename()); + PrintMessage(Message::mkInfo, "File %s is missing", pFileHash->GetFilename()); m_bHasMissedFiles = true; } } diff --git a/daemon/postprocess/PostScript.cpp b/daemon/postprocess/PostScript.cpp index e39d6959..6bfd70fe 100644 --- a/daemon/postprocess/PostScript.cpp +++ b/daemon/postprocess/PostScript.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -104,6 +104,14 @@ void PostScriptController::ExecuteScript(Options::Script* pScript) PrintMessage(Message::mkInfo, "Executing post-process-script %s for %s", pScript->GetName(), m_pPostInfo->GetNZBInfo()->GetName()); + char szProgressLabel[1024]; + snprintf(szProgressLabel, 1024, "Executing post-process-script %s", pScript->GetName()); + szProgressLabel[1024-1] = '\0'; + + DownloadQueue::Lock(); + m_pPostInfo->SetProgressLabel(szProgressLabel); + DownloadQueue::Unlock(); + SetScript(pScript->GetLocation()); SetArgs(NULL, false); @@ -277,7 +285,8 @@ void PostScriptController::AddMessage(Message::EKind eKind, const char* szText) } else { - error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName()); + m_pPostInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Invalid command \"%s\" received from %s", szMsgText, GetInfoName()); } free(szParam); } @@ -290,17 +299,16 @@ void PostScriptController::AddMessage(Message::EKind eKind, const char* szText) } else { - error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName()); + m_pPostInfo->GetNZBInfo()->PrintMessage(Message::mkError, + "Invalid command \"%s\" received from %s", szMsgText, GetInfoName()); } } - else if (!strncmp(szMsgText, "[HISTORY] ", 10)) - { - m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szMsgText); - } else { - ScriptController::AddMessage(eKind, szText); - m_pPostInfo->AppendMessage(eKind, szText); + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText); + DownloadQueue::Lock(); + m_pPostInfo->SetProgressLabel(szText); + DownloadQueue::Unlock(); } if (g_pOptions->GetPausePostProcess() && !m_pPostInfo->GetNZBInfo()->GetForcePriority()) diff --git a/daemon/postprocess/PrePostProcessor.cpp b/daemon/postprocess/PrePostProcessor.cpp index d8f625bb..e42dde2d 100644 --- a/daemon/postprocess/PrePostProcessor.cpp +++ b/daemon/postprocess/PrePostProcessor.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -198,7 +198,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect) { // the deleting of nzbs is usually handled via eaFileDeleted-event, but when deleting nzb without // any files left the eaFileDeleted-event is not fired and we need to process eaNzbDeleted-event instead - info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName()); + pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo, + "Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName()); NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo); } else if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted || @@ -222,7 +223,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect) IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))) && pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth) { - info("Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName()); + pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo, + "Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName()); g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeNzbDownloaded); NZBDownloaded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo); } @@ -232,7 +234,8 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect) !pQueueAspect->pNZBInfo->GetParCleanup() && IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true)) { - info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName()); + pQueueAspect->pNZBInfo->PrintMessage(Message::mkInfo, + "Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName()); NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo); } } @@ -269,7 +272,7 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ { if (!pNZBInfo->GetPostInfo() && g_pOptions->GetDecode()) { - info("Queueing %s for post-processing", pNZBInfo->GetName()); + pNZBInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", pNZBInfo->GetName()); pNZBInfo->EnterPostProcess(); m_iJobCount++; @@ -449,13 +452,15 @@ void PrePostProcessor::CheckPostQueue() if (!pPostInfo->GetNZBInfo()->GetFileList()->empty()) { - info("Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName()); + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName()); pDownloadQueue->EditEntry(pPostInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupResume, 0, NULL); pPostInfo->SetStage(PostInfo::ptFinished); } else { - info("There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName()); + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName()); pPostInfo->SetStage(PostInfo::ptQueued); } } @@ -564,7 +569,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn } else { - info("Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName()); + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName()); pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSkipped); pPostInfo->SetWorking(false); pPostInfo->SetStage(PostInfo::ptQueued); @@ -576,7 +582,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000 && m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL)) { - warn("Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(), + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkWarning, + "Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) / 10.0); pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure); return; @@ -585,7 +592,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn pPostInfo->GetNZBInfo()->GetFailedSize() - pPostInfo->GetNZBInfo()->GetParFailedSize() > 0 && m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL)) { - info("Collection %s with health %.1f%% needs par-check", + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "Collection %s with health %.1f%% needs par-check", pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->CalcHealth() / 10.0); pPostInfo->SetRequestParCheck(true); return; @@ -626,7 +634,8 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn if (bUnpack && bParFailed) { - warn("Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(), + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkWarning, + "Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure"); pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped); bUnpack = false; @@ -703,7 +712,7 @@ void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPo pNZBInfo->CalcCriticalHealth(false) < 1000); if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue && !pNZBInfo->GetFileList()->empty()) { - info("Cleaning up download queue for %s", pNZBInfo->GetName()); + pNZBInfo->PrintMessage(Message::mkInfo, "Cleaning up download queue for %s", pNZBInfo->GetName()); pNZBInfo->SetParCleanup(true); pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL); } @@ -809,7 +818,8 @@ bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pI { if (pPostInfo->GetWorking()) { - info("Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName()); + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName()); pPostInfo->SetDeleted(true); #ifndef DISABLE_PARCHECK if (PostInfo::ptLoadingPars <= pPostInfo->GetStage() && pPostInfo->GetStage() <= PostInfo::ptRenaming) @@ -834,7 +844,8 @@ bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pI } else { - info("Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName()); + pPostInfo->GetNZBInfo()->PrintMessage(Message::mkInfo, + "Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName()); JobCompleted(pDownloadQueue, pPostInfo); bOK = true; } diff --git a/daemon/postprocess/Unpack.cpp b/daemon/postprocess/Unpack.cpp index bdc29853..6c024276 100644 --- a/daemon/postprocess/Unpack.cpp +++ b/daemon/postprocess/Unpack.cpp @@ -562,7 +562,7 @@ bool UnpackController::JoinFile(const char* szFragBaseName) FILE* pOutFile = fopen(szDestFilename, FOPEN_WBP); if (!pOutFile) { - error("Could not create file %s: %s", szDestFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); + PrintMessage(Message::mkError, "Could not create file %s: %s", szDestFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf))); return false; } if (g_pOptions->GetWriteBuffer() > 0) @@ -614,7 +614,7 @@ bool UnpackController::JoinFile(const char* szFragBaseName) } else { - error("Could not open file %s", szFragFilename); + PrintMessage(Message::mkError, "Could not open file %s", szFragFilename); bOK = false; break; } @@ -704,7 +704,7 @@ void UnpackController::CreateUnpackDir() char szErrBuf[1024]; if (!Util::ForceDirectories(m_szUnpackDir, szErrBuf, sizeof(szErrBuf))) { - error("Could not create directory %s: %s", m_szUnpackDir, szErrBuf); + PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szUnpackDir, szErrBuf); } } @@ -961,8 +961,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText) szMsgText[1024-1] = '\0'; } - ScriptController::AddMessage(eKind, szMsgText); - m_pPostInfo->AppendMessage(eKind, szMsgText); + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szMsgText); if (m_eUnpacker == upUnrar && !strncmp(szMsgText, "Unrar: UNRAR ", 6) && strstr(szMsgText, " Copyright ") && strstr(szMsgText, " Alexander Roshal")) @@ -1012,8 +1011,7 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText) char szMsgText[1024]; snprintf(szMsgText, 1024, "Cancelling %s due to errors", m_szInfoName); szMsgText[1024-1] = '\0'; - ScriptController::AddMessage(Message::mkWarning, szMsgText); - m_pPostInfo->AppendMessage(Message::mkWarning, szMsgText); + m_pPostInfo->GetNZBInfo()->AddMessage(Message::mkWarning, szMsgText); m_bAutoTerminated = true; Stop(); } @@ -1073,7 +1071,7 @@ void MoveController::Run() DownloadQueue::Unlock(); - info("Moving completed files for %s", szNZBName); + PrintMessage(Message::mkInfo, "Moving completed files for %s", szNZBName); bool bOK = MoveFiles(); @@ -1081,7 +1079,7 @@ void MoveController::Run() if (bOK) { - info("%s successful", szInfoName); + PrintMessage(Message::mkInfo, "%s successful", szInfoName); // save new dest dir DownloadQueue::Lock(); m_pPostInfo->GetNZBInfo()->SetDestDir(m_szDestDir); @@ -1090,7 +1088,7 @@ void MoveController::Run() } else { - error("%s failed", szInfoName); + PrintMessage(Message::mkError, "%s failed", szInfoName); m_pPostInfo->GetNZBInfo()->SetMoveStatus(NZBInfo::msFailure); } @@ -1103,7 +1101,7 @@ bool MoveController::MoveFiles() char szErrBuf[1024]; if (!Util::ForceDirectories(m_szDestDir, szErrBuf, sizeof(szErrBuf))) { - error("Could not create directory %s: %s", m_szDestDir, szErrBuf); + PrintMessage(Message::mkError, "Could not create directory %s: %s", m_szDestDir, szErrBuf); return false; } @@ -1138,6 +1136,10 @@ bool MoveController::MoveFiles() return bOK; } +void MoveController::AddMessage(Message::EKind eKind, const char* szText) +{ + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText); +} void CleanupController::StartJob(PostInfo* pPostInfo) { @@ -1181,7 +1183,7 @@ void CleanupController::Run() DownloadQueue::Unlock(); - info("Cleaning up %s", szNZBName); + PrintMessage(Message::mkInfo, "Cleaning up %s", szNZBName); bool bDeleted = false; bool bOK = Cleanup(m_szDestDir, &bDeleted); @@ -1197,17 +1199,17 @@ void CleanupController::Run() if (bOK && bDeleted) { - info("%s successful", szInfoName); + PrintMessage(Message::mkInfo, "%s successful", szInfoName); m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess); } else if (bOK) { - info("Nothing to cleanup for %s", szNZBName); + PrintMessage(Message::mkInfo, "Nothing to cleanup for %s", szNZBName); m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess); } else { - error("%s failed", szInfoName); + PrintMessage(Message::mkError, "%s failed", szInfoName); m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csFailure); } @@ -1246,3 +1248,8 @@ bool CleanupController::Cleanup(const char* szDestDir, bool *bDeleted) return bOK; } + +void CleanupController::AddMessage(Message::EKind eKind, const char* szText) +{ + m_pPostInfo->GetNZBInfo()->AddMessage(eKind, szText); +} diff --git a/daemon/postprocess/Unpack.h b/daemon/postprocess/Unpack.h index 9f22b1ac..1c26687f 100644 --- a/daemon/postprocess/Unpack.h +++ b/daemon/postprocess/Unpack.h @@ -124,6 +124,9 @@ private: bool MoveFiles(); +protected: + virtual void AddMessage(Message::EKind eKind, const char* szText); + public: virtual void Run(); static void StartJob(PostInfo* pPostInfo); @@ -138,6 +141,9 @@ private: bool Cleanup(const char* szDestDir, bool *bDeleted); +protected: + virtual void AddMessage(Message::EKind eKind, const char* szText); + public: virtual void Run(); static void StartJob(PostInfo* pPostInfo); diff --git a/daemon/queue/DiskState.cpp b/daemon/queue/DiskState.cpp index 955546b7..c2378157 100644 --- a/daemon/queue/DiskState.cpp +++ b/daemon/queue/DiskState.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -29,6 +29,9 @@ #ifdef WIN32 #include "win32.h" +#else +#include +#include #endif #include @@ -136,7 +139,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue) return false; } - fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 51); + fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 52); // save nzb-infos SaveNZBQueue(pDownloadQueue, outfile); @@ -179,7 +182,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServe char FileSignatur[128]; fgets(FileSignatur, sizeof(FileSignatur), infile); iFormatVersion = ParseFormatVersion(FileSignatur); - if (iFormatVersion < 3 || iFormatVersion > 51) + if (iFormatVersion < 3 || iFormatVersion > 52) { error("Could not load diskstate due to file version mismatch"); fclose(infile); @@ -361,7 +364,7 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile) (int)pNZBInfo->GetMarkStatus(), (int)pNZBInfo->GetUrlStatus()); fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetUnpackCleanedUpDisk(), (int)pNZBInfo->GetHealthPaused(), (int)pNZBInfo->GetAddUrlPaused()); - fprintf(outfile, "%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount()); + fprintf(outfile, "%i,%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(), pNZBInfo->GetMessageCount()); fprintf(outfile, "%i,%i\n", (int)pNZBInfo->GetMinTime(), (int)pNZBInfo->GetMaxTime()); fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetParFull(), pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceParFull() : 0, @@ -389,9 +392,6 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile) fprintf(outfile, "%lu,%lu,%i,%i,%i,%i,%i\n", High1, Low1, pNZBInfo->GetDownloadSec(), pNZBInfo->GetPostTotalSec(), pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec()); - char DestDirSlash[1024]; - snprintf(DestDirSlash, 1023, "%s%c", pNZBInfo->GetDestDir(), PATH_SEPARATOR); - fprintf(outfile, "%i\n", (int)pNZBInfo->GetCompletedFiles()->size()); for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++) { @@ -416,15 +416,6 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile) SaveServerStats(pNZBInfo->GetServerStats(), outfile); - NZBInfo::Messages* pMessages = pNZBInfo->LockMessages(); - fprintf(outfile, "%i\n", (int)pMessages->size()); - for (NZBInfo::Messages::iterator it = pMessages->begin(); it != pMessages->end(); it++) - { - Message* pMessage = *it; - fprintf(outfile, "%i,%i,%s\n", pMessage->GetKind(), (int)pMessage->GetTime(), pMessage->GetText()); - } - pNZBInfo->UnlockMessages(); - // save file-infos int iSize = 0; for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++) @@ -638,10 +629,19 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile, if (iFormatVersion >= 28) { - int iFileCount, iParkedFileCount; - if (fscanf(infile, "%i,%i\n", &iFileCount, &iParkedFileCount) != 2) goto error; + int iFileCount, iParkedFileCount, iMessageCount = 0; + if (iFormatVersion >= 52) + { + if (fscanf(infile, "%i,%i,%i\n", &iFileCount, &iParkedFileCount, &iMessageCount) != 3) goto error; + } + else + { + if (fscanf(infile, "%i,%i\n", &iFileCount, &iParkedFileCount) != 2) goto error; + } + pNZBInfo->SetFileCount(iFileCount); pNZBInfo->SetParkedFileCount(iParkedFileCount); + pNZBInfo->SetMessageCount(iMessageCount); } else { @@ -852,23 +852,13 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile, pNZBInfo->GetCurrentServerStats()->ListOp(pNZBInfo->GetServerStats(), ServerStatList::soSet); } - if (iFormatVersion >= 11) + if (iFormatVersion >= 11 && iFormatVersion < 52) { int iLogCount; if (fscanf(infile, "%i\n", &iLogCount) != 1) goto error; for (int i = 0; i < iLogCount; i++) { if (!fgets(buf, sizeof(buf), infile)) goto error; - if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n' - - int iKind, iTime; - sscanf(buf, "%i,%i", &iKind, &iTime); - char* szText = strchr(buf + 2, ','); - if (szText) - { - szText++; - } - pNZBInfo->AppendMessage((Message::EKind)iKind, (time_t)iTime, szText); } } @@ -1372,12 +1362,13 @@ void DiskState::DiscardFiles(NZBInfo* pNZBInfo) DiscardFile(pFileInfo, true, true, true); } + char szFilename[1024]; + for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++) { CompletedFile* pCompletedFile = *it; if (pCompletedFile->GetStatus() != CompletedFile::cfSuccess && pCompletedFile->GetID() > 0) { - char szFilename[1024]; snprintf(szFilename, 1024, "%s%i", g_pOptions->GetQueueDir(), pCompletedFile->GetID()); szFilename[1024-1] = '\0'; remove(szFilename); @@ -1391,6 +1382,10 @@ void DiskState::DiscardFiles(NZBInfo* pNZBInfo) remove(szFilename); } } + + snprintf(szFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), pNZBInfo->GetID()); + szFilename[1024-1] = '\0'; + remove(szFilename); } bool DiskState::LoadPostQueue12(DownloadQueue* pDownloadQueue, NZBList* pNZBList, FILE* infile, int iFormatVersion) @@ -1973,7 +1968,7 @@ bool DiskState::DownloadQueueExists() return Util::FileExists(fileName); } -bool DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState) +void DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState) { char fileName[1024]; @@ -2000,8 +1995,6 @@ bool DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeleteP fileName[1024-1] = '\0'; remove(fileName); } - - return true; } void DiskState::CleanupTempDir(DownloadQueue* pDownloadQueue) @@ -2884,3 +2877,123 @@ void DiskState::DeleteCacheFlag() remove(szFlagFilename); } + +void DiskState::AppendNZBMessage(int iNZBID, Message::EKind eKind, const char* szText) +{ + char szLogFilename[1024]; + snprintf(szLogFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), iNZBID); + szLogFilename[1024-1] = '\0'; + + FILE* outfile = fopen(szLogFilename, FOPEN_ABP); + if (!outfile) + { + error("Error saving log: Could not create file %s", szLogFilename); + return; + } + + const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"}; + + char tmp2[1024]; + strncpy(tmp2, szText, 1024); + tmp2[1024-1] = '\0'; + + // replace bad chars + for (char* p = tmp2; *p; p++) + { + char ch = *p; + if (ch == '\n' || ch == '\r' || ch == '\t') + { + *p = ' '; + } + } + + time_t tm = time(NULL); + time_t rawtime = tm + g_pOptions->GetTimeCorrection(); + + char szTime[50]; +#ifdef HAVE_CTIME_R_3 + ctime_r(&rawtime, szTime, 50); +#else + ctime_r(&rawtime, szTime); +#endif + szTime[50-1] = '\0'; + szTime[strlen(szTime) - 1] = '\0'; // trim LF + + fprintf(outfile, "%s\t%u\t%s\t%s%s", szTime, (int)tm, szMessageType[eKind], tmp2, LINE_ENDING); + + fclose(outfile); +} + +void DiskState::LoadNZBMessages(int iNZBID, MessageList* pMessages) +{ + // Important: + // - Other threads may be writing into the log-file at any time; + // - The log-file may also be deleted from another thread; + + char szLogFilename[1024]; + snprintf(szLogFilename, 1024, "%sn%i.log", g_pOptions->GetQueueDir(), iNZBID); + szLogFilename[1024-1] = '\0'; + + if (!Util::FileExists(szLogFilename)) + { + return; + } + + FILE* infile = fopen(szLogFilename, FOPEN_RB); + if (!infile) + { + error("Error reading log: could not open file %s", szLogFilename); + return; + } + + int iID = 0; + char szLine[1024]; + while (fgets(szLine, sizeof(szLine), infile)) + { + Util::TrimRight(szLine); + + // time (skip formatted time first) + char* p = strchr(szLine, '\t'); + if (!p) goto exit; + int iTime = atoi(p + 1); + + // kind + p = strchr(p + 1, '\t'); + if (!p) goto exit; + char* szKind = p + 1; + + Message::EKind eKind = Message::mkError; + if (!strncmp(szKind, "INFO", 4)) + { + eKind = Message::mkInfo; + } + else if (!strncmp(szKind, "WARNING", 7)) + { + eKind = Message::mkWarning; + } + else if (!strncmp(szKind, "ERROR", 5)) + { + eKind = Message::mkError; + } + else if (!strncmp(szKind, "DETAIL", 6)) + { + eKind = Message::mkDetail; + } + else if (!strncmp(szKind, "DEBUG", 5)) + { + eKind = Message::mkDebug; + } + + // text + p = strchr(p + 1, '\t'); + if (!p) goto exit; + char* szText = p + 1; + + Message* pMessage = new Message(++iID, eKind, (time_t)iTime, szText); + pMessages->push_back(pMessage); + } + +exit: + fclose(infile); + return; +} diff --git a/daemon/queue/DiskState.h b/daemon/queue/DiskState.h index a5b08ad4..93f8b3f6 100644 --- a/daemon/queue/DiskState.h +++ b/daemon/queue/DiskState.h @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "FeedInfo.h" #include "NewsServer.h" #include "StatMeter.h" +#include "Log.h" class DiskState { @@ -83,7 +84,7 @@ public: bool LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bCompleted); bool LoadArticles(FileInfo* pFileInfo); void DiscardDownloadQueue(); - bool DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState); + void DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState); void DiscardFiles(NZBInfo* pNZBInfo); bool SaveFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory); bool LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory); @@ -92,6 +93,8 @@ public: void CleanupTempDir(DownloadQueue* pDownloadQueue); void WriteCacheFlag(); void DeleteCacheFlag(); + void AppendNZBMessage(int iNZBID, Message::EKind eKind, const char* szText); + void LoadNZBMessages(int iNZBID, MessageList* pMessages); }; #endif diff --git a/daemon/queue/DownloadInfo.cpp b/daemon/queue/DownloadInfo.cpp index c657de48..d64760cb 100644 --- a/daemon/queue/DownloadInfo.cpp +++ b/daemon/queue/DownloadInfo.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,11 +43,13 @@ #include "nzbget.h" #include "DownloadInfo.h" #include "ArticleWriter.h" +#include "DiskState.h" #include "Options.h" #include "Util.h" extern Options* g_pOptions; extern ArticleCache* g_pArticleCache; +extern DiskState* g_pDiskState; int FileInfo::m_iIDGen = 0; int FileInfo::m_iIDMax = 0; @@ -342,6 +345,8 @@ NZBInfo::NZBInfo() : m_FileList(true) m_bReprocess = false; m_tQueueScriptTime = 0; m_bParFull = false; + m_iMessageCount = 0; + m_iCachedMessageCount = 0; } NZBInfo::~NZBInfo() @@ -360,12 +365,6 @@ NZBInfo::~NZBInfo() ClearCompletedFiles(); - for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++) - { - delete *it; - } - m_Messages.clear(); - m_FileList.Clear(); } @@ -658,27 +657,81 @@ void NZBInfo::UpdateMinMaxTime() } } -NZBInfo::Messages* NZBInfo::LockMessages() +MessageList* NZBInfo::LockCachedMessages() { m_mutexLog.Lock(); return &m_Messages; } -void NZBInfo::UnlockMessages() +void NZBInfo::UnlockCachedMessages() { m_mutexLog.Unlock(); } -void NZBInfo::AppendMessage(Message::EKind eKind, time_t tTime, const char * szText) +void NZBInfo::AddMessage(Message::EKind eKind, const char * szText) { - if (tTime == 0) + switch (eKind) { - tTime = time(NULL); + case Message::mkDetail: + detail("%s", szText); + break; + + case Message::mkInfo: + info("%s", szText); + break; + + case Message::mkWarning: + warn("%s", szText); + break; + + case Message::mkError: + error("%s", szText); + break; + + case Message::mkDebug: + debug("%s", szText); + break; } m_mutexLog.Lock(); - Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText); + Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText); m_Messages.push_back(pMessage); + + if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode() && g_pOptions->GetNzbLog()) + { + g_pDiskState->AppendNZBMessage(m_iID, eKind, szText); + m_iMessageCount++; + } + + while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize()) + { + Message* pMessage = m_Messages.front(); + delete pMessage; + m_Messages.pop_front(); + } + + m_iCachedMessageCount = m_Messages.size(); + m_mutexLog.Unlock(); +} + +void NZBInfo::PrintMessage(Message::EKind eKind, const char* szFormat, ...) +{ + char tmp2[1024]; + + va_list ap; + va_start(ap, szFormat); + vsnprintf(tmp2, 1024, szFormat, ap); + tmp2[1024-1] = '\0'; + va_end(ap); + + AddMessage(eKind, tmp2); +} + +void NZBInfo::ClearMessages() +{ + m_mutexLog.Lock(); + m_Messages.Clear(); + m_iCachedMessageCount = 0; m_mutexLog.Unlock(); } @@ -735,6 +788,7 @@ void NZBInfo::LeavePostProcess() { delete m_pPostInfo; m_pPostInfo = NULL; + ClearMessages(); } void NZBInfo::SetActiveDownloads(int iActiveDownloads) @@ -1207,7 +1261,6 @@ PostInfo::PostInfo() m_tStageTime = 0; m_eStage = ptQueued; m_pPostThread = NULL; - m_iIDMessageGen = 0; } PostInfo::~ PostInfo() @@ -1216,11 +1269,6 @@ PostInfo::~ PostInfo() free(m_szProgressLabel); - for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++) - { - delete *it; - } - for (ParredFiles::iterator it = m_ParredFiles.begin(); it != m_ParredFiles.end(); it++) { free(*it); @@ -1233,32 +1281,6 @@ void PostInfo::SetProgressLabel(const char* 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) -{ - m_mutexLog.Lock(); - Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText); - 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(); -} - DupInfo::DupInfo() { diff --git a/daemon/queue/DownloadInfo.h b/daemon/queue/DownloadInfo.h index dc1653a3..1ae11e60 100644 --- a/daemon/queue/DownloadInfo.h +++ b/daemon/queue/DownloadInfo.h @@ -418,8 +418,6 @@ public: nkUrl }; - typedef std::deque Messages; - static const int FORCE_PRIORITY = 900; friend class DupInfo; @@ -489,7 +487,7 @@ private: ServerStatList m_ServerStats; ServerStatList m_CurrentServerStats; Mutex m_mutexLog; - Messages m_Messages; + MessageList m_Messages; int m_iIDMessageGen; PostInfo* m_pPostInfo; long long m_lDownloadedSize; @@ -502,10 +500,14 @@ private: bool m_bReprocess; time_t m_tQueueScriptTime; bool m_bParFull; + int m_iMessageCount; + int m_iCachedMessageCount; static int m_iIDGen; static int m_iIDMax; + void ClearMessages(); + public: NZBInfo(); ~NZBInfo(); @@ -666,9 +668,13 @@ public: bool IsDupeSuccess(); const char* MakeTextStatus(bool bIgnoreScriptStatus); - void AppendMessage(Message::EKind eKind, time_t tTime, const char* szText); - Messages* LockMessages(); - void UnlockMessages(); + void AddMessage(Message::EKind eKind, const char* szText); + void PrintMessage(Message::EKind eKind, const char* szFormat, ...); + int GetMessageCount() { return m_iMessageCount; } + void SetMessageCount(int iMessageCount) { m_iMessageCount = iMessageCount; } + int GetCachedMessageCount() { return m_iCachedMessageCount; } + MessageList* LockCachedMessages(); + void UnlockCachedMessages(); }; typedef std::deque NZBQueueBase; @@ -703,7 +709,6 @@ public: ptFinished }; - typedef std::deque Messages; typedef std::vector ParredFiles; private: @@ -725,9 +730,6 @@ private: time_t m_tStageTime; Thread* m_pPostThread; - Mutex m_mutexLog; - Messages m_Messages; - int m_iIDMessageGen; ParredFiles m_ParredFiles; public: @@ -767,9 +769,6 @@ public: void SetLastUnpackStatus(int eUnpackStatus) { m_eLastUnpackStatus = eUnpackStatus; } Thread* GetPostThread() { return m_pPostThread; } void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; } - void AppendMessage(Message::EKind eKind, const char* szText); - Messages* LockMessages(); - void UnlockMessages(); ParredFiles* GetParredFiles() { return &m_ParredFiles; } }; diff --git a/daemon/queue/HistoryCoordinator.cpp b/daemon/queue/HistoryCoordinator.cpp index 674ad13e..c34e62cf 100644 --- a/daemon/queue/HistoryCoordinator.cpp +++ b/daemon/queue/HistoryCoordinator.cpp @@ -228,7 +228,7 @@ void HistoryCoordinator::AddToHistory(DownloadQueue* pDownloadQueue, NZBInfo* pN pNZBInfo->GetFileList()->Clear(); } - info("Collection %s added to history", pNZBInfo->GetName()); + pNZBInfo->PrintMessage(Message::mkInfo, "Collection %s added to history", pNZBInfo->GetName()); } void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex) @@ -449,7 +449,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl) { - NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo(); + pNZBInfo = pHistoryInfo->GetNZBInfo(); pHistoryInfo->DiscardNZBInfo(); pNZBInfo->SetUrlStatus(NZBInfo::lsNone); pNZBInfo->SetDeleteStatus(NZBInfo::dsNone); @@ -458,7 +458,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis pDownloadQueue->GetHistory()->erase(itHistory); // the object "pHistoryInfo" is released few lines later, after the call to "NZBDownloaded" - info("%s returned from history back to download queue", szNiceName); + pNZBInfo->PrintMessage(Message::mkInfo, "%s returned from history back to download queue", szNiceName); if (bReprocess) { diff --git a/daemon/queue/QueueCoordinator.cpp b/daemon/queue/QueueCoordinator.cpp index 8e53cddf..1a6958a7 100644 --- a/daemon/queue/QueueCoordinator.cpp +++ b/daemon/queue/QueueCoordinator.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2005 Bo Cordes Petersen - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -398,7 +398,7 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, NZBInfo* pUrlInfo, b if (eDeleteStatus == NZBInfo::dsNone) { - info("Collection %s added to queue", pNZBInfo->GetName()); + pNZBInfo->PrintMessage(Message::mkInfo, "Collection %s added to queue", pNZBInfo->GetName()); } if (eDeleteStatus != NZBInfo::dsManual) @@ -887,8 +887,10 @@ void QueueCoordinator::CheckHealth(DownloadQueue* pDownloadQueue, FileInfo* pFil } else if (g_pOptions->GetHealthCheck() == Options::hcDelete) { - warn("Cancelling download and deleting %s due to health %.1f%% below critical %.1f%%", pFileInfo->GetNZBInfo()->GetName(), - pFileInfo->GetNZBInfo()->CalcHealth() / 10.0, pFileInfo->GetNZBInfo()->CalcCriticalHealth(true) / 10.0); + pFileInfo->GetNZBInfo()->PrintMessage(Message::mkWarning, + "Cancelling download and deleting %s due to health %.1f%% below critical %.1f%%", + pFileInfo->GetNZBInfo()->GetName(), pFileInfo->GetNZBInfo()->CalcHealth() / 10.0, + pFileInfo->GetNZBInfo()->CalcCriticalHealth(true) / 10.0); pFileInfo->GetNZBInfo()->SetDeleteStatus(NZBInfo::dsHealth); pDownloadQueue->EditEntry(pFileInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupDelete, 0, NULL); } @@ -1141,6 +1143,7 @@ bool QueueCoordinator::MergeQueueEntries(DownloadQueue* pDownloadQueue, NZBInfo* free(szQueuedFilename); pDownloadQueue->GetQueue()->Remove(pSrcNZBInfo); + g_pDiskState->DiscardFiles(pSrcNZBInfo); delete pSrcNZBInfo; return true; @@ -1258,6 +1261,7 @@ bool QueueCoordinator::SplitQueueEntries(DownloadQueue* pDownloadQueue, FileList if (pSrcNZBInfo->GetFileList()->empty()) { pDownloadQueue->GetQueue()->Remove(pSrcNZBInfo); + g_pDiskState->DiscardFiles(pSrcNZBInfo); delete pSrcNZBInfo; } diff --git a/daemon/queue/QueueEditor.cpp b/daemon/queue/QueueEditor.cpp index d9057704..ecff7ca6 100644 --- a/daemon/queue/QueueEditor.cpp +++ b/daemon/queue/QueueEditor.cpp @@ -309,14 +309,9 @@ void QueueEditor::PauseUnpauseEntry(FileInfo* pFileInfo, bool bPause) */ void QueueEditor::DeleteEntry(FileInfo* pFileInfo) { - if (pFileInfo->GetNZBInfo()->GetDeleting()) - { - detail("Deleting file %s from download queue", pFileInfo->GetFilename()); - } - else - { - info("Deleting file %s from download queue", pFileInfo->GetFilename()); - } + pFileInfo->GetNZBInfo()->PrintMessage( + pFileInfo->GetNZBInfo()->GetDeleting() ? Message::mkDetail : Message::mkInfo, + "Deleting file %s from download queue", pFileInfo->GetFilename()); g_pQueueCoordinator->DeleteQueueEntry(m_pDownloadQueue, pFileInfo); } diff --git a/daemon/queue/UrlCoordinator.cpp b/daemon/queue/UrlCoordinator.cpp index 96131f8c..07b052a2 100644 --- a/daemon/queue/UrlCoordinator.cpp +++ b/daemon/queue/UrlCoordinator.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2012-2014 Andrey Prygunkov + * Copyright (C) 2012-2015 Andrey Prygunkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,9 +47,11 @@ #include "Util.h" #include "NZBFile.h" #include "Scanner.h" +#include "DiskState.h" extern Options* g_pOptions; extern Scanner* g_pScanner; +extern DiskState* g_pDiskState; UrlDownloader::UrlDownloader() : WebDownloader() { @@ -453,6 +455,7 @@ void UrlCoordinator::UrlCompleted(UrlDownloader* pUrlDownloader) if (bDeleteObj) { + g_pDiskState->DiscardFiles(pNZBInfo); delete pNZBInfo; } } @@ -490,6 +493,7 @@ bool UrlCoordinator::DeleteQueueEntry(DownloadQueue* pDownloadQueue, NZBInfo* pN } else { + g_pDiskState->DiscardFiles(pNZBInfo); delete pNZBInfo; } diff --git a/daemon/remote/BinRpc.cpp b/daemon/remote/BinRpc.cpp index 01d32de1..1e0920b9 100644 --- a/daemon/remote/BinRpc.cpp +++ b/daemon/remote/BinRpc.cpp @@ -770,7 +770,7 @@ void LogBinCommand::Execute() return; } - Log::Messages* pMessages = g_pLog->LockMessages(); + MessageList* pMessages = g_pLog->LockMessages(); int iNrEntries = ntohl(LogRequest.m_iLines); unsigned int iIDFrom = ntohl(LogRequest.m_iIDFrom); diff --git a/daemon/remote/XmlRpc.cpp b/daemon/remote/XmlRpc.cpp index 62cff7f0..4141c43c 100644 --- a/daemon/remote/XmlRpc.cpp +++ b/daemon/remote/XmlRpc.cpp @@ -50,6 +50,7 @@ #include "Maintenance.h" #include "StatMeter.h" #include "ArticleWriter.h" +#include "DiskState.h" extern Options* g_pOptions; extern Scanner* g_pScanner; @@ -58,6 +59,7 @@ extern ServerPool* g_pServerPool; extern Maintenance* g_pMaintenance; extern StatMeter* g_pStatMeter; extern ArticleCache* g_pArticleCache; +extern DiskState* g_pDiskState; extern void ExitProc(); extern void Reload(); @@ -136,10 +138,12 @@ public: class LogXmlCommand: public XmlCommand { protected: - virtual Log::Messages* LockMessages(); + int m_iIDFrom; + int m_iNrEntries; + virtual MessageList* LockMessages(); virtual void UnlockMessages(); public: - virtual void Execute(); + virtual void Execute(); }; class NzbInfoXmlCommand: public XmlCommand @@ -280,7 +284,7 @@ public: class LogUpdateXmlCommand: public LogXmlCommand { protected: - virtual Log::Messages* LockMessages(); + virtual MessageList* LockMessages(); virtual void UnlockMessages(); }; @@ -296,6 +300,18 @@ public: virtual void Execute(); }; +class LoadLogXmlCommand: public LogXmlCommand +{ +private: + MessageList m_messages; + int m_iNZBID; + NZBInfo* m_pNZBInfo; +protected: + virtual void Execute(); + virtual MessageList* LockMessages(); + virtual void UnlockMessages(); +}; + //***************************************************************** // XmlRpcProcessor @@ -608,6 +624,10 @@ XmlCommand* XmlRpcProcessor::CreateCommand(const char* szMethodName) { command = new ClearLogXmlCommand(); } + else if (!strcasecmp(szMethodName, "loadlog")) + { + command = new LoadLogXmlCommand(); + } else if (!strcasecmp(szMethodName, "scan")) { command = new ScanXmlCommand(); @@ -1347,33 +1367,33 @@ void StatusXmlCommand::Execute() // struct[] log(idfrom, entries) void LogXmlCommand::Execute() { - int iIDFrom = 0; - int iNrEntries = 0; - if (!NextParamAsInt(&iIDFrom) || !NextParamAsInt(&iNrEntries) || (iNrEntries > 0 && iIDFrom > 0)) + m_iIDFrom = 0; + m_iNrEntries = 0; + if (!NextParamAsInt(&m_iIDFrom) || !NextParamAsInt(&m_iNrEntries) || (m_iNrEntries > 0 && m_iIDFrom > 0)) { BuildErrorResponse(2, "Invalid parameter"); return; } - debug("iIDFrom=%i", iIDFrom); - debug("iNrEntries=%i", iNrEntries); + debug("iIDFrom=%i", m_iIDFrom); + debug("iNrEntries=%i", m_iNrEntries); AppendResponse(IsJson() ? "[\n" : "\n"); - Log::Messages* pMessages = LockMessages(); + MessageList* pMessages = LockMessages(); int iStart = pMessages->size(); - if (iNrEntries > 0) + if (m_iNrEntries > 0) { - if (iNrEntries > (int)pMessages->size()) + if (m_iNrEntries > (int)pMessages->size()) { - iNrEntries = pMessages->size(); + m_iNrEntries = pMessages->size(); } - iStart = pMessages->size() - iNrEntries; + iStart = pMessages->size() - m_iNrEntries; } - if (iIDFrom > 0 && !pMessages->empty()) + if (m_iIDFrom > 0 && !pMessages->empty()) { - iNrEntries = pMessages->size(); - iStart = iIDFrom - pMessages->front()->GetID(); + m_iNrEntries = pMessages->size(); + iStart = m_iIDFrom - pMessages->front()->GetID(); if (iStart < 0) { iStart = 0; @@ -1424,7 +1444,7 @@ void LogXmlCommand::Execute() AppendResponse(IsJson() ? "\n]" : "\n"); } -Log::Messages* LogXmlCommand::LockMessages() +MessageList* LogXmlCommand::LockMessages() { return g_pLog->LockMessages(); } @@ -1563,148 +1583,150 @@ void ListFilesXmlCommand::Execute() void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo) { const char* XML_NZB_ITEM_START = - "NZBID%i\n" - "NZBName%s\n" - "NZBNicename%s\n" // deprecated, use "NZBName" instead - "Kind%s\n" - "URL%s\n" - "NZBFilename%s\n" - "DestDir%s\n" - "FinalDir%s\n" - "Category%s\n" - "ParStatus%s\n" - "UnpackStatus%s\n" - "MoveStatus%s\n" - "ScriptStatus%s\n" - "DeleteStatus%s\n" - "MarkStatus%s\n" - "UrlStatus%s\n" - "FileSizeLo%u\n" - "FileSizeHi%u\n" - "FileSizeMB%i\n" - "FileCount%i\n" - "MinPostTime%i\n" - "MaxPostTime%i\n" - "TotalArticles%i\n" - "SuccessArticles%i\n" - "FailedArticles%i\n" - "Health%i\n" - "CriticalHealth%i\n" - "DupeKey%s\n" - "DupeScore%i\n" - "DupeMode%s\n" - "Deleted%s\n" // deprecated, use "DeleteStatus" instead - "DownloadedSizeLo%u\n" - "DownloadedSizeHi%u\n" - "DownloadedSizeMB%i\n" - "DownloadTimeSec%i\n" - "PostTotalTimeSec%i\n" - "ParTimeSec%i\n" - "RepairTimeSec%i\n" - "UnpackTimeSec%i\n" - "Parameters\n"; + "NZBID%i\n" + "NZBName%s\n" + "NZBNicename%s\n" // deprecated, use "NZBName" instead + "Kind%s\n" + "URL%s\n" + "NZBFilename%s\n" + "DestDir%s\n" + "FinalDir%s\n" + "Category%s\n" + "ParStatus%s\n" + "UnpackStatus%s\n" + "MoveStatus%s\n" + "ScriptStatus%s\n" + "DeleteStatus%s\n" + "MarkStatus%s\n" + "UrlStatus%s\n" + "FileSizeLo%u\n" + "FileSizeHi%u\n" + "FileSizeMB%i\n" + "FileCount%i\n" + "MinPostTime%i\n" + "MaxPostTime%i\n" + "TotalArticles%i\n" + "SuccessArticles%i\n" + "FailedArticles%i\n" + "Health%i\n" + "CriticalHealth%i\n" + "DupeKey%s\n" + "DupeScore%i\n" + "DupeMode%s\n" + "Deleted%s\n" // deprecated, use "DeleteStatus" instead + "DownloadedSizeLo%u\n" + "DownloadedSizeHi%u\n" + "DownloadedSizeMB%i\n" + "DownloadTimeSec%i\n" + "PostTotalTimeSec%i\n" + "ParTimeSec%i\n" + "RepairTimeSec%i\n" + "UnpackTimeSec%i\n" + "MessageCount%i\n" + "Parameters\n"; const char* XML_NZB_ITEM_SCRIPT_START = - "\n" - "ScriptStatuses\n"; + "\n" + "ScriptStatuses\n"; const char* XML_NZB_ITEM_STATS_START = - "\n" - "ServerStats\n"; + "\n" + "ServerStats\n"; const char* XML_NZB_ITEM_END = - "\n"; + "\n"; const char* JSON_NZB_ITEM_START = - "\"NZBID\" : %i,\n" - "\"NZBName\" : \"%s\",\n" - "\"NZBNicename\" : \"%s\",\n" // deprecated, use NZBName instead - "\"Kind\" : \"%s\",\n" - "\"URL\" : \"%s\",\n" - "\"NZBFilename\" : \"%s\",\n" - "\"DestDir\" : \"%s\",\n" - "\"FinalDir\" : \"%s\",\n" - "\"Category\" : \"%s\",\n" - "\"ParStatus\" : \"%s\",\n" - "\"UnpackStatus\" : \"%s\",\n" - "\"MoveStatus\" : \"%s\",\n" - "\"ScriptStatus\" : \"%s\",\n" - "\"DeleteStatus\" : \"%s\",\n" - "\"MarkStatus\" : \"%s\",\n" - "\"UrlStatus\" : \"%s\",\n" - "\"FileSizeLo\" : %u,\n" - "\"FileSizeHi\" : %u,\n" - "\"FileSizeMB\" : %i,\n" - "\"FileCount\" : %i,\n" - "\"MinPostTime\" : %i,\n" - "\"MaxPostTime\" : %i,\n" - "\"TotalArticles\" : %i,\n" - "\"SuccessArticles\" : %i,\n" - "\"FailedArticles\" : %i,\n" - "\"Health\" : %i,\n" - "\"CriticalHealth\" : %i,\n" - "\"DupeKey\" : \"%s\",\n" - "\"DupeScore\" : %i,\n" - "\"DupeMode\" : \"%s\",\n" - "\"Deleted\" : %s,\n" // deprecated, use "DeleteStatus" instead - "\"DownloadedSizeLo\" : %u,\n" - "\"DownloadedSizeHi\" : %u,\n" - "\"DownloadedSizeMB\" : %i,\n" - "\"DownloadTimeSec\" : %i,\n" - "\"PostTotalTimeSec\" : %i,\n" - "\"ParTimeSec\" : %i,\n" - "\"RepairTimeSec\" : %i,\n" - "\"UnpackTimeSec\" : %i,\n" - "\"Parameters\" : [\n"; + "\"NZBID\" : %i,\n" + "\"NZBName\" : \"%s\",\n" + "\"NZBNicename\" : \"%s\",\n" // deprecated, use NZBName instead + "\"Kind\" : \"%s\",\n" + "\"URL\" : \"%s\",\n" + "\"NZBFilename\" : \"%s\",\n" + "\"DestDir\" : \"%s\",\n" + "\"FinalDir\" : \"%s\",\n" + "\"Category\" : \"%s\",\n" + "\"ParStatus\" : \"%s\",\n" + "\"UnpackStatus\" : \"%s\",\n" + "\"MoveStatus\" : \"%s\",\n" + "\"ScriptStatus\" : \"%s\",\n" + "\"DeleteStatus\" : \"%s\",\n" + "\"MarkStatus\" : \"%s\",\n" + "\"UrlStatus\" : \"%s\",\n" + "\"FileSizeLo\" : %u,\n" + "\"FileSizeHi\" : %u,\n" + "\"FileSizeMB\" : %i,\n" + "\"FileCount\" : %i,\n" + "\"MinPostTime\" : %i,\n" + "\"MaxPostTime\" : %i,\n" + "\"TotalArticles\" : %i,\n" + "\"SuccessArticles\" : %i,\n" + "\"FailedArticles\" : %i,\n" + "\"Health\" : %i,\n" + "\"CriticalHealth\" : %i,\n" + "\"DupeKey\" : \"%s\",\n" + "\"DupeScore\" : %i,\n" + "\"DupeMode\" : \"%s\",\n" + "\"Deleted\" : %s,\n" // deprecated, use "DeleteStatus" instead + "\"DownloadedSizeLo\" : %u,\n" + "\"DownloadedSizeHi\" : %u,\n" + "\"DownloadedSizeMB\" : %i,\n" + "\"DownloadTimeSec\" : %i,\n" + "\"PostTotalTimeSec\" : %i,\n" + "\"ParTimeSec\" : %i,\n" + "\"RepairTimeSec\" : %i,\n" + "\"UnpackTimeSec\" : %i,\n" + "\"MessageCount\" : %i,\n" + "\"Parameters\" : [\n"; const char* JSON_NZB_ITEM_SCRIPT_START = - "],\n" - "\"ScriptStatuses\" : [\n"; + "],\n" + "\"ScriptStatuses\" : [\n"; const char* JSON_NZB_ITEM_STATS_START = - "],\n" - "\"ServerStats\" : [\n"; + "],\n" + "\"ServerStats\" : [\n"; const char* JSON_NZB_ITEM_END = - "],\n"; + "]\n"; const char* XML_PARAMETER_ITEM = - "\n" - "Name%s\n" - "Value%s\n" - "\n"; + "\n" + "Name%s\n" + "Value%s\n" + "\n"; const char* JSON_PARAMETER_ITEM = - "{\n" - "\"Name\" : \"%s\",\n" - "\"Value\" : \"%s\"\n" - "}"; + "{\n" + "\"Name\" : \"%s\",\n" + "\"Value\" : \"%s\"\n" + "}"; const char* XML_SCRIPT_ITEM = - "\n" - "Name%s\n" - "Status%s\n" - "\n"; + "\n" + "Name%s\n" + "Status%s\n" + "\n"; const char* JSON_SCRIPT_ITEM = - "{\n" - "\"Name\" : \"%s\",\n" - "\"Status\" : \"%s\"\n" - "}"; + "{\n" + "\"Name\" : \"%s\",\n" + "\"Status\" : \"%s\"\n" + "}"; const char* XML_STAT_ITEM = - "\n" - "ServerID%i\n" - "SuccessArticles%i\n" - "FailedArticles%i\n" - "\n"; + "\n" + "ServerID%i\n" + "SuccessArticles%i\n" + "FailedArticles%i\n" + "\n"; const char* JSON_STAT_ITEM = - "{\n" - "\"ServerID\" : %i,\n" - "\"SuccessArticles\" : %i,\n" - "\"FailedArticles\" : %i\n" - "}"; + "{\n" + "\"ServerID\" : %i,\n" + "\"SuccessArticles\" : %i,\n" + "\"FailedArticles\" : %i\n" + "}"; const char* szKindName[] = { "NZB", "URL" }; const char* szParStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS", "REPAIR_POSSIBLE", "MANUAL" }; @@ -1727,6 +1749,8 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo) Util::SplitInt64(pNZBInfo->GetDownloadedSize(), &iDownloadedSizeHi, &iDownloadedSizeLo); iDownloadedSizeMB = (int)(pNZBInfo->GetDownloadedSize() / 1024 / 1024); + int iMessageCount = pNZBInfo->GetMessageCount() > 0 ? pNZBInfo->GetMessageCount() : pNZBInfo->GetCachedMessageCount(); + char* xmlURL = EncodeStr(pNZBInfo->GetURL()); char* xmlNZBFilename = EncodeStr(pNZBInfo->GetFilename()); char* xmlNZBNicename = EncodeStr(pNZBInfo->GetName()); @@ -1751,7 +1775,7 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo) BoolToStr(pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone), iDownloadedSizeLo, iDownloadedSizeHi, iDownloadedSizeMB, pNZBInfo->GetDownloadSec(), pNZBInfo->GetPostInfo() && pNZBInfo->GetPostInfo()->GetStartTime() ? time(NULL) - pNZBInfo->GetPostInfo()->GetStartTime() : pNZBInfo->GetPostTotalSec(), - pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec()); + pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec(), iMessageCount); free(xmlURL); free(xmlNZBNicename); @@ -1925,7 +1949,7 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie if (iLogEntries > 0 && pPostInfo) { - PostInfo::Messages* pMessages = pPostInfo->LockMessages(); + MessageList* pMessages = pPostInfo->GetNZBInfo()->LockCachedMessages(); if (!pMessages->empty()) { if (iLogEntries > (int)pMessages->size()) @@ -1951,7 +1975,7 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie AppendResponse(szItemBuf); } } - pPostInfo->UnlockMessages(); + pPostInfo->GetNZBInfo()->UnlockCachedMessages(); } AppendResponse(IsJson() ? JSON_POSTQUEUE_ITEM_END : XML_POSTQUEUE_ITEM_END); @@ -2039,6 +2063,10 @@ void ListGroupsXmlCommand::Execute() AppendResponse(szItemBuf); AppendNZBInfoFields(pNZBInfo); + if (IsJson()) + { + AppendResponse(",\n"); + } AppendPostInfoFields(pNZBInfo->GetPostInfo(), iNrEntries, false); AppendResponse(IsJson() ? JSON_LIST_ITEM_END : XML_LIST_ITEM_END); @@ -2402,6 +2430,10 @@ void PostQueueXmlCommand::Execute() AppendResponse(szItemBuf); AppendNZBInfoFields(pPostInfo->GetNZBInfo()); + if (IsJson()) + { + AppendResponse(",\n"); + } AppendPostInfoFields(pPostInfo, iNrEntries, true); AppendResponse(IsJson() ? JSON_POSTQUEUE_ITEM_END : XML_POSTQUEUE_ITEM_END); @@ -2500,44 +2532,22 @@ void HistoryXmlCommand::Execute() "Name%s\n" "RemainingFileCount%i\n" "HistoryTime%i\n" - "Status%s\n"; - - const char* XML_HISTORY_ITEM_LOG_START = - "Log\n"; - - const char* XML_HISTORY_ITEM_END = - "\n" - "\n"; + "Status%s\n" + "Log\n"; // Deprected, always empty const char* JSON_HISTORY_ITEM_START = "{\n" - "\"ID\" : %i,\n" // Deprecated, use "NZBID" instead + "\"ID\" : %i,\n" // Deprecated, use "NZBID" instead "\"Name\" : \"%s\",\n" "\"RemainingFileCount\" : %i,\n" "\"HistoryTime\" : %i,\n" - "\"Status\" : \"%s\",\n"; + "\"Status\" : \"%s\",\n" + "\"Log\" : [],\n"; // Deprected, always empty - const char* JSON_HISTORY_ITEM_LOG_START = - "\"Log\" : [\n"; + const char* XML_HISTORY_ITEM_END = + ""; const char* JSON_HISTORY_ITEM_END = - "]\n" - "}"; - - const char* XML_LOG_ITEM = - "\n" - "ID%i\n" - "Kind%s\n" - "Time%i\n" - "Text%s\n" - "\n"; - - const char* JSON_LOG_ITEM = - "{\n" - "\"ID\" : %i,\n" - "\"Kind\" : \"%s\",\n" - "\"Time\" : %i,\n" - "\"Text\" : \"%s\"\n" "}"; const char* XML_HISTORY_DUP_ITEM = @@ -2570,10 +2580,9 @@ void HistoryXmlCommand::Execute() "\"DupeScore\" : %i,\n" "\"DupeMode\" : \"%s\",\n" "\"DupStatus\" : \"%s\",\n" - "\"Status\" : \"%s\",\n"; + "\"Status\" : \"%s\"\n"; const char* szDupStatusName[] = { "UNKNOWN", "SUCCESS", "FAILURE", "DELETED", "DUPE", "BAD", "GOOD" }; - const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"}; const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" }; bool bDup = false; @@ -2644,34 +2653,6 @@ void HistoryXmlCommand::Execute() AppendNZBInfoFields(pNZBInfo); } - AppendResponse(IsJson() ? JSON_HISTORY_ITEM_LOG_START : XML_HISTORY_ITEM_LOG_START); - - if (pNZBInfo) - { - // Log-Messages - NZBInfo::Messages* pMessages = pNZBInfo->LockMessages(); - if (!pMessages->empty()) - { - int iLogIndex = 0; - for (NZBInfo::Messages::iterator it = pMessages->begin(); it != pMessages->end(); it++) - { - Message* pMessage = *it; - char* xmltext = EncodeStr(pMessage->GetText()); - snprintf(szItemBuf, iItemBufSize, IsJson() ? JSON_LOG_ITEM : XML_LOG_ITEM, - pMessage->GetID(), szMessageType[pMessage->GetKind()], pMessage->GetTime(), xmltext); - szItemBuf[iItemBufSize-1] = '\0'; - free(xmltext); - - if (IsJson() && iLogIndex++ > 0) - { - AppendResponse(",\n"); - } - AppendResponse(szItemBuf); - } - } - pNZBInfo->UnlockMessages(); - } - AppendResponse(IsJson() ? JSON_HISTORY_ITEM_END : XML_HISTORY_ITEM_END); } free(szItemBuf); @@ -3359,7 +3340,7 @@ void StartUpdateXmlCommand::Execute() } // struct[] logupdate(idfrom, entries) -Log::Messages* LogUpdateXmlCommand::LockMessages() +MessageList* LogUpdateXmlCommand::LockMessages() { return g_pMaintenance->LockMessages(); } @@ -3555,3 +3536,48 @@ void ResetServerVolumeXmlCommand::Execute() BuildBoolResponse(bOK); } + +// struct[] loadlog(nzbid, logidfrom, logentries) +void LoadLogXmlCommand::Execute() +{ + m_pNZBInfo = NULL; + m_iNZBID = 0; + if (!NextParamAsInt(&m_iNZBID)) + { + BuildErrorResponse(2, "Invalid parameter"); + return; + } + + LogXmlCommand::Execute(); +} + +MessageList* LoadLogXmlCommand::LockMessages() +{ + // TODO: optimize for m_iIDFrom and m_iNrEntries + g_pDiskState->LoadNZBMessages(m_iNZBID, &m_messages); + + if (m_messages.empty()) + { + DownloadQueue* pDownloadQueue = DownloadQueue::Lock(); + m_pNZBInfo = pDownloadQueue->GetQueue()->Find(m_iNZBID); + if (m_pNZBInfo) + { + return m_pNZBInfo->LockCachedMessages(); + } + else + { + DownloadQueue::Unlock(); + } + } + + return &m_messages; +} + +void LoadLogXmlCommand::UnlockMessages() +{ + if (m_pNZBInfo) + { + m_pNZBInfo->UnlockCachedMessages(); + DownloadQueue::Unlock(); + } +} diff --git a/daemon/util/Log.cpp b/daemon/util/Log.cpp index 91b0c447..9466a566 100644 --- a/daemon/util/Log.cpp +++ b/daemon/util/Log.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -179,7 +179,7 @@ void debug(const char* msg, ...) Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDebugTarget() : Options::mtScreen; if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth) { - g_pLog->AppendMessage(Message::mkDebug, tmp2); + g_pLog->AddMessage(Message::mkDebug, tmp2); } if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth) { @@ -205,7 +205,7 @@ void error(const char* msg, ...) Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetErrorTarget() : Options::mtBoth; if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth) { - g_pLog->AppendMessage(Message::mkError, tmp2); + g_pLog->AddMessage(Message::mkError, tmp2); } if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth) { @@ -230,7 +230,7 @@ void warn(const char* msg, ...) Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetWarningTarget() : Options::mtScreen; if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth) { - g_pLog->AppendMessage(Message::mkWarning, tmp2); + g_pLog->AddMessage(Message::mkWarning, tmp2); } if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth) { @@ -255,7 +255,7 @@ void info(const char* msg, ...) Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetInfoTarget() : Options::mtScreen; if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth) { - g_pLog->AppendMessage(Message::mkInfo, tmp2); + g_pLog->AddMessage(Message::mkInfo, tmp2); } if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth) { @@ -280,7 +280,7 @@ void detail(const char* msg, ...) Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDetailTarget() : Options::mtScreen; if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth) { - g_pLog->AppendMessage(Message::mkDetail, tmp2); + g_pLog->AddMessage(Message::mkDetail, tmp2); } if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth) { @@ -334,18 +334,28 @@ Message::~ Message() free(m_szText); } -void Log::Clear() +MessageList::~MessageList() { - m_mutexLog.Lock(); - for (Messages::iterator it = m_Messages.begin(); it != m_Messages.end(); it++) + Clear(); +} + +void MessageList::Clear() +{ + for (iterator it = begin(); it != end(); it++) { delete *it; } - m_Messages.clear(); + clear(); +} + +void Log::Clear() +{ + m_mutexLog.Lock(); + m_Messages.Clear(); m_mutexLog.Unlock(); } -void Log::AppendMessage(Message::EKind eKind, const char * szText) +void Log::AddMessage(Message::EKind eKind, const char * szText) { Message* pMessage = new Message(++m_iIDGen, eKind, time(NULL), szText); m_Messages.push_back(pMessage); @@ -361,7 +371,7 @@ void Log::AppendMessage(Message::EKind eKind, const char * szText) } } -Log::Messages* Log::LockMessages() +MessageList* Log::LockMessages() { m_mutexLog.Lock(); return &m_Messages; @@ -433,7 +443,7 @@ void Log::RotateLog() char szMessage[1024]; snprintf(szMessage, 1024, "Deleting old log-file %s\n", filename); szMessage[1024-1] = '\0'; - g_pLog->AppendMessage(Message::mkInfo, szMessage); + g_pLog->AddMessage(Message::mkInfo, szMessage); remove(szFullFilename); } diff --git a/daemon/util/Log.h b/daemon/util/Log.h index e34db288..85a6b02f 100644 --- a/daemon/util/Log.h +++ b/daemon/util/Log.h @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2014 Andrey Prygunkov + * Copyright (C) 2007-2015 Andrey Prygunkov * * 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 @@ -76,6 +76,15 @@ public: const char* GetText() { return m_szText; } }; +typedef std::deque MessageListBase; + +class MessageList: public MessageListBase +{ +public: + ~MessageList(); + void Clear(); +}; + class Debuggable { protected: @@ -86,12 +95,11 @@ protected: class Log { public: - typedef std::deque Messages; typedef std::list Debuggables; private: Mutex m_mutexLog; - Messages m_Messages; + MessageList m_Messages; Debuggables m_Debuggables; Mutex m_mutexDebug; char* m_szLogFilename; @@ -102,7 +110,7 @@ private: #endif void Filelog(const char* msg, ...); - void AppendMessage(Message::EKind eKind, const char* szText); + void AddMessage(Message::EKind eKind, const char* szText); void RotateLog(); friend void error(const char* msg, ...); @@ -121,7 +129,7 @@ private: public: Log(); ~Log(); - Messages* LockMessages(); + MessageList* LockMessages(); void UnlockMessages(); void Clear(); void ResetLog(); diff --git a/daemon/util/Script.cpp b/daemon/util/Script.cpp index 041fc636..dec42bd9 100644 --- a/daemon/util/Script.cpp +++ b/daemon/util/Script.cpp @@ -422,15 +422,15 @@ int ScriptController::Execute() szErrMsg[255-1] = '\0'; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, 0, szErrMsg, 255, NULL)) { - error("Could not start %s: %s", m_szInfoName, szErrMsg); + PrintMessage(Message::mkError, "Could not start %s: %s", m_szInfoName, szErrMsg); } else { - error("Could not start %s: error %i", m_szInfoName, dwErrCode); + PrintMessage(Message::mkError, "Could not start %s: error %i", m_szInfoName, dwErrCode); } if (!Util::FileExists(m_szScript)) { - error("Could not find file %s", m_szScript); + PrintMessage(Message::mkError, "Could not find file %s", m_szScript); } free(szEnvironmentStrings); return -1; @@ -455,7 +455,7 @@ int ScriptController::Execute() // create the pipe if (pipe(p)) { - error("Could not open pipe: errno %i", errno); + PrintMessage(Message::mkError, "Could not open pipe: errno %i", errno); return -1; } @@ -469,7 +469,7 @@ int ScriptController::Execute() if (pid == -1) { - error("Could not start %s: errno %i", m_szInfoName, errno); + PrintMessage(Message::mkError, "Could not start %s: errno %i", m_szInfoName, errno); free(pEnvironmentStrings); return -1; } @@ -529,7 +529,7 @@ int ScriptController::Execute() m_pReadpipe = fdopen(pipein, "r"); if (!m_pReadpipe) { - error("Could not open pipe to %s", m_szInfoName); + PrintMessage(Message::mkError, "Could not open pipe to %s", m_szInfoName); return -1; } diff --git a/nzbget.conf b/nzbget.conf index a5dbc852..7e654338 100644 --- a/nzbget.conf +++ b/nzbget.conf @@ -917,7 +917,6 @@ WriteLog=append # (option is set to "rotate"). RotateLog=3 - # How error messages must be printed (screen, log, both, none). ErrorTarget=both @@ -940,7 +939,13 @@ DebugTarget=both # clients (messages). LogBufferSize=1000 -# Create a log of all broken files (yes ,no). +# Create log for each downloaded nzb-file (yes, no). +# +# The messages are saved for each download separately and can be viewed +# at any time in download details dialog or history details dialog. +NzbLog=yes + +# Create a log of all broken files (yes, no). # # It is a text file placed near downloaded files, which contains # the names of broken files. diff --git a/webui/downloads.js b/webui/downloads.js index c6415a4b..1bfb22f4 100644 --- a/webui/downloads.js +++ b/webui/downloads.js @@ -79,7 +79,7 @@ var Downloads = (new function($) $DownloadsRecordsPerPage = $('#DownloadsRecordsPerPage'); $DownloadsTable_Name = $('#DownloadsTable_Name'); - var recordsPerPage = UISettings.read('$DownloadsRecordsPerPage', 10); + var recordsPerPage = UISettings.read('DownloadsRecordsPerPage', 10); $DownloadsRecordsPerPage.val(recordsPerPage); $DownloadsTable.fasttable( @@ -109,7 +109,7 @@ var Downloads = (new function($) this.applyTheme = function() { - $DownloadsTable.fasttable('setPageSize', UISettings.read('$DownloadsRecordsPerPage', 10), + $DownloadsTable.fasttable('setPageSize', UISettings.read('DownloadsRecordsPerPage', 10), UISettings.miniTheme ? 1 : 5, !UISettings.miniTheme); } @@ -120,7 +120,7 @@ var Downloads = (new function($) $('#DownloadsTable_Category').css('width', DownloadsUI.calcCategoryColumnWidth()); } - RPC.call('listgroups', [100], groups_loaded); + RPC.call('listgroups', [], groups_loaded); } function groups_loaded(_groups) @@ -303,7 +303,7 @@ var Downloads = (new function($) this.recordsPerPageChange = function() { var val = $DownloadsRecordsPerPage.val(); - UISettings.write('$DownloadsRecordsPerPage', val); + UISettings.write('DownloadsRecordsPerPage', val); $DownloadsTable.fasttable('setPageSize', val); } @@ -710,26 +710,13 @@ var DownloadsUI = (new function($) { switch (group.Status) { - case "REPAIRING": - break; case "LOADING_PARS": case "VERIFYING_SOURCES": case "VERIFYING_REPAIRED": case "UNPACKING": case "RENAMING": - text = group.PostInfoText; - break; case "EXECUTING_SCRIPT": - if (group.Log && group.Log.length > 0) - { - text = group.Log[group.Log.length-1].Text; - // remove "for " from label text - text = text.replace(' for ' + group.NZBName, ' '); - } - else - { - text = group.PostInfoText; - } + text = group.PostInfoText; break; } } diff --git a/webui/edit.js b/webui/edit.js index ab7f34a4..241b907a 100644 --- a/webui/edit.js +++ b/webui/edit.js @@ -39,7 +39,6 @@ var DownloadsEditDialog = (new function($) // Controls var $DownloadsEditDialog; - var $DownloadsLogTable; var $DownloadsFileTable; var $DownloadsEdit_ParamData; var $ServStatsTable; @@ -70,17 +69,7 @@ var DownloadsEditDialog = (new function($) $('#DownloadsEdit_Back').click(backClick); $('#DownloadsEdit_Category').change(categoryChange); - $DownloadsLogTable = $('#DownloadsEdit_LogTable'); - $DownloadsLogTable.fasttable( - { - filterInput: '#DownloadsEdit_LogTable_filter', - pagerContainer: '#DownloadsEdit_LogTable_pager', - filterCaseSensitive: false, - pageSize: 100, - maxPages: 3, - hasHeader: true, - renderCellCallback: logTableRenderCellCallback - }); + LogTab.init('Downloads'); $DownloadsFileTable = $('#DownloadsEdit_FileTable'); $DownloadsFileTable.fasttable( @@ -114,7 +103,7 @@ var DownloadsEditDialog = (new function($) $DownloadsEditDialog.on('hidden', function() { // cleanup - $DownloadsLogTable.fasttable('update', []); + LogTab.reset('Downloads'); $DownloadsFileTable.fasttable('update', []); $DownloadsEdit_ParamData.empty(); clearTimeout(refreshTimer); @@ -225,7 +214,6 @@ var DownloadsEditDialog = (new function($) $('#DownloadsEdit_DupeScore').val(group.DupeScore); $('#DownloadsEdit_DupeMode').val(group.DupeMode); - $DownloadsLogTable.fasttable('update', []); $DownloadsFileTable.fasttable('update', []); var postParamConfig = ParamTab.createPostParamConfig(); @@ -243,7 +231,7 @@ var DownloadsEditDialog = (new function($) var dupeCheck = Options.option('DupeCheck') === 'yes'; Util.show('#DownloadsEdit_Dupe', dupeCheck); var postParam = postParamConfig[0].options.length > 0 && group.Kind === 'NZB'; - var postLog = group.postprocess && group.Log.length > 0; + var postLog = group.MessageCount > 0; Util.show('#DownloadsEdit_Param', postParam); Util.show('#DownloadsEdit_Log', postLog); @@ -291,8 +279,8 @@ var DownloadsEditDialog = (new function($) $DownloadsEditDialog.restoreTab(); $('#DownloadsEdit_FileTable_filter').val(''); - $('#DownloadsEdit_LogTable_filter').val(''); - $('#DownloadsEdit_LogTable_pagerBlock').hide(); + + LogTab.reset('Downloads'); files = null; logFilled = false; @@ -359,10 +347,10 @@ var DownloadsEditDialog = (new function($) } }}); - if (tab === '#DownloadsEdit_LogTab' && !logFilled && curGroup.postprocess && - curGroup.Log && curGroup.Log.length > 0) + if (tab === '#DownloadsEdit_LogTab' && !logFilled && (curGroup.postprocess || curGroup.MessageCount > 0)) { - fillLog(); + LogTab.fill('Downloads', curGroup); + logFilled = true; } if (tab === '#DownloadsEdit_FileTab' && files === null) @@ -576,64 +564,6 @@ var DownloadsEditDialog = (new function($) :saveParam(); } - /*** TAB: LOG *************************************************************************/ - - function fillLog() - { - logFilled = true; - var data = []; - - for (var i=0; i < curGroup.Log.length; i++) - { - var message = curGroup.Log[i]; - - var kind; - switch (message.Kind) - { - case 'INFO': kind = 'info'; break; - case 'DETAIL': kind = 'detail'; break; - case 'WARNING': kind = 'warning'; break; - case 'ERROR': kind = 'error'; break; - case 'DEBUG': kind = 'debug'; break; - } - - var text = Util.textToHtml(message.Text); - var time = Util.formatDateTime(message.Time + UISettings.timeZoneCorrection*60*60); - var fields; - - if (!UISettings.miniTheme) - { - fields = [kind, time, text]; - } - else - { - var info = kind + ' ' + time + ' ' + text; - fields = [info]; - } - - var item = - { - id: message, - fields: fields, - search: message.Kind + ' ' + time + ' ' + message.Text - }; - - data.unshift(item); - } - - $DownloadsLogTable.fasttable('update', data); - $DownloadsLogTable.fasttable('setCurPage', 1); - Util.show('#DownloadsEdit_LogTable_pagerBlock', data.length > 100); - } - - function logTableRenderCellCallback(cell, index, item) - { - if (index === 0) - { - cell.width = '65px'; - } - } - /*** TAB: FILES *************************************************************************/ function fillFiles() @@ -1157,6 +1087,114 @@ var ParamTab = (new function($) }(jQuery)); +/*** LOG TAB FOR EDIT DIALOGS ************************************************************/ + +var LogTab = (new function($) +{ + 'use strict' + + this.init = function(name) + { + var recordsPerPage = UISettings.read('ItemLogRecordsPerPage', 10); + $('#' + name + 'LogRecordsPerPage').val(recordsPerPage); + + var $LogTable = $('#' + name + 'Edit_LogTable'); + $LogTable.fasttable( + { + filterInput: '#' + name + 'Edit_LogTable_filter', + pagerContainer: '#' + name + 'Edit_LogTable_pager', + filterCaseSensitive: false, + pageSize: recordsPerPage, + maxPages: 3, + hasHeader: true, + renderCellCallback: logTableRenderCellCallback + }); + } + + this.reset = function(name) + { + var $LogTable = $('#' + name + 'Edit_LogTable'); + $LogTable.fasttable('update', []); + + $('#' + name + 'Edit_LogTable_filter').val(''); + } + + this.fill = function(name, item) + { + function logLoaded(log) + { + $('#' + name + 'EditDialog .loading-block').hide(); + var $LogTable = $('#' + name + 'Edit_LogTable'); + var data = []; + + for (var i=0; i < log.length; i++) + { + var message = log[i]; + + var kind; + switch (message.Kind) + { + case 'INFO': kind = 'info'; break; + case 'DETAIL': kind = 'detail'; break; + case 'WARNING': kind = 'warning'; break; + case 'ERROR': kind = 'error'; break; + case 'DEBUG': kind = 'debug'; break; + } + + var text = Util.textToHtml(message.Text); + var time = Util.formatDateTime(message.Time + UISettings.timeZoneCorrection*60*60); + var fields; + + if (!UISettings.miniTheme) + { + fields = [kind, time, text]; + } + else + { + var info = kind + ' ' + time + ' ' + text; + fields = [info]; + } + + var item = + { + id: message, + fields: fields, + search: message.Kind + ' ' + time + ' ' + message.Text + }; + + data.unshift(item); + } + + $LogTable.fasttable('update', data); + $LogTable.fasttable('setCurPage', 1); + } + + var recordsPerPage = UISettings.read('ItemLogRecordsPerPage', 10); + $('#' + name + 'LogRecordsPerPage').val(recordsPerPage); + + $('#' + name + 'EditDialog .loading-block').show(); + RPC.call('loadlog', [item.NZBID, 0, 1000], logLoaded); + } + + function logTableRenderCellCallback(cell, index, item) + { + if (index === 0) + { + cell.width = '65px'; + } + } + + this.recordsPerPageChange = function(name) + { + var val = $('#' + name + 'LogRecordsPerPage').val(); + UISettings.write('ItemLogRecordsPerPage', val); + var $LogTable = $('#' + name + 'Edit_LogTable'); + $LogTable.fasttable('setPageSize', val); + } + +}(jQuery)); + + /*** DOWNLOAD MULTI EDIT DIALOG ************************************************************/ var DownloadsMultiDialog = (new function($) @@ -1497,6 +1535,7 @@ var HistoryEditDialog = (new function() var lastPage; var lastFullscreen; var saveCompleted; + var logFilled; this.init = function() { @@ -1508,11 +1547,13 @@ var HistoryEditDialog = (new function() $('#HistoryEdit_Return, #HistoryEdit_ReturnURL').click(itemReturn); $('#HistoryEdit_Reprocess').click(itemReprocess); $('#HistoryEdit_Redownload').click(itemRedownload); - $('#HistoryEdit_Param, #HistoryEdit_Dupe').click(tabClick); + $('#HistoryEdit_Param, #HistoryEdit_Dupe, #HistoryEdit_Log').click(tabClick); $('#HistoryEdit_Back').click(backClick); $('#HistoryEdit_MarkGood').click(itemGood); $('#HistoryEdit_MarkBad').click(itemBad); + LogTab.init('History'); + $ServStatsTable = $('#HistoryEdit_ServStatsTable'); $ServStatsTable.fasttable( { @@ -1527,6 +1568,7 @@ var HistoryEditDialog = (new function() $HistoryEditDialog.on('hidden', function () { $HistoryEdit_ParamData.empty(); + LogTab.reset('History'); // resume updates Refresher.resume(); }); @@ -1681,6 +1723,9 @@ var HistoryEditDialog = (new function() postParams = ParamTab.buildPostParamTab($HistoryEdit_ParamData, postParamConfig, curHist.Parameters); } + var postLog = hist.MessageCount > 0; + Util.show('#HistoryEdit_Log', postLog); + EditUI.buildDNZBLinks(curHist.Parameters ? curHist.Parameters : [], 'HistoryEdit_DNZB'); enableAllButtons(); @@ -1690,10 +1735,14 @@ var HistoryEditDialog = (new function() $('#HistoryEdit_ServStatsTab').hide(); $('#HistoryEdit_TimeStatsTab').hide(); $('#HistoryEdit_DupeTab').hide(); + $('#HistoryEdit_LogTab').hide(); $('#HistoryEdit_Back').hide(); $('#HistoryEdit_BackSpace').show(); $HistoryEditDialog.restoreTab(); + LogTab.reset('History'); + + logFilled = false; notification = null; $HistoryEditDialog.modal({backdrop: 'static'}); @@ -1763,6 +1812,12 @@ var HistoryEditDialog = (new function() $HistoryEditDialog.switchTab($('#HistoryEdit_GeneralTab'), lastPage, e.shiftKey || !UISettings.slideAnimation ? 0 : 500, {fullscreen: lastFullscreen, mini: UISettings.miniTheme}); + + if (tab === '#HistoryEdit_LogTab' && !logFilled && curHist.MessageCount > 0) + { + LogTab.fill('History', curHist); + logFilled = true; + } } function backClick(e) diff --git a/webui/index.html b/webui/index.html index 260a89f9..3e0d58c6 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1027,10 +1027,29 @@ @@ -1331,6 +1350,40 @@ + +