6 * Tine 2.0 - http://www.tine20.org
9 * @license http://www.gnu.org/licenses/agpl.html
10 * @copyright Copyright (c) 2009-2014 Metaways Infosystems GmbH (http://www.metaways.de)
11 * @author Philipp Schüle <p.schuele@metaways.de>
17 require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
20 * Test class for Tinebase_Group
22 class Felamimail_Frontend_JsonTest extends TestCase
25 * @var Felamimail_Frontend_Json
27 protected $_json = array();
30 * message ids to delete
34 protected $_messageIds = array();
37 * @var Felamimail_Model_Account
39 protected $_account = NULL;
44 * @var Felamimail_Backend_ImapProxy
46 protected $_imap = NULL;
49 * name of the folder to use for tests
52 protected $_testFolderName = 'Junk';
55 * folders to delete in tearDown()
59 protected $_createdFolders = array();
62 * are there messages to delete?
66 protected $_foldersToClear = array();
69 * active sieve script name to be restored
73 protected $_oldActiveSieveScriptName = NULL;
76 * was sieve_vacation_active ?
80 protected $_oldSieveVacationActiveState = FALSE;
85 * @var Felamimail_Sieve_Backend_Sql
87 protected $_oldSieveData = NULL;
90 * sieve script name to delete
94 protected $_testSieveScriptName = NULL;
97 * sieve vacation template file name
101 protected $_sieveVacationTemplateFile = 'vacation_template.tpl';
108 protected $_mailDomain = 'tine20.org';
111 * @var Felamimail_Model_Folder
113 protected $_folder = NULL;
116 * paths in the vfs to delete
120 protected $_pathsToDelete = array();
124 * @var Tinebase_Frontend_Json
126 protected $_frontend = NULL;
129 * Sets up the fixture.
130 * This method is called before a test is executed.
134 protected function setUp()
136 Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
138 // get (or create) test accout
139 $this->_account = Felamimail_Controller_Account::getInstance()->search()->getFirstRecord();
140 $this->_oldSieveVacationActiveState = $this->_account->sieve_vacation_active;
142 $this->_oldSieveData = new Felamimail_Sieve_Backend_Sql($this->_account);
143 } catch (Tinebase_Exception_NotFound $tenf) {
147 $this->_json = new Felamimail_Frontend_Json();
148 $this->_imap = Felamimail_Backend_ImapFactory::factory($this->_account);
150 foreach (array($this->_testFolderName, $this->_account->sent_folder, $this->_account->trash_folder) as $folderToCreate) {
151 // create folder if it does not exist
152 $this->_getFolder($folderToCreate);
155 $this->_mailDomain = TestServer::getPrimaryMailDomain();
157 $this->_frontend = new Tinebase_Frontend_Json();
161 * Tears down the fixture
162 * This method is called after a test is executed.
166 protected function tearDown()
168 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
169 . ' Tearing down ...');
171 if (count($this->_createdFolders) > 0) {
172 foreach ($this->_createdFolders as $folderName) {
173 //echo "delete $folderName\n";
175 $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($folderName));
176 } catch (Zend_Mail_Storage_Exception $zmse) {
180 Felamimail_Controller_Cache_Folder::getInstance()->clear($this->_account);
183 if (! empty($this->_foldersToClear)) {
184 foreach ($this->_foldersToClear as $folderName) {
185 // delete test messages from given folders on imap server (search by special header)
186 $this->_imap->selectFolder($folderName);
187 $result = $this->_imap->search(array(
188 'HEADER X-Tine20TestMessage jsontest'
191 foreach ($result as $messageUid) {
192 $this->_imap->removeMessage($messageUid);
195 // clear message cache
196 $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $folderName);
197 Felamimail_Controller_Cache_Message::getInstance()->clear($folder);
202 if ($this->_testSieveScriptName !== NULL) {
203 Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
205 Felamimail_Controller_Sieve::getInstance()->deleteScript($this->_account->getId());
206 } catch (Zend_Mail_Protocol_Exception $zmpe) {
207 // do not delete script if active
209 Felamimail_Controller_Account::getInstance()->setVacationActive($this->_account, $this->_oldSieveVacationActiveState);
211 if ($this->_oldSieveData !== NULL) {
212 $this->_oldSieveData->save();
215 if ($this->_oldActiveSieveScriptName !== NULL) {
216 Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_oldActiveSieveScriptName);
217 Felamimail_Controller_Sieve::getInstance()->activateScript($this->_account->getId());
221 foreach ($this->_pathsToDelete as $path) {
222 $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
223 //echo "delete $path";
224 $webdavRoot->delete($path);
227 Tinebase_TransactionManager::getInstance()->rollBack();
230 /************************ test functions *********************************/
232 /*********************** folder tests ****************************/
235 * test search folders (check order of folders as well)
237 public function testSearchFolders()
239 $filter = $this->_getFolderFilter();
240 $result = $this->_json->searchFolders($filter);
242 $this->assertGreaterThan(1, $result['totalcount']);
243 $expectedFolders = array('INBOX', $this->_testFolderName, $this->_account->trash_folder, $this->_account->sent_folder);
246 foreach ($result['results'] as $index => $folder) {
247 if (in_array($folder['localname'], $expectedFolders)) {
251 $this->assertEquals(count($expectedFolders), $foundCount);
257 public function testClearFolder()
259 $folderName = $this->_testFolderName;
260 $folder = $this->_getFolder($this->_testFolderName);
261 $folder = Felamimail_Controller_Folder::getInstance()->emptyFolder($folder->getId());
263 $filter = $this->_getMessageFilter($folder->getId());
264 $result = $this->_json->searchMessages($filter, '');
266 $this->assertEquals(0, $result['totalcount'], 'Found too many messages in folder ' . $this->_testFolderName);
267 $this->assertEquals(0, $folder->cache_totalcount);
271 * try to create some folders
273 public function testCreateFolders()
275 $filter = $this->_getFolderFilter();
276 $result = $this->_json->searchFolders($filter);
278 $foldernames = array('test' => 'test', 'Schlüssel' => 'Schlüssel', 'test//1' => 'test1', 'test\2' => 'test2');
280 foreach ($foldernames as $foldername => $expected) {
281 $result = $this->_json->addFolder($foldername, $this->_testFolderName, $this->_account->getId());
282 $globalname = $this->_testFolderName . $this->_account->delimiter . $expected;
283 $this->_createdFolders[] = $globalname;
284 $this->assertEquals($expected, $result['localname']);
285 $this->assertEquals($globalname, $result['globalname']);
286 $this->assertEquals(Felamimail_Model_Folder::CACHE_STATUS_EMPTY, $result['cache_status']);
291 * test emtpy folder (with subfolder)
293 public function testEmptyFolderWithSubfolder()
295 $folderName = $this->_testFolderName;
296 $folder = $this->_getFolder($this->_testFolderName);
297 $this->testCreateFolders();
299 $folderArray = $this->_json->emptyFolder($folder->getId());
300 $this->assertEquals(0, $folderArray['has_children']);
302 $result = $this->_json->updateFolderCache($this->_account->getId(), $this->_testFolderName);
303 $this->assertEquals(0, count($result));
307 * testUpdateFolderCache
309 public function testUpdateFolderCache()
311 $result = $this->_json->updateFolderCache($this->_account->getId(), '');
313 // create folders directly on imap server
314 $this->_imap->createFolder('test', $this->_testFolderName, $this->_account->delimiter);
315 $this->_imap->createFolder('testsub', $this->_testFolderName . $this->_account->delimiter . 'test', $this->_account->delimiter);
316 // if something goes wrong, we need to delete these folders in tearDown
317 $this->_createdFolders[] = $this->_testFolderName . $this->_account->delimiter . 'test' . $this->_account->delimiter . 'testsub';
318 $this->_createdFolders[] = $this->_testFolderName . $this->_account->delimiter . 'test';
320 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
321 . ' Update cache and check if folder is found');
323 $result = $this->_json->updateFolderCache($this->_account->getId(), $this->_testFolderName);
324 $testfolder = $result[0];
325 $this->assertGreaterThan(0, count($result));
326 $this->assertEquals($this->_testFolderName . $this->_account->delimiter . 'test', $testfolder['globalname']);
327 $this->assertEquals(TRUE, (bool)$testfolder['has_children'], 'should have children');
329 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
330 . ' Delete subfolder directly on imap server');
332 $this->_imap->removeFolder($this->_testFolderName . $this->_account->delimiter . 'test' . $this->_account->delimiter . 'testsub');
333 array_shift($this->_createdFolders);
335 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
336 . ' Check if has_children got updated and folder is removed from cache');
338 $this->_json->updateFolderCache($this->_account->getId(), '');
339 $testfolder = $this->_getFolder($this->_testFolderName . $this->_account->delimiter . 'test');
340 $this->assertEquals(FALSE, (bool)$testfolder['has_children'], 'should have no children');
346 * testUpdateFolderCacheOfNonexistantFolder
348 * @see 0009800: unselectable folder with subfolders disappears
350 public function testUpdateFolderCacheOfNonexistantFolder()
352 $testfolder = $this->testUpdateFolderCache();
355 $folderName = $this->_testFolderName . $this->_account->delimiter . 'test' . $this->_account->delimiter . 'testsub';
356 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
357 . ' Trying to fetch deleted folder ' . $folderName);
359 $testfoldersub = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $folderName);
360 $this->fail('Tinebase_Exception_NotFound expected when looking for folder ' . $folderName);
361 } catch (Tinebase_Exception_NotFound $tenf) {
364 $this->_imap->removeFolder($this->_testFolderName . $this->_account->delimiter . 'test');
365 array_shift($this->_createdFolders);
367 // try to update message cache of nonexistant folder
368 $removedTestfolder = $this->_json->updateMessageCache($testfolder['id'], 1);
369 $this->assertEquals(0, $removedTestfolder['is_selectable'], 'Folder should not be selectable');
371 // update cache and check if folder is deleted
372 $result = $this->_json->updateFolderCache($this->_account->getId(), $this->_testFolderName);
373 $this->assertEquals(0, count($result));
376 /*********************** accounts tests **************************/
379 * test search for accounts and check default account from config
381 public function testSearchAccounts()
383 $system = $this->_getSystemAccount();
385 $this->assertTrue(! empty($system), 'no accounts found');
386 if (TestServer::getInstance()->getConfig()->mailserver) {
387 $this->assertEquals(TestServer::getInstance()->getConfig()->mailserver, $system['host']);
388 $this->assertEquals(TestServer::getInstance()->getConfig()->mailserver, $system['sieve_hostname']);
397 protected function _getSystemAccount()
399 $results = $this->_json->searchAccounts(array());
401 $this->assertGreaterThan(0, $results['totalcount']);
403 foreach ($results['results'] as $result) {
404 if ($result['name'] == Tinebase_Core::getUser()->accountLoginName . '@' . $this->_mailDomain) {
413 * test change / delete of account
415 public function testChangeDeleteAccount()
417 $system = $this->_getSystemAccount();
418 unset($system['id']);
419 $system['type'] = Felamimail_Model_Account::TYPE_USER;
420 $account = $this->_json->saveAccount($system);
422 $accountRecord = new Felamimail_Model_Account($account, TRUE);
423 $accountRecord->resolveCredentials(FALSE);
424 if (TestServer::getInstance()->getConfig()->mailserver) {
425 $this->assertEquals(TestServer::getInstance()->getConfig()->mailserver, $account['host']);
428 $this->_json->changeCredentials($account['id'], $accountRecord->user, 'neuespasswort');
429 $account = $this->_json->getAccount($account['id']);
431 $accountRecord = new Felamimail_Model_Account($account, TRUE);
432 $accountRecord->resolveCredentials(FALSE);
433 $this->assertEquals('neuespasswort', $accountRecord->password);
435 $this->_json->deleteAccounts($account['id']);
438 /*********************** message tests ****************************/
441 * test update message cache
443 public function testUpdateMessageCache()
445 $message = $this->_sendMessage();
446 $inbox = $this->_getFolder('INBOX');
447 // update message cache and check result
448 $result = $this->_json->updateMessageCache($inbox['id'], 30);
450 if ($result['cache_status'] == Felamimail_Model_Folder::CACHE_STATUS_COMPLETE) {
451 $this->assertEquals($result['imap_totalcount'], $result['cache_totalcount'], 'totalcounts should be equal');
452 } else if ($result['cache_status'] == Felamimail_Model_Folder::CACHE_STATUS_INCOMPLETE) {
453 $this->assertNotEquals(0, $result['cache_job_actions_est']);
460 public function testGetFolderStatus()
462 $filter = $this->_getFolderFilter();
463 $result = $this->_json->searchFolders($filter);
464 $this->assertGreaterThan(1, $result['totalcount']);
465 $expectedFolders = array('INBOX', $this->_testFolderName, $this->_account->trash_folder, $this->_account->sent_folder);
467 foreach ($result['results'] as $folder) {
468 $this->_json->updateMessageCache($folder['id'], 30);
471 $message = $this->_sendMessage();
473 $status = $this->_json->getFolderStatus(array(array('field' => 'account_id', 'operator' => 'equals', 'value' => $this->_account->getId())));
474 $this->assertEquals(1, count($status));
475 $this->assertEquals($this->_account->sent_folder, $status[0]['localname']);
479 * test folder status of deleted folder
481 * @see 0007134: getFolderStatus should ignore non-existent folders
483 public function testGetFolderStatusOfDeletedFolder()
485 $this->testCreateFolders();
486 // remove one of the created folders
487 $removedFolder = $this->_createdFolders[0];
488 $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($removedFolder));
490 $status = $this->_json->getFolderStatus(array(array('field' => 'account_id', 'operator' => 'equals', 'value' => $this->_account->getId())));
491 $this->assertGreaterThan(2, count($status), 'Expected more than 2 folders that need an update: ' . print_r($status, TRUE));
492 foreach ($status as $folder) {
493 if ($folder['globalname'] == $removedFolder) {
494 $this->fail('removed folder should not appear in status array!');
502 public function testSendMessage()
504 // set email to unittest@tine20.org
505 $contactFilter = new Addressbook_Model_ContactFilter(array(
506 array('field' => 'n_family', 'operator' => 'equals', 'value' => 'Clever')
508 $contactIds = Addressbook_Controller_Contact::getInstance()->search($contactFilter, NULL, FALSE, TRUE);
509 $this->assertTrue(count($contactIds) > 0, 'sclever not found in addressbook');
511 $contact = Addressbook_Controller_Contact::getInstance()->get($contactIds[0]);
512 $originalEmail = $contact->email;
513 $contact->email = $this->_account->email;
514 $contact = Addressbook_Controller_Contact::getInstance()->update($contact, FALSE);
517 $messageToSend = $this->_getMessageData('unittestalias@' . $this->_mailDomain);
518 $messageToSend['note'] = 1;
519 $messageToSend['bcc'] = array(Tinebase_Core::getUser()->accountEmailAddress);
520 //print_r($messageToSend);
521 $returned = $this->_json->saveMessage($messageToSend);
522 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
524 // check if message is in sent folder
525 $message = $this->_searchForMessageBySubject($messageToSend['subject'], $this->_account->sent_folder);
526 $this->assertEquals($message['from_email'], $messageToSend['from_email']);
527 $this->assertTrue(isset($message['to'][0]));
528 $this->assertEquals($message['to'][0], $messageToSend['to'][0], 'recipient not found');
529 $this->assertEquals($message['bcc'][0], $messageToSend['bcc'][0], 'bcc recipient not found');
530 $this->assertEquals($message['subject'], $messageToSend['subject']);
532 $this->_checkEmailNote($contact, $messageToSend['subject']);
534 // reset sclevers original email address
535 $contact->email = $originalEmail;
536 Addressbook_Controller_Contact::getInstance()->update($contact, FALSE);
542 * @param Addressbook_Model_Contact $contact
543 * @param string $subject
545 protected function _checkEmailNote($contact, $subject)
547 // check if email note has been added to contact(s)
548 $contact = Addressbook_Controller_Contact::getInstance()->get($contact->getId());
549 $emailNoteType = Tinebase_Notes::getInstance()->getNoteTypeByName('email');
551 // check / delete notes
552 $emailNotes = new Tinebase_Record_RecordSet('Tinebase_Model_Note');
553 foreach ($contact->notes as $note) {
554 if ($note->note_type_id == $emailNoteType->getId()) {
555 $this->assertContains($subject, $note->note, 'did not find note subject');
556 $this->assertEquals(Tinebase_Core::getUser()->getId(), $note->created_by);
557 $this->assertContains('aaaaaä', $note->note);
558 $emailNotes->addRecord($note);
561 $this->assertGreaterThan(0, $emailNotes->count(), 'no email notes found');
562 Tinebase_Notes::getInstance()->deleteNotes($emailNotes);
566 * test send message to invalid recipient
568 public function testSendMessageToInvalidRecipient()
570 $messageToSend = $this->_getMessageData($this->_account->email);
571 $invalidEmail = 'invaliduser@' . $this->_mailDomain;
572 $messageToSend['to'] = array($invalidEmail);
573 $translation = Tinebase_Translation::getTranslation('Felamimail');
576 $returned = $this->_json->saveMessage($messageToSend);
577 $this->fail('Tinebase_Exception_SystemGeneric expected');
578 } catch (Tinebase_Exception_SystemGeneric $tesg) {
579 $this->assertContains('<' . $invalidEmail . '>: ' . $translation->_('Recipient address rejected'), $tesg->getMessage(),
580 'exception message did not match: ' . $tesg->getMessage());
585 * try to get a message from imap server (with complete body, attachments, etc)
587 * @see 0006300: add unique message-id header to new messages (for message-id check)
589 public function testGetMessage()
591 $message = $this->_sendMessage();
593 // get complete message
594 $message = $this->_json->getMessage($message['id']);
597 $this->assertTrue(isset($message['headers']) && $message['headers']['message-id']);
598 $this->assertContains('@' . $this->_mailDomain, $message['headers']['message-id']);
599 $this->assertGreaterThan(0, preg_match('/aaaaaä/', $message['body']));
601 // delete message on imap server and check if correct exception is thrown when trying to get it
602 $this->_imap->selectFolder('INBOX');
603 $this->_imap->removeMessage($message['messageuid']);
604 Tinebase_Core::getCache()->clean();
605 $this->setExpectedException('Felamimail_Exception_IMAPMessageNotFound');
606 $message = $this->_json->getMessage($message['id']);
610 * try to get a message as plain/text
612 public function testGetPlainTextMessage()
614 $accountBackend = new Felamimail_Backend_Account();
615 $message = $this->_sendMessage();
617 // get complete message
618 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_PLAIN;
619 $accountBackend->update($this->_account);
620 $message = $this->_json->getMessage($message['id']);
621 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_HTML;
622 $accountBackend->update($this->_account);
625 $this->assertEquals("aaaaaä \n\r\n", $message['body']);
629 * try search for a message with path filter
631 public function testSearchMessageWithPathFilter()
633 $sentMessage = $this->_sendMessage();
634 $filter = array(array(
635 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId()
637 $result = $this->_json->searchMessages($filter, '');
638 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
639 $this->assertTrue(! empty($message), 'Sent message not found with account path filter');
641 $inbox = $this->_getFolder('INBOX');
642 $filter = array(array(
643 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId() . '/' . $inbox->getId()
645 $result = $this->_json->searchMessages($filter, '');
646 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
647 $this->assertTrue(! empty($message), 'Sent message not found with path filter');
648 foreach ($result['results'] as $mail) {
649 $this->assertEquals($inbox->getId(), $mail['folder_id'], 'message is in wrong folder: ' . print_r($mail, TRUE));
654 * try search for a message with all inboxes and flags filter
656 public function testSearchMessageWithAllInboxesFilter()
658 $sentMessage = $this->_sendMessage();
660 array('field' => 'path', 'operator' => 'in', 'value' => Felamimail_Model_MessageFilter::PATH_ALLINBOXES),
661 array('field' => 'flags', 'operator' => 'notin', 'value' => Zend_Mail_Storage::FLAG_FLAGGED),
663 $result = $this->_json->searchMessages($filter, '');
664 $this->assertGreaterThan(0, $result['totalcount']);
665 $this->assertEquals($result['totalcount'], count($result['results']));
667 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
668 $this->assertTrue(! empty($message), 'Sent message not found with all inboxes filter');
672 * try search for a message with three cache filters to force a foreign relation join with at least 2 tables
674 public function testSearchMessageWithThreeCacheFilter()
677 array('field' => 'flags', 'operator' => 'in', 'value' => Zend_Mail_Storage::FLAG_ANSWERED),
678 array('field' => 'to', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
679 array('field' => 'subject', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
681 $result = $this->_json->searchMessages($filter, '');
682 $this->assertEquals(0, $result['totalcount']);
686 * try search for a message with empty path filter
688 public function testSearchMessageEmptyPath()
690 $sentMessage = $this->_sendMessage();
693 array('field' => 'path', 'operator' => 'equals', 'value' => ''),
695 $result = $this->_json->searchMessages($filter, '');
697 $this->assertEquals(0, $result['totalcount']);
698 $accountFilterFound = FALSE;
700 foreach ($result['filter'] as $filter) {
701 if ($filter['field'] === 'account_id' && empty($filter['value'])) {
702 $accountFilterFound = TRUE;
706 $this->assertTrue($accountFilterFound);
710 * test flags (add + clear + deleted)
712 public function testAddAndClearFlags()
714 $message = $this->_sendMessage();
715 $inboxBefore = $this->_getFolder('INBOX');
717 $this->_json->addFlags($message['id'], Zend_Mail_Storage::FLAG_SEEN);
719 // check if unread count got decreased
720 $inboxAfter = $this->_getFolder('INBOX');
721 $this->assertTrue($inboxBefore->cache_unreadcount - 1 == $inboxAfter->cache_unreadcount, 'wrong cache unreadcount');
723 $message = $this->_json->getMessage($message['id']);
724 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag not set');
728 array('field' => 'id', 'operator' => 'in', array($message['id']))
730 $this->_json->clearFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
732 $message = $this->_json->getMessage($message['id']);
733 $this->assertFalse(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag should not be set');
735 $this->setExpectedException('Tinebase_Exception_NotFound');
736 $this->_json->addFlags(array($message['id']), Zend_Mail_Storage::FLAG_DELETED);
737 $this->_json->getMessage($message['id']);
743 * @see 0009812: mark folder as read does not work with pgsql
745 public function testMarkFolderRead()
747 $inboxBefore = $this->_getFolder('INBOX');
748 $filter = array(array(
749 'field' => 'folder_id', 'operator' => 'equals', 'value' => $inboxBefore->getId()
751 'field' => 'flags', 'operator' => 'notin', 'value' => array(Zend_Mail_Storage::FLAG_SEEN)
753 $this->_json->addFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
755 $inboxAfter = $this->_getFolder('INBOX');
756 $this->assertEquals(0, $inboxAfter->cache_unreadcount);
760 * test delete from trash
762 public function testDeleteFromTrashWithFilter()
764 $message = $this->_sendMessage();
765 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
767 $trash = $this->_getFolder($this->_account->trash_folder);
768 $result = $this->_json->moveMessages(array(array(
769 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
770 )), $trash->getId());
772 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
774 // delete messages in trash with filter
775 $this->_json->addFlags(array(array(
776 'field' => 'folder_id', 'operator' => 'equals', 'value' => $trash->getId()
778 'field' => 'id', 'operator' => 'in', 'value' => array($messageInTrash['id'])
779 )), Zend_Mail_Storage::FLAG_DELETED);
781 $this->setExpectedException('Tinebase_Exception_NotFound');
782 $this->_json->getMessage($messageInTrash['id']);
786 * move message to trash with trash folder constant (Felamimail_Model_Folder::FOLDER_TRASH)
788 public function testMoveMessagesToTrash()
790 $message = $this->_sendMessage();
791 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
793 $result = $this->_json->moveMessages(array(array(
794 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
795 )), Felamimail_Model_Folder::FOLDER_TRASH);
797 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
801 * test reply mail and check some headers
803 * @see 0006106: Add References header / https://forge.tine20.org/mantisbt/view.php?id=6106
805 public function testReplyMessage()
807 $message = $this->_sendMessage();
809 $replyMessage = $this->_getReply($message);
810 $returned = $this->_json->saveMessage($replyMessage);
812 $result = $this->_getMessages();
814 $replyMessageFound = array();
815 $originalMessage = array();
816 foreach ($result['results'] as $mail) {
817 if ($mail['subject'] == $replyMessage['subject']) {
818 $replyMessageFound = $mail;
820 if ($mail['subject'] == $message['subject']) {
821 $originalMessage = $mail;
824 $replyMessageFound = $this->_json->getMessage($replyMessageFound['id']);
825 $originalMessage = $this->_json->getMessage($originalMessage['id']);
827 $this->assertTrue(! empty($replyMessageFound), 'replied message not found');
828 $this->assertTrue(! empty($originalMessage), 'original message not found');
831 $this->assertTrue(isset($replyMessageFound['headers']['in-reply-to']));
832 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['in-reply-to']);
833 $this->assertTrue(isset($replyMessageFound['headers']['references']));
834 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['references']);
836 // check answered flag
837 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_ANSWERED, $originalMessage['flags'], 'could not find flag'));
841 * get reply message data
843 * @param array $_original
846 protected function _getReply($_original)
848 $replyMessage = $this->_getMessageData();
849 $replyMessage['subject'] = 'Re: ' . $_original['subject'];
850 $replyMessage['original_id']= $_original['id'];
851 $replyMessage['flags'] = Zend_Mail_Storage::FLAG_ANSWERED;
853 return $replyMessage;
857 * test reply mail in sent folder
859 public function testReplyMessageInSentFolder()
861 $messageInSent = $this->_sendMessage($this->_account->sent_folder);
862 $replyMessage = $this->_getReply($messageInSent);
863 $returned = $this->_json->saveMessage($replyMessage);
865 $result = $this->_getMessages();
866 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
867 $this->assertTrue(! empty($sentMessage));
871 * test reply mail with long references header
873 * @see 0006644: "At least one mail header line is too long"
875 public function testReplyMessageWithLongHeader()
877 $messageInSent = $this->_sendMessage($this->_account->sent_folder, array(
878 'references' => '<c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
879 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
880 <20120530154350.1854610131@ganymed.de>
881 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
882 <4FC8B49C.8040704@funk.de>
883 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
884 <20120601123551.5E98610131@ganymed.de>
885 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
886 <20120619093658.37E4210131@ganymed.de>
887 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
888 <20120619130652.03DD310131@ganymed.de>
889 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
890 <20120620074843.42E2010131@ganymed.de>
891 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
892 <20120620092902.88C8C10131@ganymed.de>
893 <c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
894 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
895 <20120530154350.1854610131@ganymed.de>
896 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
897 <4FC8B49C.8040704@funk.de>
898 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
899 <20120601123551.5E98610131@ganymed.de>
900 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
901 <20120619093658.37E4210131@ganymed.de>
902 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
903 <20120619130652.03DD310131@ganymed.de>
904 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
905 <20120620074843.42E2010131@ganymed.de>
906 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
907 <20120620092902.88C8C10131@ganymed.de>'
909 $replyMessage = $this->_getReply($messageInSent);
910 $returned = $this->_json->saveMessage($replyMessage);
912 $result = $this->_getMessages();
913 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
914 $this->assertTrue(! empty($sentMessage));
920 public function testMoveMessage()
922 $message = $this->_sendMessage();
923 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_testFolderName);
925 $inbox = $this->_getFolder('INBOX');
926 $inboxBefore = $this->_json->updateMessageCache($inbox['id'], 30);
929 $testFolder = $this->_getFolder($this->_testFolderName);
930 $result = $this->_json->moveMessages(array(array(
931 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
932 )), $testFolder->getId());
934 // sleep for 2 secs because mailserver may be slower than expected
937 $inboxAfter = $this->_getFolder('INBOX');
939 // check if count was decreased correctly
940 $this->assertEquals($inboxBefore['cache_unreadcount'] - 1, $inboxAfter['cache_unreadcount']);
941 $this->assertEquals($inboxBefore['cache_totalcount'] - 1, $inboxAfter['cache_totalcount']);
943 $result = $this->_getMessages($this->_testFolderName);
944 $movedMessage = array();
945 foreach ($result['results'] as $mail) {
946 if ($mail['subject'] == $message['subject']) {
947 $movedMessage = $mail;
950 $this->assertTrue(! empty($movedMessage), 'moved message not found');
954 * forward message test
956 * @see 0007624: losing umlauts in attached filenames
958 public function testForwardMessageWithAttachment()
960 $testFolder = $this->_getFolder($this->_testFolderName);
961 $message = fopen(dirname(__FILE__) . '/../files/multipart_related.eml', 'r');
962 Felamimail_Controller_Message::getInstance()->appendMessage($testFolder, $message);
964 $subject = 'Tine 2.0 bei Metaways - Verbessurngsvorschlag';
965 $message = $this->_searchForMessageBySubject($subject, $this->_testFolderName);
967 $fwdSubject = 'Fwd: ' . $subject;
968 $forwardMessageData = array(
969 'account_id' => $this->_account->getId(),
970 'subject' => $fwdSubject,
971 'to' => array($this->_getEmailAddress()),
972 'body' => "aaaaaä <br>",
973 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
974 'original_id' => $message['id'],
975 'attachments' => array(new Tinebase_Model_TempFile(array(
976 'type' => Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822,
977 'name' => 'Verbessurüngsvorschlag',
979 'flags' => Zend_Mail_Storage::FLAG_PASSED,
982 $this->_foldersToClear[] = 'INBOX';
983 $this->_json->saveMessage($forwardMessageData);
984 $forwardMessage = $this->_searchForMessageBySubject($fwdSubject);
986 // check attachment name
987 $forwardMessageComplete = $this->_json->getMessage($forwardMessage['id']);
988 $this->assertEquals(1, count($forwardMessageComplete['attachments']));
989 $this->assertEquals('Verbessurüngsvorschlag.eml', $forwardMessageComplete['attachments'][0]['filename'], 'umlaut missing from attachment filename');
991 $forwardMessage = $this->_json->getMessage($forwardMessage['id']);
992 $this->assertTrue((isset($forwardMessage['structure']) || array_key_exists('structure', $forwardMessage)), 'structure should be set when fetching complete message: ' . print_r($forwardMessage, TRUE));
993 $this->assertEquals(Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822, $forwardMessage['structure']['parts'][2]['contentType']);
995 $message = $this->_json->getMessage($message['id']);
996 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_PASSED, $message['flags']), 'forwarded flag missing in flags: ' . print_r($message, TRUE));
1000 * testSendMessageWithAttachmentWithoutExtension
1002 * @see 0008328: email attachment without file extension is not sent properly
1004 public function testSendMessageWithAttachmentWithoutExtension()
1006 $subject = 'attachment test';
1007 $messageToSend = $this->_getMessageData('unittestalias@' . $this->_mailDomain, $subject);
1008 $tempfileName = 'jsontest' . Tinebase_Record_Abstract::generateUID(10);
1009 $tempfilePath = Tinebase_Core::getTempDir() . DIRECTORY_SEPARATOR . $tempfileName;
1010 file_put_contents($tempfilePath, 'some content');
1011 $tempFile = Tinebase_TempFile::getInstance()->createTempFile($tempfilePath, $tempfileName);
1012 $messageToSend['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
1013 $this->_json->saveMessage($messageToSend);
1014 $forwardMessage = $this->_searchForMessageBySubject($subject);
1015 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1017 $fullMessage = $this->_json->getMessage($forwardMessage['id']);
1018 $this->assertTrue(count($fullMessage['attachments']) === 1);
1019 $attachment = $fullMessage['attachments'][0];
1020 $this->assertContains($tempfileName, $attachment['filename'], 'wrong attachment filename: ' . print_r($attachment, TRUE));
1021 $this->assertEquals(16, $attachment['size'], 'wrong attachment size: ' . print_r($attachment, TRUE));
1025 * save message in folder (draft) test
1027 * @see 0007178: BCC does not save the draft message
1029 public function testSaveMessageInFolder()
1031 $messageToSave = $this->_getMessageData();
1032 $messageToSave['bcc'] = array('bccaddress@email.org', 'bccaddress2@email.org');
1034 $draftsFolder = $this->_getFolder($this->_account->drafts_folder);
1035 $returned = $this->_json->saveMessageInFolder($this->_account->drafts_folder, $messageToSave);
1036 $this->_foldersToClear = array($this->_account->drafts_folder);
1038 // check if message is in drafts folder and recipients are present
1039 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->drafts_folder);
1040 $this->assertEquals($messageToSave['subject'], $message['subject']);
1041 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1042 $this->assertEquals(2, count($message['bcc']), 'bcc recipient not found: ' . print_r($message, TRUE));
1043 $this->assertEquals($messageToSave['bcc'][0], $message['bcc'][0], '1st bcc recipient not found');
1044 $this->assertEquals($messageToSave['bcc'][1], $message['bcc'][1], '2nd bcc recipient not found');
1048 * testSendReadingConfirmation
1050 * @see 0007736: ask user before sending reading confirmation
1051 * @see 0008402: Wrong recipient with read confirmation
1053 public function testSendReadingConfirmation()
1055 $messageToSave = $this->_getMessageData();
1056 $messageToSave['headers']['disposition-notification-to'] = '"' . Tinebase_Core::getUser()->accountFullName . '" <' . $this->_account->email . '>';
1057 $returned = $this->_json->saveMessageInFolder($this->_testFolderName, $messageToSave);
1058 $messageWithReadingConfirmationHeader = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_testFolderName);
1059 $this->_messageIds[] = $messageWithReadingConfirmationHeader['id'];
1060 $this->_json->sendReadingConfirmation($messageWithReadingConfirmationHeader['id']);
1062 $translate = Tinebase_Translation::getTranslation('Felamimail');
1063 $subject = $translate->_('Reading Confirmation:') . ' '. $messageToSave['subject'];
1064 $message = $this->_searchForMessageBySubject($subject);
1065 $this->_messageIds[] = $message['id'];
1067 $complete = $this->_json->getMessage($message['id']);
1068 $this->assertContains($translate->_('Was read by:') . ' ' . $this->_account->from, $complete['body']);
1072 * save message in non-existant folder (templates) test
1074 * @see 0008476: Drafts are not working
1076 public function testSaveMessageInNonExistantTemplatesFolder()
1078 $messageToSave = $this->_getMessageData();
1080 $templatesFolder = $this->_getFolder($this->_account->templates_folder, FALSE);
1081 if ($templatesFolder) {
1082 $this->_json->deleteFolder($templatesFolder['id'], $this->_account->getId());
1084 $returned = $this->_json->saveMessageInFolder($this->_account->templates_folder, $messageToSave);
1085 $this->_foldersToClear = array($this->_account->templates_folder);
1087 // check if message is in templates folder
1088 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->templates_folder);
1089 $this->assertEquals($messageToSave['subject'], $message['subject']);
1090 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1094 * testSaveMessageNoteWithInvalidChar
1096 * @see 0008644: error when sending mail with note (wrong charset)
1098 public function testSaveMessageNoteWithInvalidChar()
1100 $subject = Tinebase_Core::filterInputForDatabase("\xF0\x9F\x98\x8A\xC2"); // :-) emoji
1101 $messageData = $this->_getMessageData('', $subject);
1102 $messageData['note'] = true;
1103 $messageData['body'] .= " ";
1105 $this->_foldersToClear[] = 'INBOX';
1106 $this->_json->saveMessage($messageData);
1107 $message = $this->_searchForMessageBySubject($subject);
1109 $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
1110 $this->_checkEmailNote($contact, $subject);
1114 * testSaveMessageNoteWithInvalidChar
1116 * @see 0008644: error when sending mail with note (wrong charset)
1118 public function testSaveMessageWithInvalidChar()
1120 $subject = "\xF0\x9F\x98\x8A"; // :-) emoji
1121 $messageData = $this->_getMessageData('', $subject);
1122 $this->_foldersToClear[] = 'INBOX';
1123 $this->_json->saveMessage($messageData);
1124 $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1128 * testMessageWithInvalidICS
1130 * @see 0008786: broken ics causes js error when showing details
1132 public function testMessageWithInvalidICS()
1134 $inbox = $this->_getFolder('INBOX');
1135 $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/invalidimip.eml');
1136 Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1138 $this->_foldersToClear = array('INBOX');
1139 $message = $this->_searchForMessageBySubject('test invalid imip');
1141 $fullMessage = $this->_json->getMessage($message['id']);
1142 $this->assertTrue(empty($fullMessage->preparedParts));
1146 * testSendMailveopeAPIMessage
1148 * - envolpe amored message into PGP MIME structure
1150 public function testSendMailveopeAPIMessage()
1152 $subject = 'testSendMailveopeAPIMessage';
1153 $messageData = $this->_getMessageData('', $subject);
1154 $messageData['body'] = '-----BEGIN PGP MESSAGE-----
1155 Version: Mailvelope v1.3.3
1156 Comment: https://www.mailvelope.com
1158 wcFMA/0LJF28pDbGAQ//YgtsmEZN+pgIJiBDb7iYwPEOchDRIEjGOx543KF6
1159 5YigW9p39pfcJgvGfT8x9cUIrYGxyw5idPSOEftYXyjjGaOYGaKpRSR4hI83
1160 OcJSlEHKq72xhg04mNpCjjJ8dLBstPcQ7tDtsA8Nfb4PwkUYB9IhIBnARg+n
1161 NvrN8mSA2UnY9ElFCvf30sar8EuM5swAjbk64C8TIypMy/Bg4T93zRdxwik6
1162 7BCcbOpm/2PTsiVYBOTcU4+XdG5eyTENXH58M6UTxTD4/g7Qi5PjN+PxyXqf
1163 v2Y1k9F49Y1egf2QJ2r4PX0EWS8SaynSHiIoBsp1xb07nLwZwCdMPG1QNPpF
1164 l2FqlS4dEuQTdkv0deMvd7gtiNynRTAVcJc1ZC6RuWJ+EH2jA49XWkn14eRC
1165 e5jMtPPudkhubnN9Je5lwatGKbJGyuXh+IaM0E0WQMZ3dm8+ST1l4WpVuGbw
1166 KozLUiTRJP9UoxWOcwpQOnzcSlc4rHmWdtF0y3usM9u9GPREqpNUWkEyEEuv
1167 XdZE7rKKj22dJHLCXxAQEh3m29Y2WVaq50YbtEZ+SwwbrHhxP4+FJEru+byh
1168 fiZ47sVW2KvYGJPvbFoSZHiSvMecxDg8BVwe+naZXww/Rwa/TlaX4bYyzpUG
1169 KeJUAzWEfFpJ0+yAvMGQEC7psIJ9NCx149C4ujiQmajSwhUB3XANcmCGB0wm
1170 JjcqC4AHvc7/t4MrQZm0F/W+nrMmNqbZk+gylVrPs9rFEqu7wbjwTmsFA3sS
1171 LkenvQIxBali6uzCR+nd09REqcYirG9cLti39DW048lhhG/ml+gAxxNEaSpG
1172 NbIoV/3w8n7sAIM1fjuHne8bX0gWG43TTjU8MwSMryG7tCOG5u+Cebh6TAoY
1173 NzbX2dpDhOYq5zXdCgKU4P3eh0csSs4UrqFT3TdAxIGrQJ7KrXvB6+N8gRZo
1174 FcUaR+zrRPJjPUZfi46ecP5SG/tM5ea1hqvkwEnEpqjLmCUxqB+rfxx46USX
1175 hMZd2ukUv6kEKv3EUDsRYu1SlDLhDLhWNx8RJae5XkMR+eUUMyNNVwbeMQbB
1176 VAcMcaPITTk84sH7XElr9eF6sCUN4V79OSBRPGY/aNGrcwcoDSD4Hwu+Lw9w
1177 Q+1n8EQ66gAkbJzCNd5GaYMZR9echkBaD/rdWDS3ktcrMehra+h44MTQONV9
1178 8W+RI+IT5jaIXtB4jePmGjsJjbC9aEhTRBRkUnPA7phgknc52dD74AY/6lzK
1179 yd4uZ6S3vhurJW0Vt4iBWJzhFNiSODh5PzteeNzCVAkGMsQvy1IHk0d3uzcE
1180 0tEuSh8fZOFGB4fvMx9Mk8oAU92wfj4J7AVpSo5oRdxMqAXfaYKqfr2Gn++q
1181 E5LClhVIBbFXclCoe0RYNz4wtxjeeYbP40Bq5g0JvPutD/dBMp8hz8Qt+yyG
1182 d8X4/KmQIXyFZ8aP17GMckE5GVVvY9y89eWnWuTUJdwM540hB/EJNeHHTE5y
1183 N2FSLGcmNkvE+3H7BczQ2ZI1SZDhof+umbUst0qoQW+hHmY3CSma48yGAVox
1184 52u2t7hosHCfpf631Ve/6fcICo8vJ2Qfufu2BGIMlSfx4WzUuaMQBynuxFSa
1185 IbVx8ZTO7dJRKrg72aFmWTf0uNla7vicAhpiLWobyNYcZbIjrAGDfg==
1187 -----END PGP MESSAGE-----';
1189 $this->_foldersToClear[] = 'INBOX';
1190 $this->_json->saveMessage($messageData);
1192 $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1193 $fullMessage = $this->_json->getMessage($message['id']);
1195 $this->assertContains('multipart/encrypted', $fullMessage['headers']['content-type']);
1196 $this->assertContains('protocol="application/pgp-encrypted"', $fullMessage['headers']['content-type']);
1197 $this->assertCount(2, $fullMessage['structure']['parts']);
1198 $this->assertEquals('application/pgp-encrypted', $fullMessage['structure']['parts'][1]['contentType']);
1199 $this->assertEquals('application/octet-stream', $fullMessage['structure']['parts'][2]['contentType']);
1201 return $fullMessage;
1205 * testMessagePGPMime
1207 * - prepare amored part of PGP MIME structure
1209 public function testMessagePGPMime()
1211 $fullMessage = $this->testSendMailveopeAPIMessage();
1213 $this->assertEquals('application/pgp-encrypted', $fullMessage['preparedParts'][0]['contentType']);
1214 $this->assertContains('-----BEGIN PGP MESSAGE-----', $fullMessage['preparedParts'][0]['preparedData']);
1217 public function testMessagePGPInline()
1219 $inbox = $this->_getFolder('INBOX');
1220 $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/multipart_alternative_pgp_inline.eml');
1221 Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1223 $this->_foldersToClear = array('INBOX');
1224 $message = $this->_searchForMessageBySubject('Re: mailvelope und tine20');
1226 $fullMessage = $this->_json->getMessage($message['id']);
1227 $this->assertFalse(empty($fullMessage['preparedParts']));
1230 /*********************** sieve tests ****************************/
1233 * set and get vacation sieve script
1235 * @see 0007768: Sieve - Vacation notify frequency not being set (Cyrus)
1237 public function testGetSetVacation()
1239 $vacationData = $this->_getVacationData();
1240 $this->_sieveTestHelper($vacationData);
1242 // check if script was activated
1243 $activeScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1244 $this->assertEquals($this->_testSieveScriptName, $activeScriptName);
1245 $updatedAccount = Felamimail_Controller_Account::getInstance()->get($this->_account->getId());
1246 $this->assertTrue((bool) $updatedAccount->sieve_vacation_active);
1248 $result = $this->_json->getVacation($this->_account->getId());
1250 $this->assertEquals($this->_account->email, $result['addresses'][0]);
1252 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1253 if (preg_match('/dbmail/i', $sieveBackend->getImplementation())) {
1254 $translate = Tinebase_Translation::getTranslation('Felamimail');
1255 $vacationData['subject'] = sprintf($translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName);
1258 foreach (array('reason', 'enabled', 'subject', 'from', 'days') as $field) {
1259 $this->assertEquals($vacationData[$field], $result[$field], 'vacation data mismatch: ' . $field);
1268 protected function _getVacationData()
1271 'id' => $this->_account->getId(),
1272 'subject' => 'unittest vacation subject',
1273 'from' => $this->_account->from . ' <' . $this->_account->email . '>',
1276 'reason' => 'unittest vacation message<br /><br />signature',
1282 * test mime vacation sieve script
1284 public function testMimeVacation()
1286 $vacationData = $this->_getVacationData();
1287 $vacationData['reason'] = "\n<html><body><h1>unittest vacation message</h1></body></html>";
1289 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1290 if (! in_array('mime', $_sieveBackend->capability())) {
1291 $vacationData['mime'] = 'text/html';
1294 $this->_sieveTestHelper($vacationData, TRUE);
1298 * test get/set of rules sieve script
1300 public function testGetSetRules()
1302 $ruleData = $this->_getRuleData();
1304 $this->_sieveTestHelper($ruleData);
1307 $result = $this->_json->getRules($this->_account->getId());
1308 $this->assertEquals($result['totalcount'], count($ruleData));
1310 // check by sending mail
1311 $messageData = $this->_getMessageData('', 'viagra');
1312 $returned = $this->_json->saveMessage($messageData);
1313 $this->_foldersToClear = array('INBOX', $this->_testFolderName);
1314 // check if message is in test folder
1315 $message = $this->_searchForMessageBySubject($messageData['subject'], $this->_testFolderName);
1321 * @see 0006490: can not delete single filter rule
1323 public function testRemoveRules()
1325 $this->testGetSetRules();
1326 $this->_json->saveRules($this->_account->getId(), array());
1328 $result = $this->_json->getRules($this->_account->getId());
1329 $this->assertEquals(0, $result['totalcount'], 'found rules: ' . print_r($result, TRUE));
1333 * get sieve rule data
1337 protected function _getRuleData()
1341 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1342 'action_argument' => $this->_testFolderName,
1343 'conjunction' => 'allof',
1344 'conditions' => array(array(
1345 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1346 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1348 'key' => '"abcd" <info@example.org>',
1353 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1354 'action_argument' => $this->_testFolderName,
1355 'conjunction' => 'allof',
1356 'conditions' => array(array(
1357 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1358 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1360 'key' => 'info@example.org',
1365 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1366 'action_argument' => $this->_testFolderName,
1367 'conjunction' => 'allof',
1368 'conditions' => array(array(
1369 'test' => Felamimail_Sieve_Rule_Condition::TEST_HEADER,
1370 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_REGEX,
1371 'header' => 'subject',
1372 'key' => '[vV]iagra|cyalis',
1379 * test to set a forward rule to this accounts email address
1380 * -> should throw exception to prevent mail cycling
1382 public function testSetForwardRuleToSelf()
1384 $ruleData = array(array(
1386 'action_type' => Felamimail_Sieve_Rule_Action::REDIRECT,
1387 'action_argument' => $this->_account->email,
1388 'conjunction' => 'allof',
1389 'conditions' => array(array(
1390 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1391 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1393 'key' => 'info@example.org',
1399 $this->_sieveTestHelper($ruleData);
1400 $this->assertTrue(FALSE, 'it is not allowed to set own email address for redirect!');
1401 } catch (Felamimail_Exception_Sieve $e) {
1402 $this->assertTrue(TRUE);
1406 $ruleData[0]['enabled'] = 0;
1407 $this->_sieveTestHelper($ruleData);
1411 * @see 0006222: Keep a copy from mails forwarded to another emailaddress
1413 public function testSetForwardRuleWithCopy()
1415 $ruleData = array(array(
1417 'action_type' => Felamimail_Sieve_Rule_Action::REDIRECT,
1418 'action_argument' => array(
1419 'emails' => 'someaccount@example.org',
1422 'conjunction' => 'allof',
1423 'conditions' => array(array(
1424 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1425 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1427 'key' => 'info@example.org',
1432 $this->_sieveTestHelper($ruleData);
1436 * @see 0006222: Keep a copy from mails forwarded to another emailaddress
1438 public function testSetForwardRuleWithoutCopy()
1440 $ruleData = array(array(
1442 'action_type' => Felamimail_Sieve_Rule_Action::REDIRECT,
1443 'action_argument' => array(
1444 'emails' => 'someaccount@example.org',
1447 'conjunction' => 'allof',
1448 'conditions' => array(array(
1449 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1450 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1452 'key' => 'info@example.org',
1457 $this->_sieveTestHelper($ruleData);
1461 * testGetVacationTemplates
1465 public function testGetVacationTemplates()
1467 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1469 $this->_addVacationTemplateFile();
1470 $result = $this->_json->getVacationMessageTemplates();
1472 $this->assertTrue($result['totalcount'] > 0, 'no templates found');
1474 foreach ($result['results'] as $template) {
1475 if ($template['name'] === $this->_sieveVacationTemplateFile) {
1481 $this->assertTrue($found, 'wrong templates: ' . print_r($result['results'], TRUE));
1487 * add vacation template file to vfs
1489 protected function _addVacationTemplateFile()
1491 $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
1492 $path = '/webdav/Felamimail/shared/Vacation Templates';
1493 $node = $webdavRoot->getNodeForPath($path);
1494 $this->_pathsToDelete[] = $path . '/' . $this->_sieveVacationTemplateFile;
1495 $node->createFile($this->_sieveVacationTemplateFile, fopen(dirname(__FILE__) . '/../files/' . $this->_sieveVacationTemplateFile, 'r'));
1499 * testGetVacationMessage
1501 public function testGetVacationMessage()
1503 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1505 $result = $this->_getVacationMessageWithTemplate();
1506 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1507 $pwulf = Tinebase_User::getInstance()->getFullUserByLoginName('pwulf');
1508 $this->assertEquals("Ich bin vom 18.04.2012 bis zum 20.04.2012 im Urlaub. Bitte kontaktieren Sie<br /> Paul Wulf (" .
1509 $pwulf->accountEmailAddress . ") oder Susan Clever (" .
1510 $sclever->accountEmailAddress . ").<br /><br />I am on vacation until Apr 20, 2012. Please contact Paul Wulf<br />(" .
1511 $pwulf->accountEmailAddress . ") or Susan Clever (" .
1512 $sclever->accountEmailAddress . ") instead.<br /><br />" .
1513 Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId())->n_fn, $result['message']);
1517 * get vacation message with template
1521 protected function _getVacationMessageWithTemplate()
1523 $template = $this->testGetVacationTemplates();
1524 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1525 $result = $this->_json->getVacationMessage(array(
1526 'start_date' => '2012-04-18',
1527 'end_date' => '2012-04-20',
1528 'contact_ids' => array(
1529 Tinebase_User::getInstance()->getFullUserByLoginName('pwulf')->contact_id,
1530 $sclever->contact_id,
1532 'template_id' => $template['id'],
1533 'signature' => $this->_account->signature
1540 * testGetVacationWithSignature
1542 * @see 0006866: check signature linebreaks in vacation message from template
1544 public function testGetVacationWithSignature()
1546 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1548 $this->_sieveVacationTemplateFile = 'vacation_template_sig.tpl';
1550 // set signature with <br> + linebreaks
1551 $this->_account->signature = "llalala<br>\nxyz<br>\nblubb<br>";
1553 $result = $this->_getVacationMessageWithTemplate();
1554 $this->assertContains('-- <br />llalala<br />xyz<br />blubb<br />', $result['message'], 'wrong linebreaks or missing signature');
1558 * testSetVacationWithStartAndEndDate
1560 * @see 0006266: automatic deactivation of vacation message
1562 public function testSetVacationWithStartAndEndDate()
1564 $vacationData = $this->_getVacationData();
1565 $vacationData['start_date'] = '2012-04-18';
1566 $vacationData['end_date'] = '2012-04-20';
1567 $result = $this->_sieveTestHelper($vacationData);
1569 $this->assertContains($vacationData['start_date'], $result['start_date']);
1570 $this->assertContains($vacationData['end_date'], $result['end_date']);
1574 * testSieveRulesOrder
1576 * @see 0007240: order of sieve rules changes when vacation message is saved
1578 public function testSieveRulesOrder()
1580 $this->_setTestScriptname();
1582 // disable vacation first
1583 $this->_setDisabledVacation();
1585 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1587 $ruleData = $this->_getRuleData();
1588 $ruleData[0]['id'] = $ruleData[2]['id'];
1589 $ruleData[2]['id'] = 11;
1590 $resultSet = $this->_json->saveRules($this->_account->getId(), $ruleData);
1591 $sieveScriptRules = $sieveBackend->getScript($this->_testSieveScriptName);
1593 $this->_setDisabledVacation();
1594 $sieveScriptVacation = $sieveBackend->getScript($this->_testSieveScriptName);
1596 // compare sieve scripts
1597 $this->assertContains($sieveScriptRules, $sieveScriptVacation, 'rule order changed');
1601 * use another name for test sieve script
1603 protected function _setTestScriptname()
1605 $this->_oldActiveSieveScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1606 $this->_testSieveScriptName = 'Felamimail_Unittest';
1607 Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
1611 * set disabled vacation message
1613 protected function _setDisabledVacation()
1615 $vacationData = $this->_getVacationData();
1616 $vacationData['enabled'] = FALSE;
1617 $resultSet = $this->_json->saveVacation($vacationData);
1625 protected function _getFolderFilter()
1628 'field' => 'globalname', 'operator' => 'equals', 'value' => ''
1633 * get message filter
1635 * @param string $_folderId
1638 protected function _getMessageFilter($_folderId)
1640 $result = array(array(
1641 'field' => 'folder_id', 'operator' => 'equals', 'value' => $_folderId
1650 * @param string $name
1651 * @param boolean $createFolder
1652 * @return Felamimail_Model_Folder|NULL
1654 protected function _getFolder($name, $createFolder = TRUE)
1656 Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId());
1658 $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $name);
1659 } catch (Tinebase_Exception_NotFound $tenf) {
1660 $folder = ($createFolder) ? Felamimail_Controller_Folder::getInstance()->create($this->_account, $name) : NULL;
1671 protected function _getMessageData($_emailFrom = '', $_subject = 'test')
1674 'account_id' => $this->_account->getId(),
1675 'subject' => $_subject,
1676 'to' => array(Tinebase_Core::getUser()->accountEmailAddress),
1677 'body' => 'aaaaaä <br>',
1678 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
1679 'from_email' => $_emailFrom,
1680 'content_type' => Felamimail_Model_Message::CONTENT_TYPE_HTML,
1685 * send message and return message array
1687 * @param string $folderName
1688 * @param array $addtionalHeaders
1691 protected function _sendMessage($folderName = 'INBOX', $addtionalHeaders = array())
1693 $messageToSend = $this->_getMessageData();
1694 $messageToSend['headers'] = array_merge($messageToSend['headers'], $addtionalHeaders);
1695 $this->_json->saveMessage($messageToSend);
1696 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1700 $result = $this->_getMessages($folderName);
1701 $message = $this->_getMessageFromSearchResult($result, $messageToSend['subject']);
1702 if (! empty($message)) {
1705 // sleep for 1 sec because mailserver may be slower than expected
1710 $this->assertTrue(! empty($message), 'Sent message not found.');
1716 * returns message array from result
1718 * @param array $_result
1719 * @param string $_subject
1722 protected function _getMessageFromSearchResult($_result, $_subject)
1725 foreach ($_result['results'] as $mail) {
1726 if ($mail['subject'] == $_subject) {
1735 * get messages from folder
1737 * @param string $_folderName
1740 protected function _getMessages($_folderName = 'INBOX')
1742 $folder = $this->_getFolder($_folderName);
1743 $filter = $this->_getMessageFilter($folder->getId());
1745 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10, 1);
1747 while ($folder->cache_status != Felamimail_Model_Folder::CACHE_STATUS_COMPLETE && $i < 10) {
1748 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10);
1751 $result = $this->_json->searchMessages($filter, '');
1757 * search for message defined by subject in folder
1759 * @param string $_subject
1760 * @param string $_folderName
1761 * @return string message data
1763 protected function _searchForMessageBySubject($_subject, $_folderName = 'INBOX')
1765 // give server some time to send and receive messages
1768 $result = $this->_getMessages($_folderName);
1771 foreach ($result['results'] as $mail) {
1772 if ($mail['subject'] == $_subject) {
1776 $this->assertGreaterThan(0, $result['totalcount'], 'folder is empty');
1777 $this->assertTrue(! empty($message), 'Message not found');
1785 * @param array $_sieveData
1788 protected function _sieveTestHelper($_sieveData, $_isMime = FALSE)
1790 $this->_setTestScriptname();
1792 // check which save fn to use
1793 if ((isset($_sieveData['reason']) || array_key_exists('reason', $_sieveData))) {
1794 $resultSet = $this->_json->saveVacation($_sieveData);
1795 $this->assertEquals($this->_account->email, $resultSet['addresses'][0]);
1797 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1799 if (preg_match('/dbmail/i', $_sieveBackend->getImplementation())) {
1800 $translate = Tinebase_Translation::getTranslation('Felamimail');
1801 $this->assertEquals(sprintf(
1802 $translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName),
1803 $resultSet['subject']
1806 $this->assertEquals($_sieveData['subject'], $resultSet['subject']);
1810 $this->assertEquals(html_entity_decode('unittest vacation message', ENT_NOQUOTES, 'UTF-8'), $resultSet['reason']);
1812 $this->assertEquals($_sieveData['reason'], $resultSet['reason']);
1815 } else if ((isset($_sieveData[0]['action_type']) || array_key_exists('action_type', $_sieveData[0]))) {
1816 $resultSet = $this->_json->saveRules($this->_account->getId(), $_sieveData);
1817 $this->assertEquals($_sieveData, $resultSet);
1824 * search preferences by application felamimail
1827 public function testSearchFelamimailPreferences()
1830 $result = $this->_frontend->searchPreferencesForApplication('Felamimail', '');
1833 $this->assertTrue(isset($result['results']));
1834 $this->assertGreaterThan(0, $result['totalcount']);
1838 * testGetRegistryData
1840 * @see 0010251: do not send unused config data to client
1842 public function testGetRegistryData()
1844 $regData = $this->_json->getRegistryData();
1846 $this->assertFalse(isset($regData['defaults']));
1847 $supportedFlags = Felamimail_Config::getInstance()->featureEnabled(Felamimail_Config::FEATURE_TINE20_FLAG)
1850 $this->assertEquals($supportedFlags, $regData['supportedFlags']['totalcount']);