~ubuntu-branches/debian/experimental/nzbget/experimental

« back to all changes in this revision

Viewing changes to ParCoordinator.cpp

  • Committer: Package Import Robot
  • Author(s): Andreas Moog
  • Date: 2014-12-25 12:58:06 UTC
  • mfrom: (1.2.1) (3.1.4 sid)
  • Revision ID: package-import@ubuntu.com-20141225125806-vnzgajhm7mju9933
Tags: 14.1+dfsg-1
* New Upstream release (Closes: #768863)
* debian/patches:
  - Remove 0010_unnecessary_gcryptdep.patch, included upstream
  - Refresh remaining patches
* debian/control:
  - Remove no longer needed build-depends on libpar2-dev and libsigc++-dev
* debian/nzbget.conf
  - Update sample configuration file to include new options introduced by
    new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  This file is part of nzbget
3
 
 *
4
 
 *  Copyright (C) 2007-2013 Andrey Prygunkov <hugbug@users.sourceforge.net>
5
 
 *
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.
10
 
 *
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.
15
 
 *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
 
 *
20
 
 * $Revision: 680 $
21
 
 * $Date: 2013-05-15 18:45:36 +0200 (Wed, 15 May 2013) $
22
 
 *
23
 
 */
24
 
 
25
 
 
26
 
#ifdef HAVE_CONFIG_H
27
 
#include "config.h"
28
 
#endif
29
 
 
30
 
#ifdef WIN32
31
 
#include "win32.h"
32
 
#endif
33
 
 
34
 
#include <stdlib.h>
35
 
#include <string.h>
36
 
#include <stdio.h>
37
 
#include <stdarg.h>
38
 
#ifdef WIN32
39
 
#include <direct.h>
40
 
#else
41
 
#include <unistd.h>
42
 
#endif
43
 
 
44
 
#include "nzbget.h"
45
 
#include "ParCoordinator.h"
46
 
#include "Options.h"
47
 
#include "Log.h"
48
 
#include "Util.h"
49
 
#include "QueueCoordinator.h"
50
 
#include "DiskState.h"
51
 
 
52
 
extern QueueCoordinator* g_pQueueCoordinator;
53
 
extern Options* g_pOptions;
54
 
extern DiskState* g_pDiskState;
55
 
 
56
 
#ifndef DISABLE_PARCHECK
57
 
bool ParCoordinator::PostParChecker::RequestMorePars(int iBlockNeeded, int* pBlockFound)
58
 
{
59
 
        return m_pOwner->RequestMorePars(m_pPostInfo->GetNZBInfo(), GetParFilename(), iBlockNeeded, pBlockFound);
60
 
}
61
 
 
62
 
void ParCoordinator::PostParChecker::UpdateProgress()
63
 
{
64
 
        m_pOwner->UpdateParCheckProgress();
65
 
}
66
 
 
67
 
void ParCoordinator::PostParChecker::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
68
 
{
69
 
        char szText[1024];
70
 
        va_list args;
71
 
        va_start(args, szFormat);
72
 
        vsnprintf(szText, 1024, szFormat, args);
73
 
        va_end(args);
74
 
        szText[1024-1] = '\0';
75
 
 
76
 
        m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
77
 
}
78
 
 
79
 
void ParCoordinator::PostParRenamer::UpdateProgress()
80
 
{
81
 
        m_pOwner->UpdateParRenameProgress();
82
 
}
83
 
 
84
 
void ParCoordinator::PostParRenamer::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
85
 
{
86
 
        char szText[1024];
87
 
        va_list args;
88
 
        va_start(args, szFormat);
89
 
        vsnprintf(szText, 1024, szFormat, args);
90
 
        va_end(args);
91
 
        szText[1024-1] = '\0';
92
 
        
93
 
        m_pOwner->PrintMessage(m_pPostInfo, eKind, "%s", szText);
94
 
}
95
 
#endif
96
 
 
97
 
ParCoordinator::ParCoordinator()
98
 
{
99
 
        debug("Creating ParCoordinator");
100
 
 
101
 
#ifndef DISABLE_PARCHECK
102
 
        m_bStopped = false;
103
 
        m_ParChecker.m_pOwner = this;
104
 
        m_ParRenamer.m_pOwner = this;
105
 
#endif
106
 
}
107
 
 
108
 
ParCoordinator::~ParCoordinator()
109
 
{
110
 
        debug("Destroying ParCoordinator");
111
 
}
112
 
 
113
 
#ifndef DISABLE_PARCHECK
114
 
void ParCoordinator::Stop()
115
 
{
116
 
        debug("Stopping ParCoordinator");
117
 
 
118
 
        m_bStopped = true;
119
 
 
120
 
        if (m_ParChecker.IsRunning())
121
 
        {
122
 
                m_ParChecker.Stop();
123
 
                int iMSecWait = 5000;
124
 
                while (m_ParChecker.IsRunning() && iMSecWait > 0)
125
 
                {
126
 
                        usleep(50 * 1000);
127
 
                        iMSecWait -= 50;
128
 
                }
129
 
                if (m_ParChecker.IsRunning())
130
 
                {
131
 
                        warn("Terminating par-check for %s", m_ParChecker.GetInfoName());
132
 
                        m_ParChecker.Kill();
133
 
                }
134
 
        }
135
 
}
136
 
#endif
137
 
 
138
 
void ParCoordinator::PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
139
 
{
140
 
        debug("ParCoordinator: Pausing pars");
141
 
        
142
 
        for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
143
 
        {
144
 
                FileInfo* pFileInfo = *it;
145
 
                if (pFileInfo->GetNZBInfo() == pNZBInfo)
146
 
                {
147
 
                        g_pQueueCoordinator->GetQueueEditor()->LockedEditEntry(pDownloadQueue, pFileInfo->GetID(), false, 
148
 
                                QueueEditor::eaGroupPauseExtraPars, 0, NULL);
149
 
                        break;
150
 
                }
151
 
        }
152
 
}
153
 
 
154
 
bool ParCoordinator::FindMainPars(const char* szPath, FileList* pFileList)
155
 
{
156
 
        if (pFileList)
157
 
        {
158
 
                pFileList->clear();
159
 
        }
160
 
 
161
 
        DirBrowser dir(szPath);
162
 
        while (const char* filename = dir.Next())
163
 
        {
164
 
                int iBaseLen = 0;
165
 
                if (ParseParFilename(filename, &iBaseLen, NULL))
166
 
                {
167
 
                        if (!pFileList)
168
 
                        {
169
 
                                return true;
170
 
                        }
171
 
 
172
 
                        // check if the base file already added to list
173
 
                        bool exists = false;
174
 
                        for (FileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
175
 
                        {
176
 
                                const char* filename2 = *it;
177
 
                                exists = SameParCollection(filename, filename2);
178
 
                                if (exists)
179
 
                                {
180
 
                                        break;
181
 
                                }
182
 
                        }
183
 
                        if (!exists)
184
 
                        {
185
 
                                pFileList->push_back(strdup(filename));
186
 
                        }
187
 
                }
188
 
        }
189
 
        return pFileList && !pFileList->empty();
190
 
}
191
 
 
192
 
bool ParCoordinator::SameParCollection(const char* szFilename1, const char* szFilename2)
193
 
{
194
 
        int iBaseLen1 = 0, iBaseLen2 = 0;
195
 
        return ParseParFilename(szFilename1, &iBaseLen1, NULL) &&
196
 
                ParseParFilename(szFilename2, &iBaseLen2, NULL) &&
197
 
                iBaseLen1 == iBaseLen2 &&
198
 
                !strncasecmp(szFilename1, szFilename2, iBaseLen1);
199
 
}
200
 
 
201
 
bool ParCoordinator::ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks)
202
 
{
203
 
        char szFilename[1024];
204
 
        strncpy(szFilename, szParFilename, 1024);
205
 
        szFilename[1024-1] = '\0';
206
 
        for (char* p = szFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
207
 
 
208
 
        int iLen = strlen(szFilename);
209
 
        if (iLen < 6)
210
 
        {
211
 
                return false;
212
 
        }
213
 
 
214
 
        // find last occurence of ".par2" and trim filename after it
215
 
        char* szEnd = szFilename;
216
 
        while (char* p = strstr(szEnd, ".par2")) szEnd = p + 5;
217
 
        *szEnd = '\0';
218
 
        iLen = strlen(szFilename);
219
 
        
220
 
        if (strcasecmp(szFilename + iLen - 5, ".par2"))
221
 
        {
222
 
                return false;
223
 
        }
224
 
        *(szFilename + iLen - 5) = '\0';
225
 
 
226
 
        int blockcnt = 0;
227
 
        char* p = strrchr(szFilename, '.');
228
 
        if (p && !strncasecmp(p, ".vol", 4))
229
 
        {
230
 
                char* b = strchr(p, '+');
231
 
                if (!b)
232
 
                {
233
 
                        b = strchr(p, '-');
234
 
                }
235
 
                if (b)
236
 
                {
237
 
                        blockcnt = atoi(b+1);
238
 
                        *p = '\0';
239
 
                }
240
 
        }
241
 
 
242
 
        if (iBaseNameLen)
243
 
        {
244
 
                *iBaseNameLen = strlen(szFilename);
245
 
        }
246
 
        if (iBlocks)
247
 
        {
248
 
                *iBlocks = blockcnt;
249
 
        }
250
 
        
251
 
        return true;
252
 
}
253
 
 
254
 
#ifndef DISABLE_PARCHECK
255
 
 
256
 
/**
257
 
 * DownloadQueue must be locked prior to call of this function.
258
 
 */
259
 
void ParCoordinator::StartParCheckJob(PostInfo* pPostInfo)
260
 
{
261
 
        m_eCurrentJob = jkParCheck;
262
 
        m_ParChecker.SetPostInfo(pPostInfo);
263
 
        m_ParChecker.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
264
 
        m_ParChecker.SetNZBName(pPostInfo->GetNZBInfo()->GetName());
265
 
        m_ParChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", pPostInfo->GetInfoName());
266
 
        pPostInfo->SetWorking(true);
267
 
        m_ParChecker.Start();
268
 
}
269
 
 
270
 
/**
271
 
 * DownloadQueue must be locked prior to call of this function.
272
 
 */
273
 
void ParCoordinator::StartParRenameJob(PostInfo* pPostInfo)
274
 
{
275
 
        m_eCurrentJob = jkParRename;
276
 
        m_ParRenamer.SetPostInfo(pPostInfo);
277
 
        m_ParRenamer.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
278
 
        m_ParRenamer.SetInfoName(pPostInfo->GetNZBInfo()->GetName());
279
 
        m_ParRenamer.PrintMessage(Message::mkInfo, "Checking renamed files for %s", pPostInfo->GetNZBInfo()->GetName());
280
 
        pPostInfo->SetWorking(true);
281
 
        m_ParRenamer.Start();
282
 
}
283
 
 
284
 
bool ParCoordinator::Cancel()
285
 
{
286
 
        if (m_eCurrentJob == jkParCheck)
287
 
        {
288
 
#ifdef HAVE_PAR2_CANCEL
289
 
                if (!m_ParChecker.GetCancelled())
290
 
                {
291
 
                        debug("Cancelling par-repair for %s", m_ParChecker.GetInfoName());
292
 
                        m_ParChecker.Cancel();
293
 
                        return true;
294
 
                }
295
 
#else
296
 
                warn("Cannot cancel par-repair for %s, used version of libpar2 does not support cancelling", m_ParChecker.GetInfoName());
297
 
#endif
298
 
        }
299
 
        else if (m_eCurrentJob == jkParRename)
300
 
        {
301
 
                if (!m_ParRenamer.GetCancelled())
302
 
                {
303
 
                        debug("Cancelling par-rename for %s", m_ParRenamer.GetInfoName());
304
 
                        m_ParRenamer.Cancel();
305
 
                        return true;
306
 
                }
307
 
        }
308
 
        return false;
309
 
}
310
 
 
311
 
/**
312
 
 * DownloadQueue must be locked prior to call of this function.
313
 
 */
314
 
bool ParCoordinator::AddPar(FileInfo* pFileInfo, bool bDeleted)
315
 
{
316
 
        bool bSameCollection = m_ParChecker.IsRunning() &&
317
 
                pFileInfo->GetNZBInfo() == m_ParChecker.GetPostInfo()->GetNZBInfo() &&
318
 
                SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(m_ParChecker.GetParFilename()));
319
 
        if (bSameCollection && !bDeleted)
320
 
        {
321
 
                char szFullFilename[1024];
322
 
                snprintf(szFullFilename, 1024, "%s%c%s", pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, pFileInfo->GetFilename());
323
 
                szFullFilename[1024-1] = '\0';
324
 
                m_ParChecker.AddParFile(szFullFilename);
325
 
 
326
 
                if (g_pOptions->GetParPauseQueue())
327
 
                {
328
 
                        PauseDownload();
329
 
                }
330
 
        }
331
 
        else
332
 
        {
333
 
                m_ParChecker.QueueChanged();
334
 
        }
335
 
        return bSameCollection;
336
 
}
337
 
 
338
 
void ParCoordinator::ParCheckCompleted()
339
 
{
340
 
        DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
341
 
 
342
 
        PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
343
 
 
344
 
        // Update ParStatus (accumulate result)
345
 
        if ((m_ParChecker.GetStatus() == ParChecker::psRepaired ||
346
 
                m_ParChecker.GetStatus() == ParChecker::psRepairNotNeeded) &&
347
 
                pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
348
 
        {
349
 
                pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSuccess);
350
 
        }
351
 
        else if (m_ParChecker.GetStatus() == ParChecker::psRepairPossible &&
352
 
                pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)
353
 
        {
354
 
                pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psRepairPossible);
355
 
        }
356
 
        else
357
 
        {
358
 
                pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
359
 
        }
360
 
 
361
 
        pPostInfo->SetWorking(false);
362
 
        pPostInfo->SetStage(PostInfo::ptQueued);
363
 
 
364
 
        if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
365
 
        {
366
 
                g_pDiskState->SaveDownloadQueue(pDownloadQueue);
367
 
        }
368
 
 
369
 
        g_pQueueCoordinator->UnlockQueue();
370
 
}
371
 
 
372
 
