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);
575 $returned = $this->_json->saveMessage($messageToSend);
576 $this->fail('Tinebase_Exception_SystemGeneric expected');
577 } catch (Tinebase_Exception_SystemGeneric $tesg) {
578 $this->assertContains('550 5.1.1 <' . $invalidEmail . '>: Recipient address rejected', $tesg->getMessage(),
579 'exception message did not match: ' . $tesg->getMessage());
584 * try to get a message from imap server (with complete body, attachments, etc)
586 * @see 0006300: add unique message-id header to new messages (for message-id check)
588 public function testGetMessage()
590 $message = $this->_sendMessage();
592 // get complete message
593 $message = $this->_json->getMessage($message['id']);
596 $this->assertTrue(isset($message['headers']) && $message['headers']['message-id']);
597 $this->assertContains('@' . $this->_mailDomain, $message['headers']['message-id']);
598 $this->assertGreaterThan(0, preg_match('/aaaaaä/', $message['body']));
600 // delete message on imap server and check if correct exception is thrown when trying to get it
601 $this->_imap->selectFolder('INBOX');
602 $this->_imap->removeMessage($message['messageuid']);
603 Tinebase_Core::getCache()->clean();
604 $this->setExpectedException('Felamimail_Exception_IMAPMessageNotFound');
605 $message = $this->_json->getMessage($message['id']);
609 * try to get a message as plain/text
611 public function testGetPlainTextMessage()
613 $accountBackend = new Felamimail_Backend_Account();
614 $message = $this->_sendMessage();
616 // get complete message
617 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_PLAIN;
618 $accountBackend->update($this->_account);
619 $message = $this->_json->getMessage($message['id']);
620 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_HTML;
621 $accountBackend->update($this->_account);
624 $this->assertEquals("aaaaaä \n\r\n", $message['body']);
628 * try search for a message with path filter
630 public function testSearchMessageWithPathFilter()
632 $sentMessage = $this->_sendMessage();
633 $filter = array(array(
634 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId()
636 $result = $this->_json->searchMessages($filter, '');
637 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
638 $this->assertTrue(! empty($message), 'Sent message not found with account path filter');
640 $inbox = $this->_getFolder('INBOX');
641 $filter = array(array(
642 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId() . '/' . $inbox->getId()
644 $result = $this->_json->searchMessages($filter, '');
645 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
646 $this->assertTrue(! empty($message), 'Sent message not found with path filter');
647 foreach ($result['results'] as $mail) {
648 $this->assertEquals($inbox->getId(), $mail['folder_id'], 'message is in wrong folder: ' . print_r($mail, TRUE));
653 * try search for a message with all inboxes and flags filter
655 public function testSearchMessageWithAllInboxesFilter()
657 $sentMessage = $this->_sendMessage();
659 array('field' => 'path', 'operator' => 'in', 'value' => Felamimail_Model_MessageFilter::PATH_ALLINBOXES),
660 array('field' => 'flags', 'operator' => 'notin', 'value' => Zend_Mail_Storage::FLAG_FLAGGED),
662 $result = $this->_json->searchMessages($filter, '');
663 $this->assertGreaterThan(0, $result['totalcount']);
664 $this->assertEquals($result['totalcount'], count($result['results']));
666 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
667 $this->assertTrue(! empty($message), 'Sent message not found with all inboxes filter');
671 * try search for a message with three cache filters to force a foreign relation join with at least 2 tables
673 public function testSearchMessageWithThreeCacheFilter()
676 array('field' => 'flags', 'operator' => 'in', 'value' => Zend_Mail_Storage::FLAG_ANSWERED),
677 array('field' => 'to', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
678 array('field' => 'subject', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
680 $result = $this->_json->searchMessages($filter, '');
681 $this->assertEquals(0, $result['totalcount']);
685 * try search for a message with empty path filter
687 public function testSearchMessageEmptyPath()
689 $sentMessage = $this->_sendMessage();
692 array('field' => 'path', 'operator' => 'equals', 'value' => ''),
694 $result = $this->_json->searchMessages($filter, '');
696 $this->assertEquals(0, $result['totalcount']);
697 $accountFilterFound = FALSE;
699 foreach ($result['filter'] as $filter) {
700 if ($filter['field'] === 'account_id' && empty($filter['value'])) {
701 $accountFilterFound = TRUE;
705 $this->assertTrue($accountFilterFound);
709 * test flags (add + clear + deleted)
711 public function testAddAndClearFlags()
713 $message = $this->_sendMessage();
714 $inboxBefore = $this->_getFolder('INBOX');
716 $this->_json->addFlags($message['id'], Zend_Mail_Storage::FLAG_SEEN);
718 // check if unread count got decreased
719 $inboxAfter = $this->_getFolder('INBOX');
720 $this->assertTrue($inboxBefore->cache_unreadcount - 1 == $inboxAfter->cache_unreadcount, 'wrong cache unreadcount');
722 $message = $this->_json->getMessage($message['id']);
723 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag not set');
727 array('field' => 'id', 'operator' => 'in', array($message['id']))
729 $this->_json->clearFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
731 $message = $this->_json->getMessage($message['id']);
732 $this->assertFalse(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag should not be set');
734 $this->setExpectedException('Tinebase_Exception_NotFound');
735 $this->_json->addFlags(array($message['id']), Zend_Mail_Storage::FLAG_DELETED);
736 $this->_json->getMessage($message['id']);
742 * @see 0009812: mark folder as read does not work with pgsql
744 public function testMarkFolderRead()
746 $inboxBefore = $this->_getFolder('INBOX');
747 $filter = array(array(
748 'field' => 'folder_id', 'operator' => 'equals', 'value' => $inboxBefore->getId()
750 'field' => 'flags', 'operator' => 'notin', 'value' => array(Zend_Mail_Storage::FLAG_SEEN)
752 $this->_json->addFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
754 $inboxAfter = $this->_getFolder('INBOX');
755 $this->assertEquals(0, $inboxAfter->cache_unreadcount);
759 * test delete from trash
761 public function testDeleteFromTrashWithFilter()
763 $message = $this->_sendMessage();
764 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
766 $trash = $this->_getFolder($this->_account->trash_folder);
767 $result = $this->_json->moveMessages(array(array(
768 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
769 )), $trash->getId());
771 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
773 // delete messages in trash with filter
774 $this->_json->addFlags(array(array(
775 'field' => 'folder_id', 'operator' => 'equals', 'value' => $trash->getId()
777 'field' => 'id', 'operator' => 'in', 'value' => array($messageInTrash['id'])
778 )), Zend_Mail_Storage::FLAG_DELETED);
780 $this->setExpectedException('Tinebase_Exception_NotFound');
781 $this->_json->getMessage($messageInTrash['id']);
785 * move message to trash with trash folder constant (Felamimail_Model_Folder::FOLDER_TRASH)
787 public function testMoveMessagesToTrash()
789 $message = $this->_sendMessage();
790 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
792 $result = $this->_json->moveMessages(array(array(
793 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
794 )), Felamimail_Model_Folder::FOLDER_TRASH);
796 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
800 * test reply mail and check some headers
802 * @see 0006106: Add References header / https://forge.tine20.org/mantisbt/view.php?id=6106
804 public function testReplyMessage()
806 $message = $this->_sendMessage();
808 $replyMessage = $this->_getReply($message);
809 $returned = $this->_json->saveMessage($replyMessage);
811 $result = $this->_getMessages();
813 $replyMessageFound = array();
814 $originalMessage = array();
815 foreach ($result['results'] as $mail) {
816 if ($mail['subject'] == $replyMessage['subject']) {
817 $replyMessageFound = $mail;
819 if ($mail['subject'] == $message['subject']) {
820 $originalMessage = $mail;
823 $replyMessageFound = $this->_json->getMessage($replyMessageFound['id']);
824 $originalMessage = $this->_json->getMessage($originalMessage['id']);
826 $this->assertTrue(! empty($replyMessageFound), 'replied message not found');
827 $this->assertTrue(! empty($originalMessage), 'original message not found');
830 $this->assertTrue(isset($replyMessageFound['headers']['in-reply-to']));
831 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['in-reply-to']);
832 $this->assertTrue(isset($replyMessageFound['headers']['references']));
833 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['references']);
835 // check answered flag
836 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_ANSWERED, $originalMessage['flags'], 'could not find flag'));
840 * get reply message data
842 * @param array $_original
845 protected function _getReply($_original)
847 $replyMessage = $this->_getMessageData();
848 $replyMessage['subject'] = 'Re: ' . $_original['subject'];
849 $replyMessage['original_id']= $_original['id'];
850 $replyMessage['flags'] = Zend_Mail_Storage::FLAG_ANSWERED;
852 return $replyMessage;
856 * test reply mail in sent folder
858 public function testReplyMessageInSentFolder()
860 $messageInSent = $this->_sendMessage($this->_account->sent_folder);
861 $replyMessage = $this->_getReply($messageInSent);
862 $returned = $this->_json->saveMessage($replyMessage);
864 $result = $this->_getMessages();
865 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
866 $this->assertTrue(! empty($sentMessage));
870 * test reply mail with long references header
872 * @see 0006644: "At least one mail header line is too long"
874 public function testReplyMessageWithLongHeader()
876 $messageInSent = $this->_sendMessage($this->_account->sent_folder, array(
877 'references' => '<c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
878 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
879 <20120530154350.1854610131@ganymed.de>
880 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
881 <4FC8B49C.8040704@funk.de>
882 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
883 <20120601123551.5E98610131@ganymed.de>
884 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
885 <20120619093658.37E4210131@ganymed.de>
886 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
887 <20120619130652.03DD310131@ganymed.de>
888 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
889 <20120620074843.42E2010131@ganymed.de>
890 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
891 <20120620092902.88C8C10131@ganymed.de>
892 <c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
893 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
894 <20120530154350.1854610131@ganymed.de>
895 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
896 <4FC8B49C.8040704@funk.de>
897 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
898 <20120601123551.5E98610131@ganymed.de>
899 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
900 <20120619093658.37E4210131@ganymed.de>
901 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
902 <20120619130652.03DD310131@ganymed.de>
903 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
904 <20120620074843.42E2010131@ganymed.de>
905 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
906 <20120620092902.88C8C10131@ganymed.de>'
908 $replyMessage = $this->_getReply($messageInSent);
909 $returned = $this->_json->saveMessage($replyMessage);
911 $result = $this->_getMessages();
912 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
913 $this->assertTrue(! empty($sentMessage));
919 public function testMoveMessage()
921 $message = $this->_sendMessage();
922 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_testFolderName);
924 $inbox = $this->_getFolder('INBOX');
925 $inboxBefore = $this->_json->updateMessageCache($inbox['id'], 30);
928 $testFolder = $this->_getFolder($this->_testFolderName);
929 $result = $this->_json->moveMessages(array(array(
930 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
931 )), $testFolder->getId());
933 // sleep for 2 secs because mailserver may be slower than expected
936 $inboxAfter = $this->_getFolder('INBOX');
938 // check if count was decreased correctly
939 $this->assertEquals($inboxBefore['cache_unreadcount'] - 1, $inboxAfter['cache_unreadcount']);
940 $this->assertEquals($inboxBefore['cache_totalcount'] - 1, $inboxAfter['cache_totalcount']);
942 $result = $this->_getMessages($this->_testFolderName);
943 $movedMessage = array();
944 foreach ($result['results'] as $mail) {
945 if ($mail['subject'] == $message['subject']) {
946 $movedMessage = $mail;
949 $this->assertTrue(! empty($movedMessage), 'moved message not found');
953 * forward message test
955 * @see 0007624: losing umlauts in attached filenames
957 public function testForwardMessageWithAttachment()
959 $testFolder = $this->_getFolder($this->_testFolderName);
960 $message = fopen(dirname(__FILE__) . '/../files/multipart_related.eml', 'r');
961 Felamimail_Controller_Message::getInstance()->appendMessage($testFolder, $message);
963 $subject = 'Tine 2.0 bei Metaways - Verbessurngsvorschlag';
964 $message = $this->_searchForMessageBySubject($subject, $this->_testFolderName);
966 $fwdSubject = 'Fwd: ' . $subject;
967 $forwardMessageData = array(
968 'account_id' => $this->_account->getId(),
969 'subject' => $fwdSubject,
970 'to' => array($this->_getEmailAddress()),
971 'body' => "aaaaaä <br>",
972 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
973 'original_id' => $message['id'],
974 'attachments' => array(new Tinebase_Model_TempFile(array(
975 'type' => Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822,
976 'name' => 'Verbessurüngsvorschlag',
978 'flags' => Zend_Mail_Storage::FLAG_PASSED,
981 $this->_foldersToClear[] = 'INBOX';
982 $this->_json->saveMessage($forwardMessageData);
983 $forwardMessage = $this->_searchForMessageBySubject($fwdSubject);
985 // check attachment name
986 $forwardMessageComplete = $this->_json->getMessage($forwardMessage['id']);
987 $this->assertEquals(1, count($forwardMessageComplete['attachments']));
988 $this->assertEquals('Verbessurüngsvorschlag.eml', $forwardMessageComplete['attachments'][0]['filename'], 'umlaut missing from attachment filename');
990 $forwardMessage = $this->_json->getMessage($forwardMessage['id']);
991 $this->assertTrue((isset($forwardMessage['structure']) || array_key_exists('structure', $forwardMessage)), 'structure should be set when fetching complete message: ' . print_r($forwardMessage, TRUE));
992 $this->assertEquals(Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822, $forwardMessage['structure']['parts'][2]['contentType']);
994 $message = $this->_json->getMessage($message['id']);
995 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_PASSED, $message['flags']), 'forwarded flag missing in flags: ' . print_r($message, TRUE));
999 * testSendMessageWithAttachmentWithoutExtension
1001 * @see 0008328: email attachment without file extension is not sent properly
1003 public function testSendMessageWithAttachmentWithoutExtension()
1005 $subject = 'attachment test';
1006 $messageToSend = $this->_getMessageData('unittestalias@' . $this->_mailDomain, $subject);
1007 $tempfileName = 'jsontest' . Tinebase_Record_Abstract::generateUID(10);
1008 $tempfilePath = Tinebase_Core::getTempDir() . DIRECTORY_SEPARATOR . $tempfileName;
1009 file_put_contents($tempfilePath, 'some content');
1010 $tempFile = Tinebase_TempFile::getInstance()->createTempFile($tempfilePath, $tempfileName);
1011 $messageToSend['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
1012 $this->_json->saveMessage($messageToSend);
1013 $forwardMessage = $this->_searchForMessageBySubject($subject);
1014 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1016 $fullMessage = $this->_json->getMessage($forwardMessage['id']);
1017 $this->assertTrue(count($fullMessage['attachments']) === 1);
1018 $attachment = $fullMessage['attachments'][0];
1019 $this->assertContains($tempfileName, $attachment['filename'], 'wrong attachment filename: ' . print_r($attachment, TRUE));
1020 $this->assertEquals(16, $attachment['size'], 'wrong attachment size: ' . print_r($attachment, TRUE));
1024 * save message in folder (draft) test
1026 * @see 0007178: BCC does not save the draft message
1028 public function testSaveMessageInFolder()
1030 $messageToSave = $this->_getMessageData();
1031 $messageToSave['bcc'] = array('bccaddress@email.org', 'bccaddress2@email.org');
1033 $draftsFolder = $this->_getFolder($this->_account->drafts_folder);
1034 $returned = $this->_json->saveMessageInFolder($this->_account->drafts_folder, $messageToSave);
1035 $this->_foldersToClear = array($this->_account->drafts_folder);
1037 // check if message is in drafts folder and recipients are present
1038 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->drafts_folder);
1039 $this->assertEquals($messageToSave['subject'], $message['subject']);
1040 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1041 $this->assertEquals(2, count($message['bcc']), 'bcc recipient not found: ' . print_r($message, TRUE));
1042 $this->assertEquals($messageToSave['bcc'][0], $message['bcc'][0], '1st bcc recipient not found');
1043 $this->assertEquals($messageToSave['bcc'][1], $message['bcc'][1], '2nd bcc recipient not found');
1047 * testSendReadingConfirmation
1049 * @see 0007736: ask user before sending reading confirmation
1050 * @see 0008402: Wrong recipient with read confirmation
1052 public function testSendReadingConfirmation()
1054 $messageToSave = $this->_getMessageData();
1055 $messageToSave['headers']['disposition-notification-to'] = '"' . Tinebase_Core::getUser()->accountFullName . '" <' . $this->_account->email . '>';
1056 $returned = $this->_json->saveMessageInFolder($this->_testFolderName, $messageToSave);
1057 $messageWithReadingConfirmationHeader = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_testFolderName);
1058 $this->_messageIds[] = $messageWithReadingConfirmationHeader['id'];
1059 $this->_json->sendReadingConfirmation($messageWithReadingConfirmationHeader['id']);
1061 $translate = Tinebase_Translation::getTranslation('Felamimail');
1062 $subject = $translate->_('Reading Confirmation:') . ' '. $messageToSave['subject'];
1063 $message = $this->_searchForMessageBySubject($subject);
1064 $this->_messageIds[] = $message['id'];
1066 $complete = $this->_json->getMessage($message['id']);
1067 $this->assertContains($translate->_('Was read by:') . ' ' . $this->_account->from, $complete['body']);
1071 * save message in non-existant folder (templates) test
1073 * @see 0008476: Drafts are not working
1075 public function testSaveMessageInNonExistantTemplatesFolder()
1077 $messageToSave = $this->_getMessageData();
1079 $templatesFolder = $this->_getFolder($this->_account->templates_folder, FALSE);
1080 if ($templatesFolder) {
1081 $this->_json->deleteFolder($templatesFolder['id'], $this->_account->getId());
1083 $returned = $this->_json->saveMessageInFolder($this->_account->templates_folder, $messageToSave);
1084 $this->_foldersToClear = array($this->_account->templates_folder);
1086 // check if message is in templates folder
1087 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->templates_folder);
1088 $this->assertEquals($messageToSave['subject'], $message['subject']);
1089 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1093 * testSaveMessageNoteWithInvalidChar
1095 * @see 0008644: error when sending mail with note (wrong charset)
1097 public function testSaveMessageNoteWithInvalidChar()
1099 $subject = Tinebase_Core::filterInputForDatabase("\xF0\x9F\x98\x8A\xC2"); // :-) emoji
1100 $messageData = $this->_getMessageData('', $subject);
1101 $messageData['note'] = true;
1102 $messageData['body'] .= " ";
1104 $this->_foldersToClear[] = 'INBOX';
1105 $this->_json->saveMessage($messageData);
1106 $message = $this->_searchForMessageBySubject($subject);
1108 $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
1109 $this->_checkEmailNote($contact, $subject);
1113 * testSaveMessageNoteWithInvalidChar
1115 * @see 0008644: error when sending mail with note (wrong charset)
1117 public function testSaveMessageWithInvalidChar()
1119 $subject = "\xF0\x9F\x98\x8A"; // :-) emoji
1120 $messageData = $this->_getMessageData('', $subject);
1121 $this->_foldersToClear[] = 'INBOX';
1122 $this->_json->saveMessage($messageData);
1123 $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1127 * testMessageWithInvalidICS
1129 * @see 0008786: broken ics causes js error when showing details
1131 public function testMessageWithInvalidICS()
1133 $inbox = $this->_getFolder('INBOX');
1134 $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/invalidimip.eml');
1135 Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1137 $this->_foldersToClear = array('INBOX');
1138 $message = $this->_searchForMessageBySubject('test invalid imip');
1140 $fullMessage = $this->_json->getMessage($message['id']);
1141 $this->assertTrue(empty($fullMessage->preparedParts));
1144 /*********************** sieve tests ****************************/
1147 * set and get vacation sieve script
1149 * @see 0007768: Sieve - Vacation notify frequency not being set (Cyrus)
1151 public function testGetSetVacation()
1153 $vacationData = $this->_getVacationData();
1154 $this->_sieveTestHelper($vacationData);
1156 // check if script was activated
1157 $activeScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1158 $this->assertEquals($this->_testSieveScriptName, $activeScriptName);
1159 $updatedAccount = Felamimail_Controller_Account::getInstance()->get($this->_account->getId());
1160 $this->assertTrue((bool) $updatedAccount->sieve_vacation_active);
1162 $result = $this->_json->getVacation($this->_account->getId());
1164 $this->assertEquals($this->_account->email, $result['addresses'][0]);
1166 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1167 if (preg_match('/dbmail/i', $sieveBackend->getImplementation())) {
1168 $translate = Tinebase_Translation::getTranslation('Felamimail');
1169 $vacationData['subject'] = sprintf($translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName);
1172 foreach (array('reason', 'enabled', 'subject', 'from', 'days') as $field) {
1173 $this->assertEquals($vacationData[$field], $result[$field], 'vacation data mismatch: ' . $field);
1182 protected function _getVacationData()
1185 'id' => $this->_account->getId(),
1186 'subject' => 'unittest vacation subject',
1187 'from' => $this->_account->from . ' <' . $this->_account->email . '>',
1190 'reason' => 'unittest vacation message<br /><br />signature',
1196 * test mime vacation sieve script
1198 public function testMimeVacation()
1200 $vacationData = $this->_getVacationData();
1201 $vacationData['reason'] = "\n<html><body><h1>unittest vacation message</h1></body></html>";
1203 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1204 if (! in_array('mime', $_sieveBackend->capability())) {
1205 $vacationData['mime'] = 'text/html';
1208 $this->_sieveTestHelper($vacationData, TRUE);
1212 * test get/set of rules sieve script
1214 public function testGetSetRules()
1216 $ruleData = $this->_getRuleData();
1218 $this->_sieveTestHelper($ruleData);
1221 $result = $this->_json->getRules($this->_account->getId());
1222 $this->assertEquals($result['totalcount'], count($ruleData));
1224 // check by sending mail
1225 $messageData = $this->_getMessageData('', 'viagra');
1226 $returned = $this->_json->saveMessage($messageData);
1227 $this->_foldersToClear = array('INBOX', $this->_testFolderName);
1228 // check if message is in test folder
1229 $message = $this->_searchForMessageBySubject($messageData['subject'], $this->_testFolderName);
1235 * @see 0006490: can not delete single filter rule
1237 public function testRemoveRules()
1239 $this->testGetSetRules();
1240 $this->_json->saveRules($this->_account->getId(), array());
1242 $result = $this->_json->getRules($this->_account->getId());
1243 $this->assertEquals(0, $result['totalcount'], 'found rules: ' . print_r($result, TRUE));
1247 * get sieve rule data
1251 protected function _getRuleData()
1255 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1256 'action_argument' => $this->_testFolderName,
1257 'conjunction' => 'allof',
1258 'conditions' => array(array(
1259 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1260 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1262 'key' => '"abcd" <info@example.org>',
1267 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1268 'action_argument' => $this->_testFolderName,
1269 'conjunction' => 'allof',
1270 'conditions' => array(array(
1271 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1272 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1274 'key' => 'info@example.org',
1279 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1280 'action_argument' => $this->_testFolderName,
1281 'conjunction' => 'allof',
1282 'conditions' => array(array(
1283 'test' => Felamimail_Sieve_Rule_Condition::TEST_HEADER,
1284 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_REGEX,
1285 'header' => 'subject',
1286 'key' => '[vV]iagra|cyalis',
1293 * test to set a forward rule to this accounts email address
1294 * -> should throw exception to prevent mail cycling
1296 public function testSetForwardRuleToSelf()
1298 $ruleData = array(array(
1300 'action_type' => Felamimail_Sieve_Rule_Action::REDIRECT,
1301 'action_argument' => $this->_account->email,
1302 'conjunction' => 'allof',
1303 'conditions' => array(array(
1304 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1305 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1307 'key' => 'info@example.org',
1313 $this->_sieveTestHelper($ruleData);
1314 $this->assertTrue(FALSE, 'it is not allowed to set own email address for redirect!');
1315 } catch (Felamimail_Exception_Sieve $e) {
1316 $this->assertTrue(TRUE);
1320 $ruleData[0]['enabled'] = 0;
1321 $this->_sieveTestHelper($ruleData);
1325 * testGetVacationTemplates
1329 public function testGetVacationTemplates()
1331 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1333 $this->_addVacationTemplateFile();
1334 $result = $this->_json->getVacationMessageTemplates();
1336 $this->assertTrue($result['totalcount'] > 0, 'no templates found');
1338 foreach ($result['results'] as $template) {
1339 if ($template['name'] === $this->_sieveVacationTemplateFile) {
1345 $this->assertTrue($found, 'wrong templates: ' . print_r($result['results'], TRUE));
1351 * add vacation template file to vfs
1353 protected function _addVacationTemplateFile()
1355 $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
1356 $path = '/webdav/Felamimail/shared/Vacation Templates';
1357 $node = $webdavRoot->getNodeForPath($path);
1358 $this->_pathsToDelete[] = $path . '/' . $this->_sieveVacationTemplateFile;
1359 $node->createFile($this->_sieveVacationTemplateFile, fopen(dirname(__FILE__) . '/../files/' . $this->_sieveVacationTemplateFile, 'r'));
1363 * testGetVacationMessage
1365 public function testGetVacationMessage()
1367 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1369 $result = $this->_getVacationMessageWithTemplate();
1370 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1371 $pwulf = Tinebase_User::getInstance()->getFullUserByLoginName('pwulf');
1372 $this->assertEquals("Ich bin vom 18.04.2012 bis zum 20.04.2012 im Urlaub. Bitte kontaktieren Sie<br /> Paul Wulf (" .
1373 $pwulf->accountEmailAddress . ") oder Susan Clever (" .
1374 $sclever->accountEmailAddress . ").<br /><br />I am on vacation until Apr 20, 2012. Please contact Paul Wulf<br />(" .
1375 $pwulf->accountEmailAddress . ") or Susan Clever (" .
1376 $sclever->accountEmailAddress . ") instead.<br /><br />" .
1377 Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId())->n_fn, $result['message']);
1381 * get vacation message with template
1385 protected function _getVacationMessageWithTemplate()
1387 $template = $this->testGetVacationTemplates();
1388 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1389 $result = $this->_json->getVacationMessage(array(
1390 'start_date' => '2012-04-18',
1391 'end_date' => '2012-04-20',
1392 'contact_ids' => array(
1393 Tinebase_User::getInstance()->getFullUserByLoginName('pwulf')->contact_id,
1394 $sclever->contact_id,
1396 'template_id' => $template['id'],
1397 'signature' => $this->_account->signature
1404 * testGetVacationWithSignature
1406 * @see 0006866: check signature linebreaks in vacation message from template
1408 public function testGetVacationWithSignature()
1410 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1412 $this->_sieveVacationTemplateFile = 'vacation_template_sig.tpl';
1414 // set signature with <br> + linebreaks
1415 $this->_account->signature = "llalala<br>\nxyz<br>\nblubb<br>";
1417 $result = $this->_getVacationMessageWithTemplate();
1418 $this->assertContains('-- <br />llalala<br />xyz<br />blubb<br />', $result['message'], 'wrong linebreaks or missing signature');
1422 * testSetVacationWithStartAndEndDate
1424 * @see 0006266: automatic deactivation of vacation message
1426 public function testSetVacationWithStartAndEndDate()
1428 $vacationData = $this->_getVacationData();
1429 $vacationData['start_date'] = '2012-04-18';
1430 $vacationData['end_date'] = '2012-04-20';
1431 $result = $this->_sieveTestHelper($vacationData);
1433 $this->assertContains($vacationData['start_date'], $result['start_date']);
1434 $this->assertContains($vacationData['end_date'], $result['end_date']);
1438 * testSieveRulesOrder
1440 * @see 0007240: order of sieve rules changes when vacation message is saved
1442 public function testSieveRulesOrder()
1444 $this->_setTestScriptname();
1446 // disable vacation first
1447 $this->_setDisabledVacation();
1449 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1451 $ruleData = $this->_getRuleData();
1452 $ruleData[0]['id'] = $ruleData[2]['id'];
1453 $ruleData[2]['id'] = 11;
1454 $resultSet = $this->_json->saveRules($this->_account->getId(), $ruleData);
1455 $sieveScriptRules = $sieveBackend->getScript($this->_testSieveScriptName);
1457 $this->_setDisabledVacation();
1458 $sieveScriptVacation = $sieveBackend->getScript($this->_testSieveScriptName);
1460 // compare sieve scripts
1461 $this->assertContains($sieveScriptRules, $sieveScriptVacation, 'rule order changed');
1465 * use another name for test sieve script
1467 protected function _setTestScriptname()
1469 $this->_oldActiveSieveScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1470 $this->_testSieveScriptName = 'Felamimail_Unittest';
1471 Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
1475 * set disabled vacation message
1477 protected function _setDisabledVacation()
1479 $vacationData = $this->_getVacationData();
1480 $vacationData['enabled'] = FALSE;
1481 $resultSet = $this->_json->saveVacation($vacationData);
1489 protected function _getFolderFilter()
1492 'field' => 'globalname', 'operator' => 'equals', 'value' => ''
1497 * get message filter
1499 * @param string $_folderId
1502 protected function _getMessageFilter($_folderId)
1504 $result = array(array(
1505 'field' => 'folder_id', 'operator' => 'equals', 'value' => $_folderId
1514 * @param string $name
1515 * @param boolean $createFolder
1516 * @return Felamimail_Model_Folder|NULL
1518 protected function _getFolder($name, $createFolder = TRUE)
1520 Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId());
1522 $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $name);
1523 } catch (Tinebase_Exception_NotFound $tenf) {
1524 $folder = ($createFolder) ? Felamimail_Controller_Folder::getInstance()->create($this->_account, $name) : NULL;
1535 protected function _getMessageData($_emailFrom = '', $_subject = 'test')
1538 'account_id' => $this->_account->getId(),
1539 'subject' => $_subject,
1540 'to' => array(Tinebase_Core::getUser()->accountEmailAddress),
1541 'body' => 'aaaaaä <br>',
1542 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
1543 'from_email' => $_emailFrom,
1544 'content_type' => Felamimail_Model_Message::CONTENT_TYPE_HTML,
1549 * send message and return message array
1551 * @param string $folderName
1552 * @param array $addtionalHeaders
1555 protected function _sendMessage($folderName = 'INBOX', $addtionalHeaders = array())
1557 $messageToSend = $this->_getMessageData();
1558 $messageToSend['headers'] = array_merge($messageToSend['headers'], $addtionalHeaders);
1559 $this->_json->saveMessage($messageToSend);
1560 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1564 $result = $this->_getMessages($folderName);
1565 $message = $this->_getMessageFromSearchResult($result, $messageToSend['subject']);
1566 if (! empty($message)) {
1569 // sleep for 1 sec because mailserver may be slower than expected
1574 $this->assertTrue(! empty($message), 'Sent message not found.');
1580 * returns message array from result
1582 * @param array $_result
1583 * @param string $_subject
1586 protected function _getMessageFromSearchResult($_result, $_subject)
1589 foreach ($_result['results'] as $mail) {
1590 if ($mail['subject'] == $_subject) {
1599 * get messages from folder
1601 * @param string $_folderName
1604 protected function _getMessages($_folderName = 'INBOX')
1606 $folder = $this->_getFolder($_folderName);
1607 $filter = $this->_getMessageFilter($folder->getId());
1609 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10, 1);
1611 while ($folder->cache_status != Felamimail_Model_Folder::CACHE_STATUS_COMPLETE && $i < 10) {
1612 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10);
1615 $result = $this->_json->searchMessages($filter, '');
1621 * search for message defined by subject in folder
1623 * @param string $_subject
1624 * @param string $_folderName
1625 * @return string message data
1627 protected function _searchForMessageBySubject($_subject, $_folderName = 'INBOX')
1629 // give server some time to send and receive messages
1632 $result = $this->_getMessages($_folderName);
1635 foreach ($result['results'] as $mail) {
1636 if ($mail['subject'] == $_subject) {
1640 $this->assertGreaterThan(0, $result['totalcount'], 'folder is empty');
1641 $this->assertTrue(! empty($message), 'Message not found');
1649 * @param array $_sieveData
1652 protected function _sieveTestHelper($_sieveData, $_isMime = FALSE)
1654 $this->_setTestScriptname();
1656 // check which save fn to use
1657 if ((isset($_sieveData['reason']) || array_key_exists('reason', $_sieveData))) {
1658 $resultSet = $this->_json->saveVacation($_sieveData);
1659 $this->assertEquals($this->_account->email, $resultSet['addresses'][0]);
1661 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1663 if (preg_match('/dbmail/i', $_sieveBackend->getImplementation())) {
1664 $translate = Tinebase_Translation::getTranslation('Felamimail');
1665 $this->assertEquals(sprintf(
1666 $translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName),
1667 $resultSet['subject']
1670 $this->assertEquals($_sieveData['subject'], $resultSet['subject']);
1674 $this->assertEquals(html_entity_decode('unittest vacation message', ENT_NOQUOTES, 'UTF-8'), $resultSet['reason']);
1676 $this->assertEquals($_sieveData['reason'], $resultSet['reason']);
1679 } else if ((isset($_sieveData[0]['action_type']) || array_key_exists('action_type', $_sieveData[0]))) {
1680 $resultSet = $this->_json->saveRules($this->_account->getId(), $_sieveData);
1681 $this->assertEquals($_sieveData, $resultSet);
1688 * search preferences by application felamimail
1691 public function testSearchFelamimailPreferences()
1694 $result = $this->_frontend->searchPreferencesForApplication('Felamimail', '');
1697 $this->assertTrue(isset($result['results']));
1698 $this->assertGreaterThan(0, $result['totalcount']);
1702 * testGetRegistryData
1704 * @see 0010251: do not send unused config data to client
1706 public function testGetRegistryData()
1708 $regData = $this->_json->getRegistryData();
1710 $this->assertFalse(isset($regData['defaults']));
1711 $supportedFlags = Felamimail_Config::getInstance()->featureEnabled(Felamimail_Config::FEATURE_TINE20_FLAG)
1714 $this->assertEquals($supportedFlags, $regData['supportedFlags']['totalcount']);