/** * Search for records matching given filter * * @param Tinebase_Model_Filter_FilterGroup $_filter * @param Tinebase_Model_Pagination $_pagination * @param array|string|boolean $_cols columns to get, * per default / use self::IDCOL or TRUE to get only ids * @return Tinebase_Record_RecordSet|array * * @todo implement optimizations on flags and security sorting * @todo implement messageuid,account_id search */ public function search(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Model_Pagination $_pagination = NULL, $_cols = '*') { /* Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Message Search = $_filter ' . print_r($_filter,true)); Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Message Search = $_pagination' . print_r($_filter,true)); Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Message Search = $_cols' . print_r($_cols,true)); */ $return = null; $messages = array(); $filterObjects = $_filter->getFilterObjects(); $imapFilters = $this->_parseFilterGroup($_filter, $_pagination); $pagination = !$_pagination ? new Tinebase_Model_Pagination(NULL, TRUE) : $_pagination; if (empty($imapFilters['paths'])) { $paths = $this->_getAllFolders(); $imapFilters['paths'] = $this->_getFoldersInfo($paths); } // TODO: do pagination on $ids and return after getMultiple if ($imapFilters['filters'] == 'Id') { $ids = $filterObjects[0]->getValue(); $ids = $this->_doPagination((array) $ids, $pagination); if ($_cols === TRUE) { return empty($ids) ? array() : $ids; } else { return empty($ids) ? $this->_rawDataToRecordSet(array()) : $this->getMultiple($ids); } } else { $ids = $this->_getIds($imapFilters, $_pagination); // get Summarys and merge results foreach ($ids as $folderId => $idsInFolder) { $folder = Felamimail_Controller_Folder::getInstance()->get($folderId); $imap = Felamimail_Backend_ImapFactory::factory($folder->account_id); $imap->selectFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); $idsInFolder = count($ids) === 1 ? $this->_doPagination($idsInFolder, $_pagination) : $idsInFolder; // do pagination early $messagesInFolder = $imap->getSummary($idsInFolder, null, null, $folderId); if (count($ids) === 1) { $tmp = array(); // We cannot trust the order we get from getSummary(), so we'll have to // put it the right order, defined by $idsInFolder // TODO: Put it into Felamilail_Backend_Imap->getSummary()???? foreach ($idsInFolder as $id) { $tmp[$id] = $messagesInFolder[$id]; } $messagesInFolder = $tmp; unset($tmp); } $messages = array_merge($messages, $messagesInFolder); if (count($ids) !== 1 && count($messages) > 1000) { throw new Felamimail_Exception_IMAPCacheTooMuchResults(); } } if (count($ids) === 1 && !in_array($pagination->sort, $this->_imapSortParams) || count($ids) > 1) { $callback = new Felamimail_Backend_Cache_Imap_MessageComparator($pagination); uasort($messages, array($callback, 'compare')); } } if (empty($messages)) { return $this->_rawDataToRecordSet(array()); } // Apply Pagination and get the resulting summary $page = count($ids) === 1 ? $messages : $this->_doPagination($messages, $_pagination); // $limit = empty($pagination->limit) ? count($messages) : $pagination->limit; // $chunked = array_chunk($messages, $limit, true); // $chunkIndex = empty($pagination->start) ? 0 : $pagination->start/$limit; // Put headers into model // if($imapFilters['filters'] == 'Id'){ // $return = empty($chunked[$chunkIndex])?new Tinebase_Record_RecordSet('Felamimail_Model_Message', array(), true): new Tinebase_Record_RecordSet('Felamimail_Model_Message', $chunked[$chunkIndex], true); // }else $return = empty($page) ? $this->_rawDataToRecordSet(array()) : $this->_rawDataToRecordSet($this->_createModelMessageArray($page)); Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Imap Sort = $sorted ' . print_r($messages, true)); return $return; // // Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Could\'nt use Imap directly' . print_r($return,true)); // $aux = new Felamimail_Backend_Cache_Sql_Message(); // $return = $aux->search($_filter,$_pagination, $_cols); //Tinebase_Core::getLogger()->alert(__METHOD__ . '#####::#####' . __LINE__ . ' Message Search = $retorno' . print_r($retorno,true)); }
/** * delete all messages in one folder -> be careful, they are completly removed and not moved to trash * -> delete subfolders if param set * * @param string $_folderId * @param boolean $_deleteSubfolders * @return Felamimail_Model_Folder * @throws Felamimail_Exception_IMAPServiceUnavailable */ public function emptyFolder($_folderId, $_deleteSubfolders = FALSE) { $folder = $this->_backend->get($_folderId); $account = Felamimail_Controller_Account::getInstance()->get($folder->account_id); $imap = Felamimail_Backend_ImapFactory::factory($account); try { // try to delete messages in imap folder Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Delete all messages in folder ' . $folder->globalname); $imap->emptyFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); } catch (Zend_Mail_Protocol_Exception $zmpe) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $zmpe->getMessage()); throw new Felamimail_Exception_IMAPServiceUnavailable($zmpe->getMessage()); } catch (Zend_Mail_Storage_Exception $zmse) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Folder could be empty (' . $zmse->getMessage() . ')'); } if ($_deleteSubfolders) { $this->deleteSubfolders($folder); } $folder = Felamimail_Controller_Cache_Message::getInstance()->clear($_folderId); return $folder; }
/** * test folder status of deleted folder * * @see 0007134: getFolderStatus should ignore non-existent folders */ public function testGetFolderStatusOfDeletedFolder() { $this->testCreateFolders(); // remove one of the created folders $removedFolder = $this->_createdFolders[0]; $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($removedFolder)); $status = $this->_json->getFolderStatus(array(array('field' => 'account_id', 'operator' => 'equals', 'value' => $this->_account->getId()))); $this->assertGreaterThan(2, count($status), 'Expected more than 2 folders that need an update: ' . print_r($status, TRUE)); foreach ($status as $folder) { if ($folder['globalname'] == $removedFolder) { $this->fail('removed folder should not appear in status array!'); } } }
/** * check if folder is selectable: try to select folder on imap server if isSelectable is false/not set * - courier imap servers subfolder have isSelectable = 0 but they still can be selected * @see http://www.tine20.org/bugtracker/view.php?id=2736 * * @param array $_folderData * @param Felamimail_Model_Account $_account * @return boolean */ protected function _isSelectable($_folderData, $_account) { $result = TRUE; if (!$_folderData['isSelectable'] == '1') { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Folder ' . $_folderData['globalName'] . ' is not selectable.'); } $imap = Felamimail_Backend_ImapFactory::factory($_account); try { $folderData = $imap->examineFolder(Felamimail_Model_Folder::encodeFolderName($_folderData['globalName'])); } catch (Zend_Mail_Storage_Exception $zmse) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Could not select folder. Skipping it.'); } $result = FALSE; } } return $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; }
/** * append mail to send folder * * @param Felamimail_Transport $_transport * @param Felamimail_Model_Account $_account * @param array $_additionalHeaders * @return void */ protected function _saveInSent(Felamimail_Transport $_transport, Felamimail_Model_Account $_account, $_additionalHeaders = array()) { try { $mailAsString = $_transport->getRawMessage(NULL, $_additionalHeaders); $sentFolder = Felamimail_Controller_Account::getInstance()->getSystemFolder($_account, Felamimail_Model_Folder::FOLDER_SENT); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' About to save message in sent folder (' . $sentFolder->globalname . ') ...'); } Felamimail_Backend_ImapFactory::factory($_account)->appendMessage($mailAsString, Felamimail_Model_Folder::encodeFolderName($sentFolder->globalname)); Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Saved sent message in "' . $sentFolder->globalname . '".'); } catch (Zend_Mail_Protocol_Exception $zmpe) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not save sent message in "' . $sentFolder->globalname . '".' . ' Please check if a folder with this name exists.' . '(' . $zmpe->getMessage() . ')'); } catch (Zend_Mail_Storage_Exception $zmse) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not save sent message in "' . $sentFolder->globalname . '".' . ' Please check if a folder with this name exists.' . '(' . $zmse->getMessage() . ')'); } }
/** * fetch message summary from IMAP server * * @param string $messageUid * @param string $accountId * @param string $folderId * @return array */ public function getMessageSummary($messageUid, $accountId, $folderId = NULL) { $imap = Felamimail_Backend_ImapFactory::factory($accountId); if ($folderId !== NULL) { try { $folder = Felamimail_Controller_Folder::getInstance()->get($folderId); $imap->selectFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); } catch (Exception $e) { if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not select folder ' . $folder->globalname . ': ' . $e->getMessage()); } } } $summary = $imap->getSummary($messageUid, NULL, TRUE); return $summary; }
/** * get subfolders * * @param $_account * @param $_folderName * @return array of folders */ protected function _getSubfolders(Felamimail_Model_Account $_account, $_folderName) { $result = array(); try { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' trying to get subfolders of ' . $_folderName . self::IMAPDELIMITER); } $imap = Felamimail_Backend_ImapFactory::factory($_account); $result = $imap->getFolders(Felamimail_Model_Folder::encodeFolderName($_folderName) . self::IMAPDELIMITER, '%'); // remove folder if self if (in_array($_folderName, array_keys($result))) { unset($result[$_folderName]); } } catch (Zend_Mail_Storage_Exception $zmse) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' No subfolders of ' . $_folderName . ' found.'); } } return $result; }
/** * move messages on imap server * * @param array $_uids * @param string $_targetFolderName * @param Felamimail_Backend_ImapProxy $_imap * * @todo perhaps we should check the existance of the messages on the imap instead of catching the exceptions here */ protected function _moveBatchOfMessages($_uids, $_targetFolderName, Felamimail_Backend_ImapProxy $_imap) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Move ' . count($_uids) . ' messages to folder ' . $_targetFolderName . ' on imap server'); } try { $_imap->copyMessage($_uids, Felamimail_Model_Folder::encodeFolderName($_targetFolderName)); $_imap->addFlags($_uids, array(Zend_Mail_Storage::FLAG_DELETED)); } catch (Zend_Mail_Storage_Exception $zmse) { if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) { Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $zmse); } } catch (Felamimail_Exception_IMAP $fei) { if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) { Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $fei); } } }
/** * get imap backend and folder (and select folder) * * @param string $_folderId * @param Felamimail_Backend_Folder &$_folder * @param boolean $_select * @param Felamimail_Backend_ImapProxy $_imapBackend * @throws Felamimail_Exception_IMAPServiceUnavailable * @throws Felamimail_Exception_IMAPFolderNotFound * @return Felamimail_Backend_ImapProxy */ protected function _getBackendAndSelectFolder($_folderId = NULL, &$_folder = NULL, $_select = TRUE, Felamimail_Backend_ImapProxy $_imapBackend = NULL) { if ($_folder === NULL || empty($_folder)) { $folderBackend = new Felamimail_Backend_Folder(); $_folder = $folderBackend->get($_folderId); } try { $imapBackend = $_imapBackend === NULL ? Felamimail_Backend_ImapFactory::factory($_folder->account_id) : $_imapBackend; if ($_select) { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Select folder ' . $_folder->globalname); } $imapBackend->selectFolder(Felamimail_Model_Folder::encodeFolderName($_folder->globalname)); } } catch (Zend_Mail_Storage_Exception $zmse) { // @todo remove the folder from cache if it could not be found on the IMAP server? throw new Felamimail_Exception_IMAPFolderNotFound($zmse->getMessage()); } catch (Zend_Mail_Protocol_Exception $zmpe) { throw new Felamimail_Exception_IMAPServiceUnavailable($zmpe->getMessage()); } return $imapBackend; }
/** * expunge cache folder * * @param Felamimail_Model_Folder $_folder * @param Felamimail_Backend_ImapProxy $_imap * @throws Felamimail_Exception_IMAPFolderNotFound */ protected function _expungeCacheFolder(Felamimail_Model_Folder $_folder, Felamimail_Backend_ImapProxy $_imap) { try { $_imap->expunge(Felamimail_Model_Folder::encodeFolderName($_folder->globalname)); } catch (Zend_Mail_Storage_Exception $zmse) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Removing no longer existing folder ' . $_folder->globalname . ' from cache. ' . $zmse->getMessage()); } Felamimail_Controller_Cache_Folder::getInstance()->delete($_folder->getId()); throw new Felamimail_Exception_IMAPFolderNotFound('Folder not found: ' . $_folder->globalname); } }
/** * 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; }
/** * get folder status/values from imap server and update folder cache record in database * * @param Felamimail_Model_Folder $_folder * @param Felamimail_Backend_Imap|boolean $_imap * @return Felamimail_Model_Folder */ public function getIMAPFolderCounter(Felamimail_Model_Folder $_folder) { $folder = $_folder instanceof Felamimail_Model_Folder ? $_folder : Felamimail_Controller_Folder::getInstance()->get($_folder); $imap = Felamimail_Backend_ImapFactory::factory($folder->account_id); // get folder values / status from imap server $counter = $imap->examineFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname)); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($counter, TRUE)); } // check validity $folder->cache_uidvalidity = $folder->imap_uidvalidity; $folder->imap_uidvalidity = $counter['uidvalidity']; $folder->cache_uidvalidity = empty($folder->cache_uidvalidity) ? $folder->imap_uidvalidity : $folder->cache_uidvalidity; $folder->imap_totalcount = $counter['exists']; $folder->imap_status = Felamimail_Model_Folder::IMAP_STATUS_OK; $folder->imap_timestamp = Tinebase_DateTime::now(); return $folder; }
/** * get imap backend and folder (and select folder) * * @param string $_folderId * @param Felamimail_Backend_Folder &$_folder * @param boolean $_select * @param Felamimail_Backend_ImapProxy $_imapBackend * @throws Felamimail_Exception_IMAPServiceUnavailable * @return Felamimail_Backend_ImapProxy */ protected function _getBackendAndSelectFolder($_folderId = NULL, &$_folder = NULL, $_select = TRUE, Felamimail_Backend_ImapProxy $_imapBackend = NULL) { if ($_folder === NULL || empty($_folder)) { $folderBackend = Felamimail_Backend_Folder::getInstance(); $_folder = $folderBackend->get($_folderId); } try { $imapBackend = $_imapBackend === NULL ? Felamimail_Backend_ImapFactory::factory($_folder->account_id) : $_imapBackend; if ($_select) { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Select folder ' . $_folder->globalname); } $backendFolderValues = $imapBackend->selectFolder(Felamimail_Model_Folder::encodeFolderName($_folder->globalname)); } } catch (Zend_Mail_Protocol_Exception $zmpe) { // no imap connection throw new Felamimail_Exception_IMAPServiceUnavailable(); } return $imapBackend; }
/** * Tears down the fixture * This method is called after a test is executed. * * @access protected */ protected function tearDown() { if (count($this->_createdFolders) > 0) { foreach ($this->_createdFolders as $folderName) { //echo "delete $folderName\n"; try { $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($folderName)); } catch (Zend_Mail_Storage_Exception $zmse) { // already deleted } } Felamimail_Controller_Cache_Folder::getInstance()->clear($this->_account); } if (!empty($this->_foldersToClear)) { foreach ($this->_foldersToClear as $folderName) { // delete test messages from given folders on imap server (search by special header) $this->_imap->selectFolder($folderName); $result = $this->_imap->search(array('HEADER X-Tine20TestMessage jsontest')); //print_r($result); foreach ($result as $messageUid) { $this->_imap->removeMessage($messageUid); } // clear message cache $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $folderName); Felamimail_Controller_Cache_Message::getInstance()->clear($folder); } } // sieve cleanup if ($this->_testSieveScriptName !== NULL) { Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName); try { Felamimail_Controller_Sieve::getInstance()->deleteScript($this->_account->getId()); } catch (Zend_Mail_Protocol_Exception $zmpe) { // do not delete script if active } Felamimail_Controller_Account::getInstance()->setVacationActive($this->_account, $this->_oldSieveVacationActiveState); if ($this->_oldSieveData !== NULL) { $this->_oldSieveData->save(); } } if ($this->_oldActiveSieveScriptName !== NULL) { Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_oldActiveSieveScriptName); Felamimail_Controller_Sieve::getInstance()->activateScript($this->_account->getId()); } }