/**
373
 
* Unpause par2-files
374
 
* returns true, if the files with required number of blocks were unpaused,
375
 
* or false if there are no more files in queue for this collection or not enough blocks
376
 
*/
377
 
bool ParCoordinator::RequestMorePars(NZBInfo* pNZBInfo, const char* szParFilename, int iBlockNeeded, int* pBlockFound)
378
 
{
379
 
        DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
380
 
        
381
 
        Blocks blocks;
382
 
        blocks.clear();
383
 
        int iBlockFound = 0;
384
 
    int iCurBlockFound = 0;
385
 
 
386
 
        FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, true, true, &iCurBlockFound);
387
 
    iBlockFound += iCurBlockFound;
388
 
        if (iBlockFound < iBlockNeeded)
389
 
        {
390
 
                FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, true, false, &iCurBlockFound);
391
 
        iBlockFound += iCurBlockFound;
392
 
        }
393
 
        if (iBlockFound < iBlockNeeded && !g_pOptions->GetStrictParName())
394
 
        {
395
 
                FindPars(pDownloadQueue, pNZBInfo, szParFilename, &blocks, false, false, &iCurBlockFound);
396
 
        iBlockFound += iCurBlockFound;
397
 
        }
398
 
 
399
 
        if (iBlockFound >= iBlockNeeded)
