2
* This file is part of nzbget
4
* Copyright (C) 2007-2010 Andrei Prygounkov <hugbug@users.sourceforge.net>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
* $Date: 2010-01-29 10:34:44 +0100 (Fri, 29 Jan 2010) $
47
#include "QueueCoordinator.h"
48
#include "ScriptController.h"
49
#include "DiskState.h"
52
extern QueueCoordinator* g_pQueueCoordinator;
53
extern Options* g_pOptions;
54
extern DiskState* g_pDiskState;
56
Scanner::FileData::FileData(const char* szFilename)
58
m_szFilename = strdup(szFilename);
63
Scanner::FileData::~FileData()
70
debug("Creating Scanner");
72
m_bRequestedNZBDirScan = false;
73
m_iNZBDirInterval = g_pOptions->GetNzbDirInterval() * 1000;
77
const char* szNZBScript = g_pOptions->GetNZBProcess();
78
m_bNZBScript = szNZBScript && strlen(szNZBScript) > 0;
83
debug("Destroying Scanner");
85
for (FileList::iterator it = m_FileList.begin(); it != m_FileList.end(); it++)
94
if (g_pOptions->GetNzbDir() && (m_bRequestedNZBDirScan ||
95
(!g_pOptions->GetPauseScan() && g_pOptions->GetNzbDirInterval() > 0 &&
96
m_iNZBDirInterval >= g_pOptions->GetNzbDirInterval() * 1000)))
98
// check nzbdir every g_pOptions->GetNzbDirInterval() seconds or if requested
99
bool bCheckStat = !m_bRequestedNZBDirScan;
100
m_bRequestedNZBDirScan = false;
101
CheckIncomingNZBs(g_pOptions->GetNzbDir(), "", bCheckStat);
102
m_iNZBDirInterval = 0;
104
// if NzbDirFileAge is less than NzbDirInterval (that can happen if NzbDirInterval
105
// is set for rare scans like once per hour) we make 4 scans:
106
// - one additional scan is neccessary to check sizes of detected files;
107
// - another scan is required to check files which were extracted by NzbProcess-script;
108
// - third scan is needed to check sizes of extracted files.
109
if (g_pOptions->GetNzbDirFileAge() < g_pOptions->GetNzbDirInterval())
111
int iMaxPass = m_bNZBScript ? 3 : 1;
112
if (m_iPass < iMaxPass)
114
// scheduling another scan of incoming directory in NzbDirFileAge seconds.
115
m_iNZBDirInterval = (g_pOptions->GetNzbDirInterval() - g_pOptions->GetNzbDirFileAge()) * 1000;
126
m_iNZBDirInterval += m_iStepMSec;
130
* Check if there are files in directory for incoming nzb-files
131
* and add them to download queue
133
void Scanner::CheckIncomingNZBs(const char* szDirectory, const char* szCategory, bool bCheckStat)
135
DirBrowser dir(szDirectory);
136
while (const char* filename = dir.Next())
139
char fullfilename[1023 + 1]; // one char reserved for the trailing slash (if needed)
140
snprintf(fullfilename, 1023, "%s%s", szDirectory, filename);
141
fullfilename[1023 - 1] = '\0';
142
if (!stat(fullfilename, &buffer))
145
if ((buffer.st_mode & S_IFDIR) != 0 && strcmp(filename, ".") && strcmp(filename, ".."))
147
fullfilename[strlen(fullfilename) + 1] = '\0';
148
fullfilename[strlen(fullfilename)] = PATH_SEPARATOR;
149
const char* szUseCategory = filename;
150
char szSubCategory[1024];
151
if (strlen(szCategory) > 0)
153
snprintf(szSubCategory, 1023, "%s%c%s", szCategory, PATH_SEPARATOR, filename);
154
szSubCategory[1024 - 1] = '\0';
155
szUseCategory = szSubCategory;
157
CheckIncomingNZBs(fullfilename, szUseCategory, bCheckStat);
159
else if ((buffer.st_mode & S_IFDIR) == 0 && CanProcessFile(fullfilename, bCheckStat))
161
ProcessIncomingFile(szDirectory, filename, fullfilename, szCategory);
168
* Only files which were not changed during last g_pOptions->GetNzbDirFileAge() seconds
169
* can be processed. That prevents the processing of files, which are currently being
170
* copied into nzb-directory (eg. being downloaded in web-browser).
172
bool Scanner::CanProcessFile(const char* szFullFilename, bool bCheckStat)
174
const char* szExtension = strrchr(szFullFilename, '.');
176
!strcasecmp(szExtension, ".queued") ||
177
!strcasecmp(szExtension, ".error") ||
178
!strcasecmp(szExtension, ".processed"))
188
long long lSize = Util::FileSize(szFullFilename);
189
time_t tCurrent = time(NULL);
190
bool bCanProcess = false;
191
bool bInList = false;
193
for (FileList::iterator it = m_FileList.begin(); it != m_FileList.end(); it++)
195
FileData* pFileData = *it;
196
if (!strcmp(pFileData->GetFilename(), szFullFilename))
199
if (pFileData->GetSize() == lSize &&
200
tCurrent - pFileData->GetLastChange() >= g_pOptions->GetNzbDirFileAge())
204
m_FileList.erase(it);
208
pFileData->SetSize(lSize);
209
if (pFileData->GetSize() != lSize)
211
pFileData->SetLastChange(tCurrent);
220
FileData* pFileData = new FileData(szFullFilename);
221
pFileData->SetSize(lSize);
222
pFileData->SetLastChange(tCurrent);
223
m_FileList.push_back(pFileData);
230
* Remove old files from the list of monitored files.
231
* Normally these files are deleted from the list when they are processed.
232
* However if a file was detected by function "CanProcessFile" once but wasn't
233
* processed later (for example if the user deleted it), it will stay in the list,
234
* until we remove it here.
236
void Scanner::DropOldFiles()
238
time_t tCurrent = time(NULL);
241
for (FileList::iterator it = m_FileList.begin(); it != m_FileList.end(); )
243
FileData* pFileData = *it;
244
if ((tCurrent - pFileData->GetLastChange() >=
245
(g_pOptions->GetNzbDirInterval() + g_pOptions->GetNzbDirFileAge()) * 2) ||
246
// can occur if the system clock was adjusted
247
tCurrent < pFileData->GetLastChange())
249
debug("Removing file %s from scan file list", pFileData->GetFilename());
252
m_FileList.erase(it);
253
it = m_FileList.begin() + i;
263
void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename, const char* szFullFilename, const char* szCategory)
265
const char* szExtension = strrchr(szBaseFilename, '.');
271
char* szNZBCategory = strdup(szCategory);
272
NZBParameterList* pParameterList = new NZBParameterList;
276
if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed"))
278
NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory, &szNZBCategory, pParameterList);
279
bExists = Util::FileExists(szFullFilename);
280
if (bExists && strcasecmp(szExtension, ".nzb"))
283
bool bRenameOK = Util::RenameBak(szFullFilename, "processed", false, bakname2, 1024);
286
error("Could not rename file %s to %s! Errcode: %i", szFullFilename, bakname2, errno);
291
if (!strcasecmp(szExtension, ".nzb_processed"))
293
char szRenamedName[1024];
294
bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024);
297
AddFileToQueue(szRenamedName, szNZBCategory, pParameterList);
301
error("Could not rename file %s to %s! Errcode: %i", szFullFilename, szRenamedName, errno);
304
else if (bExists && !strcasecmp(szExtension, ".nzb"))
306
AddFileToQueue(szFullFilename, szNZBCategory, pParameterList);
309
for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++)
313
pParameterList->clear();
314
delete pParameterList;
319
void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList)
321
const char* szBasename = Util::BaseFileName(szFilename);
323
info("Collection %s found", szBasename);
325
NZBFile* pNZBFile = NZBFile::CreateFromFile(szFilename, szCategory);
328
error("Could not add collection %s to queue", szBasename);
332
bool bRenameOK = Util::RenameBak(szFilename, pNZBFile ? "queued" : "error", false, bakname2, 1024);
335
error("Could not rename file %s to %s! Errcode: %i", szFilename, bakname2, errno);
338
if (pNZBFile && bRenameOK)
340
pNZBFile->GetNZBInfo()->SetQueuedFilename(bakname2);
342
for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++)
344
NZBParameter* pParameter = *it;
345
pNZBFile->GetNZBInfo()->SetParameter(pParameter->GetName(), pParameter->GetValue());
348
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, false);
349
info("Collection %s added to queue", szBasename);
358
void Scanner::ScanNZBDir()
360
// ideally we should use mutex to access "m_bRequestedNZBDirScan",
361
// but it's not critical here.
362
m_bRequestedNZBDirScan = true;