function handleNzbAction($messageIds, array $currentSession, $action, Services_Providers_FullSpot $svcProvSpot, Services_Providers_Nzb $svcProvNzb)
 {
     if (!is_array($messageIds)) {
         $messageIds = array($messageIds);
     }
     # if
     # Make sure the user has the appropriate permissions
     $currentSession['security']->fatalPermCheck(SpotSecurity::spotsec_retrieve_nzb, '');
     if ($action != 'display') {
         $currentSession['security']->fatalPermCheck(SpotSecurity::spotsec_download_integration, $action);
     }
     # if
     /*
      * Get all the full spots for all of the specified NZB files
      */
     $nzbList = array();
     $fullSpot = array();
     foreach ($messageIds as $thisMsgId) {
         $fullSpot = $svcProvSpot->fetchFullSpot($thisMsgId, $currentSession['user']['userid']);
         if (!empty($fullSpot['nzb'])) {
             $nzbList[] = array('spot' => $fullSpot, 'nzb' => $svcProvNzb->fetchNzb($fullSpot));
         }
         # if
     }
     # foreach
     /*
      * send nzblist to NzbHandler plugin
      */
     $nzbHandlerFactory = new Services_NzbHandler_Factory();
     $nzbHandler = $nzbHandlerFactory->build($this->_settings, $action, $currentSession['user']['prefs']['nzbhandling']);
     $nzbHandler->processNzb($fullSpot, $nzbList);
     /*
      * and mark the spot as downloaded
      */
     if ($currentSession['user']['prefs']['keep_downloadlist']) {
         if ($currentSession['security']->allowed(SpotSecurity::spotsec_keep_own_downloadlist, '')) {
             $spotStateListDao = $this->_daoFactory->getSpotStateListDao();
             foreach ($messageIds as $thisMsgId) {
                 $spotStateListDao->addToDownloadList($thisMsgId, $currentSession['user']['userid']);
             }
             # foreach
         }
         # if
     }
     # if
     # and send notifications
     $spotsNotifications = new SpotNotifications($this->_daoFactory, $this->_settings, $currentSession);
     $spotsNotifications->sendNzbHandled($action, $fullSpot);
 }