400
 
        {
401
 
                // 1. first unpause all files with par-blocks less or equal iBlockNeeded
402
 
                // starting from the file with max block count.
403
 
                // if par-collection was built exponentially and all par-files present,
404
 
                // this step selects par-files with exact number of blocks we need.
405
 
                while (iBlockNeeded > 0)
406
 
                {               
407
 
                        BlockInfo* pBestBlockInfo = NULL;
408
 
                        for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
409
 
                        {
410
 
                                BlockInfo* pBlockInfo = *it;
411
 
                                if (pBlockInfo->m_iBlockCount <= iBlockNeeded &&
412
 
                                   (!pBestBlockInfo || pBestBlockInfo->m_iBlockCount < pBlockInfo->m_iBlockCount))
413
 
                                {
414
 
                                        pBestBlockInfo = pBlockInfo;
415
 
                                }
416
 
                        }
417
 
                        if (pBestBlockInfo)
418
 
                        {
419
 
                                if (pBestBlockInfo->m_pFileInfo->GetPaused())
420
 
                                {
421
 
                                        m_ParChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", pNZBInfo->GetName(), (int)PATH_SEPARATOR, pBestBlockInfo->m_pFileInfo->GetFilename());
422
 
                                        pBestBlockInfo->m_pFileInfo->SetPaused(false);
423
 
                                        pBestBlockInfo->m_pFileInfo->SetExtraPriority(true);
424
 
                                }
425
 
                                iBlockNeeded -= pBestBlockInfo->m_iBlockCount;
426
 
                                blocks.remove(pBestBlockInfo);
427
 
                                delete pBestBlockInfo;
428
 
                        }
429
 
                        else
430
 
                        {
431
 
                                break;
432
 
                        }
433
 
                }
434
 
                        
435
 
                // 2. then unpause other files
436
 
                // this step only needed if the par-collection was built not exponentially 
437
 
                // or not all par-files present (or some of them were corrupted)
438
 
                // this step is not optimal, but we hope, that the first step will work good 
439
 
                // in most cases and we will not need the second step often
440
 
                while (iBlockNeeded > 0)
441
 
                {
442
 
                        BlockInfo* pBlockInfo = blocks.front();
443
 
                        if (pBlockInfo->m_pFileInfo->GetPaused())
444
 
                        {
445
 
                                m_ParChecker.PrintMessage(Message::mkInfo, "Unpausing %s%c%s for par-recovery", pNZBInfo->GetName(), (int)PATH_SEPARATOR, pBlockInfo->m_pFileInfo->GetFilename());
446
 
                                pBlockInfo->m_pFileInfo->SetPaused(false);
447
 
                                pBlockInfo->m_pFileInfo->SetExtraPriority(true);
448
 
                        }
449
 
                        iBlockNeeded -= pBlockInfo->m_iBlockCount;
450
 
                }
451
 
        }
