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 $this->markTestSkipped('FIXME: 0011802: Felamimail_Frontend_JsonTest::testSendMessageToInvalidRecipient fails');
572 $messageToSend = $this->_getMessageData($this->_account->email);
573 $invalidEmail = 'invaliduser@' . $this->_mailDomain;
574 $messageToSend['to'] = array($invalidEmail);
575 $translation = Tinebase_Translation::getTranslation('Felamimail');
578 $returned = $this->_json->saveMessage($messageToSend);
579 $this->fail('Tinebase_Exception_SystemGeneric expected');
580 } catch (Tinebase_Exception_SystemGeneric $tesg) {
581 $this->assertContains('<' . $invalidEmail . '>: ' . $translation->_('Recipient address rejected'), $tesg->getMessage(),
582 'exception message did not match: ' . $tesg->getMessage());
587 * try to get a message from imap server (with complete body, attachments, etc)
589 * @see 0006300: add unique message-id header to new messages (for message-id check)
591 public function testGetMessage()
593 $message = $this->_sendMessage();
595 // get complete message
596 $message = $this->_json->getMessage($message['id']);
599 $this->assertTrue(isset($message['headers']) && $message['headers']['message-id']);
600 $this->assertContains('@' . $this->_mailDomain, $message['headers']['message-id']);
601 $this->assertGreaterThan(0, preg_match('/aaaaaä/', $message['body']));
603 // delete message on imap server and check if correct exception is thrown when trying to get it
604 $this->_imap->selectFolder('INBOX');
605 $this->_imap->removeMessage($message['messageuid']);
606 Tinebase_Core::getCache()->clean();
607 $this->setExpectedException('Felamimail_Exception_IMAPMessageNotFound');
608 $message = $this->_json->getMessage($message['id']);
612 * try to get a message as plain/text
614 public function testGetPlainTextMessage()
616 $accountBackend = new Felamimail_Backend_Account();
617 $message = $this->_sendMessage();
619 // get complete message
620 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_PLAIN;
621 $accountBackend->update($this->_account);
622 $message = $this->_json->getMessage($message['id']);
623 $this->_account->display_format = Felamimail_Model_Account::DISPLAY_HTML;
624 $accountBackend->update($this->_account);
627 $this->assertEquals("aaaaaä \n\r\n", $message['body']);
631 * try search for a message with path filter
633 public function testSearchMessageWithPathFilter()
635 $sentMessage = $this->_sendMessage();
636 $filter = array(array(
637 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId()
639 $result = $this->_json->searchMessages($filter, '');
640 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
641 $this->assertTrue(! empty($message), 'Sent message not found with account path filter');
643 $inbox = $this->_getFolder('INBOX');
644 $filter = array(array(
645 'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId() . '/' . $inbox->getId()
647 $result = $this->_json->searchMessages($filter, '');
648 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
649 $this->assertTrue(! empty($message), 'Sent message not found with path filter');
650 foreach ($result['results'] as $mail) {
651 $this->assertEquals($inbox->getId(), $mail['folder_id'], 'message is in wrong folder: ' . print_r($mail, TRUE));
656 * try search for a message with all inboxes and flags filter
658 public function testSearchMessageWithAllInboxesFilter()
660 $sentMessage = $this->_sendMessage();
662 array('field' => 'path', 'operator' => 'in', 'value' => Felamimail_Model_MessageFilter::PATH_ALLINBOXES),
663 array('field' => 'flags', 'operator' => 'notin', 'value' => Zend_Mail_Storage::FLAG_FLAGGED),
665 $result = $this->_json->searchMessages($filter, '');
666 $this->assertGreaterThan(0, $result['totalcount']);
667 $this->assertEquals($result['totalcount'], count($result['results']));
669 $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
670 $this->assertTrue(! empty($message), 'Sent message not found with all inboxes filter');
674 * try search for a message with three cache filters to force a foreign relation join with at least 2 tables
676 public function testSearchMessageWithThreeCacheFilter()
679 array('field' => 'flags', 'operator' => 'in', 'value' => Zend_Mail_Storage::FLAG_ANSWERED),
680 array('field' => 'to', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
681 array('field' => 'subject', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
683 $result = $this->_json->searchMessages($filter, '');
684 $this->assertEquals(0, $result['totalcount']);
688 * try search for a message with empty path filter
690 public function testSearchMessageEmptyPath()
692 $sentMessage = $this->_sendMessage();
695 array('field' => 'path', 'operator' => 'equals', 'value' => ''),
697 $result = $this->_json->searchMessages($filter, '');
699 $this->assertEquals(0, $result['totalcount']);
700 $accountFilterFound = FALSE;
702 foreach ($result['filter'] as $filter) {
703 if ($filter['field'] === 'account_id' && empty($filter['value'])) {
704 $accountFilterFound = TRUE;
708 $this->assertTrue($accountFilterFound);
712 * test flags (add + clear + deleted)
714 public function testAddAndClearFlags()
716 $message = $this->_sendMessage();
717 $inboxBefore = $this->_getFolder('INBOX');
719 $this->_json->addFlags($message['id'], Zend_Mail_Storage::FLAG_SEEN);
721 // check if unread count got decreased
722 $inboxAfter = $this->_getFolder('INBOX');
723 $this->assertTrue($inboxBefore->cache_unreadcount - 1 == $inboxAfter->cache_unreadcount, 'wrong cache unreadcount');
725 $message = $this->_json->getMessage($message['id']);
726 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag not set');
730 array('field' => 'id', 'operator' => 'in', array($message['id']))
732 $this->_json->clearFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
734 $message = $this->_json->getMessage($message['id']);
735 $this->assertFalse(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag should not be set');
737 $this->setExpectedException('Tinebase_Exception_NotFound');
738 $this->_json->addFlags(array($message['id']), Zend_Mail_Storage::FLAG_DELETED);
739 $this->_json->getMessage($message['id']);
745 * @see 0009812: mark folder as read does not work with pgsql
747 public function testMarkFolderRead()
749 $inboxBefore = $this->_getFolder('INBOX');
750 $filter = array(array(
751 'field' => 'folder_id', 'operator' => 'equals', 'value' => $inboxBefore->getId()
753 'field' => 'flags', 'operator' => 'notin', 'value' => array(Zend_Mail_Storage::FLAG_SEEN)
755 $this->_json->addFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
757 $inboxAfter = $this->_getFolder('INBOX');
758 $this->assertEquals(0, $inboxAfter->cache_unreadcount);
762 * test delete from trash
764 public function testDeleteFromTrashWithFilter()
766 $message = $this->_sendMessage();
767 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
769 $trash = $this->_getFolder($this->_account->trash_folder);
770 $result = $this->_json->moveMessages(array(array(
771 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
772 )), $trash->getId());
774 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
776 // delete messages in trash with filter
777 $this->_json->addFlags(array(array(
778 'field' => 'folder_id', 'operator' => 'equals', 'value' => $trash->getId()
780 'field' => 'id', 'operator' => 'in', 'value' => array($messageInTrash['id'])
781 )), Zend_Mail_Storage::FLAG_DELETED);
783 $this->setExpectedException('Tinebase_Exception_NotFound');
784 $this->_json->getMessage($messageInTrash['id']);
788 * move message to trash with trash folder constant (Felamimail_Model_Folder::FOLDER_TRASH)
790 public function testMoveMessagesToTrash()
792 $message = $this->_sendMessage();
793 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
795 $result = $this->_json->moveMessages(array(array(
796 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
797 )), Felamimail_Model_Folder::FOLDER_TRASH);
799 $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
803 * test reply mail and check some headers
805 * @see 0006106: Add References header / https://forge.tine20.org/mantisbt/view.php?id=6106
807 public function testReplyMessage()
809 $message = $this->_sendMessage();
811 $replyMessage = $this->_getReply($message);
812 $returned = $this->_json->saveMessage($replyMessage);
814 $result = $this->_getMessages();
816 $replyMessageFound = array();
817 $originalMessage = array();
818 foreach ($result['results'] as $mail) {
819 if ($mail['subject'] == $replyMessage['subject']) {
820 $replyMessageFound = $mail;
822 if ($mail['subject'] == $message['subject']) {
823 $originalMessage = $mail;
826 $replyMessageFound = $this->_json->getMessage($replyMessageFound['id']);
827 $originalMessage = $this->_json->getMessage($originalMessage['id']);
829 $this->assertTrue(! empty($replyMessageFound), 'replied message not found');
830 $this->assertTrue(! empty($originalMessage), 'original message not found');
833 $this->assertTrue(isset($replyMessageFound['headers']['in-reply-to']));
834 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['in-reply-to']);
835 $this->assertTrue(isset($replyMessageFound['headers']['references']));
836 $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['references']);
838 // check answered flag
839 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_ANSWERED, $originalMessage['flags'], 'could not find flag'));
843 * get reply message data
845 * @param array $_original
848 protected function _getReply($_original)
850 $replyMessage = $this->_getMessageData();
851 $replyMessage['subject'] = 'Re: ' . $_original['subject'];
852 $replyMessage['original_id']= $_original['id'];
853 $replyMessage['flags'] = Zend_Mail_Storage::FLAG_ANSWERED;
855 return $replyMessage;
859 * test reply mail in sent folder
861 public function testReplyMessageInSentFolder()
863 $messageInSent = $this->_sendMessage($this->_account->sent_folder);
864 $replyMessage = $this->_getReply($messageInSent);
865 $returned = $this->_json->saveMessage($replyMessage);
867 $result = $this->_getMessages();
868 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
869 $this->assertTrue(! empty($sentMessage));
873 * test reply mail with long references header
875 * @see 0006644: "At least one mail header line is too long"
877 public function testReplyMessageWithLongHeader()
879 $messageInSent = $this->_sendMessage($this->_account->sent_folder, array(
880 'references' => '<c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
881 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
882 <20120530154350.1854610131@ganymed.de>
883 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
884 <4FC8B49C.8040704@funk.de>
885 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
886 <20120601123551.5E98610131@ganymed.de>
887 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
888 <20120619093658.37E4210131@ganymed.de>
889 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
890 <20120619130652.03DD310131@ganymed.de>
891 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
892 <20120620074843.42E2010131@ganymed.de>
893 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
894 <20120620092902.88C8C10131@ganymed.de>
895 <c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
896 <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
897 <20120530154350.1854610131@ganymed.de>
898 <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
899 <4FC8B49C.8040704@funk.de>
900 <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
901 <20120601123551.5E98610131@ganymed.de>
902 <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
903 <20120619093658.37E4210131@ganymed.de>
904 <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
905 <20120619130652.03DD310131@ganymed.de>
906 <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
907 <20120620074843.42E2010131@ganymed.de>
908 <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
909 <20120620092902.88C8C10131@ganymed.de>'
911 $replyMessage = $this->_getReply($messageInSent);
912 $returned = $this->_json->saveMessage($replyMessage);
914 $result = $this->_getMessages();
915 $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
916 $this->assertTrue(! empty($sentMessage));
922 public function testMoveMessage()
924 $message = $this->_sendMessage();
925 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_testFolderName);
927 $inbox = $this->_getFolder('INBOX');
928 $inboxBefore = $this->_json->updateMessageCache($inbox['id'], 30);
931 $testFolder = $this->_getFolder($this->_testFolderName);
932 $result = $this->_json->moveMessages(array(array(
933 'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
934 )), $testFolder->getId());
936 // sleep for 2 secs because mailserver may be slower than expected
939 $inboxAfter = $this->_getFolder('INBOX');
941 // check if count was decreased correctly
942 $this->assertEquals($inboxBefore['cache_unreadcount'] - 1, $inboxAfter['cache_unreadcount']);
943 $this->assertEquals($inboxBefore['cache_totalcount'] - 1, $inboxAfter['cache_totalcount']);
945 $result = $this->_getMessages($this->_testFolderName);
946 $movedMessage = array();
947 foreach ($result['results'] as $mail) {
948 if ($mail['subject'] == $message['subject']) {
949 $movedMessage = $mail;
952 $this->assertTrue(! empty($movedMessage), 'moved message not found');
956 * forward message test
958 * @see 0007624: losing umlauts in attached filenames
960 public function testForwardMessageWithAttachment()
962 $testFolder = $this->_getFolder($this->_testFolderName);
963 $message = fopen(dirname(__FILE__) . '/../files/multipart_related.eml', 'r');
964 Felamimail_Controller_Message::getInstance()->appendMessage($testFolder, $message);
966 $subject = 'Tine 2.0 bei Metaways - Verbessurngsvorschlag';
967 $message = $this->_searchForMessageBySubject($subject, $this->_testFolderName);
969 $fwdSubject = 'Fwd: ' . $subject;
970 $forwardMessageData = array(
971 'account_id' => $this->_account->getId(),
972 'subject' => $fwdSubject,
973 'to' => array($this->_getEmailAddress()),
974 'body' => "aaaaaä <br>",
975 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
976 'original_id' => $message['id'],
977 'attachments' => array(new Tinebase_Model_TempFile(array(
978 'type' => Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822,
979 'name' => 'Verbessurüngsvorschlag',
981 'flags' => Zend_Mail_Storage::FLAG_PASSED,
984 $this->_foldersToClear[] = 'INBOX';
985 $this->_json->saveMessage($forwardMessageData);
986 $forwardMessage = $this->_searchForMessageBySubject($fwdSubject);
988 // check attachment name
989 $forwardMessageComplete = $this->_json->getMessage($forwardMessage['id']);
990 $this->assertEquals(1, count($forwardMessageComplete['attachments']));
991 $this->assertEquals('Verbessurüngsvorschlag.eml', $forwardMessageComplete['attachments'][0]['filename'], 'umlaut missing from attachment filename');
993 $forwardMessage = $this->_json->getMessage($forwardMessage['id']);
994 $this->assertTrue((isset($forwardMessage['structure']) || array_key_exists('structure', $forwardMessage)), 'structure should be set when fetching complete message: ' . print_r($forwardMessage, TRUE));
995 $this->assertEquals(Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822, $forwardMessage['structure']['parts'][2]['contentType']);
997 $message = $this->_json->getMessage($message['id']);
998 $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_PASSED, $message['flags']), 'forwarded flag missing in flags: ' . print_r($message, TRUE));
1002 * testSendMessageWithAttachmentWithoutExtension
1004 * @see 0008328: email attachment without file extension is not sent properly
1006 public function testSendMessageWithAttachmentWithoutExtension()
1008 $subject = 'attachment test';
1009 $messageToSend = $this->_getMessageData('unittestalias@' . $this->_mailDomain, $subject);
1010 $tempfileName = 'jsontest' . Tinebase_Record_Abstract::generateUID(10);
1011 $tempfilePath = Tinebase_Core::getTempDir() . DIRECTORY_SEPARATOR . $tempfileName;
1012 file_put_contents($tempfilePath, 'some content');
1013 $tempFile = Tinebase_TempFile::getInstance()->createTempFile($tempfilePath, $tempfileName);
1014 $messageToSend['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
1015 $this->_json->saveMessage($messageToSend);
1016 $forwardMessage = $this->_searchForMessageBySubject($subject);
1017 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1019 $fullMessage = $this->_json->getMessage($forwardMessage['id']);
1020 $this->assertTrue(count($fullMessage['attachments']) === 1);
1021 $attachment = $fullMessage['attachments'][0];
1022 $this->assertContains($tempfileName, $attachment['filename'], 'wrong attachment filename: ' . print_r($attachment, TRUE));
1023 $this->assertEquals(16, $attachment['size'], 'wrong attachment size: ' . print_r($attachment, TRUE));
1027 * save message in folder (draft) test
1029 * @see 0007178: BCC does not save the draft message
1031 public function testSaveMessageInFolder()
1033 $messageToSave = $this->_getMessageData();
1034 $messageToSave['bcc'] = array('bccaddress@email.org', 'bccaddress2@email.org');
1036 $draftsFolder = $this->_getFolder($this->_account->drafts_folder);
1037 $returned = $this->_json->saveMessageInFolder($this->_account->drafts_folder, $messageToSave);
1038 $this->_foldersToClear = array($this->_account->drafts_folder);
1040 // check if message is in drafts folder and recipients are present
1041 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->drafts_folder);
1042 $this->assertEquals($messageToSave['subject'], $message['subject']);
1043 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1044 $this->assertEquals(2, count($message['bcc']), 'bcc recipient not found: ' . print_r($message, TRUE));
1045 $this->assertEquals($messageToSave['bcc'][0], $message['bcc'][0], '1st bcc recipient not found');
1046 $this->assertEquals($messageToSave['bcc'][1], $message['bcc'][1], '2nd bcc recipient not found');
1050 * testSendReadingConfirmation
1052 * @see 0007736: ask user before sending reading confirmation
1053 * @see 0008402: Wrong recipient with read confirmation
1055 public function testSendReadingConfirmation()
1057 $messageToSave = $this->_getMessageData();
1058 $messageToSave['headers']['disposition-notification-to'] = '"' . Tinebase_Core::getUser()->accountFullName . '" <' . $this->_account->email . '>';
1059 $returned = $this->_json->saveMessageInFolder($this->_testFolderName, $messageToSave);
1060 $messageWithReadingConfirmationHeader = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_testFolderName);
1061 $this->_messageIds[] = $messageWithReadingConfirmationHeader['id'];
1062 $this->_json->sendReadingConfirmation($messageWithReadingConfirmationHeader['id']);
1064 $translate = Tinebase_Translation::getTranslation('Felamimail');
1065 $subject = $translate->_('Reading Confirmation:') . ' '. $messageToSave['subject'];
1066 $message = $this->_searchForMessageBySubject($subject);
1067 $this->_messageIds[] = $message['id'];
1069 $complete = $this->_json->getMessage($message['id']);
1070 $this->assertContains($translate->_('Was read by:') . ' ' . $this->_account->from, $complete['body']);
1074 * save message in non-existant folder (templates) test
1076 * @see 0008476: Drafts are not working
1078 public function testSaveMessageInNonExistantTemplatesFolder()
1080 $messageToSave = $this->_getMessageData();
1082 $templatesFolder = $this->_getFolder($this->_account->templates_folder, FALSE);
1083 if ($templatesFolder) {
1084 $this->_json->deleteFolder($templatesFolder['id'], $this->_account->getId());
1086 $returned = $this->_json->saveMessageInFolder($this->_account->templates_folder, $messageToSave);
1087 $this->_foldersToClear = array($this->_account->templates_folder);
1089 // check if message is in templates folder
1090 $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->templates_folder);
1091 $this->assertEquals($messageToSave['subject'], $message['subject']);
1092 $this->assertEquals($messageToSave['to'][0], $message['to'][0], 'recipient not found');
1096 * testSaveMessageNoteWithInvalidChar
1098 * @see 0008644: error when sending mail with note (wrong charset)
1100 public function testSaveMessageNoteWithInvalidChar()
1102 $subject = Tinebase_Core::filterInputForDatabase("\xF0\x9F\x98\x8A\xC2"); // :-) emoji
1103 $messageData = $this->_getMessageData('', $subject);
1104 $messageData['note'] = true;
1105 $messageData['body'] .= " ";
1107 $this->_foldersToClear[] = 'INBOX';
1108 $this->_json->saveMessage($messageData);
1109 $message = $this->_searchForMessageBySubject($subject);
1111 $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
1112 $this->_checkEmailNote($contact, $subject);
1116 * testSaveMessageNoteWithInvalidChar
1118 * @see 0008644: error when sending mail with note (wrong charset)
1120 public function testSaveMessageWithInvalidChar()
1122 $subject = "\xF0\x9F\x98\x8A"; // :-) emoji
1123 $messageData = $this->_getMessageData('', $subject);
1124 $this->_foldersToClear[] = 'INBOX';
1125 $this->_json->saveMessage($messageData);
1126 $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1130 * testMessageWithInvalidICS
1132 * @see 0008786: broken ics causes js error when showing details
1134 public function testMessageWithInvalidICS()
1136 $inbox = $this->_getFolder('INBOX');
1137 $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/invalidimip.eml');
1138 Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1140 $this->_foldersToClear = array('INBOX');
1141 $message = $this->_searchForMessageBySubject('test invalid imip');
1143 $fullMessage = $this->_json->getMessage($message['id']);
1144 $this->assertTrue(empty($fullMessage->preparedParts));
1148 * testSendMailveopeAPIMessage
1150 * - envolpe amored message into PGP MIME structure
1152 public function testSendMailveopeAPIMessage()
1154 $subject = 'testSendMailveopeAPIMessage';
1155 $messageData = $this->_getMessageData('', $subject);
1156 $messageData['body'] = '-----BEGIN PGP MESSAGE-----
1157 Version: Mailvelope v1.3.3
1158 Comment: https://www.mailvelope.com
1160 wcFMA/0LJF28pDbGAQ//YgtsmEZN+pgIJiBDb7iYwPEOchDRIEjGOx543KF6
1161 5YigW9p39pfcJgvGfT8x9cUIrYGxyw5idPSOEftYXyjjGaOYGaKpRSR4hI83
1162 OcJSlEHKq72xhg04mNpCjjJ8dLBstPcQ7tDtsA8Nfb4PwkUYB9IhIBnARg+n
1163 NvrN8mSA2UnY9ElFCvf30sar8EuM5swAjbk64C8TIypMy/Bg4T93zRdxwik6
1164 7BCcbOpm/2PTsiVYBOTcU4+XdG5eyTENXH58M6UTxTD4/g7Qi5PjN+PxyXqf
1165 v2Y1k9F49Y1egf2QJ2r4PX0EWS8SaynSHiIoBsp1xb07nLwZwCdMPG1QNPpF
1166 l2FqlS4dEuQTdkv0deMvd7gtiNynRTAVcJc1ZC6RuWJ+EH2jA49XWkn14eRC
1167 e5jMtPPudkhubnN9Je5lwatGKbJGyuXh+IaM0E0WQMZ3dm8+ST1l4WpVuGbw
1168 KozLUiTRJP9UoxWOcwpQOnzcSlc4rHmWdtF0y3usM9u9GPREqpNUWkEyEEuv
1169 XdZE7rKKj22dJHLCXxAQEh3m29Y2WVaq50YbtEZ+SwwbrHhxP4+FJEru+byh
1170 fiZ47sVW2KvYGJPvbFoSZHiSvMecxDg8BVwe+naZXww/Rwa/TlaX4bYyzpUG
1171 KeJUAzWEfFpJ0+yAvMGQEC7psIJ9NCx149C4ujiQmajSwhUB3XANcmCGB0wm
1172 JjcqC4AHvc7/t4MrQZm0F/W+nrMmNqbZk+gylVrPs9rFEqu7wbjwTmsFA3sS
1173 LkenvQIxBali6uzCR+nd09REqcYirG9cLti39DW048lhhG/ml+gAxxNEaSpG
1174 NbIoV/3w8n7sAIM1fjuHne8bX0gWG43TTjU8MwSMryG7tCOG5u+Cebh6TAoY
1175 NzbX2dpDhOYq5zXdCgKU4P3eh0csSs4UrqFT3TdAxIGrQJ7KrXvB6+N8gRZo
1176 FcUaR+zrRPJjPUZfi46ecP5SG/tM5ea1hqvkwEnEpqjLmCUxqB+rfxx46USX
1177 hMZd2ukUv6kEKv3EUDsRYu1SlDLhDLhWNx8RJae5XkMR+eUUMyNNVwbeMQbB
1178 VAcMcaPITTk84sH7XElr9eF6sCUN4V79OSBRPGY/aNGrcwcoDSD4Hwu+Lw9w
1179 Q+1n8EQ66gAkbJzCNd5GaYMZR9echkBaD/rdWDS3ktcrMehra+h44MTQONV9
1180 8W+RI+IT5jaIXtB4jePmGjsJjbC9aEhTRBRkUnPA7phgknc52dD74AY/6lzK
1181 yd4uZ6S3vhurJW0Vt4iBWJzhFNiSODh5PzteeNzCVAkGMsQvy1IHk0d3uzcE
1182 0tEuSh8fZOFGB4fvMx9Mk8oAU92wfj4J7AVpSo5oRdxMqAXfaYKqfr2Gn++q
1183 E5LClhVIBbFXclCoe0RYNz4wtxjeeYbP40Bq5g0JvPutD/dBMp8hz8Qt+yyG
1184 d8X4/KmQIXyFZ8aP17GMckE5GVVvY9y89eWnWuTUJdwM540hB/EJNeHHTE5y
1185 N2FSLGcmNkvE+3H7BczQ2ZI1SZDhof+umbUst0qoQW+hHmY3CSma48yGAVox
1186 52u2t7hosHCfpf631Ve/6fcICo8vJ2Qfufu2BGIMlSfx4WzUuaMQBynuxFSa
1187 IbVx8ZTO7dJRKrg72aFmWTf0uNla7vicAhpiLWobyNYcZbIjrAGDfg==
1189 -----END PGP MESSAGE-----';
1191 $this->_foldersToClear[] = 'INBOX';
1192 $this->_json->saveMessage($messageData);
1194 $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1195 $fullMessage = $this->_json->getMessage($message['id']);
1197 $this->assertContains('multipart/encrypted', $fullMessage['headers']['content-type']);
1198 $this->assertContains('protocol="application/pgp-encrypted"', $fullMessage['headers']['content-type']);
1199 $this->assertCount(2, $fullMessage['structure']['parts']);
1200 $this->assertEquals('application/pgp-encrypted', $fullMessage['structure']['parts'][1]['contentType']);
1201 $this->assertEquals('application/octet-stream', $fullMessage['structure']['parts'][2]['contentType']);
1203 return $fullMessage;
1207 * testMessagePGPMime
1209 * - prepare amored part of PGP MIME structure
1211 public function testMessagePGPMime()
1213 $fullMessage = $this->testSendMailveopeAPIMessage();
1215 $this->assertEquals('application/pgp-encrypted', $fullMessage['preparedParts'][0]['contentType']);
1216 $this->assertContains('-----BEGIN PGP MESSAGE-----', $fullMessage['preparedParts'][0]['preparedData']);
1219 public function testMessagePGPInline()
1221 $inbox = $this->_getFolder('INBOX');
1222 $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/multipart_alternative_pgp_inline.eml');
1223 Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1225 $this->_foldersToClear = array('INBOX');
1226 $message = $this->_searchForMessageBySubject('Re: mailvelope und tine20');
1228 $fullMessage = $this->_json->getMessage($message['id']);
1229 $this->assertFalse(empty($fullMessage['preparedParts']));
1232 /*********************** sieve tests ****************************/
1235 * set and get vacation sieve script
1237 * @see 0007768: Sieve - Vacation notify frequency not being set (Cyrus)
1239 public function testGetSetVacation()
1241 $vacationData = $this->_getVacationData();
1242 $this->_sieveTestHelper($vacationData);
1244 // check if script was activated
1245 $activeScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1246 $this->assertEquals($this->_testSieveScriptName, $activeScriptName);
1247 $updatedAccount = Felamimail_Controller_Account::getInstance()->get($this->_account->getId());
1248 $this->assertTrue((bool) $updatedAccount->sieve_vacation_active);
1250 $result = $this->_json->getVacation($this->_account->getId());
1252 $this->assertEquals($this->_account->email, $result['addresses'][0]);
1254 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1255 if (preg_match('/dbmail/i', $sieveBackend->getImplementation())) {
1256 $translate = Tinebase_Translation::getTranslation('Felamimail');
1257 $vacationData['subject'] = sprintf($translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName);
1260 foreach (array('reason', 'enabled', 'subject', 'from', 'days') as $field) {
1261 $this->assertEquals($vacationData[$field], $result[$field], 'vacation data mismatch: ' . $field);
1270 protected function _getVacationData()
1273 'id' => $this->_account->getId(),
1274 'subject' => 'unittest vacation subject',
1275 'from' => $this->_account->from . ' <' . $this->_account->email . '>',
1278 'reason' => 'unittest vacation message<br /><br />signature',
1284 * test mime vacation sieve script
1286 public function testMimeVacation()
1288 $vacationData = $this->_getVacationData();
1289 $vacationData['reason'] = "\n<html><body><h1>unittest vacation message</h1></body></html>";
1291 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1292 if (! in_array('mime', $_sieveBackend->capability())) {
1293 $vacationData['mime'] = 'text/html';
1296 $this->_sieveTestHelper($vacationData, TRUE);
1300 * test get/set of rules sieve script
1302 public function testGetSetRules()
1304 $ruleData = $this->_getRuleData();
1306 $this->_sieveTestHelper($ruleData);
1309 $result = $this->_json->getRules($this->_account->getId());
1310 $this->assertEquals($result['totalcount'], count($ruleData));
1312 // check by sending mail
1313 $messageData = $this->_getMessageData('', 'viagra');
1314 $returned = $this->_json->saveMessage($messageData);
1315 $this->_foldersToClear = array('INBOX', $this->_testFolderName);
1316 // check if message is in test folder
1317 $message = $this->_searchForMessageBySubject($messageData['subject'], $this->_testFolderName);
1323 * @see 0006490: can not delete single filter rule
1325 public function testRemoveRules()
1327 $this->testGetSetRules();
1328 $this->_json->saveRules($this->_account->getId(), array());
1330 $result = $this->_json->getRules($this->_account->getId());
1331 $this->assertEquals(0, $result['totalcount'], 'found rules: ' . print_r($result, TRUE));
1335 * get sieve rule data
1339 protected function _getRuleData()
1343 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1344 'action_argument' => $this->_testFolderName,
1345 'conjunction' => 'allof',
1346 'conditions' => array(array(
1347 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1348 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1350 'key' => '"abcd" <info@example.org>',
1355 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1356 'action_argument' => $this->_testFolderName,
1357 'conjunction' => 'allof',
1358 'conditions' => array(array(
1359 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1360 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1362 'key' => 'info@example.org',
1367 'action_type' => Felamimail_Sieve_Rule_Action::FILEINTO,
1368 'action_argument' => $this->_testFolderName,
1369 'conjunction' => 'allof',
1370 'conditions' => array(array(
1371 'test' => Felamimail_Sieve_Rule_Condition::TEST_HEADER,
1372 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_REGEX,
1373 'header' => 'subject',
1374 'key' => '[vV]iagra|cyalis',
1381 * test to set a forward rule to this accounts email address
1382 * -> should throw exception to prevent mail cycling
1384 public function testSetForwardRuleToSelf()
1386 $ruleData = array(array(
1388 'action_type' => Felamimail_Sieve_Rule_Action::REDIRECT,
1389 'action_argument' => $this->_account->email,
1390 'conjunction' => 'allof',
1391 'conditions' => array(array(
1392 'test' => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1393 'comperator' => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1395 'key' => 'info@example.org',
1401 $this->_sieveTestHelper($ruleData);
1402 $this->assertTrue(FALSE, 'it is not allowed to set own email address for redirect!');
1403 } catch (Felamimail_Exception_Sieve $e) {
1404 $this->assertTrue(TRUE);
1408 $ruleData[0]['enabled'] = 0;
1409 $this->_sieveTestHelper($ruleData);
1413 * testGetVacationTemplates
1417 public function testGetVacationTemplates()
1419 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1421 $this->_addVacationTemplateFile();
1422 $result = $this->_json->getVacationMessageTemplates();
1424 $this->assertTrue($result['totalcount'] > 0, 'no templates found');
1426 foreach ($result['results'] as $template) {
1427 if ($template['name'] === $this->_sieveVacationTemplateFile) {
1433 $this->assertTrue($found, 'wrong templates: ' . print_r($result['results'], TRUE));
1439 * add vacation template file to vfs
1441 protected function _addVacationTemplateFile()
1443 $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
1444 $path = '/webdav/Felamimail/shared/Vacation Templates';
1445 $node = $webdavRoot->getNodeForPath($path);
1446 $this->_pathsToDelete[] = $path . '/' . $this->_sieveVacationTemplateFile;
1447 $node->createFile($this->_sieveVacationTemplateFile, fopen(dirname(__FILE__) . '/../files/' . $this->_sieveVacationTemplateFile, 'r'));
1451 * testGetVacationMessage
1453 public function testGetVacationMessage()
1455 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1457 $result = $this->_getVacationMessageWithTemplate();
1458 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1459 $pwulf = Tinebase_User::getInstance()->getFullUserByLoginName('pwulf');
1460 $this->assertEquals("Ich bin vom 18.04.2012 bis zum 20.04.2012 im Urlaub. Bitte kontaktieren Sie<br /> Paul Wulf (" .
1461 $pwulf->accountEmailAddress . ") oder Susan Clever (" .
1462 $sclever->accountEmailAddress . ").<br /><br />I am on vacation until Apr 20, 2012. Please contact Paul Wulf<br />(" .
1463 $pwulf->accountEmailAddress . ") or Susan Clever (" .
1464 $sclever->accountEmailAddress . ") instead.<br /><br />" .
1465 Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId())->n_fn, $result['message']);
1469 * get vacation message with template
1473 protected function _getVacationMessageWithTemplate()
1475 $template = $this->testGetVacationTemplates();
1476 $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1477 $result = $this->_json->getVacationMessage(array(
1478 'start_date' => '2012-04-18',
1479 'end_date' => '2012-04-20',
1480 'contact_ids' => array(
1481 Tinebase_User::getInstance()->getFullUserByLoginName('pwulf')->contact_id,
1482 $sclever->contact_id,
1484 'template_id' => $template['id'],
1485 'signature' => $this->_account->signature
1492 * testGetVacationWithSignature
1494 * @see 0006866: check signature linebreaks in vacation message from template
1496 public function testGetVacationWithSignature()
1498 $this->markTestSkipped('0010194: fix felamimail webdav tests');
1500 $this->_sieveVacationTemplateFile = 'vacation_template_sig.tpl';
1502 // set signature with <br> + linebreaks
1503 $this->_account->signature = "llalala<br>\nxyz<br>\nblubb<br>";
1505 $result = $this->_getVacationMessageWithTemplate();
1506 $this->assertContains('-- <br />llalala<br />xyz<br />blubb<br />', $result['message'], 'wrong linebreaks or missing signature');
1510 * testSetVacationWithStartAndEndDate
1512 * @see 0006266: automatic deactivation of vacation message
1514 public function testSetVacationWithStartAndEndDate()
1516 $vacationData = $this->_getVacationData();
1517 $vacationData['start_date'] = '2012-04-18';
1518 $vacationData['end_date'] = '2012-04-20';
1519 $result = $this->_sieveTestHelper($vacationData);
1521 $this->assertContains($vacationData['start_date'], $result['start_date']);
1522 $this->assertContains($vacationData['end_date'], $result['end_date']);
1526 * testSieveRulesOrder
1528 * @see 0007240: order of sieve rules changes when vacation message is saved
1530 public function testSieveRulesOrder()
1532 $this->_setTestScriptname();
1534 // disable vacation first
1535 $this->_setDisabledVacation();
1537 $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1539 $ruleData = $this->_getRuleData();
1540 $ruleData[0]['id'] = $ruleData[2]['id'];
1541 $ruleData[2]['id'] = 11;
1542 $resultSet = $this->_json->saveRules($this->_account->getId(), $ruleData);
1543 $sieveScriptRules = $sieveBackend->getScript($this->_testSieveScriptName);
1545 $this->_setDisabledVacation();
1546 $sieveScriptVacation = $sieveBackend->getScript($this->_testSieveScriptName);
1548 // compare sieve scripts
1549 $this->assertContains($sieveScriptRules, $sieveScriptVacation, 'rule order changed');
1553 * use another name for test sieve script
1555 protected function _setTestScriptname()
1557 $this->_oldActiveSieveScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1558 $this->_testSieveScriptName = 'Felamimail_Unittest';
1559 Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
1563 * set disabled vacation message
1565 protected function _setDisabledVacation()
1567 $vacationData = $this->_getVacationData();
1568 $vacationData['enabled'] = FALSE;
1569 $resultSet = $this->_json->saveVacation($vacationData);
1577 protected function _getFolderFilter()
1580 'field' => 'globalname', 'operator' => 'equals', 'value' => ''
1585 * get message filter
1587 * @param string $_folderId
1590 protected function _getMessageFilter($_folderId)
1592 $result = array(array(
1593 'field' => 'folder_id', 'operator' => 'equals', 'value' => $_folderId
1602 * @param string $name
1603 * @param boolean $createFolder
1604 * @return Felamimail_Model_Folder|NULL
1606 protected function _getFolder($name, $createFolder = TRUE)
1608 Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId());
1610 $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $name);
1611 } catch (Tinebase_Exception_NotFound $tenf) {
1612 $folder = ($createFolder) ? Felamimail_Controller_Folder::getInstance()->create($this->_account, $name) : NULL;
1623 protected function _getMessageData($_emailFrom = '', $_subject = 'test')
1626 'account_id' => $this->_account->getId(),
1627 'subject' => $_subject,
1628 'to' => array(Tinebase_Core::getUser()->accountEmailAddress),
1629 'body' => 'aaaaaä <br>',
1630 'headers' => array('X-Tine20TestMessage' => 'jsontest'),
1631 'from_email' => $_emailFrom,
1632 'content_type' => Felamimail_Model_Message::CONTENT_TYPE_HTML,
1637 * send message and return message array
1639 * @param string $folderName
1640 * @param array $addtionalHeaders
1643 protected function _sendMessage($folderName = 'INBOX', $addtionalHeaders = array())
1645 $messageToSend = $this->_getMessageData();
1646 $messageToSend['headers'] = array_merge($messageToSend['headers'], $addtionalHeaders);
1647 $this->_json->saveMessage($messageToSend);
1648 $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1652 $result = $this->_getMessages($folderName);
1653 $message = $this->_getMessageFromSearchResult($result, $messageToSend['subject']);
1654 if (! empty($message)) {
1657 // sleep for 1 sec because mailserver may be slower than expected
1662 $this->assertTrue(! empty($message), 'Sent message not found.');
1668 * returns message array from result
1670 * @param array $_result
1671 * @param string $_subject
1674 protected function _getMessageFromSearchResult($_result, $_subject)
1677 foreach ($_result['results'] as $mail) {
1678 if ($mail['subject'] == $_subject) {
1687 * get messages from folder
1689 * @param string $_folderName
1692 protected function _getMessages($_folderName = 'INBOX')
1694 $folder = $this->_getFolder($_folderName);
1695 $filter = $this->_getMessageFilter($folder->getId());
1697 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10, 1);
1699 while ($folder->cache_status != Felamimail_Model_Folder::CACHE_STATUS_COMPLETE && $i < 10) {
1700 $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10);
1703 $result = $this->_json->searchMessages($filter, '');
1709 * search for message defined by subject in folder
1711 * @param string $_subject
1712 * @param string $_folderName
1713 * @return string message data
1715 protected function _searchForMessageBySubject($_subject, $_folderName = 'INBOX')
1717 // give server some time to send and receive messages
1720 $result = $this->_getMessages($_folderName);
1723 foreach ($result['results'] as $mail) {
1724 if ($mail['subject'] == $_subject) {
1728 $this->assertGreaterThan(0, $result['totalcount'], 'folder is empty');
1729 $this->assertTrue(! empty($message), 'Message not found');
1737 * @param array $_sieveData
1740 protected function _sieveTestHelper($_sieveData, $_isMime = FALSE)
1742 $this->_setTestScriptname();
1744 // check which save fn to use
1745 if ((isset($_sieveData['reason']) || array_key_exists('reason', $_sieveData))) {
1746 $resultSet = $this->_json->saveVacation($_sieveData);
1747 $this->assertEquals($this->_account->email, $resultSet['addresses'][0]);
1749 $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1751 if (preg_match('/dbmail/i', $_sieveBackend->getImplementation())) {
1752 $translate = Tinebase_Translation::getTranslation('Felamimail');
1753 $this->assertEquals(sprintf(
1754 $translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName),
1755 $resultSet['subject']
1758 $this->assertEquals($_sieveData['subject'], $resultSet['subject']);
1762 $this->assertEquals(html_entity_decode('unittest vacation message', ENT_NOQUOTES, 'UTF-8'), $resultSet['reason']);
1764 $this->assertEquals($_sieveData['reason'], $resultSet['reason']);
1767 } else if ((isset($_sieveData[0]['action_type']) || array_key_exists('action_type', $_sieveData[0]))) {
1768 $resultSet = $this->_json->saveRules($this->_account->getId(), $_sieveData);
1769 $this->assertEquals($_sieveData, $resultSet);
1776 * search preferences by application felamimail
1779 public function testSearchFelamimailPreferences()
1782 $result = $this->_frontend->searchPreferencesForApplication('Felamimail', '');
1785 $this->assertTrue(isset($result['results']));
1786 $this->assertGreaterThan(0, $result['totalcount']);
1790 * testGetRegistryData
1792 * @see 0010251: do not send unused config data to client
1794 public function testGetRegistryData()
1796 $regData = $this->_json->getRegistryData();
1798 $this->assertFalse(isset($regData['defaults']));
1799 $supportedFlags = Felamimail_Config::getInstance()->featureEnabled(Felamimail_Config::FEATURE_TINE20_FLAG)
1802 $this->assertEquals($supportedFlags, $regData['supportedFlags']['totalcount']);