04a5bfe38ad5f2b183c1e7141ebc7a26abd7d4a1
[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         $result = Felamimail_Controller_Cache_Folder::getInstance()->update($accountId, $folderName, TRUE);
127         return $this->_multipleRecordsToJson($result);
128     }
129     
130     /**
131      * get folder status
132      *
133      * @param array  $filterData
134      * @return array of folder status
135      */
136     public function getFolderStatus($filterData)
137     {
138         // close session to allow other requests
139         Tinebase_Session::writeClose(true);
140         
141         $filter = new Felamimail_Model_FolderFilter($filterData);
142         $result = Felamimail_Controller_Cache_Message::getInstance()->getFolderStatus($filter);
143         return $this->_multipleRecordsToJson($result);
144     }
145     
146     /***************************** messages funcs *******************************/
147     
148     /**
149      * search messages in message cache
150      *
151      * @param  array $filter
152      * @param  array $paging
153      * @return array
154      */
155     public function searchMessages($filter, $paging)
156     {
157         $result = $this->_search($filter, $paging, Felamimail_Controller_Message::getInstance(), 'Felamimail_Model_MessageFilter');
158         
159         return $result;
160     }
161     
162     /**
163      * update message cache
164      * - use session/writeClose to update incomplete cache and allow following requests
165      *
166      * @param  string  $folderId id of active folder
167      * @param  integer $time     update time in seconds
168      * @return array
169      */
170     public function updateMessageCache($folderId, $time)
171     {
172         // close session to allow other requests
173         Tinebase_Session::writeClose(true);
174         
175         $folder = Felamimail_Controller_Cache_Message::getInstance()->updateCache($folderId, $time);
176         
177         return $this->_recordToJson($folder);
178     }
179     
180     /**
181      * get message data
182      *
183      * @param  string $id
184      * @return array
185      */
186     public function getMessage($id)
187     {
188         // close session to allow other requests
189         Tinebase_Session::writeClose(true);
190         
191         if (strpos($id, '_') !== false) {
192             list($messageId, $partId) = explode('_', $id);
193         } else {
194             $messageId = $id;
195             $partId    = null;
196         }
197         
198         $message = Felamimail_Controller_Message::getInstance()->getCompleteMessage($messageId, $partId, false);
199         $message->id = $id;
200         
201         return $this->_recordToJson($message);
202     }
203     
204     /**
205      * move messsages to folder
206      *
207      * @param  array $filterData filter data
208      * @param  string $targetFolderId
209      * @return array source folder status
210      */
211     public function moveMessages($filterData, $targetFolderId)
212     {
213         // close session to allow other requests
214         Tinebase_Session::writeClose(true);
215         
216         $filter = new Felamimail_Model_MessageFilter(array());
217         $filter->setFromArrayInUsersTimezone($filterData);
218         $updatedFolders = Felamimail_Controller_Message_Move::getInstance()->moveMessages($filter, $targetFolderId);
219         
220         $result = ($updatedFolders !== NULL) ? $this->_multipleRecordsToJson($updatedFolders) : array();
221         
222         return $result;
223     }
224     
225     /**
226      * save + send message
227      * 
228      * - this function has to be named 'saveMessage' because of the generic edit dialog function names
229      *
230      * @param  array $recordData
231      * @return array
232      */
233     public function saveMessage($recordData)
234     {
235         $message = new Felamimail_Model_Message();
236         $message->setFromJsonInUsersTimezone($recordData);
237         
238         $result = Felamimail_Controller_Message_Send::getInstance()->sendMessage($message);
239         $result = $this->_recordToJson($result);
240         
241         return $result;
242     }
243
244     /**
245      * save message in folder
246      * 
247      * @param  string $folderName
248      * @param  array $recordData
249      * @return array
250      */
251     public function saveMessageInFolder($folderName, $recordData)
252     {
253         $message = new Felamimail_Model_Message();
254         $message->setFromJsonInUsersTimezone($recordData);
255         
256         $result = Felamimail_Controller_Message_Send::getInstance()->saveMessageInFolder($folderName, $message);
257         $result = $this->_recordToJson($result);
258         
259         return $result;
260     }
261     
262     /**
263      * add given flags to given messages
264      *
265      * @param  array        $filterData
266      * @param  string|array $flags
267      * @return array
268      * 
269      * @todo remove legacy code
270      */
271     public function addFlags($filterData, $flags)
272     {
273         // close session to allow other requests
274         Tinebase_Session::writeClose(true);
275         
276         // 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)
277         if (! empty($filterData) && is_array($filterData[0])) {
278             $filter = new Felamimail_Model_MessageFilter(array());
279             $filter->setFromArrayInUsersTimezone($filterData);
280         } else {
281             $filter = $filterData;
282         }
283         
284         $affectedFolders = Felamimail_Controller_Message_Flags::getInstance()->addFlags($filter, (array) $flags);
285         
286         return array(
287             'status'    => 'success',
288             'result'    => $affectedFolders,
289         );
290     }
291     
292     /**
293      * clear given flags from given messages
294      *
295      * @param array         $filterData
296      * @param string|array  $flags
297      * @return array
298      * 
299      * @todo remove legacy code
300      * @todo return $affectedFolders to client
301      */
302     public function clearFlags($filterData, $flags)
303     {
304         // 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)
305         if (! empty($filterData) && is_array($filterData[0])) {
306             $filter = new Felamimail_Model_MessageFilter(array());
307             $filter->setFromArrayInUsersTimezone($filterData);
308         } else {
309             $filter = $filterData;
310         }
311         $affectedFolders = Felamimail_Controller_Message_Flags::getInstance()->clearFlags($filter, (array) $flags);
312         
313         return array(
314             'status' => 'success'
315         );
316     }
317     
318     /**
319      * returns message prepared for json transport
320      * - overwriten to convert recipients to array
321      *
322      * @param Tinebase_Record_Interface $_record
323      * @return array record data
324      */
325     protected function _recordToJson($_record)
326     {
327         if ($_record instanceof Felamimail_Model_Message) {
328             foreach (array('to', 'cc', 'bcc') as $type) {
329                 if (! is_array($_record->{$type})) {
330                     if (! empty($_record->{$type})) {
331                         $exploded = explode(',', $_record->{$type});
332                         $_record->{$type} = $exploded;
333                     } else {
334                         $_record->{$type} = array();
335                     }
336                 }
337             }
338             
339             if ($_record->preparedParts instanceof Tinebase_Record_RecordSet) {
340                 foreach ($_record->preparedParts as $preparedPart) {
341                     if ($preparedPart->preparedData instanceof Calendar_Model_iMIP) {
342                         try {
343                             $iMIPFrontend = new Calendar_Frontend_iMIP();
344                             $iMIPFrontend->prepareComponent($preparedPart->preparedData, /* $_throwException = */ true);
345                         } catch (Exception $e) {
346                             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not prepare calendar iMIP component: ' . $e->getMessage());
347                             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString());
348                             $_record->preparedParts->removeRecord($preparedPart);
349                         }
350                     }
351                 }
352             }
353             
354         } else if ($_record instanceof Felamimail_Model_Account) {
355             // add usernames
356             $_record->resolveCredentials();                   // imap
357             $_record->resolveCredentials(TRUE, FALSE, TRUE); // smtp
358             
359         } else if ($_record instanceof Felamimail_Model_Sieve_Vacation) {
360             if (! $_record->mime) {
361                 $_record->reason = Tinebase_Mail::convertFromTextToHTML($_record->reason, 'felamimail-body-blockquote');
362             }
363         }
364         
365         return parent::_recordToJson($_record);
366     }
367     
368     /**
369      * update flags
370      * - use session/writeClose to allow following requests
371      *
372      * @param  string  $folderId id of active folder
373      * @param  integer $time     update time in seconds
374      * @return array
375      */
376     public function updateFlags($folderId, $time)
377     {
378         // close session to allow other requests
379         Tinebase_Session::writeClose(true);
380         
381         $folder = Felamimail_Controller_Cache_Message::getInstance()->updateFlags($folderId, $time);
382         
383         return $this->_recordToJson($folder);
384     }
385     
386     /**
387      * send reading confirmation
388      * 
389      * @param string $messageId
390      * @return array
391      */
392     public function sendReadingConfirmation($messageId)
393     {
394         Felamimail_Controller_Message::getInstance()->sendReadingConfirmation($messageId);
395         
396         return array(
397             'status' => 'success'
398         );
399     }
400     
401     /***************************** accounts funcs *******************************/
402     
403     /**
404      * search accounts
405      * 
406      * @param  array $filter
407      * @return array
408      */
409     public function searchAccounts($filter)
410     {
411         return $results = $this->_search($filter, '', Felamimail_Controller_Account::getInstance(), 'Felamimail_Model_AccountFilter');
412     }
413     
414     /**
415      * get account data
416      *
417      * @param string $id
418      * @return array
419      */
420     public function getAccount($id)
421     {
422         return $this->_get($id, Felamimail_Controller_Account::getInstance());
423     }
424     
425     /**
426      * creates/updates a record
427      *
428      * @param  array $recordData
429      * @return array created/updated record
430      */
431     public function saveAccount($recordData)
432     {
433         return $this->_save($recordData, Felamimail_Controller_Account::getInstance(), 'Account');
434     }
435     
436     /**
437      * deletes existing accounts
438      *
439      * @param  array $ids
440      * @return array
441      */
442     public function deleteAccounts($ids)
443     {
444         return array('status' => $this->_delete($ids, Felamimail_Controller_Account::getInstance()));
445     }
446     
447     /**
448      * change account pwd / username
449      *
450      * @param string $id
451      * @param string $username
452      * @param string $password
453      * @return array
454      */
455     public function changeCredentials($id, $username, $password)
456     {
457         $result = Felamimail_Controller_Account::getInstance()->changeCredentials($id, $username, $password);
458         
459         return array('status' => ($result) ? 'success' : 'failure');
460     }
461     
462     /***************************** sieve funcs *******************************/
463     
464     /**
465      * get sieve vacation for account 
466      *
467      * @param  string $id account id
468      * @return array
469      */
470     public function getVacation($id)
471     {
472         $record = Felamimail_Controller_Sieve::getInstance()->getVacation($id);
473         
474         return $this->_recordToJson($record);
475     }
476
477     /**
478      * set sieve vacation for account 
479      *
480      * @param  array $recordData
481      * @return array
482      */
483     public function saveVacation($recordData)
484     {
485         $record = new Felamimail_Model_Sieve_Vacation(array(), TRUE);
486         $record->setFromJsonInUsersTimezone($recordData);
487         
488         $record = Felamimail_Controller_Sieve::getInstance()->setVacation($record);
489         
490         return $this->_recordToJson($record);
491     }
492     
493     /**
494      * get sieve rules for account 
495      *
496      * @param  string $accountId
497      * @return array
498      */
499     public function getRules($accountId)
500     {
501         $records = Felamimail_Controller_Sieve::getInstance()->getRules($accountId);
502         
503         return array(
504             'results'       => $this->_multipleRecordsToJson($records),
505             'totalcount'    => count($records),
506         );
507     }
508
509     /**
510      * set sieve rules for account 
511      *
512      * @param   array $accountId
513      * @param   array $rulesData
514      * @return  array
515      */
516     public function saveRules($accountId, $rulesData)
517     {
518         $records = new Tinebase_Record_RecordSet('Felamimail_Model_Sieve_Rule', $rulesData);
519         $records = Felamimail_Controller_Sieve::getInstance()->setRules($accountId, $records);
520         
521         return $this->_multipleRecordsToJson($records);
522     }
523
524     /**
525      * get available vacation message templates
526      * 
527      * @return array
528      */
529     public function getVacationMessageTemplates()
530     {
531         return $this->getTemplates(Felamimail_Config::getInstance()->{Felamimail_Config::VACATION_TEMPLATES_CONTAINER_ID});
532     }
533     
534     /**
535      * get vacation message defined by template / do substitutions for dates and representative 
536      * 
537      * @param array $vacationData
538      * @return array
539      */
540     public function getVacationMessage($vacationData)
541     {
542         $record = new Felamimail_Model_Sieve_Vacation(array(), TRUE);
543         $record->setFromJsonInUsersTimezone($vacationData);
544         
545         $message = Felamimail_Controller_Sieve::getInstance()->getVacationMessage($record);
546         $htmlMessage = Tinebase_Mail::convertFromTextToHTML($message, 'felamimail-body-blockquote');
547         
548         return array(
549             'message' => $htmlMessage
550         );
551     }
552     
553     /***************************** other funcs *******************************/
554     
555     /**
556      * Returns registry data of felamimail.
557      * @see Tinebase_Application_Json_Abstract
558      * 
559      * @return mixed array 'variable name' => 'data'
560      * 
561      * @todo get default account data (host, port, ...) from preferences?
562      */
563     public function getRegistryData()
564     {
565         try {
566             $accounts = $this->searchAccounts('');
567         } catch (Exception $e) {
568             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not get accounts: ' . $e->getMessage());
569             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString());
570             $accounts = array(
571                 'results'       => array(),
572                 'totalcount'    => 0,
573             );
574         }
575         
576         $supportedFlags = Felamimail_Controller_Message_Flags::getInstance()->getSupportedFlags();
577         
578         $result = array(
579             'accounts'              => $accounts,
580             'supportedFlags'        => array(
581                 'results'       => $supportedFlags,
582                 'totalcount'    => count($supportedFlags),
583             ),
584         );
585         
586         $result['vacationTemplates'] = $this->getVacationMessageTemplates();
587         
588         return $result;
589     }
590 }