452
 
 
453
 
        g_pQueueCoordinator->UnlockQueue();
454
 
 
455
 
        if (pBlockFound)
456
 
        {
457
 
                *pBlockFound = iBlockFound;
458
 
        }
459
 
 
460
 
        for (Blocks::iterator it = blocks.begin(); it != blocks.end(); it++)
461
 
        {
462
 
                delete *it;
463
 
        }
464
 
        blocks.clear();
465
 
 
466
 
        bool bOK = iBlockNeeded <= 0;
467
 
 
468
 
        if (bOK && g_pOptions->GetParPauseQueue())
469
 
        {
470
 
                UnpauseDownload();
471
 
        }
472
 
 
473
 
        return bOK;
474
 
}
475
 
 
476
 
void ParCoordinator::FindPars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szParFilename,
477
 
        Blocks* pBlocks, bool bStrictParName, bool bExactParName, int* pBlockFound)
478
 
{
479
 
    *pBlockFound = 0;
480
 
        
481
 
        // extract base name from m_szParFilename (trim .par2-extension and possible .vol-part)
482
 
        char* szBaseParFilename = Util::BaseFileName(szParFilename);
483
 
        char szMainBaseFilename[1024];
484
 
        int iMainBaseLen = 0;
485
 
        if (!ParseParFilename(szBaseParFilename, &iMainBaseLen, NULL))
486
 
        {
487
 
                // should not happen
488
 
        error("Internal error: could not parse filename %s", szBaseParFilename);
489
 
                return;
490
 
        }
491
 
        int maxlen = iMainBaseLen < 1024 ? iMainBaseLen : 1024 - 1;
492
 
        strncpy(szMainBaseFilename, szBaseParFilename, maxlen);
493
 
        szMainBaseFilename[maxlen] = '\0';
494
 
        for (char* p = szMainBaseFilename; *p; p++) *p = tolower(*p); // convert string to lowercase
495
 
 
496
 
        for (FileQueue::iterator it = pDownloadQueue->GetFileQueue()->begin(); it != pDownloadQueue->GetFileQueue()->end(); it++)
497
 
        {
498
 
                FileInfo* pFileInfo = *it;
499
 
                int iBlocks = 0;
500
 
                if (pFileInfo->GetNZBInfo() == pNZBInfo &&
501
 
                        ParseParFilename(pFileInfo->GetFilename(), NULL, &iBlocks) &&
502
 
                        iBlocks > 0)
503
 
                {
504
 
                        bool bUseFile = true;
505
 
 
506
 
                        if (bExactParName)
507
 
                        {
508
 
                                bUseFile = SameParCollection(pFileInfo->GetFilename(), Util::BaseFileName(szParFilename));
509
 
                        }
510
 
                        else if (bStrictParName)
511
 
                        {
512
 
                                // the pFileInfo->GetFilename() may be not confirmed and may contain
513
 
                                // additional texts if Subject could not be parsed correctly
514
 
 
515
 
                                char szLoFileName[1024];
516
 
                                strncpy(szLoFileName, pFileInfo->GetFilename(), 1024);
517
 
                                szLoFileName[1024-1] = '\0';
518
 
                                for (char* p = szLoFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
519
 
                                
520
 
                                char szCandidateFileName[1024];
521
 
                                snprintf(szCandidateFileName, 1024, "%s.par2", szMainBaseFilename);
522
 
                                szCandidateFileName[1024-1] = '\0';
523
 
                                if (!strstr(szLoFileName, szCandidateFileName))
524
 
                                {
525
 
                                        snprintf(szCandidateFileName, 1024, "%s.vol", szMainBaseFilename);
526
 
                                        szCandidateFileName[1024-1] = '\0';
527
 
                                        bUseFile = strstr(szLoFileName, szCandidateFileName);
528
 
                                }
529
 
                        }
530
 
 
531
 
            bool bAlreadyAdded = false;
532
 
            // check if file is not in the list already
533
 
                        if (bUseFile)
534
 
                        {
535
 
                                for (Blocks::iterator it = pBlocks->begin(); it != pBlocks->end(); it++)
536
 
                                {
537
 
                                        BlockInfo* pBlockInfo = *it;
538
 
                                        if (pBlockInfo->m_pFileInfo == pFileInfo)
539
 
                                        {
540
 
                                                bAlreadyAdded = true;
541
 
                                                break;
542
 
                        }
543
 
                        }
544
 
                        }
545
 
                
546
 
                        // if it is a par2-file with blocks and it was from the same NZB-request
547
 
                        // and it belongs to the same file collection (same base name),
548
 
                        // then OK, we can use it
549
 
            if (bUseFile && !bAlreadyAdded)
550
 
            {
551
 
                                BlockInfo* pBlockInfo = new BlockInfo();
552
 
                                pBlockInfo->m_pFileInfo = pFileInfo;
553
 
                                pBlockInfo->m_iBlockCount = iBlocks;
554
 
                                pBlocks->push_back(pBlockInfo);
555
 
                                *pBlockFound += iBlocks;
556
 
                        }
557
 
                }
558
 
        }
559
 
}
560
 
 
561
 
void ParCoordinator::UpdateParCheckProgress()
562
 
{
563
 
        g_pQueueCoordinator->LockQueue();
564
 
 
565
 
        PostInfo* pPostInfo = m_ParChecker.GetPostInfo();
566
 
        if (m_ParChecker.GetFileProgress() == 0)
567
 
        {
568
 
                pPostInfo->SetProgressLabel(m_ParChecker.GetProgressLabel());
569
 
        }
570
 
        pPostInfo->SetFileProgress(m_ParChecker.GetFileProgress());
571
 
        pPostInfo->SetStageProgress(m_ParChecker.GetStageProgress());
572
 
    PostInfo::EStage StageKind[] = { PostInfo::ptLoadingPars, PostInfo::ptVerifyingSources, PostInfo::ptRepairing, PostInfo::ptVerifyingRepaired };
573
 
        PostInfo::EStage eStage = StageKind[m_ParChecker.GetStage()];
574
 
        time_t tCurrent = time(NULL);
575
 
 
576
 
        if (!pPostInfo->GetStartTime())
577
 
        {
578
 
                pPostInfo->SetStartTime(tCurrent);
579
 
        }
580
 
 
581
 
        if (pPostInfo->GetStage() != eStage)
582
 
        {
583
 
                pPostInfo->SetStage(eStage);
584
 
                pPostInfo->SetStageTime(tCurrent);
585
 
        }
586
 
 
587
 
        bool bParCancel = false;
588
 
#ifdef HAVE_PAR2_CANCEL
589
 
        if (!m_ParChecker.GetCancelled())
590
 
        {
591
 
                if ((g_pOptions->GetParTimeLimit() > 0) &&
592
 
                        m_ParChecker.GetStage() == ParChecker::ptRepairing &&
593
 
                        ((g_pOptions->GetParTimeLimit() > 5 && tCurrent - pPostInfo->GetStageTime() > 5 * 60) ||
594
 
                        (g_pOptions->GetParTimeLimit() <= 5 && tCurrent - pPostInfo->GetStageTime() > 1 * 60)))
595
 
                {
596
 
                        // first five (or one) minutes elapsed, now can check the estimated time
597
 
                        int iEstimatedRepairTime = (int)((tCurrent - pPostInfo->GetStartTime()) * 1000 / 
598
 
                                (pPostInfo->GetStageProgress() > 0 ? pPostInfo->GetStageProgress() : 1));
599
 
                        if (iEstimatedRepairTime > g_pOptions->GetParTimeLimit() * 60)
600
 
                        {
601
 
                                debug("Estimated repair time %i seconds", iEstimatedRepairTime);
602
 
                                m_ParChecker.PrintMessage(Message::mkWarning, "Cancelling par-repair for %s, estimated repair time (%i minutes) exceeds allowed repair time", m_ParChecker.GetInfoName(), iEstimatedRepairTime / 60);
603
 
                                bParCancel = true;
604
 
                        }
605
 
                }
606
 
        }
607
 
#endif
608
 
 
609
 
        if (bParCancel)
610
 
        {
611
 
                m_ParChecker.Cancel();
612
 
        }
613
 
 
614
 
        g_pQueueCoordinator->UnlockQueue();
615
 
        
616
 
        CheckPauseState(pPostInfo);
617
 
}
618
 
 
619
 
void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
620
 
{
621
 
        if (g_pOptions->GetPausePostProcess())
622
 
        {
623
 
                time_t tStageTime = pPostInfo->GetStageTime();
624
 
                time_t tStartTime = pPostInfo->GetStartTime();
625
 
                time_t tWaitTime = time(NULL);
626
 
                
627
 
                // wait until Post-processor is unpaused
628
 
                while (g_pOptions->GetPausePostProcess() && !m_bStopped)
629
 
                {
630
 
                        usleep(100 * 1000);
631
 
                        
632
 
                        // update time stamps
633
 
                        
634
 
                        time_t tDelta = time(NULL) - tWaitTime;
635
 
                        
636
 
                        if (tStageTime > 0)
637
 
                        {
638
 
                                pPostInfo->SetStageTime(tStageTime + tDelta);
639
 
                        }
640
 
                        
641
 
                        if (tStartTime > 0)
642
 
                        {
643
 
                                pPostInfo->SetStartTime(tStartTime + tDelta);
644
 
                        }
645
 
                }
646
 
        }
647
 
}
648
 
 
649
 
void ParCoordinator::ParRenameCompleted()
650
 
{
651
 
        DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
652
 
        
653
 
        PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
654
 
        pPostInfo->GetNZBInfo()->SetRenameStatus(m_ParRenamer.GetStatus() == ParRenamer::psSuccess ? NZBInfo::rsSuccess : NZBInfo::rsFailure);
655
 
        pPostInfo->SetWorking(false);
656
 
        pPostInfo->SetStage(PostInfo::ptQueued);
657
 
        
658
 
        if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
659
 
        {
660
 
                g_pDiskState->SaveDownloadQueue(pDownloadQueue);
661
 
        }
662
 
        
663
 
        g_pQueueCoordinator->UnlockQueue();
664
 
}
665
 
 
666
 
void ParCoordinator::UpdateParRenameProgress()
667
 
{
668
 
        g_pQueueCoordinator->LockQueue();
669
 
        
670
 
        PostInfo* pPostInfo = m_ParRenamer.GetPostInfo();
671
 
        pPostInfo->SetProgressLabel(m_ParRenamer.GetProgressLabel());
672
 
        pPostInfo->SetStageProgress(m_ParRenamer.GetStageProgress());
673
 
        time_t tCurrent = time(NULL);
674
 
        
675
 
        if (!pPostInfo->GetStartTime())
676
 
        {
677
 
                pPostInfo->SetStartTime(tCurrent);
678
 
        }
679
 
        
680
 
        if (pPostInfo->GetStage() != PostInfo::ptRenaming)
681
 
        {
682
 
                pPostInfo->SetStage(PostInfo::ptRenaming);
683
 
                pPostInfo->SetStageTime(tCurrent);
684
 
        }
685
 
        
686
 
        g_pQueueCoordinator->UnlockQueue();
687
 
        
688
 
        CheckPauseState(pPostInfo);
689
 
}
690
 
 
691
 
void ParCoordinator::PrintMessage(PostInfo* pPostInfo, Message::EKind eKind, const char* szFormat, ...)
692
 
{
693
 
        char szText[1024];
694
 
        va_list args;
695
 
        va_start(args, szFormat);
696
 
        vsnprintf(szText, 1024, szFormat, args);
697
 
        va_end(args);
698
 
        szText[1024-1] = '\0';
699
 
 
700
 
        pPostInfo->AppendMessage(eKind, szText);
701
 
 
702
 
        switch (eKind)
703
 
        {
704
 
                case Message::mkDetail:
705
 
                        detail("%s", szText);
706
 
                        break;
707
 
 
708
 
                case Message::mkInfo:
709
 
                        info("%s", szText);
710
 
                        break;
711
 
 
712
 
                case Message::mkWarning:
713
 
                        warn("%s", szText);
714
 
                        break;
715
 
 
716
 
                case Message::mkError:
717
 
                        error("%s", szText);
718
 
                        break;
719
 
 
720
 
                case Message::mkDebug:
721
 
                        debug("%s", szText);
722
 
                        break;
723
 
        }
724
 
}
725
 
 
726
 
#endif