/** * create folder * * @param string|Felamimail_Model_Account $_accountId * @param string $_folderName to create * @param string $_parentFolder * @return Felamimail_Model_Folder * @throws Felamimail_Exception_IMAPServiceUnavailable */ public function create($_accountId, $_folderName, $_parentFolder = '') { $account = $_accountId instanceof Felamimail_Controller_Account ? $_accountId : Felamimail_Controller_Account::getInstance()->get($_accountId); $this->_delimiter = $account->delimiter; $foldername = $this->_prepareFolderName($_folderName); $globalname = empty($_parentFolder) ? $foldername : $_parentFolder . $this->_delimiter . $foldername; if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Trying to create new folder: ' . $globalname . ' (parent: ' . $_parentFolder . ')'); } $imap = Felamimail_Backend_ImapFactory::factory($account); try { $imap->createFolder(Felamimail_Model_Folder::encodeFolderName($foldername), empty($_parentFolder) ? NULL : Felamimail_Model_Folder::encodeFolderName($_parentFolder), $this->_delimiter); // create new folder $folder = new Felamimail_Model_Folder(array('localname' => $foldername, 'globalname' => $globalname, 'account_id' => $account->getId(), 'parent' => $_parentFolder)); $folder = $this->_backend->create($folder); if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Create new folder: ' . $globalname); } } catch (Zend_Mail_Storage_Exception $zmse) { // perhaps the folder already exists if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Could not create new folder: ' . $globalname . ' (' . $zmse->getMessage() . ')'); } // reload folder cache of parent $parentSubs = $this->_cacheController->update($account, $_parentFolder); $folder = $parentSubs->filter('globalname', $globalname)->getFirstRecord(); if ($folder === NULL) { throw new Felamimail_Exception_IMAPServiceUnavailable($zmse->getMessage()); } } // update parent (has_children) $this->_updateHasChildren($_accountId, $_parentFolder, 1); return $folder; }
/** * the singleton pattern * * @return Felamimail_Controller_Cache_Folder */ public static function getInstance() { if (self::$_instance === NULL) { self::$_instance = new Felamimail_Controller_Cache_Folder(); } return self::$_instance; }
/** * the singleton pattern * * @return Felamimail_Controller_Cache_Folder */ public static function getInstance() { if (self::$_instance === NULL) { $adapter = Tinebase_Core::getConfig()->messagecache; $adapter = empty($adapter) ? 'sql' : $adapter; $classname = 'Felamimail_Controller_Cache_' . ucfirst($adapter) . '_Folder'; self::$_instance = $classname::getInstance(); } return self::$_instance; }
/** * Sets up the fixture. * This method is called before a test is executed. * * @access protected */ protected function setUp() { // get (or create) test accout $this->_account = Felamimail_Controller_Account::getInstance()->search()->getFirstRecord(); // init controller and imap backend $this->_controller = Felamimail_Controller_Cache_Message::getInstance(); $this->_imap = Felamimail_Backend_ImapFactory::factory($this->_account); try { $this->_imap->createFolder($this->_testFolderName, '', $this->_account->delimiter); } catch (Zend_Mail_Storage_Exception $zmse) { // exists } $this->_imap->selectFolder($this->_testFolderName); // init folder cache and get INBOX Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId()); $this->_folder = $this->_getFolder($this->_testFolderName); $this->_emailTestClass = new Felamimail_Controller_MessageTest(); $this->_emailTestClass->setup(); }
/** * test search with cache * - test text_plain.eml message * - test from header */ public function testSearchWithCache() { // get inbox folder id Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId()); $folderBackend = new Felamimail_Backend_Folder(); $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $this->_testFolderName); // clear cache and empty folder $this->_cache->clear($folder->getId()); Felamimail_Controller_Folder::getInstance()->emptyFolder($folder->getId()); // append message $this->_appendMessage('text_plain.eml', $this->_folder); // search messages in test folder $this->_cache->updateCache($folder); $result = $this->_controller->search($this->_getFilter($folder->getId())); //print_r($result->toArray()); // check result $firstMessage = $result->getFirstRecord(); $this->_createdMessages->addRecord($firstMessage); $this->assertGreaterThan(0, count($result)); $this->assertEquals($folder->getId(), $firstMessage->folder_id); $this->assertEquals("Re: [gentoo-dev] `paludis --info' is not like `emerge --info'", $firstMessage->subject); $this->assertEquals('Pipping, Sebastian (Luxembourg)', $firstMessage->from_name); $this->assertEquals('*****@*****.**', $firstMessage->from_email); $this->assertEquals(array('*****@*****.**', '*****@*****.**'), $firstMessage->to); // check cache entries $cacheBackend = new Felamimail_Backend_Cache_Sql_Message(); $cachedMessage = $cacheBackend->get($firstMessage->getId()); $this->assertEquals($folder->getId(), $cachedMessage->folder_id); $this->assertEquals(Tinebase_DateTime::now()->format('Y-m-d'), $cachedMessage->timestamp->format('Y-m-d')); // clear cache $this->_cache->clear($folder->getId()); }
/** * get mailbox * * @param string $name * @param boolean $createFolder * @return Felamimail_Model_Folder|NULL */ protected function _getFolder($name, $createFolder = TRUE) { Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId()); try { $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $name); } catch (Tinebase_Exception_NotFound $tenf) { $folder = $createFolder ? Felamimail_Controller_Folder::getInstance()->create($this->_account, $name) : NULL; } return $folder; }
/** * update folder cache * * @param string $accountId * @param string $folderName of parent folder * @return array of (sub)folders in cache */ public function updateFolderCache($accountId, $folderName) { // this may take longer $this->_longRunningRequest(300); $result = Felamimail_Controller_Cache_Folder::getInstance()->update($accountId, $folderName, TRUE); return $this->_multipleRecordsToJson($result); }
/** * get system folder for account * * @param string|Felamimail_Model_Account $_account * @param string $_systemFolder * @return NULL|Felamimail_Model_Folder */ public function getSystemFolder($_account, $_systemFolder) { $account = $_account instanceof Felamimail_Model_Account ? $_account : $this->get($_account); $changed = $this->_addFolderDefaults($account); if ($changed) { // need to use backend update because we prohibit the change of some fields in _inspectBeforeUpdate() $account = $this->_backend->update($account); } $systemFolderField = $this->_getSystemFolderField($_systemFolder); $folderName = $account->{$systemFolderField}; if (empty($folderName)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' No ' . $_systemFolder . ' folder set in account.'); } return NULL; } // check if folder exists on imap server $imapBackend = $this->_getIMAPBackend($account); if ($imapBackend && $imapBackend->getFolderStatus(Felamimail_Model_Folder::encodeFolderName($folderName)) === false) { $systemFolder = $this->_createSystemFolder($account, $folderName); if ($systemFolder->globalname !== $folderName) { $account->{$systemFolderField} = $systemFolder->globalname; $this->_backend->update($account); } } else { try { $systemFolder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($account->getId(), $folderName); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found system folder: ' . $folderName); } } catch (Tinebase_Exception_NotFound $tenf) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getMessage()); } $splitFolderName = Felamimail_Model_Folder::extractLocalnameAndParent($_systemFolder, $_account->delimiter); Felamimail_Controller_Cache_Folder::getInstance()->update($account, $splitFolderName['parent'], TRUE); $systemFolder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($account->getId(), $folderName); } } return $systemFolder; }
/** * update/synchronize flags * * @param string|Felamimail_Model_Folder $_folder * @param integer $_time * @return Felamimail_Model_Folder * * @todo only get flags of current batch of messages from imap? * @todo add status/progress to start at later messages when this is called next time? */ public function updateFlags($_folder, $_time = 60) { // always read folder from database $folder = Felamimail_Controller_Folder::getInstance()->get($_folder); if ($folder->cache_status !== Felamimail_Model_Folder::CACHE_STATUS_COMPLETE) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Do not update flags of incomplete folder ' . $folder->globalname); } return $folder; } if ($this->_availableUpdateTime == 0) { $this->_availableUpdateTime = $_time; $this->_timeStart = microtime(true); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Updating flags of folder ' . $folder->globalname . ' / start time: ' . Tinebase_DateTime::now()->toString() . ' / available seconds: ' . ($this->_availableUpdateTime - $this->_timeElapsed)); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Folder: ' . print_r($folder->toArray(), true)); } $imap = Felamimail_Backend_ImapFactory::factory($folder->account_id); // switch to folder (read-only) $imap->examineFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); if ($folder->supports_condstore) { $this->_updateCondstoreFlags($imap, $folder); } else { $this->_updateAllFlags($imap, $folder); } $updatedCounters = Felamimail_Controller_Cache_Folder::getInstance()->getCacheFolderCounter($folder); $folder = Felamimail_Controller_Folder::getInstance()->updateFolderCounter($folder, array('cache_unreadcount' => $updatedCounters['cache_unreadcount'])); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' New unreadcount after flags update: ' . $updatedCounters['cache_unreadcount']); } return $folder; }
/** * update the folder cache * * @throws Syncroton_Exception_Status_FolderSync */ protected function _updateFolderCache() { $account = $this->_getAccount(); if (!$account) { return; } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " accountData " . print_r($account->toArray(), true)); } try { Felamimail_Controller_Cache_Folder::getInstance()->update($account); } catch (Felamimail_Exception_IMAPServiceUnavailable $feisu) { if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " Could not update folder cache: " . $feisu); } throw new Syncroton_Exception_Status_FolderSync(Syncroton_Exception_Status_FolderSync::FOLDER_SERVER_ERROR); } catch (Felamimail_Exception_IMAPInvalidCredentials $feiic) { Tinebase_Exception::log($feiic, null, array('accountname' => $account->name)); } }
/** * update folder counts and returns list of affected folders * * @param array $_folderCounter (folderId => unreadcounter) * @return Tinebase_Record_RecordSet of affected folders * @throws Felamimail_Exception */ protected function _updateFolderCounts($_folderCounter) { foreach ($_folderCounter as $folderId => $counter) { $folder = Felamimail_Controller_Folder::getInstance()->get($folderId); // get error condition and update array by checking $counter keys if (isset($counter['incrementUnreadCounter']) || array_key_exists('incrementUnreadCounter', $counter)) { // this is only used in clearFlags() atm $errorCondition = $folder->cache_unreadcount + $counter['incrementUnreadCounter'] > $folder->cache_totalcount; $updatedCounters = array('cache_unreadcount' => '+' . $counter['incrementUnreadCounter']); } else { if ((isset($counter['decrementMessagesCounter']) || array_key_exists('decrementMessagesCounter', $counter)) && (isset($counter['decrementUnreadCounter']) || array_key_exists('decrementUnreadCounter', $counter))) { $errorCondition = $folder->cache_unreadcount < $counter['decrementUnreadCounter'] || $folder->cache_totalcount < $counter['decrementMessagesCounter']; $updatedCounters = array('cache_totalcount' => '-' . $counter['decrementMessagesCounter'], 'cache_unreadcount' => '-' . $counter['decrementUnreadCounter']); } else { throw new Felamimail_Exception('Wrong folder counter given: ' . print_r($_folderCounter, TRUE)); } } if ($errorCondition) { // something went wrong => recalculate counter if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' folder counters dont match => refresh counters'); } $updatedCounters = Felamimail_Controller_Cache_Folder::getInstance()->getCacheFolderCounter($folder); } Felamimail_Controller_Folder::getInstance()->updateFolderCounter($folder, $updatedCounters); } return Felamimail_Controller_Folder::getInstance()->getMultiple(array_keys($_folderCounter)); }
/** * update folder cache * * @param string $accountId * @param string $folderName of parent folder * @return array of (sub)folders in cache */ public function updateFolderCache($accountId, $folderName) { $result = Felamimail_Controller_Cache_Folder::getInstance()->update($accountId, $folderName, TRUE); return $this->_multipleRecordsToJson($result); }
/** * check and update mismatching folder counts (totalcount + unreadcount) * * @param Felamimail_Model_Folder $_folder */ protected function _checkAndUpdateFolderCounts(Felamimail_Model_Folder $_folder) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Checking foldercounts.'); } $updatedCounters = Felamimail_Controller_Cache_Folder::getInstance()->getCacheFolderCounter($_folder); if ($this->_countMismatch($_folder, $updatedCounters)) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' something went wrong while in/decrementing counters => recalculate cache counters by counting rows in database.' . " Cache status cache total count: {$_folder->cache_totalcount} imap total count: {$_folder->imap_totalcount}"); } Felamimail_Controller_Folder::getInstance()->updateFolderCounter($_folder, $updatedCounters); } if ($updatedCounters['cache_totalcount'] != $_folder->imap_totalcount) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' There are still messages missing in the cache: setting status to INCOMPLETE'); } $_folder->cache_status == Felamimail_Model_Folder::CACHE_STATUS_INCOMPLETE; } }
/** * return list of supported folders for this backend * * @return array */ public function getAllFolders() { if (!Tinebase_Core::getUser()->hasRight('Felamimail', Tinebase_Acl_Rights::RUN)) { // no folders return array(); } $defaultAccountId = Tinebase_Core::getPreference('Felamimail')->{Felamimail_Preference::DEFAULTACCOUNT}; if (empty($defaultAccountId)) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " no default account set. Can't sync any folders."); } return array(); } try { $account = Felamimail_Controller_Account::getInstance()->get($defaultAccountId); } catch (Tinebase_Exception_NotFound $ten) { // no folders return array(); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " accountData " . print_r($account->toArray(), true)); } // update folder cache Felamimail_Controller_Cache_Folder::getInstance()->updateCacheFolder($account); // get folders $folderController = Felamimail_Controller_Folder::getInstance(); $folders = $folderController->getSubfolders($account->getId(), ''); $result = array(); foreach ($folders as $folder) { if (!empty($folder->parent)) { try { $parent = $folderController->getByBackendAndGlobalName($folder->account_id, $folder->parent); $parentId = $parent->getId(); } catch (Tinebase_Exception_NotFound $ten) { continue; } } else { $parentId = 0; } $result[$folder->getId()] = array('folderId' => $folder->getId(), 'parentId' => $parentId, 'displayName' => $folder->localname, 'type' => $this->_getFolderType($folder->localname)); } #if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " folder result " . print_r($result, true)); return $result; }
/** * test update folder counter */ public function testUpdateFolderCounter() { $inbox = $this->_getInbox(); $this->_folderCountsTestHelper($inbox, array('cache_totalcount' => 0, 'cache_recentcount' => 0, 'cache_unreadcount' => 0), array('cache_totalcount' => 0, 'cache_unreadcount' => 0)); $this->_folderCountsTestHelper($inbox, array('cache_totalcount' => "+200", 'cache_unreadcount' => "+25"), array('cache_totalcount' => 200, 'cache_unreadcount' => 25)); $this->_folderCountsTestHelper($inbox, array('cache_totalcount' => "-1", 'cache_unreadcount' => "22"), array('cache_totalcount' => 199, 'cache_unreadcount' => 22)); $this->_folderCountsTestHelper($inbox, array('cache_totalcount' => "-100", 'cache_unreadcount' => "-30"), array('cache_totalcount' => 99, 'cache_unreadcount' => 0)); // reset $updatedCounters = Felamimail_Controller_Cache_Folder::getInstance()->getCacheFolderCounter($inbox); $this->assertEquals(0, $updatedCounters['cache_totalcount'], 'cache_totalcount does not match.'); $this->assertEquals(0, $updatedCounters['cache_unreadcount'], 'cache_unreadcount does not match.'); }
/** * update/synchronize flags * * @param string|Felamimail_Model_Folder $_folder * @param integer $_time * @return Felamimail_Model_Folder * * @todo only get flags of current batch of messages from imap? * @todo add status/progress to start at later messages when this is called next time? */ public function updateFlags($_folder, $_time = 60) { // always read folder from database $folder = Felamimail_Controller_Folder::getInstance()->get($_folder); if ($folder->cache_status !== Felamimail_Model_Folder::CACHE_STATUS_COMPLETE) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Do not update flags of incomplete folder ' . $folder->globalname); } return $folder; } if ($this->_availableUpdateTime == 0) { $this->_availableUpdateTime = $_time; $this->_timeStart = microtime(true); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Updating flags of folder ' . $folder->globalname . ' / start time: ' . Tinebase_DateTime::now()->toString() . ' / available seconds: ' . ($this->_availableUpdateTime - $this->_timeElapsed)); } // get all flags for folder $imap = Felamimail_Backend_ImapFactory::factory($folder->account_id); $imap->selectFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); $flags = $imap->getFlags(1, INF); for ($i = $folder->cache_totalcount; $i > 0; $i -= $this->_flagSyncCountPerStep) { $firstMessageSequence = $i - $this->_flagSyncCountPerStep >= 0 ? $i - $this->_flagSyncCountPerStep : 0; $messagesWithFlags = $this->_backend->getFlagsForFolder($folder->getId(), $firstMessageSequence, $this->_flagSyncCountPerStep); $this->_setFlagsOnCache($messagesWithFlags, $flags, $folder->getId()); if (!$this->_timeLeft()) { break; } } $updatedCounters = Felamimail_Controller_Cache_Folder::getInstance()->getCacheFolderCounter($_folder); $folder = Felamimail_Controller_Folder::getInstance()->updateFolderCounter($folder, array('cache_unreadcount' => $updatedCounters['cache_unreadcount'])); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' New unreadcount after flags update: ' . $updatedCounters['cache_unreadcount']); } return $folder; }