Merge branch '2015.11' into 2015.11-develop
[tine20] / tests / tine20 / Felamimail / Frontend / JsonTest.php
1 <?php
2
3 use Sabre\DAV;
4
5 /**
6  * Tine 2.0 - http://www.tine20.org
7  *
8  * @package     Felamimail
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>
12  */
13
14 /**
15  * Test helper
16  */
17 require_once dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
18
19 /**
20  * Test class for Tinebase_Group
21  */
22 class Felamimail_Frontend_JsonTest extends TestCase
23 {
24     /**
25      * @var Felamimail_Frontend_Json
26      */
27     protected $_json = array();
28
29     /**
30      * message ids to delete
31      *
32      * @var array
33      */
34     protected $_messageIds = array();
35     
36     /**
37      * @var Felamimail_Model_Account
38      */
39     protected $_account = NULL;
40     
41     /**
42      * imap backend
43
44      * @var Felamimail_Backend_ImapProxy
45      */
46     protected $_imap = NULL;
47     
48     /**
49      * name of the folder to use for tests
50      * @var string
51      */
52     protected $_testFolderName = 'Junk';
53     
54     /**
55      * folders to delete in tearDown()
56      * 
57      * @var array
58      */
59     protected $_createdFolders = array();
60
61     /**
62      * are there messages to delete?
63      * 
64      * @var array
65      */
66     protected $_foldersToClear = array();
67
68     /**
69      * active sieve script name to be restored
70      *
71      * @var string
72      */
73     protected $_oldActiveSieveScriptName = NULL;
74
75     /**
76      * was sieve_vacation_active ?
77      *
78      * @var boolean
79      */
80     protected $_oldSieveVacationActiveState = FALSE;
81     
82     /**
83      * old sieve data
84      *
85      * @var Felamimail_Sieve_Backend_Sql
86      */
87     protected $_oldSieveData = NULL;
88
89     /**
90      * sieve script name to delete
91      *
92      * @var string
93      */
94     protected $_testSieveScriptName = NULL;
95
96     /**
97      * sieve vacation template file name
98      *
99      * @var string
100      */
101     protected $_sieveVacationTemplateFile = 'vacation_template.tpl';
102
103     /**
104      * test email domain
105      *
106      * @var string
107      */
108     protected $_mailDomain = 'tine20.org';
109
110     /**
111      * @var Felamimail_Model_Folder
112      */
113     protected $_folder = NULL;
114
115     /**
116      * paths in the vfs to delete
117      *
118      * @var array
119      */
120     protected $_pathsToDelete = array();
121
122     /**
123      *
124      * @var Tinebase_Frontend_Json
125      */
126     protected $_frontend = NULL;
127     
128     /**
129      * Sets up the fixture.
130      * This method is called before a test is executed.
131      *
132      * @access protected
133      */
134     protected function setUp()
135     {
136         Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb());
137         
138         // get (or create) test accout
139         $this->_account = Felamimail_Controller_Account::getInstance()->search()->getFirstRecord();
140         $this->_oldSieveVacationActiveState = $this->_account->sieve_vacation_active;
141         try {
142             $this->_oldSieveData = new Felamimail_Sieve_Backend_Sql($this->_account);
143         } catch (Tinebase_Exception_NotFound $tenf) {
144             // do nothing
145         }
146         
147         $this->_json = new Felamimail_Frontend_Json();
148         $this->_imap = Felamimail_Backend_ImapFactory::factory($this->_account);
149         
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);
153         }
154         
155         $this->_mailDomain = TestServer::getPrimaryMailDomain();
156
157         $this->_frontend = new Tinebase_Frontend_Json();
158     }
159
160     /**
161      * Tears down the fixture
162      * This method is called after a test is executed.
163      *
164      * @access protected
165      */
166     protected function tearDown()
167     {
168         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
169             . ' Tearing down ...');
170         
171         if (count($this->_createdFolders) > 0) {
172             foreach ($this->_createdFolders as $folderName) {
173                 //echo "delete $folderName\n";
174                 try {
175                     $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($folderName));
176                 } catch (Zend_Mail_Storage_Exception $zmse) {
177                     // already deleted
178                 }
179             }
180             Felamimail_Controller_Cache_Folder::getInstance()->clear($this->_account);
181         }
182         
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'
189                 ));
190                 //print_r($result);
191                 foreach ($result as $messageUid) {
192                     $this->_imap->removeMessage($messageUid);
193                 }
194                 
195                 // clear message cache
196                 $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $folderName);
197                 Felamimail_Controller_Cache_Message::getInstance()->clear($folder);
198             }
199         }
200         
201         // sieve cleanup
202         if ($this->_testSieveScriptName !== NULL) {
203             Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
204             try {
205                 Felamimail_Controller_Sieve::getInstance()->deleteScript($this->_account->getId());
206             } catch (Zend_Mail_Protocol_Exception $zmpe) {
207                 // do not delete script if active
208             }
209             Felamimail_Controller_Account::getInstance()->setVacationActive($this->_account, $this->_oldSieveVacationActiveState);
210             
211             if ($this->_oldSieveData !== NULL) {
212                 $this->_oldSieveData->save();
213             }
214         }
215         if ($this->_oldActiveSieveScriptName !== NULL) {
216             Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_oldActiveSieveScriptName);
217             Felamimail_Controller_Sieve::getInstance()->activateScript($this->_account->getId());
218         }
219         
220         // vfs cleanup
221         foreach ($this->_pathsToDelete as $path) {
222             $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
223             //echo "delete $path";
224             $webdavRoot->delete($path);
225         }
226         
227         Tinebase_TransactionManager::getInstance()->rollBack();
228     }
229
230     /************************ test functions *********************************/
231     
232     /*********************** folder tests ****************************/
233     
234     /**
235      * test search folders (check order of folders as well)
236      */
237     public function testSearchFolders()
238     {
239         $filter = $this->_getFolderFilter();
240         $result = $this->_json->searchFolders($filter);
241         
242         $this->assertGreaterThan(1, $result['totalcount']);
243         $expectedFolders = array('INBOX', $this->_testFolderName, $this->_account->trash_folder, $this->_account->sent_folder);
244         
245         $foundCount = 0;
246         foreach ($result['results'] as $index => $folder) {
247             if (in_array($folder['localname'], $expectedFolders)) {
248                 $foundCount++;
249             }
250         }
251         $this->assertEquals(count($expectedFolders), $foundCount);
252     }
253     
254     /**
255      * clear test folder
256      */
257     public function testClearFolder()
258     {
259         $folderName = $this->_testFolderName;
260         $folder = $this->_getFolder($this->_testFolderName);
261         $folder = Felamimail_Controller_Folder::getInstance()->emptyFolder($folder->getId());
262
263         $filter = $this->_getMessageFilter($folder->getId());
264         $result = $this->_json->searchMessages($filter, '');
265         
266         $this->assertEquals(0, $result['totalcount'], 'Found too many messages in folder ' . $this->_testFolderName);
267         $this->assertEquals(0, $folder->cache_totalcount);
268     }
269
270     /**
271      * try to create some folders
272      */
273     public function testCreateFolders()
274     {
275         $filter = $this->_getFolderFilter();
276         $result = $this->_json->searchFolders($filter);
277         
278         $foldernames = array('test' => 'test', 'Schlüssel' => 'Schlüssel', 'test//1' => 'test1', 'test\2' => 'test2');
279         
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']);
287         }
288     }
289     
290     /**
291      * test emtpy folder (with subfolder)
292      */
293     public function testEmptyFolderWithSubfolder()
294     {
295         $folderName = $this->_testFolderName;
296         $folder = $this->_getFolder($this->_testFolderName);
297         $this->testCreateFolders();
298         
299         $folderArray = $this->_json->emptyFolder($folder->getId());
300         $this->assertEquals(0, $folderArray['has_children']);
301         
302         $result = $this->_json->updateFolderCache($this->_account->getId(), $this->_testFolderName);
303         $this->assertEquals(0, count($result));
304     }
305     
306     /**
307      * testUpdateFolderCache
308      */
309     public function testUpdateFolderCache()
310     {
311         $result = $this->_json->updateFolderCache($this->_account->getId(), '');
312         
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';
319         
320         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
321             . ' Update cache and check if folder is found');
322         
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');
328         
329         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
330             . ' Delete subfolder directly on imap server');
331         
332         $this->_imap->removeFolder($this->_testFolderName . $this->_account->delimiter . 'test' . $this->_account->delimiter . 'testsub');
333         array_shift($this->_createdFolders);
334         
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');
337         
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');
341
342         return $testfolder;
343     }
344     
345     /**
346      * testUpdateFolderCacheOfNonexistantFolder
347      *
348      * @see 0009800: unselectable folder with subfolders disappears
349      */
350     public function testUpdateFolderCacheOfNonexistantFolder()
351     {
352         $testfolder = $this->testUpdateFolderCache();
353         
354         try {
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);
358             
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) {
362         }
363         
364         $this->_imap->removeFolder($this->_testFolderName . $this->_account->delimiter . 'test');
365         array_shift($this->_createdFolders);
366         
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');
370         
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));
374     }
375     
376     /*********************** accounts tests **************************/
377     
378     /**
379      * test search for accounts and check default account from config
380      */
381     public function testSearchAccounts()
382     {
383         $system = $this->_getSystemAccount();
384         
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']);
389         }
390     }
391     
392     /**
393      * get system account
394      *
395      * @return array
396      */
397     protected function _getSystemAccount()
398     {
399         $results = $this->_json->searchAccounts(array());
400         
401         $this->assertGreaterThan(0, $results['totalcount']);
402         $system = array();
403         foreach ($results['results'] as $result) {
404             if ($result['name'] == Tinebase_Core::getUser()->accountLoginName . '@' . $this->_mailDomain) {
405                 $system = $result;
406             }
407         }
408         
409         return $system;
410     }
411     
412     /**
413      * test change / delete of account
414      */
415     public function testChangeDeleteAccount()
416     {
417         $system = $this->_getSystemAccount();
418         unset($system['id']);
419         $system['type'] = Felamimail_Model_Account::TYPE_USER;
420         $account = $this->_json->saveAccount($system);
421         
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']);
426         }
427         
428         $this->_json->changeCredentials($account['id'], $accountRecord->user, 'neuespasswort');
429         $account = $this->_json->getAccount($account['id']);
430         
431         $accountRecord = new Felamimail_Model_Account($account, TRUE);
432         $accountRecord->resolveCredentials(FALSE);
433         $this->assertEquals('neuespasswort', $accountRecord->password);
434         
435         $this->_json->deleteAccounts($account['id']);
436     }
437     
438     /*********************** message tests ****************************/
439     
440     /**
441      * test update message cache
442      */
443     public function testUpdateMessageCache()
444     {
445         $message = $this->_sendMessage();
446         $inbox = $this->_getFolder('INBOX');
447         // update message cache and check result
448         $result = $this->_json->updateMessageCache($inbox['id'], 30);
449         
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']);
454         }
455     }
456     
457     /**
458      * test folder status
459      */
460     public function testGetFolderStatus()
461     {
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);
466         
467         foreach ($result['results'] as $folder) {
468             $this->_json->updateMessageCache($folder['id'], 30);
469         }
470         
471         $message = $this->_sendMessage();
472         
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']);
476     }
477
478     /**
479      * test folder status of deleted folder
480      *
481      * @see 0007134: getFolderStatus should ignore non-existent folders
482      */
483     public function testGetFolderStatusOfDeletedFolder()
484     {
485         $this->testCreateFolders();
486         // remove one of the created folders
487         $removedFolder = $this->_createdFolders[0];
488         $this->_imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($removedFolder));
489         
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!');
495             }
496         }
497     }
498     
499     /**
500      * test send message
501      */
502     public function testSendMessage()
503     {
504         // set email to unittest@tine20.org
505         $contactFilter = new Addressbook_Model_ContactFilter(array(
506             array('field' => 'n_family', 'operator' => 'equals', 'value' => 'Clever')
507         ));
508         $contactIds = Addressbook_Controller_Contact::getInstance()->search($contactFilter, NULL, FALSE, TRUE);
509         $this->assertTrue(count($contactIds) > 0, 'sclever not found in addressbook');
510
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);
515
516         // send email
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);
523         
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']);
531         
532         $this->_checkEmailNote($contact, $messageToSend['subject']);
533         
534         // reset sclevers original email address
535         $contact->email = $originalEmail;
536         Addressbook_Controller_Contact::getInstance()->update($contact, FALSE);
537     }
538     
539     /**
540      * check email note
541      *
542      * @param Addressbook_Model_Contact $contact
543      * @param string $subject
544      */
545     protected function _checkEmailNote($contact, $subject)
546     {
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');
550         
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);
559             }
560         }
561         $this->assertGreaterThan(0, $emailNotes->count(), 'no email notes found');
562         Tinebase_Notes::getInstance()->deleteNotes($emailNotes);
563     }
564
565     /**
566      * test send message to invalid recipient
567      */
568     public function testSendMessageToInvalidRecipient()
569     {
570         $messageToSend = $this->_getMessageData($this->_account->email);
571         $invalidEmail = 'invaliduser@' . $this->_mailDomain;
572         $messageToSend['to'] = array($invalidEmail);
573         $translation = Tinebase_Translation::getTranslation('Felamimail');
574         
575         try {
576             $returned = $this->_json->saveMessage($messageToSend);
577             $this->fail('Tinebase_Exception_SystemGeneric expected');
578         } catch (Tinebase_Exception_SystemGeneric $tesg) {
579             $this->assertContains('<' . $invalidEmail . '>: ' . $translation->_('Recipient address rejected'), $tesg->getMessage(),
580                 'exception message did not match: ' . $tesg->getMessage());
581         }
582     }
583     
584     /**
585      * try to get a message from imap server (with complete body, attachments, etc)
586      *
587      * @see 0006300: add unique message-id header to new messages (for message-id check)
588      */
589     public function testGetMessage()
590     {
591         $message = $this->_sendMessage();
592         
593         // get complete message
594         $message = $this->_json->getMessage($message['id']);
595         
596         // check
597         $this->assertTrue(isset($message['headers']) && $message['headers']['message-id']);
598         $this->assertContains('@' . $this->_mailDomain, $message['headers']['message-id']);
599         $this->assertGreaterThan(0, preg_match('/aaaaaä/', $message['body']));
600         
601         // delete message on imap server and check if correct exception is thrown when trying to get it
602         $this->_imap->selectFolder('INBOX');
603         $this->_imap->removeMessage($message['messageuid']);
604         Tinebase_Core::getCache()->clean();
605         $this->setExpectedException('Felamimail_Exception_IMAPMessageNotFound');
606         $message = $this->_json->getMessage($message['id']);
607     }
608     
609     /**
610      * try to get a message as plain/text
611      */
612     public function testGetPlainTextMessage()
613     {
614         $accountBackend = new Felamimail_Backend_Account();
615         $message = $this->_sendMessage();
616         
617         // get complete message
618         $this->_account->display_format = Felamimail_Model_Account::DISPLAY_PLAIN;
619         $accountBackend->update($this->_account);
620         $message = $this->_json->getMessage($message['id']);
621         $this->_account->display_format = Felamimail_Model_Account::DISPLAY_HTML;
622         $accountBackend->update($this->_account);
623         
624         // check
625         $this->assertEquals("aaaaaä \n\r\n", $message['body']);
626     }
627     
628     /**
629      * try search for a message with path filter
630      */
631     public function testSearchMessageWithPathFilter()
632     {
633         $sentMessage = $this->_sendMessage();
634         $filter = array(array(
635             'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId()
636         ));
637         $result = $this->_json->searchMessages($filter, '');
638         $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
639         $this->assertTrue(! empty($message), 'Sent message not found with account path filter');
640
641         $inbox = $this->_getFolder('INBOX');
642         $filter = array(array(
643             'field' => 'path', 'operator' => 'in', 'value' => '/' . $this->_account->getId() . '/' . $inbox->getId()
644         ));
645         $result = $this->_json->searchMessages($filter, '');
646         $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
647         $this->assertTrue(! empty($message), 'Sent message not found with path filter');
648         foreach ($result['results'] as $mail) {
649             $this->assertEquals($inbox->getId(), $mail['folder_id'], 'message is in wrong folder: ' . print_r($mail, TRUE));
650         }
651     }
652     
653     /**
654      * try search for a message with all inboxes and flags filter
655      */
656     public function testSearchMessageWithAllInboxesFilter()
657     {
658         $sentMessage = $this->_sendMessage();
659         $filter = array(
660             array('field' => 'path',  'operator' => 'in',       'value' => Felamimail_Model_MessageFilter::PATH_ALLINBOXES),
661             array('field' => 'flags', 'operator' => 'notin',    'value' => Zend_Mail_Storage::FLAG_FLAGGED),
662         );
663         $result = $this->_json->searchMessages($filter, '');
664         $this->assertGreaterThan(0, $result['totalcount']);
665         $this->assertEquals($result['totalcount'], count($result['results']));
666         
667         $message = $this->_getMessageFromSearchResult($result, $sentMessage['subject']);
668         $this->assertTrue(! empty($message), 'Sent message not found with all inboxes filter');
669     }
670     
671     /**
672      * try search for a message with three cache filters to force a foreign relation join with at least 2 tables
673      */
674     public function testSearchMessageWithThreeCacheFilter()
675     {
676         $filter = array(
677             array('field' => 'flags',   'operator' => 'in',       'value' => Zend_Mail_Storage::FLAG_ANSWERED),
678             array('field' => 'to',      'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
679             array('field' => 'subject', 'operator' => 'contains', 'value' => 'testDOESNOTEXIST'),
680         );
681         $result = $this->_json->searchMessages($filter, '');
682         $this->assertEquals(0, $result['totalcount']);
683     }
684     
685     /**
686      * try search for a message with empty path filter
687      */
688     public function testSearchMessageEmptyPath()
689     {
690         $sentMessage = $this->_sendMessage();
691         
692         $filter = array(
693             array('field' => 'path',  'operator' => 'equals',   'value' => ''),
694         );
695         $result = $this->_json->searchMessages($filter, '');
696         
697         $this->assertEquals(0, $result['totalcount']);
698         $accountFilterFound = FALSE;
699         
700         foreach ($result['filter'] as $filter) {
701             if ($filter['field'] === 'account_id' && empty($filter['value'])) {
702                 $accountFilterFound = TRUE;
703                 break;
704             }
705         }
706         $this->assertTrue($accountFilterFound);
707     }
708     
709     /**
710      * test flags (add + clear + deleted)
711      */
712     public function testAddAndClearFlags()
713     {
714         $message = $this->_sendMessage();
715         $inboxBefore = $this->_getFolder('INBOX');
716         
717         $this->_json->addFlags($message['id'], Zend_Mail_Storage::FLAG_SEEN);
718         
719         // check if unread count got decreased
720         $inboxAfter = $this->_getFolder('INBOX');
721         $this->assertTrue($inboxBefore->cache_unreadcount - 1 == $inboxAfter->cache_unreadcount, 'wrong cache unreadcount');
722         
723         $message = $this->_json->getMessage($message['id']);
724         $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag not set');
725         
726         // try with a filter
727         $filter = array(
728             array('field' => 'id', 'operator' => 'in', array($message['id']))
729         );
730         $this->_json->clearFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
731         
732         $message = $this->_json->getMessage($message['id']);
733         $this->assertFalse(in_array(Zend_Mail_Storage::FLAG_SEEN, $message['flags']), 'seen flag should not be set');
734
735         $this->setExpectedException('Tinebase_Exception_NotFound');
736         $this->_json->addFlags(array($message['id']), Zend_Mail_Storage::FLAG_DELETED);
737         $this->_json->getMessage($message['id']);
738     }
739     
740     /**
741      * testMarkFolderRead
742      *
743      * @see 0009812: mark folder as read does not work with pgsql
744      */
745     public function testMarkFolderRead()
746     {
747         $inboxBefore = $this->_getFolder('INBOX');
748         $filter = array(array(
749             'field' => 'folder_id', 'operator' => 'equals', 'value' => $inboxBefore->getId()
750         ), array(
751             'field' => 'flags', 'operator' => 'notin', 'value' => array(Zend_Mail_Storage::FLAG_SEEN)
752         ));
753         $this->_json->addFlags($filter, Zend_Mail_Storage::FLAG_SEEN);
754         
755         $inboxAfter = $this->_getFolder('INBOX');
756         $this->assertEquals(0, $inboxAfter->cache_unreadcount);
757     }
758     
759     /**
760      * test delete from trash
761      */
762     public function testDeleteFromTrashWithFilter()
763     {
764         $message = $this->_sendMessage();
765         $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
766         
767         $trash = $this->_getFolder($this->_account->trash_folder);
768         $result = $this->_json->moveMessages(array(array(
769             'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
770         )), $trash->getId());
771
772         $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
773         
774         // delete messages in trash with filter
775         $this->_json->addFlags(array(array(
776             'field' => 'folder_id', 'operator' => 'equals', 'value' => $trash->getId()
777         ), array(
778             'field' => 'id', 'operator' => 'in', 'value' => array($messageInTrash['id'])
779         )), Zend_Mail_Storage::FLAG_DELETED);
780         
781         $this->setExpectedException('Tinebase_Exception_NotFound');
782         $this->_json->getMessage($messageInTrash['id']);
783     }
784     
785     /**
786      * move message to trash with trash folder constant (Felamimail_Model_Folder::FOLDER_TRASH)
787      */
788     public function testMoveMessagesToTrash()
789     {
790         $message = $this->_sendMessage();
791         $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_account->trash_folder);
792         
793         $result = $this->_json->moveMessages(array(array(
794             'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
795         )), Felamimail_Model_Folder::FOLDER_TRASH);
796
797         $messageInTrash = $this->_searchForMessageBySubject($message['subject'], $this->_account->trash_folder);
798     }
799     
800     /**
801      * test reply mail and check some headers
802      *
803      * @see 0006106: Add References header / https://forge.tine20.org/mantisbt/view.php?id=6106
804      */
805     public function testReplyMessage()
806     {
807         $message = $this->_sendMessage();
808         
809         $replyMessage = $this->_getReply($message);
810         $returned = $this->_json->saveMessage($replyMessage);
811         
812         $result = $this->_getMessages();
813         
814         $replyMessageFound = array();
815         $originalMessage = array();
816         foreach ($result['results'] as $mail) {
817             if ($mail['subject'] == $replyMessage['subject']) {
818                 $replyMessageFound = $mail;
819             }
820             if ($mail['subject'] == $message['subject']) {
821                 $originalMessage = $mail;
822             }
823         }
824         $replyMessageFound = $this->_json->getMessage($replyMessageFound['id']);
825         $originalMessage = $this->_json->getMessage($originalMessage['id']);
826         
827         $this->assertTrue(! empty($replyMessageFound), 'replied message not found');
828         $this->assertTrue(! empty($originalMessage), 'original message not found');
829         
830         // check headers
831         $this->assertTrue(isset($replyMessageFound['headers']['in-reply-to']));
832         $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['in-reply-to']);
833         $this->assertTrue(isset($replyMessageFound['headers']['references']));
834         $this->assertEquals($originalMessage['headers']['message-id'], $replyMessageFound['headers']['references']);
835         
836         // check answered flag
837         $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_ANSWERED, $originalMessage['flags'], 'could not find flag'));
838     }
839     
840     /**
841      * get reply message data
842      *
843      * @param array $_original
844      * @return array
845      */
846     protected function _getReply($_original)
847     {
848         $replyMessage               = $this->_getMessageData();
849         $replyMessage['subject']    = 'Re: ' . $_original['subject'];
850         $replyMessage['original_id']= $_original['id'];
851         $replyMessage['flags']      = Zend_Mail_Storage::FLAG_ANSWERED;
852         
853         return $replyMessage;
854     }
855
856     /**
857      * test reply mail in sent folder
858      */
859     public function testReplyMessageInSentFolder()
860     {
861         $messageInSent = $this->_sendMessage($this->_account->sent_folder);
862         $replyMessage = $this->_getReply($messageInSent);
863         $returned = $this->_json->saveMessage($replyMessage);
864         
865         $result = $this->_getMessages();
866         $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
867         $this->assertTrue(! empty($sentMessage));
868     }
869
870     /**
871      * test reply mail with long references header
872      *
873      * @see 0006644: "At least one mail header line is too long"
874      */
875     public function testReplyMessageWithLongHeader()
876     {
877         $messageInSent = $this->_sendMessage($this->_account->sent_folder, array(
878             'references' => '<c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
879    <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
880    <20120530154350.1854610131@ganymed.de>
881    <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
882    <4FC8B49C.8040704@funk.de>
883    <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
884    <20120601123551.5E98610131@ganymed.de>
885    <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
886    <20120619093658.37E4210131@ganymed.de>
887    <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
888    <20120619130652.03DD310131@ganymed.de>
889    <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
890    <20120620074843.42E2010131@ganymed.de>
891    <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
892    <20120620092902.88C8C10131@ganymed.de>
893    <c95d8187-2c71-437e-adb8-5e1dcdbdc507@email.test.org>
894    <2601bbfa-566e-4490-a3db-aad005733d32@email.test.org>
895    <20120530154350.1854610131@ganymed.de>
896    <7e393ce1-d193-44fc-bf5f-30c61a271fe6@email.test.org>
897    <4FC8B49C.8040704@funk.de>
898    <dba2ad5c-6726-4171-8710-984847c010a1@email.test.org>
899    <20120601123551.5E98610131@ganymed.de>
900    <f1cc3195-8641-46e3-8f20-f60f3e16b107@email.test.org>
901    <20120619093658.37E4210131@ganymed.de>
902    <CA+6Rn2PX2Q3tOk2tCQfCjcaC8zYS5XZX327OoyJfUb+w87vCLQ@mail.net.com>
903    <20120619130652.03DD310131@ganymed.de>
904    <37616c6a-4c47-4b54-9ca6-56875bc9205d@email.test.org>
905    <20120620074843.42E2010131@ganymed.de>
906    <CA+6Rn2MAb2x0qeSfcaW6F=0S7LEQL442Sx2ha9RtwMs4B0esBg@mail.net.com>
907    <20120620092902.88C8C10131@ganymed.de>'
908         ));
909         $replyMessage = $this->_getReply($messageInSent);
910         $returned = $this->_json->saveMessage($replyMessage);
911         
912         $result = $this->_getMessages();
913         $sentMessage = $this->_getMessageFromSearchResult($result, $replyMessage['subject']);
914         $this->assertTrue(! empty($sentMessage));
915     }
916     
917     /**
918      * test move
919      */
920     public function testMoveMessage()
921     {
922         $message = $this->_sendMessage();
923         $this->_foldersToClear = array('INBOX', $this->_account->sent_folder, $this->_testFolderName);
924         
925         $inbox = $this->_getFolder('INBOX');
926         $inboxBefore = $this->_json->updateMessageCache($inbox['id'], 30);
927         
928         // move
929         $testFolder = $this->_getFolder($this->_testFolderName);
930         $result = $this->_json->moveMessages(array(array(
931             'field' => 'id', 'operator' => 'in', 'value' => array($message['id'])
932         )), $testFolder->getId());
933
934         // sleep for 2 secs because mailserver may be slower than expected
935         sleep(2);
936
937         $inboxAfter = $this->_getFolder('INBOX');
938         
939         // check if count was decreased correctly
940         $this->assertEquals($inboxBefore['cache_unreadcount'] - 1, $inboxAfter['cache_unreadcount']);
941         $this->assertEquals($inboxBefore['cache_totalcount'] - 1, $inboxAfter['cache_totalcount']);
942         
943         $result = $this->_getMessages($this->_testFolderName);
944         $movedMessage = array();
945         foreach ($result['results'] as $mail) {
946             if ($mail['subject'] == $message['subject']) {
947                 $movedMessage = $mail;
948             }
949         }
950         $this->assertTrue(! empty($movedMessage), 'moved message not found');
951     }
952     
953     /**
954      * forward message test
955      *
956      * @see 0007624: losing umlauts in attached filenames
957      */
958     public function testForwardMessageWithAttachment()
959     {
960         $testFolder = $this->_getFolder($this->_testFolderName);
961         $message = fopen(dirname(__FILE__) . '/../files/multipart_related.eml', 'r');
962         Felamimail_Controller_Message::getInstance()->appendMessage($testFolder, $message);
963         
964         $subject = 'Tine 2.0 bei Metaways - Verbessurngsvorschlag';
965         $message = $this->_searchForMessageBySubject($subject, $this->_testFolderName);
966         
967         $fwdSubject = 'Fwd: ' . $subject;
968         $forwardMessageData = array(
969             'account_id'    => $this->_account->getId(),
970             'subject'       => $fwdSubject,
971             'to'            => array($this->_getEmailAddress()),
972             'body'          => "aaaaaä <br>",
973             'headers'       => array('X-Tine20TestMessage' => 'jsontest'),
974             'original_id'   => $message['id'],
975             'attachments'   => array(new Tinebase_Model_TempFile(array(
976                 'type'  => Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822,
977                 'name'  => 'Verbessurüngsvorschlag',
978             ), TRUE)),
979             'flags'         => Zend_Mail_Storage::FLAG_PASSED,
980         );
981         
982         $this->_foldersToClear[] = 'INBOX';
983         $this->_json->saveMessage($forwardMessageData);
984         $forwardMessage = $this->_searchForMessageBySubject($fwdSubject);
985         
986         // check attachment name
987         $forwardMessageComplete = $this->_json->getMessage($forwardMessage['id']);
988         $this->assertEquals(1, count($forwardMessageComplete['attachments']));
989         $this->assertEquals('Verbessurüngsvorschlag.eml', $forwardMessageComplete['attachments'][0]['filename'], 'umlaut missing from attachment filename');
990         
991         $forwardMessage = $this->_json->getMessage($forwardMessage['id']);
992         $this->assertTrue((isset($forwardMessage['structure']) || array_key_exists('structure', $forwardMessage)), 'structure should be set when fetching complete message: ' . print_r($forwardMessage, TRUE));
993         $this->assertEquals(Felamimail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822, $forwardMessage['structure']['parts'][2]['contentType']);
994         
995         $message = $this->_json->getMessage($message['id']);
996         $this->assertTrue(in_array(Zend_Mail_Storage::FLAG_PASSED, $message['flags']), 'forwarded flag missing in flags: ' . print_r($message, TRUE));
997     }
998     
999     /**
1000      * testSendMessageWithAttachmentWithoutExtension
1001      *
1002      * @see 0008328: email attachment without file extension is not sent properly
1003      */
1004     public function testSendMessageWithAttachmentWithoutExtension()
1005     {
1006         $subject = 'attachment test';
1007         $messageToSend = $this->_getMessageData('unittestalias@' . $this->_mailDomain, $subject);
1008         $tempfileName = 'jsontest' . Tinebase_Record_Abstract::generateUID(10);
1009         $tempfilePath = Tinebase_Core::getTempDir() . DIRECTORY_SEPARATOR . $tempfileName;
1010         file_put_contents($tempfilePath, 'some content');
1011         $tempFile = Tinebase_TempFile::getInstance()->createTempFile($tempfilePath, $tempfileName);
1012         $messageToSend['attachments'] = array(array('tempFile' => array('id' => $tempFile->getId())));
1013         $this->_json->saveMessage($messageToSend);
1014         $forwardMessage = $this->_searchForMessageBySubject($subject);
1015         $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1016         
1017         $fullMessage = $this->_json->getMessage($forwardMessage['id']);
1018         $this->assertTrue(count($fullMessage['attachments']) === 1);
1019         $attachment = $fullMessage['attachments'][0];
1020         $this->assertContains($tempfileName, $attachment['filename'], 'wrong attachment filename: ' . print_r($attachment, TRUE));
1021         $this->assertEquals(16, $attachment['size'], 'wrong attachment size: ' . print_r($attachment, TRUE));
1022     }
1023     
1024     /**
1025      * save message in folder (draft) test
1026      *
1027      * @see 0007178: BCC does not save the draft message
1028      */
1029     public function testSaveMessageInFolder()
1030     {
1031         $messageToSave = $this->_getMessageData();
1032         $messageToSave['bcc'] = array('bccaddress@email.org', 'bccaddress2@email.org');
1033         
1034         $draftsFolder = $this->_getFolder($this->_account->drafts_folder);
1035         $returned = $this->_json->saveMessageInFolder($this->_account->drafts_folder, $messageToSave);
1036         $this->_foldersToClear = array($this->_account->drafts_folder);
1037         
1038         // check if message is in drafts folder and recipients are present
1039         $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->drafts_folder);
1040         $this->assertEquals($messageToSave['subject'],  $message['subject']);
1041         $this->assertEquals($messageToSave['to'][0],    $message['to'][0], 'recipient not found');
1042         $this->assertEquals(2, count($message['bcc']), 'bcc recipient not found: ' . print_r($message, TRUE));
1043         $this->assertEquals($messageToSave['bcc'][0],   $message['bcc'][0], '1st bcc recipient not found');
1044         $this->assertEquals($messageToSave['bcc'][1],   $message['bcc'][1], '2nd bcc recipient not found');
1045     }
1046     
1047     /**
1048      * testSendReadingConfirmation
1049      *
1050      * @see 0007736: ask user before sending reading confirmation
1051      * @see 0008402: Wrong recipient with read confirmation
1052      */
1053     public function testSendReadingConfirmation()
1054     {
1055         $messageToSave = $this->_getMessageData();
1056         $messageToSave['headers']['disposition-notification-to'] = '"' . Tinebase_Core::getUser()->accountFullName . '" <' . $this->_account->email . '>';
1057         $returned = $this->_json->saveMessageInFolder($this->_testFolderName, $messageToSave);
1058         $messageWithReadingConfirmationHeader = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_testFolderName);
1059         $this->_messageIds[] = $messageWithReadingConfirmationHeader['id'];
1060         $this->_json->sendReadingConfirmation($messageWithReadingConfirmationHeader['id']);
1061         
1062         $translate = Tinebase_Translation::getTranslation('Felamimail');
1063         $subject = $translate->_('Reading Confirmation:') . ' '. $messageToSave['subject'];
1064         $message = $this->_searchForMessageBySubject($subject);
1065         $this->_messageIds[] = $message['id'];
1066         
1067         $complete = $this->_json->getMessage($message['id']);
1068         $this->assertContains($translate->_('Was read by:') . ' ' . $this->_account->from, $complete['body']);
1069     }
1070
1071     /**
1072      * save message in non-existant folder (templates) test
1073      *
1074      * @see 0008476: Drafts are not working
1075      */
1076     public function testSaveMessageInNonExistantTemplatesFolder()
1077     {
1078         $messageToSave = $this->_getMessageData();
1079         
1080         $templatesFolder = $this->_getFolder($this->_account->templates_folder, FALSE);
1081         if ($templatesFolder) {
1082             $this->_json->deleteFolder($templatesFolder['id'], $this->_account->getId());
1083         }
1084         $returned = $this->_json->saveMessageInFolder($this->_account->templates_folder, $messageToSave);
1085         $this->_foldersToClear = array($this->_account->templates_folder);
1086         
1087         // check if message is in templates folder
1088         $message = $this->_searchForMessageBySubject($messageToSave['subject'], $this->_account->templates_folder);
1089         $this->assertEquals($messageToSave['subject'],  $message['subject']);
1090         $this->assertEquals($messageToSave['to'][0],    $message['to'][0], 'recipient not found');
1091     }
1092     
1093     /**
1094      * testSaveMessageNoteWithInvalidChar
1095      *
1096      * @see 0008644: error when sending mail with note (wrong charset)
1097      */
1098     public function testSaveMessageNoteWithInvalidChar()
1099     {
1100         $subject = Tinebase_Core::filterInputForDatabase("\xF0\x9F\x98\x8A\xC2"); // :-) emoji &nbsp;
1101         $messageData = $this->_getMessageData('', $subject);
1102         $messageData['note'] = true;
1103         $messageData['body'] .= "&nbsp;";
1104         
1105         $this->_foldersToClear[] = 'INBOX';
1106         $this->_json->saveMessage($messageData);
1107         $message = $this->_searchForMessageBySubject($subject);
1108         
1109         $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId());
1110         $this->_checkEmailNote($contact, $subject);
1111     }
1112     
1113     /**
1114      * testSaveMessageNoteWithInvalidChar
1115      *
1116      * @see 0008644: error when sending mail with note (wrong charset)
1117      */
1118     public function testSaveMessageWithInvalidChar()
1119     {
1120         $subject = "\xF0\x9F\x98\x8A"; // :-) emoji
1121         $messageData = $this->_getMessageData('', $subject);
1122         $this->_foldersToClear[] = 'INBOX';
1123         $this->_json->saveMessage($messageData);
1124         $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1125     }
1126     
1127     /**
1128      * testMessageWithInvalidICS
1129      *
1130      * @see 0008786: broken ics causes js error when showing details
1131      */
1132     public function testMessageWithInvalidICS()
1133     {
1134         $inbox = $this->_getFolder('INBOX');
1135         $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/invalidimip.eml');
1136         Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1137         
1138         $this->_foldersToClear = array('INBOX');
1139         $message = $this->_searchForMessageBySubject('test invalid imip');
1140         
1141         $fullMessage = $this->_json->getMessage($message['id']);
1142         $this->assertTrue(empty($fullMessage->preparedParts));
1143     }
1144
1145     /**
1146      * testSendMailveopeAPIMessage
1147      *
1148      * - envolpe amored message into PGP MIME structure
1149      */
1150     public function testSendMailveopeAPIMessage()
1151     {
1152         $subject = 'testSendMailveopeAPIMessage';
1153         $messageData = $this->_getMessageData('', $subject);
1154         $messageData['body'] = '-----BEGIN PGP MESSAGE-----
1155 Version: Mailvelope v1.3.3
1156 Comment: https://www.mailvelope.com
1157
1158 wcFMA/0LJF28pDbGAQ//YgtsmEZN+pgIJiBDb7iYwPEOchDRIEjGOx543KF6
1159 5YigW9p39pfcJgvGfT8x9cUIrYGxyw5idPSOEftYXyjjGaOYGaKpRSR4hI83
1160 OcJSlEHKq72xhg04mNpCjjJ8dLBstPcQ7tDtsA8Nfb4PwkUYB9IhIBnARg+n
1161 NvrN8mSA2UnY9ElFCvf30sar8EuM5swAjbk64C8TIypMy/Bg4T93zRdxwik6
1162 7BCcbOpm/2PTsiVYBOTcU4+XdG5eyTENXH58M6UTxTD4/g7Qi5PjN+PxyXqf
1163 v2Y1k9F49Y1egf2QJ2r4PX0EWS8SaynSHiIoBsp1xb07nLwZwCdMPG1QNPpF
1164 l2FqlS4dEuQTdkv0deMvd7gtiNynRTAVcJc1ZC6RuWJ+EH2jA49XWkn14eRC
1165 e5jMtPPudkhubnN9Je5lwatGKbJGyuXh+IaM0E0WQMZ3dm8+ST1l4WpVuGbw
1166 KozLUiTRJP9UoxWOcwpQOnzcSlc4rHmWdtF0y3usM9u9GPREqpNUWkEyEEuv
1167 XdZE7rKKj22dJHLCXxAQEh3m29Y2WVaq50YbtEZ+SwwbrHhxP4+FJEru+byh
1168 fiZ47sVW2KvYGJPvbFoSZHiSvMecxDg8BVwe+naZXww/Rwa/TlaX4bYyzpUG
1169 KeJUAzWEfFpJ0+yAvMGQEC7psIJ9NCx149C4ujiQmajSwhUB3XANcmCGB0wm
1170 JjcqC4AHvc7/t4MrQZm0F/W+nrMmNqbZk+gylVrPs9rFEqu7wbjwTmsFA3sS
1171 LkenvQIxBali6uzCR+nd09REqcYirG9cLti39DW048lhhG/ml+gAxxNEaSpG
1172 NbIoV/3w8n7sAIM1fjuHne8bX0gWG43TTjU8MwSMryG7tCOG5u+Cebh6TAoY
1173 NzbX2dpDhOYq5zXdCgKU4P3eh0csSs4UrqFT3TdAxIGrQJ7KrXvB6+N8gRZo
1174 FcUaR+zrRPJjPUZfi46ecP5SG/tM5ea1hqvkwEnEpqjLmCUxqB+rfxx46USX
1175 hMZd2ukUv6kEKv3EUDsRYu1SlDLhDLhWNx8RJae5XkMR+eUUMyNNVwbeMQbB
1176 VAcMcaPITTk84sH7XElr9eF6sCUN4V79OSBRPGY/aNGrcwcoDSD4Hwu+Lw9w
1177 Q+1n8EQ66gAkbJzCNd5GaYMZR9echkBaD/rdWDS3ktcrMehra+h44MTQONV9
1178 8W+RI+IT5jaIXtB4jePmGjsJjbC9aEhTRBRkUnPA7phgknc52dD74AY/6lzK
1179 yd4uZ6S3vhurJW0Vt4iBWJzhFNiSODh5PzteeNzCVAkGMsQvy1IHk0d3uzcE
1180 0tEuSh8fZOFGB4fvMx9Mk8oAU92wfj4J7AVpSo5oRdxMqAXfaYKqfr2Gn++q
1181 E5LClhVIBbFXclCoe0RYNz4wtxjeeYbP40Bq5g0JvPutD/dBMp8hz8Qt+yyG
1182 d8X4/KmQIXyFZ8aP17GMckE5GVVvY9y89eWnWuTUJdwM540hB/EJNeHHTE5y
1183 N2FSLGcmNkvE+3H7BczQ2ZI1SZDhof+umbUst0qoQW+hHmY3CSma48yGAVox
1184 52u2t7hosHCfpf631Ve/6fcICo8vJ2Qfufu2BGIMlSfx4WzUuaMQBynuxFSa
1185 IbVx8ZTO7dJRKrg72aFmWTf0uNla7vicAhpiLWobyNYcZbIjrAGDfg==
1186 =BaAn
1187 -----END PGP MESSAGE-----';
1188
1189         $this->_foldersToClear[] = 'INBOX';
1190         $this->_json->saveMessage($messageData);
1191
1192         $message = $this->_searchForMessageBySubject(Tinebase_Core::filterInputForDatabase($subject));
1193         $fullMessage = $this->_json->getMessage($message['id']);
1194
1195         $this->assertContains('multipart/encrypted', $fullMessage['headers']['content-type']);
1196         $this->assertContains('protocol="application/pgp-encrypted"', $fullMessage['headers']['content-type']);
1197         $this->assertCount(2, $fullMessage['structure']['parts']);
1198         $this->assertEquals('application/pgp-encrypted', $fullMessage['structure']['parts'][1]['contentType']);
1199         $this->assertEquals('application/octet-stream', $fullMessage['structure']['parts'][2]['contentType']);
1200
1201         return $fullMessage;
1202     }
1203
1204     /**
1205      * testMessagePGPMime
1206      *
1207      * - prepare amored part of PGP MIME structure
1208      */
1209     public function testMessagePGPMime()
1210     {
1211         $fullMessage = $this->testSendMailveopeAPIMessage();
1212
1213         $this->assertEquals('application/pgp-encrypted', $fullMessage['preparedParts'][0]['contentType']);
1214         $this->assertContains('-----BEGIN PGP MESSAGE-----', $fullMessage['preparedParts'][0]['preparedData']);
1215     }
1216
1217     public function testMessagePGPInline()
1218     {
1219         $inbox = $this->_getFolder('INBOX');
1220         $mailAsString = file_get_contents(dirname(__FILE__) . '/../files/multipart_alternative_pgp_inline.eml');
1221         Felamimail_Controller_Message::getInstance()->appendMessage($inbox, $mailAsString);
1222
1223         $this->_foldersToClear = array('INBOX');
1224         $message = $this->_searchForMessageBySubject('Re: mailvelope und tine20');
1225
1226         $fullMessage = $this->_json->getMessage($message['id']);
1227         $this->assertFalse(empty($fullMessage['preparedParts']));
1228     }
1229
1230     /*********************** sieve tests ****************************/
1231     
1232     /**
1233      * set and get vacation sieve script
1234      *
1235      * @see 0007768: Sieve - Vacation notify frequency not being set (Cyrus)
1236      */
1237     public function testGetSetVacation()
1238     {
1239         $vacationData = $this->_getVacationData();
1240         $this->_sieveTestHelper($vacationData);
1241         
1242         // check if script was activated
1243         $activeScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1244         $this->assertEquals($this->_testSieveScriptName, $activeScriptName);
1245         $updatedAccount = Felamimail_Controller_Account::getInstance()->get($this->_account->getId());
1246         $this->assertTrue((bool) $updatedAccount->sieve_vacation_active);
1247         
1248         $result = $this->_json->getVacation($this->_account->getId());
1249
1250         $this->assertEquals($this->_account->email, $result['addresses'][0]);
1251         
1252         $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1253         if (preg_match('/dbmail/i', $sieveBackend->getImplementation())) {
1254             $translate = Tinebase_Translation::getTranslation('Felamimail');
1255             $vacationData['subject'] = sprintf($translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName);
1256         }
1257         
1258         foreach (array('reason', 'enabled', 'subject', 'from', 'days') as $field) {
1259             $this->assertEquals($vacationData[$field], $result[$field], 'vacation data mismatch: ' . $field);
1260         }
1261     }
1262     
1263     /**
1264      * get vacation data
1265      *
1266      * @return array
1267      */
1268     protected function _getVacationData()
1269     {
1270         return array(
1271             'id'                    => $this->_account->getId(),
1272             'subject'               => 'unittest vacation subject',
1273             'from'                  => $this->_account->from . ' <' . $this->_account->email . '>',
1274             'days'                  => 3,
1275             'enabled'               => TRUE,
1276             'reason'                => 'unittest vacation message<br /><br />signature',
1277             'mime'                  => NULL,
1278         );
1279     }
1280     
1281     /**
1282      * test mime vacation sieve script
1283      */
1284     public function testMimeVacation()
1285     {
1286         $vacationData = $this->_getVacationData();
1287         $vacationData['reason'] = "\n<html><body><h1>unittest vacation&nbsp;message</h1></body></html>";
1288         
1289         $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1290         if (! in_array('mime', $_sieveBackend->capability())) {
1291             $vacationData['mime'] = 'text/html';
1292         }
1293         
1294         $this->_sieveTestHelper($vacationData, TRUE);
1295     }
1296     
1297     /**
1298      * test get/set of rules sieve script
1299      */
1300     public function testGetSetRules()
1301     {
1302         $ruleData = $this->_getRuleData();
1303         
1304         $this->_sieveTestHelper($ruleData);
1305         
1306         // check getRules
1307         $result = $this->_json->getRules($this->_account->getId());
1308         $this->assertEquals($result['totalcount'], count($ruleData));
1309         
1310         // check by sending mail
1311         $messageData = $this->_getMessageData('', 'viagra');
1312         $returned = $this->_json->saveMessage($messageData);
1313         $this->_foldersToClear = array('INBOX', $this->_testFolderName);
1314         // check if message is in test folder
1315         $message = $this->_searchForMessageBySubject($messageData['subject'], $this->_testFolderName);
1316     }
1317     
1318     /**
1319      * testRemoveRules
1320      *
1321      * @see 0006490: can not delete single filter rule
1322      */
1323     public function testRemoveRules()
1324     {
1325         $this->testGetSetRules();
1326         $this->_json->saveRules($this->_account->getId(), array());
1327         
1328         $result = $this->_json->getRules($this->_account->getId());
1329         $this->assertEquals(0, $result['totalcount'], 'found rules: ' . print_r($result, TRUE));
1330     }
1331     
1332     /**
1333      * get sieve rule data
1334      *
1335      * @return array
1336      */
1337     protected function _getRuleData()
1338     {
1339         return array(array(
1340             'id'            => 1,
1341             'action_type'   => Felamimail_Sieve_Rule_Action::FILEINTO,
1342             'action_argument' => $this->_testFolderName,
1343             'conjunction'  => 'allof',
1344             'conditions'    => array(array(
1345                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1346                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1347                 'header'        => 'From',
1348                 'key'           => '"abcd" <info@example.org>',
1349             )),
1350             'enabled'       => 1,
1351         ), array(
1352             'id'            => 2,
1353             'action_type'   => Felamimail_Sieve_Rule_Action::FILEINTO,
1354             'action_argument' => $this->_testFolderName,
1355             'conjunction'  => 'allof',
1356             'conditions'    => array(array(
1357                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1358                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1359                 'header'        => 'From',
1360                 'key'           => 'info@example.org',
1361             )),
1362             'enabled'       => 0,
1363         ), array(
1364             'id'            => 3,
1365             'action_type'   => Felamimail_Sieve_Rule_Action::FILEINTO,
1366             'action_argument' => $this->_testFolderName,
1367             'conjunction'  => 'allof',
1368             'conditions'    => array(array(
1369                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_HEADER,
1370                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_REGEX,
1371                 'header'        => 'subject',
1372                 'key'           => '[vV]iagra|cyalis',
1373             )),
1374             'enabled'       => 1,
1375         ));
1376     }
1377     
1378     /**
1379      * test to set a forward rule to this accounts email address
1380      * -> should throw exception to prevent mail cycling
1381      */
1382     public function testSetForwardRuleToSelf()
1383     {
1384         $ruleData = array(array(
1385             'id'            => 1,
1386             'action_type'   => Felamimail_Sieve_Rule_Action::REDIRECT,
1387             'action_argument' => $this->_account->email,
1388             'conjunction'     => 'allof',
1389             'conditions'    => array(array(
1390                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1391                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1392                 'header'        => 'From',
1393                 'key'           => 'info@example.org',
1394             )),
1395             'enabled'       => 1,
1396         ));
1397         
1398         try {
1399             $this->_sieveTestHelper($ruleData);
1400             $this->assertTrue(FALSE, 'it is not allowed to set own email address for redirect!');
1401         } catch (Felamimail_Exception_Sieve $e) {
1402             $this->assertTrue(TRUE);
1403         }
1404
1405         // this should work
1406         $ruleData[0]['enabled'] = 0;
1407         $this->_sieveTestHelper($ruleData);
1408     }
1409
1410     /**
1411      * @see 0006222: Keep a copy from mails forwarded to another emailaddress
1412      */
1413     public function testSetForwardRuleWithCopy()
1414     {
1415         $ruleData = array(array(
1416             'id'            => 1,
1417             'action_type'   => Felamimail_Sieve_Rule_Action::REDIRECT,
1418             'action_argument' => array(
1419                 'emails' => 'someaccount@example.org',
1420                 'copy'   => 1,
1421             ),
1422             'conjunction'     => 'allof',
1423             'conditions'    => array(array(
1424                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1425                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1426                 'header'        => 'From',
1427                 'key'           => 'info@example.org',
1428             )),
1429             'enabled'       => 1,
1430         ));
1431
1432         $this->_sieveTestHelper($ruleData);
1433     }
1434
1435     /**
1436      * @see 0006222: Keep a copy from mails forwarded to another emailaddress
1437      */
1438     public function testSetForwardRuleWithoutCopy()
1439     {
1440         $ruleData = array(array(
1441             'id'            => 1,
1442             'action_type'   => Felamimail_Sieve_Rule_Action::REDIRECT,
1443             'action_argument' => array(
1444                 'emails' => 'someaccount@example.org',
1445                 'copy'   => 0,
1446             ),
1447             'conjunction'     => 'allof',
1448             'conditions'    => array(array(
1449                 'test'          => Felamimail_Sieve_Rule_Condition::TEST_ADDRESS,
1450                 'comperator'    => Felamimail_Sieve_Rule_Condition::COMPERATOR_CONTAINS,
1451                 'header'        => 'From',
1452                 'key'           => 'info@example.org',
1453             )),
1454             'enabled'       => 1,
1455         ));
1456
1457         $this->_sieveTestHelper($ruleData);
1458     }
1459
1460     /**
1461      * testGetVacationTemplates
1462      *
1463      * @return array
1464      */
1465     public function testGetVacationTemplates()
1466     {
1467         $this->markTestSkipped('0010194: fix felamimail webdav tests');
1468         
1469         $this->_addVacationTemplateFile();
1470         $result = $this->_json->getVacationMessageTemplates();
1471         
1472         $this->assertTrue($result['totalcount'] > 0, 'no templates found');
1473         $found = FALSE;
1474         foreach ($result['results'] as $template) {
1475             if ($template['name'] === $this->_sieveVacationTemplateFile) {
1476                 $found = TRUE;
1477                 break;
1478             }
1479         }
1480         
1481         $this->assertTrue($found, 'wrong templates: ' . print_r($result['results'], TRUE));
1482         
1483         return $template;
1484     }
1485     
1486     /**
1487      * add vacation template file to vfs
1488      */
1489     protected function _addVacationTemplateFile()
1490     {
1491         $webdavRoot = new DAV\ObjectTree(new Tinebase_WebDav_Root());
1492         $path = '/webdav/Felamimail/shared/Vacation Templates';
1493         $node = $webdavRoot->getNodeForPath($path);
1494         $this->_pathsToDelete[] = $path . '/' . $this->_sieveVacationTemplateFile;
1495         $node->createFile($this->_sieveVacationTemplateFile, fopen(dirname(__FILE__) . '/../files/' . $this->_sieveVacationTemplateFile, 'r'));
1496     }
1497     
1498     /**
1499      * testGetVacationMessage
1500      */
1501     public function testGetVacationMessage()
1502     {
1503         $this->markTestSkipped('0010194: fix felamimail webdav tests');
1504         
1505         $result = $this->_getVacationMessageWithTemplate();
1506         $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1507         $pwulf = Tinebase_User::getInstance()->getFullUserByLoginName('pwulf');
1508         $this->assertEquals("Ich bin vom 18.04.2012 bis zum 20.04.2012 im Urlaub. Bitte kontaktieren Sie<br /> Paul Wulf (" .
1509             $pwulf->accountEmailAddress . ") oder Susan Clever (" .
1510             $sclever->accountEmailAddress . ").<br /><br />I am on vacation until Apr 20, 2012. Please contact Paul Wulf<br />(" .
1511             $pwulf->accountEmailAddress . ") or Susan Clever (" .
1512             $sclever->accountEmailAddress . ") instead.<br /><br />" .
1513             Addressbook_Controller_Contact::getInstance()->getContactByUserId(Tinebase_Core::getUser()->getId())->n_fn, $result['message']);
1514     }
1515     
1516     /**
1517      * get vacation message with template
1518      *
1519      * @return array
1520      */
1521     protected function _getVacationMessageWithTemplate()
1522     {
1523         $template = $this->testGetVacationTemplates();
1524         $sclever = Tinebase_User::getInstance()->getFullUserByLoginName('sclever');
1525         $result = $this->_json->getVacationMessage(array(
1526             'start_date' => '2012-04-18',
1527             'end_date'   => '2012-04-20',
1528             'contact_ids' => array(
1529                 Tinebase_User::getInstance()->getFullUserByLoginName('pwulf')->contact_id,
1530                 $sclever->contact_id,
1531             ),
1532             'template_id' => $template['id'],
1533             'signature' => $this->_account->signature
1534         ));
1535         
1536         return $result;
1537     }
1538     
1539     /**
1540      * testGetVacationWithSignature
1541      *
1542      * @see 0006866: check signature linebreaks in vacation message from template
1543      */
1544     public function testGetVacationWithSignature()
1545     {
1546         $this->markTestSkipped('0010194: fix felamimail webdav tests');
1547         
1548         $this->_sieveVacationTemplateFile = 'vacation_template_sig.tpl';
1549         
1550         // set signature with <br> + linebreaks
1551         $this->_account->signature = "llalala<br>\nxyz<br>\nblubb<br>";
1552         
1553         $result = $this->_getVacationMessageWithTemplate();
1554         $this->assertContains('-- <br />llalala<br />xyz<br />blubb<br />', $result['message'], 'wrong linebreaks or missing signature');
1555     }
1556     
1557     /**
1558     * testSetVacationWithStartAndEndDate
1559     *
1560     * @see 0006266: automatic deactivation of vacation message
1561     */
1562     public function testSetVacationWithStartAndEndDate()
1563     {
1564         $vacationData = $this->_getVacationData();
1565         $vacationData['start_date'] = '2012-04-18';
1566         $vacationData['end_date'] = '2012-04-20';
1567         $result = $this->_sieveTestHelper($vacationData);
1568         
1569         $this->assertContains($vacationData['start_date'], $result['start_date']);
1570         $this->assertContains($vacationData['end_date'], $result['end_date']);
1571     }
1572     
1573     /**
1574      * testSieveRulesOrder
1575      *
1576      * @see 0007240: order of sieve rules changes when vacation message is saved
1577      */
1578     public function testSieveRulesOrder()
1579     {
1580         $this->_setTestScriptname();
1581         
1582         // disable vacation first
1583         $this->_setDisabledVacation();
1584         
1585         $sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1586         
1587         $ruleData = $this->_getRuleData();
1588         $ruleData[0]['id'] = $ruleData[2]['id'];
1589         $ruleData[2]['id'] = 11;
1590         $resultSet = $this->_json->saveRules($this->_account->getId(), $ruleData);
1591         $sieveScriptRules = $sieveBackend->getScript($this->_testSieveScriptName);
1592         
1593         $this->_setDisabledVacation();
1594         $sieveScriptVacation = $sieveBackend->getScript($this->_testSieveScriptName);
1595         
1596         // compare sieve scripts
1597         $this->assertContains($sieveScriptRules, $sieveScriptVacation, 'rule order changed');
1598     }
1599     
1600     /**
1601      * use another name for test sieve script
1602      */
1603     protected function _setTestScriptname()
1604     {
1605         $this->_oldActiveSieveScriptName = Felamimail_Controller_Sieve::getInstance()->getActiveScriptName($this->_account->getId());
1606         $this->_testSieveScriptName = 'Felamimail_Unittest';
1607         Felamimail_Controller_Sieve::getInstance()->setScriptName($this->_testSieveScriptName);
1608     }
1609     
1610     /**
1611      * set disabled vacation message
1612      */
1613     protected function _setDisabledVacation()
1614     {
1615         $vacationData = $this->_getVacationData();
1616         $vacationData['enabled'] = FALSE;
1617         $resultSet = $this->_json->saveVacation($vacationData);
1618     }
1619     
1620     /**
1621      * get folder filter
1622      *
1623      * @return array
1624      */
1625     protected function _getFolderFilter()
1626     {
1627         return array(array(
1628             'field' => 'globalname', 'operator' => 'equals', 'value' => ''
1629         ));
1630     }
1631
1632     /**
1633      * get message filter
1634      *
1635      * @param string $_folderId
1636      * @return array
1637      */
1638     protected function _getMessageFilter($_folderId)
1639     {
1640         $result = array(array(
1641             'field' => 'folder_id', 'operator' => 'equals', 'value' => $_folderId
1642         ));
1643         
1644         return $result;
1645     }
1646     
1647     /**
1648      * get mailbox
1649      *
1650      * @param string $name
1651      * @param boolean $createFolder
1652      * @return Felamimail_Model_Folder|NULL
1653      */
1654     protected function _getFolder($name, $createFolder = TRUE)
1655     {
1656         Felamimail_Controller_Cache_Folder::getInstance()->update($this->_account->getId());
1657         try {
1658             $folder = Felamimail_Controller_Folder::getInstance()->getByBackendAndGlobalName($this->_account->getId(), $name);
1659         } catch (Tinebase_Exception_NotFound $tenf) {
1660             $folder = ($createFolder) ? Felamimail_Controller_Folder::getInstance()->create($this->_account, $name) : NULL;
1661         }
1662         
1663         return $folder;
1664     }
1665
1666     /**
1667      * get message data
1668      *
1669      * @return array
1670      */
1671     protected function _getMessageData($_emailFrom = '', $_subject = 'test')
1672     {
1673         return array(
1674             'account_id'    => $this->_account->getId(),
1675             'subject'       => $_subject,
1676             'to'            => array(Tinebase_Core::getUser()->accountEmailAddress),
1677             'body'          => 'aaaaaä <br>',
1678             'headers'       => array('X-Tine20TestMessage' => 'jsontest'),
1679             'from_email'    => $_emailFrom,
1680             'content_type'  => Felamimail_Model_Message::CONTENT_TYPE_HTML,
1681         );
1682     }
1683
1684     /**
1685      * send message and return message array
1686      *
1687      * @param string $folderName
1688      * @param array $addtionalHeaders
1689      * @return array
1690      */
1691     protected function _sendMessage($folderName = 'INBOX', $addtionalHeaders = array())
1692     {
1693         $messageToSend = $this->_getMessageData();
1694         $messageToSend['headers'] = array_merge($messageToSend['headers'], $addtionalHeaders);
1695         $this->_json->saveMessage($messageToSend);
1696         $this->_foldersToClear = array('INBOX', $this->_account->sent_folder);
1697
1698         $i = 0;
1699         while ($i < 5) {
1700             $result = $this->_getMessages($folderName);
1701             $message = $this->_getMessageFromSearchResult($result, $messageToSend['subject']);
1702             if (! empty($message)) {
1703                 break;
1704             }
1705             // sleep for 1 sec because mailserver may be slower than expected
1706             sleep(1);
1707             $i++;
1708         }
1709
1710         $this->assertTrue(! empty($message), 'Sent message not found.');
1711         
1712         return $message;
1713     }
1714     
1715     /**
1716      * returns message array from result
1717      *
1718      * @param array $_result
1719      * @param string $_subject
1720      * @return array
1721      */
1722     protected function _getMessageFromSearchResult($_result, $_subject)
1723     {
1724         $message = array();
1725         foreach ($_result['results'] as $mail) {
1726             if ($mail['subject'] == $_subject) {
1727                 $message = $mail;
1728             }
1729         }
1730         
1731         return $message;
1732     }
1733     
1734     /**
1735      * get messages from folder
1736      *
1737      * @param string $_folderName
1738      * @return array
1739      */
1740     protected function _getMessages($_folderName = 'INBOX')
1741     {
1742         $folder = $this->_getFolder($_folderName);
1743         $filter = $this->_getMessageFilter($folder->getId());
1744         // update cache
1745         $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10, 1);
1746         $i = 0;
1747         while ($folder->cache_status != Felamimail_Model_Folder::CACHE_STATUS_COMPLETE && $i < 10) {
1748             $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folder, 10);
1749             $i++;
1750         }
1751         $result = $this->_json->searchMessages($filter, '');
1752
1753         return $result;
1754     }
1755     
1756     /**
1757      * search for message defined by subject in folder
1758      *
1759      * @param string $_subject
1760      * @param string $_folderName
1761      * @return string message data
1762      */
1763     protected function _searchForMessageBySubject($_subject, $_folderName = 'INBOX')
1764     {
1765         // give server some time to send and receive messages
1766         sleep(1);
1767
1768         $result = $this->_getMessages($_folderName);
1769         
1770         $message = array();
1771         foreach ($result['results'] as $mail) {
1772             if ($mail['subject'] == $_subject) {
1773                 $message = $mail;
1774             }
1775         }
1776         $this->assertGreaterThan(0, $result['totalcount'], 'folder is empty');
1777         $this->assertTrue(! empty($message), 'Message not found');
1778         
1779         return $message;
1780     }
1781     
1782     /**
1783      * sieve test helper
1784      *
1785      * @param array $_sieveData
1786      * @return array
1787      */
1788     protected function _sieveTestHelper($_sieveData, $_isMime = FALSE)
1789     {
1790         $this->_setTestScriptname();
1791         
1792         // check which save fn to use
1793         if ((isset($_sieveData['reason']) || array_key_exists('reason', $_sieveData))) {
1794             $resultSet = $this->_json->saveVacation($_sieveData);
1795             $this->assertEquals($this->_account->email, $resultSet['addresses'][0]);
1796             
1797             $_sieveBackend = Felamimail_Backend_SieveFactory::factory($this->_account->getId());
1798             
1799             if (preg_match('/dbmail/i', $_sieveBackend->getImplementation())) {
1800                 $translate = Tinebase_Translation::getTranslation('Felamimail');
1801                 $this->assertEquals(sprintf(
1802                     $translate->_('Out of Office reply from %1$s'), Tinebase_Core::getUser()->accountFullName),
1803                     $resultSet['subject']
1804                 );
1805             } else {
1806                 $this->assertEquals($_sieveData['subject'], $resultSet['subject']);
1807             }
1808             
1809             if ($_isMime) {
1810                 $this->assertEquals(html_entity_decode('unittest vacation&nbsp;message', ENT_NOQUOTES, 'UTF-8'), $resultSet['reason']);
1811             } else {
1812                 $this->assertEquals($_sieveData['reason'], $resultSet['reason']);
1813             }
1814             
1815         } else if ((isset($_sieveData[0]['action_type']) || array_key_exists('action_type', $_sieveData[0]))) {
1816             $resultSet = $this->_json->saveRules($this->_account->getId(), $_sieveData);
1817             $this->assertEquals($_sieveData, $resultSet);
1818         }
1819         
1820         return $resultSet;
1821     }
1822
1823     /**
1824      * search preferences by application felamimail
1825      *
1826      */
1827     public function testSearchFelamimailPreferences()
1828     {
1829         // search prefs
1830         $result = $this->_frontend->searchPreferencesForApplication('Felamimail', '');
1831         
1832         // check results
1833         $this->assertTrue(isset($result['results']));
1834         $this->assertGreaterThan(0, $result['totalcount']);
1835     }
1836     
1837     /**
1838      * testGetRegistryData
1839      *
1840      * @see 0010251: do not send unused config data to client
1841      */
1842     public function testGetRegistryData()
1843     {
1844         $regData = $this->_json->getRegistryData();
1845
1846         $this->assertFalse(isset($regData['defaults']));
1847         $supportedFlags = Felamimail_Config::getInstance()->featureEnabled(Felamimail_Config::FEATURE_TINE20_FLAG)
1848             ? 6
1849             : 5;
1850         $this->assertEquals($supportedFlags, $regData['supportedFlags']['totalcount']);
1851     }
1852 }