Beispiel #2
0
  */
 $daoFactory->setCachePath('./cache/');
 $cacheDao = $daoFactory->getCacheDao();
 if (!is_dir('./cache')) {
     mkdir('./cache', 0777);
 }
 # if
 /*
  * Now try to get all current cache items
  */
 $dbConnection = $daoFactory->getConnection();
 /*
  * Initialize the NZB retrieval provider
  */
 $svcFullSpot = new Services_Providers_FullSpot($daoFactory->getSpotDao(), new Services_Nntp_SpotReading(Services_Nntp_EnginePool::pool($settings, 'hdr')));
 $svcNzb = new Services_Providers_Nzb($cacheDao, new Services_Nntp_SpotReading(Services_Nntp_EnginePool::pool($settings, 'bin')));
 $svcPrvHttp = new Services_Providers_Http($cacheDao);
 $svcImage = new Services_Providers_SpotImage($svcPrvHttp, new Services_Nntp_SpotReading(Services_Nntp_EnginePool::pool($settings, 'bin')), $cacheDao);
 $counter = 0;
 while (true) {
     $counter++;
     echo "Validating cache content, items " . ($counter - 1) * 1000 . ' to ' . $counter * 1000;
     $results = $dbConnection->arrayQuery("SELECT * FROM cache LIMIT 1001 OFFSET " . ($counter - 1) * 1000);
     foreach ($results as $cacheItem) {
         $cacheItem['metadata'] = unserialize($cacheItem['metadata']);
         try {
             $cacheDao->getCacheContent($cacheItem['id'], $cacheItem['cachetype'], $cacheItem['metadata']);
         } catch (CacheIsCorruptException $x) {
             echo PHP_EOL . '  Trying to fetch #' . $cacheItem['id'] . ' for ' . $cacheItem['resourceid'] . ' again, ';
             switch ($cacheItem['cachetype']) {
                 case Dao_Cache::SpotNzb:
 function process($hdrList, $curArtNr, $increment, $timer)
 {
     $this->displayStatus("progress", $curArtNr . " till " . $increment);
     $signedCount = 0;
     $hdrsParsed = 0;
     $fullsRetrieved = 0;
     $invalidCount = 0;
     $msgCounter = 0;
     $modCount = 0;
     $headerInDbCount = 0;
     $skipCount = 0;
     $lastProcessedId = '';
     $lastProcessedArtNr = 0;
     $fullSpotDbList = array();
     $spotDbList = array();
     $moderationList = array();
     $processingStartTime = time();
     /*
      * Determine the cutoff date (unixtimestamp) from whereon we do not want to 
      * load the spots
      */
     if ($this->_settings->get('retention') > 0) {
         $retentionStamp = time() - $this->_settings->get('retention') * 24 * 60 * 60;
     } else {
         $retentionStamp = 0;
     }
     # else
     SpotDebug::msg(SpotDebug::DEBUG, 'retentionStamp=' . $retentionStamp);
     SpotDebug::msg(SpotDebug::TRACE, 'hdrList=' . serialize($hdrList));
     /**
      * We ask the database to match our messageid's we just retrieved with
      * the list of id's we have just retrieved from the server
      */
     SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':matchSpotMessageIds');
     $dbIdList = $this->_spotDao->matchSpotMessageIds($hdrList);
     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':matchSpotMessageIds');
     SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':getMassCacheRecords');
     $cachedIdList = $this->_cacheDao->getMassCacheRecords($hdrList);
     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':getMassCacheRecords');
     SpotDebug::msg(SpotDebug::TRACE, 'dbIdList=' . serialize($dbIdList));
     /*
      * We get a list of spots which have been blacklisted before,
      * we do this because when the 'buggy' flag is set, we else keep
      * retrieving the same spots, nzb's and images over and over again
      */
     $preModdedList = $this->_modListDao->matchAgainst($hdrList);
     SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach');
     foreach ($hdrList as $msgheader) {
         SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
         $msgCounter++;
         SpotDebug::msg(SpotDebug::DEBUG, 'foreach-loop, start. msgId= ' . $msgCounter);
         /* 
          * Keep te usenet server alive when processing is slow.
          */
         if ($processingStartTime - time() > 30) {
             $this->_svcNntpText->sendNoop();
             $this->_svcNntpBin->sendNoop();
             $processingStartTime = time();
         }
         # if
         /*
          * We keep track whether we actually fetched this header and fullspot
          * to add it to the database, because only then we can update the
          * title from the spots title or rely on our database to fetch
          * the fullspot
          */
         $didFetchHeader = false;
         $didFetchFullSpot = false;
         # Reset timelimit
         set_time_limit(120);
         # messageid to check
         $msgId = $msgheader['Message-ID'];
         $artNr = $msgheader['Number'];
         /*
          * If this message was already deleted in a previous run,
          * les not even consider it
          */
         if (isset($preModdedList[$msgId])) {
             SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
             $skipCount++;
             continue;
         }
         # if
         /*
          * We prepare some variables to we don't have to perform an array
          * lookup for each check and the code is easier to read.
          */
         $header_isInDb = isset($dbIdList['spot'][$msgId]);
         $fullspot_isInDb = isset($dbIdList['fullspot'][$msgId]);
         /*
          * If the spotheader is not yet added to the database, parse the header
          * information.
          *
          * If the header is present, but we don't have the fullspot yet or we are
          * running in 'retro' mode, parse the header as well because some fields
          * are only in the header and not in the full.
          * 
          * We need some of those fields (for example KeyID)
          */
         if (!$header_isInDb || (!$fullspot_isInDb || $this->_retro) && $this->_retrieveFull) {
             $hdrsParsed++;
             SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, parsingXover, start. msgId= ' . $msgCounter);
             SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':parseHeader');
             $spot = $this->_svcSpotParser->parseHeader($msgheader['Subject'], $msgheader['From'], $msgheader['Date'], $msgheader['Message-ID'], $this->_rsakeys);
             SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':parseHeader');
             SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, parsingXover, done. msgId= ' . $msgCounter);
             /*
              * When a parse error occurred, we ignore the spot, also unverified
              * spots are ignored
              */
             if ($spot === false || !$spot['verified']) {
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
                 $invalidCount++;
                 continue;
             }
             # if
             /*
              * Special moderator commands always have keyid 2
              */
             if ($spot['keyid'] == 2) {
                 $commandAr = explode(' ', $spot['title']);
                 $validCommands = array('delete', 'dispose', 'remove');
                 # is this one of the defined valid commands?
                 if (in_array(strtolower($commandAr[0]), $validCommands) !== false) {
                     $moderationList[$commandAr[1]] = 1;
                     $modCount++;
                 }
                 # if
             } else {
                 /*
                  * Don't add spots older than specified for the retention stamp
                  */
                 if ($retentionStamp > 0 && $spot['stamp'] < $retentionStamp && $this->_settings->get('retentiontype') == 'everything') {
                     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
                     $skipCount++;
                     continue;
                 } elseif ($spot['stamp'] < $this->_settings->get('retrieve_newer_than')) {
                     $skipCount++;
                 } else {
                     /*
                      * Do we have the header in the database? If not, lets add it
                      */
                     if (!$header_isInDb) {
                         $spotDbList[] = $spot;
                         /*
                          * Some buggy NNTP servers give us the same messageid
                          * in one XOVER statement, hence we update the list of
                          * messageid's we already have retrieved and are ready
                          * to be added to the database
                          */
                         $dbIdList['spot'][$msgId] = 1;
                         $header_isInDb = true;
                         $lastProcessedId = $msgId;
                         $lastProcessedArtNr = $artNr;
                         $didFetchHeader = true;
                         if ($spot['wassigned']) {
                             $signedCount++;
                         }
                         # if
                     }
                     # if
                 }
                 # if
             }
             # else
         } else {
             $lastProcessedId = $msgId;
             $lastProcessedArtNr = $artNr;
             $headerInDbCount++;
         }
         # else
         SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getFullSpot');
         /*
          * We don't want to retrieve the fullspot if we don't have the header
          * in the database. Because we try to add headers in the above code we just have
          * to check if the header is in the database.
          *
          * We cannot collapse this code with the header fetching code because we want to
          * be able to add the fullspot to a system after all the headers are retrieved
          */
         if ($header_isInDb && !$fullspot_isInDb) {
             /*
              * Don't add older fullspots than specified for the retention stamp
              */
             if ($retentionStamp > 0 && strtotime($msgheader['Date']) < $retentionStamp) {
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getFullSpot');
                 continue;
             }
             # if
             if ($this->_retrieveFull) {
                 $fullSpot = array();
                 try {
                     $fullsRetrieved++;
                     SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getFullSpot, start. msgId= ' . $msgId);
                     $fullSpot = $this->_svcNntpTextReading->readFullSpot($msgId);
                     SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getFullSpot, done. msgId= ' . $msgId);
                     # did we fail to parse the spot? if so, skip this one
                     if (empty($fullSpot)) {
                         $invalidCount++;
                         continue;
                     }
                     // if
                     # add this spot to the database
                     $fullSpotDbList[] = $fullSpot;
                     $fullspot_isInDb = true;
                     $didFetchFullSpot = true;
                     /*
                      * Some buggy NNTP servers give us the same messageid
                      * in the same XOVER statement, hence we update the list of
                      * messageid's we already have retrieved and are ready
                      * to be added to the database
                      */
                     $dbIdList['fullspot'][$msgId] = 1;
                     /*
                      * Overwrite the spots' title because the fullspot contains the title in
                      * UTF-8 format.
                      * We also overwrite the spotterid from the spotsfull because the spotterid
                      * is only in the header in more recent spots.
                      */
                     if ($didFetchHeader) {
                         $spotDbList[count($spotDbList) - 1]['title'] = $fullSpot['title'];
                         $spotDbList[count($spotDbList) - 1]['spotterid'] = $fullSpot['spotterid'];
                     }
                     # if
                 } catch (ParseSpotXmlException $x) {
                     # swallow error
                 } catch (Exception $x) {
                     /**
                      * Sometimes we get an 'No such article' error for a header we just retrieved,
                      * if we want to retrieve the full article. This is messed up, but let's just
                      * swallow the error
                      */
                     if ($x->getCode() == 430) {
                         /*
                          * Reset error count, so other errors are actually re-tried
                          */
                         $this->_svcNntpText->resetErrorCount();
                         $this->_svcNntpBin->resetErrorCount();
                     } elseif ($x->getMessage() == 'String could not be parsed as XML') {
                     } else {
                         throw $x;
                     }
                     # else
                 }
                 # catch
             }
             # if retrievefull
         }
         # if fullspot is not in db yet
         SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getFullSpot');
         SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getNzbOrImage');
         /*
          * If both the image and the NZB file are already in the cache,
          * or we are set to not prefetch them, don't bother to retrieve
          * the full spot either from the database
          */
         $needPrefetch = $this->_prefetch_image || $this->_prefetch_nzb;
         if (!$this->_retrieveFull || !$header_isInDb) {
             $needPrefetch = false;
         }
         # if
         if ($needPrefetch) {
             $needPrefetch = !isset($cachedIdList[Dao_Cache::SpotImage][$msgId]) || !isset($cachedIdList[Dao_Cache::SpotNzb][$msgId]);
         }
         # if
         if ($needPrefetch) {
             try {
                 /*
                  * If we are running in 'retro' mode, it is possible both the header and spot are in the
                  * database already, however -- we need the information from the fullspot so we retrieve it
                  * again
                  */
                 if (!$didFetchFullSpot) {
                     SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':daoGetFullSpot');
                     $fullSpot = $this->_spotDao->getFullSpot($msgId, SPOTWEB_ANONYMOUS_USERID);
                     SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':retrieveParseFullSpot');
                     $fullSpot = array_merge($this->_svcSpotParser->parseFull($fullSpot['fullxml']), $fullSpot);
                     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':retrieveParseFullSpot', array());
                     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':daoGetFullSpot');
                 }
                 # if
                 /*
                  * Prefetch (cache) the spots' image
                  */
                 SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getImage');
                 if ($this->_prefetch_image) {
                     SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getImage(), start. msgId= ' . $msgId);
                     if (!isset($cachedIdList[Dao_Cache::SpotImage][$fullSpot['messageid']])) {
                         $this->_svcProvImage->fetchSpotImage($fullSpot);
                     }
                     # if
                     SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getImage(), done. msgId= ' . $msgId);
                 }
                 # if
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getImage');
                 SpotTiming::start(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getNzb');
                 /*
                  * Prefetch (cache) the spots' NZB file
                  */
                 if ($this->_prefetch_nzb) {
                     /*
                      * Only do so if we can expect an NZB file
                      */
                     if (!empty($fullSpot['nzb']) && $fullSpot['stamp'] > 1290578400) {
                         SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getNzb(), start. msgId= ' . $msgId);
                         if (!isset($cachedIdList[Dao_Cache::SpotNzb][$fullSpot['messageid']])) {
                             $this->_svcProvNzb->fetchNzb($fullSpot);
                         }
                         # if
                         SpotDebug::msg(SpotDebug::TRACE, 'foreach-loop, getNzb(), done. msgId= ' . $msgId);
                     }
                     # if
                 }
                 # if
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getNzb');
             } catch (ParseSpotXmlException $x) {
                 # swallow error
             } catch (Exception $x) {
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':retrieveParseFullSpot', array());
                 SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':daoGetFullSpot');
                 /**
                  * Sometimes we get an 'No such article' error for a header we just retrieved,
                  * if we want to retrieve the full article. This is messed up, but let's just
                  * swallow the error
                  */
                 if ($x->getCode() == 430) {
                     /*
                      * Reset error count, so other errors are actually re-tried
                      */
                     $this->_svcNntpText->resetErrorCount();
                     $this->_svcNntpBin->resetErrorCount();
                 } elseif ($x->getMessage() == 'String could not be parsed as XML') {
                 } else {
                     throw $x;
                 }
                 # else
             }
             # catch
         }
         # if prefetch image and/or nzb
         SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-getNzbOrImage');
         SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach-to-ParseHeader');
         /*
          * If we are under memory pressure, flush the cache to disk in advance so we
          * can free up memory. This is slower, but might avoid ballooning memory.
          */
         if ($this->hasMemoryPressure()) {
             SpotDebug::msg(SpotDebug::DEBUG, 'we are under memory pressure, flushing to disk');
             echo "We are under memory pressure... ";
             $this->_spotDao->addSpots($spotDbList, $fullSpotDbList);
             $spotDbList = array();
             $fullSpotDbList = array();
         }
         // if
         SpotDebug::msg(SpotDebug::DEBUG, 'foreach-loop, done. msgId= ' . $msgCounter);
     }
     # foreach
     SpotTiming::stop(__CLASS__ . '::' . __FUNCTION__ . ':forEach');
     if (count($hdrList) > 0) {
         $this->displayStatus("hdrparsed", $hdrsParsed);
         $this->displayStatus("hdrindbcount", $headerInDbCount);
         $this->displayStatus("verified", $signedCount);
         $this->displayStatus("invalidcount", $invalidCount);
         $this->displayStatus("skipcount", $skipCount);
         $this->displayStatus("modcount", $modCount);
         $this->displayStatus("fullretrieved", $fullsRetrieved);
         $this->displayStatus("loopcount", count($hdrList));
     } else {
         $this->displayStatus("hdrparsed", 0);
         $this->displayStatus("hdrindbcount", 0);
         $this->displayStatus("verified", 0);
         $this->displayStatus("invalidcount", 0);
         $this->displayStatus("skipcount", 0);
         $this->displayStatus("modcount", 0);
         $this->displayStatus("fullretrieved", 0);
         $this->displayStatus("loopcount", 0);
     }
     # else
     /* 
      * Add the spots to the database and update the last article
      * number found
      */
     $this->_spotDao->addSpots($spotDbList, $fullSpotDbList);
     SpotDebug::msg(SpotDebug::TRACE, 'added Spots, spotDbList=' . serialize($spotDbList));
     SpotDebug::msg(SpotDebug::TRACE, 'added Spots, fullSpotDbList=' . serialize($fullSpotDbList));
     /*
      * Actually act on the moderation settings. We cannot process this inline
      * because a spot can be added and moderated within the same iteration
      */
     switch ($this->_settings->get('spot_moderation')) {
         case 'disable':
             break;
         case 'markspot':
             $this->_commentDao->markCommentsModerated($moderationList);
             $this->_spotDao->markSpotsModerated($moderationList);
             break;
             # case 'markspot'
         # case 'markspot'
         default:
             $this->_spotDao->removeSpots($moderationList);
             $this->_commentDao->removeComments($moderationList);
             /*
              * If the spots actually get removed, we want to make
              * sure we write the deleted spots down. This prevents
              * us from retrieving and deleting them over and over again
              */
             $this->_modListDao->addToRingBuffer($moderationList);
             break;
             # default
     }
     # switch
     # update the maximum article id
     if (!empty($lastProcessedId) && $lastProcessedArtNr > 0) {
         $this->_usenetStateDao->setMaxArticleId(Dao_UsenetState::State_Spots, $lastProcessedArtNr, $lastProcessedId);
     }
     # if
     SpotDebug::msg(SpotDebug::DEBUG, 'loop finished, setMaxArticleId=' . serialize($increment));
     /*
      * And remove old list of moderated spots
      */
     $this->_modListDao->deleteOldest();
     $this->displayStatus("timer", round(microtime(true) - $timer, 2));
     return array('count' => count($hdrList), 'headercount' => $hdrsParsed, 'lastmsgid' => $lastProcessedId);
 }