increase timeout for update folder cache to 5 mins
[tine20] / tine20 / Felamimail / Frontend / Json.php
1 <?php
2 /**
3  * json frontend for Felamimail
4  *
5  * This class handles all Json requests for the Felamimail application
6  *
7  * @package     Felamimail
8  * @subpackage  Frontend
9  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
10  * @author      Philipp Schüle <p.schuele@metaways.de>
11  * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
12  *
13  */
14 class Felamimail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
15 {
16     /**
17      * application name
18      *
19      * @var string
20      */
21     protected $_applicationName = 'Felamimail';
22     
23     /***************************** folder funcs *******************************/
24     
25     /**
26      * search folders and update/initialize cache of subfolders 
27      *
28      * @param  array $filter
29      * @return array
30      */
31     public function searchFolders($filter)
32     {
33         // close session to allow other requests
34         Tinebase_Session::writeClose(true);
35         
36         $result = $this->_search($filter, '', Felamimail_Controller_Folder::getInstance(), 'Felamimail_Model_FolderFilter');
37         
38         return $result;
39     }
40
41     /**
42      * add new folder
43      *
44      * @param string $name
45      * @param string $parent
46      * @param string $accountId
47      * @return array
48      */
49     public function addFolder($name, $parent, $accountId)
50     {
51         $result = Felamimail_Controller_Folder::getInstance()->create($accountId, $name, $parent);
52         
53         return $result->toArray();
54     }
55
56     /**
57      * rename folder
58      *
59      * @param string $newName
60      * @param string $oldGlobalName
61      * @param string $accountId
62      * @return array
63      */
64     public function renameFolder($newName, $oldGlobalName, $accountId)
65     {
66         $result = Felamimail_Controller_Folder::getInstance()->rename($accountId, $newName, $oldGlobalName);
67         
68         return $result->toArray();
69     }
70     
71     /**
72      * delete folder
73      *
74      * @param string $folder the folder global name to delete
75      * @param string $accountId
76      * @return array
77      */
78     public function deleteFolder($folder, $accountId)
79     {
80         $result = Felamimail_Controller_Folder::getInstance()->delete($accountId, $folder);
81
82         return array(
83             'status'    => ($result) ? 'success' : 'failure'
84         );
85     }
86     
87     /**
88      * refresh folder
89      *
90      * @param string $folderId the folder id to delete
91      * @return array
92      */
93     public function refreshFolder($folderId)
94     {
95         $result = Felamimail_Controller_Cache_Message::getInstance()->clear($folderId);
96
97         return array(
98             'status'    => ($result) ? 'success' : 'failure'
99         );
100     }
101
102     /**
103      * remove all messages from folder and delete subfolders
104      *
105      * @param  string $folderId the folder id to delete
106      * @return array with folder status
107      */
108     public function emptyFolder($folderId)
109     {
110         // close session to allow other requests
111         Tinebase_Session::writeClose(true);
112         
113         $result = Felamimail_Controller_Folder::getInstance()->emptyFolder($folderId, TRUE);
114         return $this->_recordToJson($result);
115     }
116     
117     /**
118      * update folder cache
119      *
120      * @param string $accountId
121      * @param string  $folderName of parent folder
122      * @return array of (sub)folders in cache
123      */
124     public function updateFolderCache($accountId, $folderName)
125     {
126         // this may take longer
127         $this->_longRunningRequest(300);
128
129         $result = Felamimail_Controller_Cache_Folder::getInstance()->update($accountId, $folderName, TRUE);
130         return $this->_multipleRecordsToJson($result);
131     }
132     
133     /**
134      * get folder status
135      *
136      * @param array  $filterData
137      * @return array of folder status
138      */
139     public function getFolderStatus($filterData)
140     {
141         // close session to allow other requests
142         Tinebase_Session::writeClose(true);
143         
144         $filter = new Felamimail_Model_FolderFilter($filterData);
145         $result = Felamimail_Controller_Cache_Message::getInstance()->getFolderStatus($filter);
146         return $this->_multipleRecordsToJson($result);
147     }
148     
149     /***************************** messages funcs *******************************/
150     
151     /**
152      * search messages in message cache
153      *
154      * @param  array $filter
155      * @param  array $paging
156      * @return array
157      */
158     public function searchMessages($filter, $paging)
159     {
160         $result = $this->_search($filter, $paging, Felamimail_Controller_Message::getInstance(), 'Felamimail_Model_MessageFilter');
161         
162         return $result;
163     }
164     
165     /**
166      * update message cache
167      * - use session/writeClose to update incomplete cache and allow following requests
168      *
169      * @param  string  $folderId id of active folder
170      * @param  integer $time     update time in seconds
171      * @return array
172      */
173     public function updateMessageCache($folderId, $time)
174     {
175         // close session to allow other requests
176         Tinebase_Session::writeClose(true);
177         
178         $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folderId, $time);
179         
180         return $this->_recordToJson($folder);
181     }
182     
183     /**
184      * get message data
185      *
186      * @param  string $id
187      * @return array
188      */
189     public function getMessage($id)
190     {
191         // close session to allow other requests
192         Tinebase_Session::writeClose(true);
193         
194         if (strpos($id, '_') !== false) {
195             list($messageId, $partId) = explode('_', $id);
196         } else {
197             $messageId = $id;
198             $partId    = null;
199         }
200         
201         $message = Felamimail_Controller_Message::getInstance()->getCompleteMessage($messageId, $partId, false);
202         $message->id = $id;
203         
204         return $this->_recordToJson($message);
205     }
206     
207     /**
208      * move messsages to folder
209      *
210      * @param  array $filterData filter data
211      * @param  string $targetFolderId
212      * @return array source folder status
213      */
214     public function moveMessages($filterData, $targetFolderId)
215     {
216         // close session to allow other requests
217         Tinebase_Session::writeClose(true);
218         
219         $filter = new Felamimail_Model_MessageFilter(array());
220         $filter->setFromArrayInUsersTimezone($filterData);
221         $updatedFolders = Felamimail_Controller_Message_Move::getInstance()->moveMessages($filter, $targetFolderId);
222         
223         $result = ($updatedFolders !== NULL) ? $this->_multipleRecordsToJson($updatedFolders) : array();
224         
225         return $result;
226     }
227     
228     /**
229      * save + send message
230      * 
231      * - this function has to be named 'saveMessage' because of the generic edit dialog function names
232      *
233      * @param  array $recordData
234      * @return array
235      */
236     public function saveMessage($recordData)
237     {
238         $message = new Felamimail_Model_Message();
239         $message->setFromJsonInUsersTimezone($recordData);
240         
241         $result = Felamimail_Controller_Message_Send::getInstance()->sendMessage($message);
242         $result = $this->_recordToJson($result);
243         
244         return $result;
245     }
246
247     /**
248      * save message in folder
249      * 
250      * @param  string $folderName
251      * @param  array $recordData
252      * @return array
253      */
254     public function saveMessageInFolder($folderName, $recordData)
255     {
256         $message = new Felamimail_Model_Message();
257         $message->setFromJsonInUsersTimezone($recordData);
258         
259         $result = Felamimail_Controller_Message_Send::getInstance()->saveMessageInFolder($folderName, $message);
260         $result = $this->_recordToJson($result);
261         
262         return $result;
263     }
264     
265     /**
266      * add given flags to given messages
267      *
268      * @param  array        $filterData
269      * @param  string|array $flags
270      * @return array
271      * 
272      * @todo remove legacy code
273      */
274     public function addFlags($filterData, $flags)
275     {
276         // close session to allow other requests
277         Tinebase_Session::writeClose(true);
278         
279         // as long as we get array of ids or filter data from the client, we need to do this legacy handling (1 dimensional -> ids / 2 dimensional -> filter data)
280         if (! empty($filterData) && is_array($filterData[0])) {
281             $filter = new Felamimail_Model_MessageFilter(array());
282             $filter->setFromArrayInUsersTimezone($filterData);
283         } else {
284             $filter = $filterData;
285         }
286         
287         $affectedFolders = Felamimail_Controller_Message_Flags::getInstance()->addFlags($filter, (array) $flags);
288         
289         return array(
290             'status'    => 'success',
291             'result'    => $affectedFolders,
292         );
293     }
294     
295     /**
296      * clear given flags from given messages
297      *
298      * @param array         $filterData
299      * @param string|array  $flags
300      * @return array
301      * 
302      * @todo remove legacy code
303      * @todo return $affectedFolders to client
304      */
305     public function clearFlags($filterData, $flags)
306     {
307         // as long as we get array of ids or filter data from the client, we need to do this legacy handling (1 dimensional -> ids / 2 dimensional -> filter data)
308         if (! empty($filterData) && is_array($filterData[0])) {
309             $filter = new Felamimail_Model_MessageFilter(array());
310             $filter->setFromArrayInUsersTimezone($filterData);
311         } else {
312             $filter = $filterData;
313         }
314         $affectedFolders = Felamimail_Controller_Message_Flags::getInstance()->clearFlags($filter, (array) $flags);
315         
316         return array(
317             'status' => 'success'
318         );
319     }
320     
321     /**
322      * returns message prepared for json transport
323      * - overwriten to convert recipients to array
324      *
325      * @param Tinebase_Record_Interface $_record
326      * @return array record data
327      */
328     protected function _recordToJson($_record)
329     {
330         if ($_record instanceof Felamimail_Model_Message) {
331             foreach (array('to', 'cc', 'bcc') as $type) {
332                 if (! is_array($_record->{$type})) {
333                     if (! empty($_record->{$type})) {
334                         $exploded = explode(',', $_record->{$type});
335                         $_record->{$type} = $exploded;
336                     } else {
337                         $_record->{$type} = array();
338                     }
339                 }
340             }
341             
342             if ($_record->preparedParts instanceof Tinebase_Record_RecordSet) {
343                 foreach ($_record->preparedParts as $preparedPart) {
344                     if ($preparedPart->preparedData instanceof Calendar_Model_iMIP) {
345                         try {
346                             $iMIPFrontend = new Calendar_Frontend_iMIP();
347                             $iMIPFrontend->prepareComponent($preparedPart->preparedData, /* $_throwException = */ true);
348                         } catch (Exception $e) {
349                             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not prepare calendar iMIP component: ' . $e->getMessage());
350                             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString());
351                             $_record->preparedParts->removeRecord($preparedPart);
352                         }
353                     }
354                 }
355             }
356             
357         } else if ($_record instanceof Felamimail_Model_Account) {
358             // add usernames
359             $_record->resolveCredentials();                   // imap
360             $_record->resolveCredentials(TRUE, FALSE, TRUE); // smtp
361             
362         } else if ($_record instanceof Felamimail_Model_Sieve_Vacation) {
363             if (! $_record->mime) {
364                 $_record->reason = Tinebase_Mail::convertFromTextToHTML($_record->reason, 'felamimail-body-blockquote');
365             }
366         }
367         
368         return parent::_recordToJson($_record);
369     }
370     
371     /**
372      * update flags
373      * - use session/writeClose to allow following requests
374      *
375      * @param  string  $folderId id of active folder
376      * @param  integer $time     update time in seconds
377      * @return array
378      */
379     public function updateFlags($folderId, $time)
380     {
381         // close session to allow other requests
382         Tinebase_Session::writeClose(true);
383         
384         $folder = Felamimail_Controller_Cache_Message::getInstance()->updateFlags($folderId, $time);
385         
386         return $this->_recordToJson($folder);
387     }
388     
389     /**
390      * send reading confirmation
391      * 
392      * @param string $messageId
393      * @return array
394      */
395     public function sendReadingConfirmation($messageId)
396     {
397         Felamimail_Controller_Message::getInstance()->sendReadingConfirmation($messageId);
398         
399         return array(
400             'status' => 'success'
401         );
402     }
403     
404     /***************************** accounts funcs *******************************/
405     
406     /**
407      * search accounts
408      * 
409      * @param  array $filter
410      * @return array
411      */
412     public function searchAccounts($filter)
413     {
414         return $results = $this->_search($filter, '', Felamimail_Controller_Account::getInstance(), 'Felamimail_Model_AccountFilter');
415     }
416     
417     /**
418      * get account data
419      *
420      * @param string $id
421      * @return array
422      */
423     public function getAccount($id)
424     {
425         return $this->_get($id, Felamimail_Controller_Account::getInstance());
426     }
427     
428     /**
429      * creates/updates a record
430      *
431      * @param  array $recordData
432      * @return array created/updated record
433      */
434     public function saveAccount($recordData)
435     {
436         return $this->_save($recordData, Felamimail_Controller_Account::getInstance(), 'Account');
437     }
438     
439     /**
440      * deletes existing accounts
441      *
442      * @param  array $ids
443      * @return array
444      */
445     public function deleteAccounts($ids)
446     {
447         return array('status' => $this->_delete($ids, Felamimail_Controller_Account::getInstance()));
448     }
449     
450     /**
451      * change account pwd / username
452      *
453      * @param string $id
454      * @param string $username
455      * @param string $password
456      * @return array
457      */
458     public function changeCredentials($id, $username, $password)
459     {
460         $result = Felamimail_Controller_Account::getInstance()->changeCredentials($id, $username, $password);
461         
462         return array('status' => ($result) ? 'success' : 'failure');
463     }
464     
465     /***************************** sieve funcs *******************************/
466     
467     /**
468      * get sieve vacation for account 
469      *
470      * @param  string $id account id
471      * @return array
472      */
473     public function getVacation($id)
474     {
475         $record = Felamimail_Controller_Sieve::getInstance()->getVacation($id);
476         
477         return $this->_recordToJson($record);
478     }
479
480     /**
481      * set sieve vacation for account 
482      *
483      * @param  array $recordData
484      * @return array
485      */
486     public function saveVacation($recordData)
487     {
488         $record = new Felamimail_Model_Sieve_Vacation(array(), TRUE);
489         $record->setFromJsonInUsersTimezone($recordData);
490         
491         $record = Felamimail_Controller_Sieve::getInstance()->setVacation($record);
492         
493         return $this->_recordToJson($record);
494     }
495     
496     /**
497      * get sieve rules for account 
498      *
499      * @param  string $accountId
500      * @return array
501      */
502     public function getRules($accountId)
503     {
504         $records = Felamimail_Controller_Sieve::getInstance()->getRules($accountId);
505         
506         return array(
507             'results'       => $this->_multipleRecordsToJson($records),
508             'totalcount'    => count($records),
509         );
510     }
511
512     /**
513      * set sieve rules for account 
514      *
515      * @param   array $accountId
516      * @param   array $rulesData
517      * @return  array
518      */
519     public function saveRules($accountId, $rulesData)
520     {
521         $records = new Tinebase_Record_RecordSet('Felamimail_Model_Sieve_Rule', $rulesData);
522         $records = Felamimail_Controller_Sieve::getInstance()->setRules($accountId, $records);
523         
524         return $this->_multipleRecordsToJson($records);
525     }
526
527     /**
528      * get available vacation message templates
529      * 
530      * @return array
531      */
532     public function getVacationMessageTemplates()
533     {
534         return $this->getTemplates(Felamimail_Config::getInstance()->{Felamimail_Config::VACATION_TEMPLATES_CONTAINER_ID});
535     }
536     
537     /**
538      * get vacation message defined by template / do substitutions for dates and representative 
539      * 
540      * @param array $vacationData
541      * @return array
542      */
543     public function getVacationMessage($vacationData)
544     {
545         $record = new Felamimail_Model_Sieve_Vacation(array(), TRUE);
546         $record->setFromJsonInUsersTimezone($vacationData);
547         
548         $message = Felamimail_Controller_Sieve::getInstance()->getVacationMessage($record);
549         $htmlMessage = Tinebase_Mail::convertFromTextToHTML($message, 'felamimail-body-blockquote');
550         
551         return array(
552             'message' => $htmlMessage
553         );
554     }
555     
556     /***************************** other funcs *******************************/
557     
558     /**
559      * Returns registry data of felamimail.
560      * @see Tinebase_Application_Json_Abstract
561      * 
562      * @return mixed array 'variable name' => 'data'
563      * 
564      * @todo get default account data (host, port, ...) from preferences?
565      */
566     public function getRegistryData()
567     {
568         try {
569             $accounts = $this->searchAccounts('');
570         } catch (Exception $e) {
571             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not get accounts: ' . $e->getMessage());
572             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString());
573             $accounts = array(
574                 'results'       => array(),
575                 'totalcount'    => 0,
576             );
577         }
578         
579         $supportedFlags = Felamimail_Controller_Message_Flags::getInstance()->getSupportedFlags();
580         
581         $result = array(
582             'accounts'              => $accounts,
583             'supportedFlags'        => array(
584                 'results'       => $supportedFlags,
585                 'totalcount'    => count($supportedFlags),
586             ),
587         );
588         
589         $result['vacationTemplates'] = $this->getVacationMessageTemplates();
590         
591         return $result;
592     }
593 }