0011664: Update Expressomail to 0.6 version
authorFlávio Gomes da Silva Lisboa <flavio.lisboa@serpro.gov.br>
Thu, 10 Mar 2016 12:58:29 +0000 (09:58 -0300)
committerPhilipp Schüle <p.schuele@metaways.de>
Wed, 16 Mar 2016 11:18:03 +0000 (12:18 +0100)
- Allow to add customfields into e-mail model
- Fix signed messages with embbeded images
- Fix message preview position
- Fix session handling issues
- Fix token loading process
- Fix adding subfolder in shared folder error
- Fix Delivery Status Notification Message
- Fix IE errors on preferences initialization
- Fix IE reloading after preferences initialization
- Fix loss of embedded images and attachments
- Fix deletion when sending mail from template
- Fix ActiveSync Forward/Reply
- Share just individual folders recursively
- Fix wrong variable name
- Prevent session expired popup
- Fix error message after login
- Improve treatment of session namespace
- Fix reference to contact search combo
- Fix test for maximum table name length
- Keep application disabled by default

Details about changes are into Mantis ticket

Change-Id: Ie8fc212076ad8edc9b9e9e3d37e35320bc6a7e4e
Reviewed-on: https://gerrit.tine20.org/tine20/3291
Tested-by: jenkins user
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
56 files changed:
tests/tine20/Tinebase/ApplicationTest.php
tine20/Expressomail/Backend/Folder.php
tine20/Expressomail/Backend/Imap.php
tine20/Expressomail/Backend/Message.php
tine20/Expressomail/Backend/Scheduler.php [new file with mode: 0644]
tine20/Expressomail/Config.php
tine20/Expressomail/Controller.php
tine20/Expressomail/Controller/Account.php
tine20/Expressomail/Controller/Folder.php
tine20/Expressomail/Controller/Message.php
tine20/Expressomail/Controller/Message/Send.php
tine20/Expressomail/Controller/Scheduler.php [new file with mode: 0644]
tine20/Expressomail/Controller/Sieve.php
tine20/Expressomail/Exception/IMAPCommandFailed.php [new file with mode: 0644]
tine20/Expressomail/Expressomail.jsb2
tine20/Expressomail/Frontend/ActiveSync.php [new file with mode: 0644]
tine20/Expressomail/Frontend/Http.php
tine20/Expressomail/Frontend/Json.php
tine20/Expressomail/Java/ExpressoCertMail-all.jar [new file with mode: 0644]
tine20/Expressomail/Mail.php
tine20/Expressomail/Model/Account.php
tine20/Expressomail/Model/DeliveryStatusNotificationMessagePart.php
tine20/Expressomail/Model/Filter/DateTime.php
tine20/Expressomail/Model/Folder.php
tine20/Expressomail/Model/Message.php
tine20/Expressomail/Model/Scheduler.php [new file with mode: 0644]
tine20/Expressomail/Model/Sieve/Vacation.php
tine20/Expressomail/Protocol/Imap.php
tine20/Expressomail/Session.php
tine20/Expressomail/Setup/Initialize.php
tine20/Expressomail/Setup/Update/Release0.php
tine20/Expressomail/Setup/setup.xml
tine20/Expressomail/Transport.php
tine20/Expressomail/css/Expressomail.css
tine20/Expressomail/js/AccountEditDialog.js
tine20/Expressomail/js/AclsEditDialog.js
tine20/Expressomail/js/AclsGrid.js
tine20/Expressomail/js/AdminPanel.js
tine20/Expressomail/js/ContactGrid.js
tine20/Expressomail/js/Expressomail.js
tine20/Expressomail/js/GridDetailsPanel.js
tine20/Expressomail/js/GridPanel.js
tine20/Expressomail/js/MessageDisplayDialog.js
tine20/Expressomail/js/MessageEditDialog.js
tine20/Expressomail/js/Model.js
tine20/Expressomail/js/TreeContextMenu.js
tine20/Expressomail/js/TreeLoader.js
tine20/Expressomail/js/TreePanel.js
tine20/Expressomail/js/sieve/RuleEditDialog.js
tine20/Expressomail/translations/de.po
tine20/Expressomail/translations/en.po
tine20/Expressomail/translations/es.po
tine20/Expressomail/translations/pt_BR.po
tine20/Expressomail/translations/template.pot
tine20/Tinebase/Helper.php
tine20/Tinebase/Session/Abstract.php

index ce24cd9..ec46257 100644 (file)
@@ -227,7 +227,8 @@ class Tinebase_ApplicationTest extends TestCase
     }
     
     /**
-     * Test length name for table name and column name (Oracle Database limitation) 
+     * Test length name for table name and column name (Oracle Database limitation)
+     * Table name is less than 30 at least since Oracle 7
      * 
      * @see 0007452: use json encoded array for saving of policy settings
      */
@@ -247,7 +248,7 @@ class Tinebase_ApplicationTest extends TestCase
                 foreach ($xml->tables[0] as $tableXML) {
                     $table = Setup_Backend_Schema_Table_Factory::factory('Xml', $tableXML);
                     $currentTable = $table->name;
-                    $this->assertLessThan(29, strlen($currentTable), $applicationName." -> ". $table->name . "  (" . strlen($currentTable).")");
+                    $this->assertLessThan(30, strlen($currentTable), $applicationName." -> ". $table->name . "  (" . strlen($currentTable).")");
                     foreach ($table->fields as $field) {
                         $this->assertLessThan(31, strlen($field->name), $applicationName." -> ". $table->name . "  (" . strlen($field->name).")");
                     }
index 3cc853c..a2fc01e 100644 (file)
  */
 class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
 {
+    /**
+     * Constant for Expressomail Model folder cache id
+     */
+    const EXPRESSOMAIL_MODEL_FOLDER = 'Expressomail_Model_Folder';
+
      private $_accounts = null;
      const IMAPDELIMITER = '/';
      public static $SYSTEM_FOLDERS_DEFAULT = array('Sent', 'Trash', 'Drafts', 'Templates');
@@ -39,6 +44,16 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
         $this->_accounts = $accounts;
     }
 
+
+    /**
+     * Gets a folder cache id
+     * @param integer $folderId
+     */
+    public function getFolderCacheId($folderId)
+    {
+        return Tinebase_Helper::arrayToCacheId(array(self::EXPRESSOMAIL_MODEL_FOLDER, $folderId));
+    }
+
     /*************************** abstract functions ****************************/
     /**
      * Search for records matching given filter
@@ -333,7 +348,7 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
     public function get($_id, $_useCache = TRUE)
     {
         $cache = Tinebase_Core::getCache();
-        $cacheKey = 'Expressomail_Model_Folder_'.$_id;
+        $cacheKey = $this->getFolderCacheId($_id);
         $folderFromCache = $_useCache ? $cache->load($cacheKey) : FALSE;
         if ($folderFromCache) {
             return $folderFromCache;
@@ -342,9 +357,12 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
         $folderDecoded = self::decodeFolderUid($_id);
         if (isset($folderDecoded['accountId'])){
             $imap = Expressomail_Backend_ImapFactory::factory($folderDecoded['accountId'],TRUE);
+            $account = Expressomail_Controller_Account::getInstance()->get($folderDecoded['accountId']);
+            $ns_other = preg_replace('/\/$/', '', $account->ns_other);
+            $delimiter = $account->delimiter;
             $folder = $imap->getFolders('',$folderDecoded['globalName'],
             $this->_accounts[$folderDecoded['accountId']]);
-            //$status = $imap->examineFolder($folderDecoded['globalName']);
+            $acls = $imap->getFolderAcls($folderDecoded['globalName'], TRUE);
             $status = $imap->getFolderStatus($folderDecoded['globalName']);
             if($status === FALSE){
                 // we can not access folder, create Model as unselectable
@@ -371,8 +389,9 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
                     'cache_job_startuid' => 0,
                     'cache_job_actions_est' => 0,
                     'cache_job_actions_done' => 0
-                ),true); 
+                ),true);
 
+                $newFolder->setSharingValues($acls);
                 $cache->save($newFolder, $cacheKey);
                 return $newFolder;
             }
@@ -418,7 +437,13 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
                     }
             }
 
-            $expressomailSession = Expressomail_Session::getSessionNamespace();
+            try {
+                $expressomailSession = Expressomail_Session::getSessionNamespace();
+            } catch (Zend_Session_Exception $zse) {
+                Tinebase_Core::getLogger()->warn(__METHOD__ . "::" . __LINE__ .
+                        ":: It was not possible to get Expressomail Session Namespace");
+                $expressomailSession = null;
+            }
             $userNameSpace = $imap->getUserNameSpace() . self::IMAPDELIMITER;
             $arrDecodedFolder = explode(self::IMAPDELIMITER, $folderDecoded['globalName']);
             if (
@@ -438,7 +463,9 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
                             . ' Getting quota from IMAP for ' . $folderDecoded['globalName']);
                 }
                 $quota = $imap->getQuota($folderDecoded['globalName']);
-                $expressomailSession->quota[$folderDecoded['globalName']] = $quota;
+                if ($expressomailSession instanceof Zend_Session_Namespace && Tinebase_Session::isWritable()) {
+                    $expressomailSession->quota[$folderDecoded['globalName']] = $quota;
+                }
             }else {
                 if($arrDecodedFolder[0] === 'INBOX' && isset($arrDecodedFolder[1]) && $arrDecodedFolder[1] === 'Arquivo Remoto'){
                     $globalNameFolder = $arrDecodedFolder[0] . self::IMAPDELIMITER . $arrDecodedFolder[1];
@@ -453,7 +480,13 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
                             . ' Getting quota from Session for ' . $folderDecoded['globalName']);
                 }
-                $quota = isset($expressomailSession->quota[$globalNameFolder]) ? $expressomailSession->quota[$globalNameFolder] : 0;
+
+                $quota = 0;
+                if(($expressomailSession instanceof Zend_Session_Namespace)
+                        && isset($expressomailSession->quota)
+                        && isset($expressomailSession->quota[$globalNameFolder])) {
+                    $quota = $expressomailSession->quota[$globalNameFolder];
+                }
             }
 
             $return = new Expressomail_Model_Folder(array(
@@ -483,8 +516,9 @@ class Expressomail_Backend_Folder //extends Tinebase_Backend_Sql_Abstract
                     'quota_limit'   => !empty($quota) ? $quota['STORAGE']['limit'] : 0,
                 ),true);
 
-             $cache->save($return, $cacheKey);
-             return $return;
+            $return->setSharingValues($acls);
+            $cache->save($return, $cacheKey);
+            return $return;
         }
     }
     
index cc0350f..3f0d604 100644 (file)
@@ -1197,12 +1197,13 @@ class Expressomail_Backend_Imap extends Zend_Mail_Storage_Imap
      * get folder Acls
      *
      * @param  Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
+     * @param  bool $returnOwnerACL true if it will return owner's ACL
      * @return array with folder values
      */
-    public function getFolderAcls($_globalName)
+    public function getFolderAcls($_globalName, $returnOwnerACL = FALSE)
     {
         $this->_currentFolder = $_globalName;
-        $result = $this->_protocol->getFolderAcls($this->_currentFolder);
+        $result = $this->_protocol->getFolderAcls($this->_currentFolder, $returnOwnerACL);
         return $result;
     }
 
@@ -1254,4 +1255,64 @@ class Expressomail_Backend_Imap extends Zend_Mail_Storage_Imap
     {
         return $this->_userNameSpace;
     }
+
+    /**
+     * Set shared seen value to imap
+     *
+     * @param string $value
+     * @return boolean return operation's success status
+     */
+    public function setSharedSeen($value)
+    {
+        $stringValue = $value ? '"true"' : '"false"';
+        $annotation[] = '"INBOX"';
+        $annotation[] = '"/vendor/cmu/cyrus-imapd/sharedseen"';
+        $annotation[] = '("value.shared" ' . $stringValue . ')';
+
+        return $this->_protocol->requestAndResponse('SETANNOTATION', $annotation);
+    }
+
+    /**
+     * Get Shared seen value
+     *
+     * @return boolean shared seen value
+     */
+    public function getSharedSeen()
+    {
+        $annotation[] = '"INBOX"';
+        $annotation[] = '"/vendor/cmu/cyrus-imapd/sharedseen"';
+        $annotation[] = '"value.shared"';
+        $result = $this->_protocol->requestAndResponse('GETANNOTATION', $annotation);
+
+        if (is_array($result) && isset($result[0][3][1])) {
+            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
+                . ' Shared Seen value from Imap ' . $result[0][3][1]);
+            return strtolower($result[0][3][1]) === 'true' ? TRUE : FALSE;
+        } else {
+            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__
+                . ' Imap command failed when getting sharedseen value!');
+            return FALSE;
+        }
+    }
+
+    /**
+     * Getting cyrus  murder backend hostname
+     *
+     * @return mixed
+     */
+    public function getCyrusMurderBackend()
+    {
+        $annotation[] = '"INBOX"';
+        $annotation[] = '"/vendor/cmu/cyrus-imapd/server"';
+        $annotation[] = '"value.shared"';
+
+        $result = $this->_protocol->requestAndResponse('GETANNOTATION', $annotation);
+        if (is_array($result) && isset($result[0][3][1])) {
+            return $result[0][3][1];
+        } else {
+            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__
+                . ' Imap command failed when getting cyrus murder backend hostname!');
+            return FALSE;
+        }
+    }
 }
index 8bb3af2..7a8f823 100644 (file)
@@ -254,7 +254,7 @@ class Expressomail_Backend_Message //extends Tinebase_Backend_Sql_Abstract
                         }
                         break;
                     case 'received' :  // => array('filter' => 'Tinebase_Model_Filter_DateTime'),
-                        if (!empty($value))
+                        if (!empty($value) && $filter instanceof Expressomail_Model_Filter_DateTime)
                         {
                             $return[] = $filter->getFilterImap();
                         }
diff --git a/tine20/Expressomail/Backend/Scheduler.php b/tine20/Expressomail/Backend/Scheduler.php
new file mode 100644 (file)
index 0000000..86ee828
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Expressomail
+ * @subpackage  Backend
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Fernando Alberto Reuter Wendt <fernando-alberto.wendt@serpro.gov.br>
+ * @copyright   Copyright (c) 2009-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+                Copyright (c) 2015 SERPRO GmbH (https://www.serpro.gov.br)
+ *
+ */
+
+/**
+ * sql backend class for Expressomail Scheduler
+ *
+ * @package     Expressomail
+ */
+class Expressomail_Backend_Scheduler extends Tinebase_Backend_Sql_Abstract
+{
+    /**
+     * Table name without prefix
+     *
+     * @var string
+     */
+    protected $_tableName = 'expressomail_backup_scheduler';
+
+    /**
+     * Model name
+     *
+     * @var string
+     */
+    protected $_modelName = 'Expressomail_Model_Scheduler';
+
+    /**
+     * if modlog is active, we add 'is_deleted = 0' to select object in _getSelect()
+     *
+     * @var boolean
+     */
+    protected $_modlogActive = TRUE;
+
+   /**
+    * default column(s) for count
+    *
+    * @var string
+    */
+    protected $_defaultCountCol = 'account_id';
+
+    /**
+     * foreign tables (key => tablename)
+     *
+     * @var array
+     */
+    protected $_foreignTables = array(
+        'contact_id_contacts'    => array(
+            'table'         => 'accounts',
+            'field'         => 'account_id',
+            'joinOn'        => 'id',
+            'singleValue'   => TRUE,
+            'preserve'      => TRUE,
+        ),
+    );
+
+    /**
+     * (non-PHPdoc)
+     * @see Tinebase_Backend_Sql_Abstract::__construct()
+     */
+    public function __construct($_dbAdapter = NULL, $_options = array())
+    {
+        parent::__construct($_dbAdapter, $_options);
+    }
+
+    /**
+     * Creates new entry
+     *
+     * @param   Tinebase_Record_Interface $_record
+     * @return  Tinebase_Record_Interface
+     * @throws  Tinebase_Exception_Database
+     * @throws  Tinebase_Exception
+     */
+    public function create(Tinebase_Record_Interface $_record)
+    {
+        try{
+            $newEntry = parent::create($_record);
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . 'Successfully added new schedule task on database system.');
+            return $newEntry;
+        } catch (Tinebase_Exception_Backend_Database $ex){
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . 'Database insertion fails at backend unit: ' . print_r($ex, true));
+            return $ex->getMessage();
+        }
+    }
+
+    /**
+     * Find entry
+     *
+     * @param   array $fetchArray
+     * @return  integer
+     * @throws  Tinebase_Exception_Database
+     */
+    public function findOne($fetchArray)
+    {
+        try{
+            $select = "SELECT status FROM " . SQL_TABLE_PREFIX . $this->_tableName 
+                    . " WHERE "
+                    . "account_id='" . $fetchArray[0] . "' AND "
+                    . "folder='" . $fetchArray[1] . "' AND "
+                    . "status='" . $fetchArray[2] . "' AND "
+                    . "priority=" . $fetchArray[3] . " AND "
+                    . "is_deleted=0;";
+            $stmt = $this->_db->fetchRow($select);
+            return ($stmt ? count($stmt) : 0);
+        } catch (Tinebase_Exception_Backend_Database $edb){
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . 'Database insertion fails at backend unit: ' . print_r($edb, true));
+            return $edb->getMessage();
+        }
+    }
+}
\ No newline at end of file
index 0502348..4c91633 100644 (file)
@@ -64,6 +64,13 @@ class Expressomail_Config extends Tinebase_Config_Abstract
     const MAX_CONTACT_ADD_TO_UNKNOWN = 'maxContactAddToUnknown';
 
     /**
+     * Activate users to export mail dir compressed data
+     *
+     * @var boolean
+     */
+    const ENABLEMAILDIREXPORT = 'enableMailDirExport';
+
+    /**
      * (non-PHPdoc)
      * @see tine20/Tinebase/Config/Definition::$_properties
      */
@@ -124,6 +131,15 @@ class Expressomail_Config extends Tinebase_Config_Abstract
             'setBySetupModule'      => TRUE,
             'default'               => 10,
         ),
+        self::ENABLEMAILDIREXPORT => array(
+            'label'                 => 'Enable mail folders for exportation',
+            'description'           => 'Enable mail folders for exportation (compressed)',
+            'type'                  => Tinebase_Config_Abstract::TYPE_BOOL,
+            'clientRegistryInclude' => TRUE,
+            'setByAdminModule'      => TRUE,
+            'setBySetupModule'      => FALSE,
+            'default'               => FALSE,
+        ),
     );
     
     /**
@@ -183,8 +199,8 @@ class Expressomail_Config extends Tinebase_Config_Abstract
      */
     public function clearCache($appFilter = null)
     {
-       parent::clearCache();
-           $cache = Tinebase_Core::getCache();
-           $cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array(Expressomail_Config::EXPRESSOMAIL_SETTINGS));
+        parent::clearCache();
+        $cache = Tinebase_Core::getCache();
+        $cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array(Expressomail_Config::EXPRESSOMAIL_SETTINGS));
     }
 }
index dab1c18..8763b71 100644 (file)
@@ -36,6 +36,7 @@ class Expressomail_Controller extends Tinebase_Controller_Event
             Expressomail_Config::IMAPSEARCHMAXRESULTS => 1000,
             Expressomail_Config::AUTOSAVEDRAFTSINTERVAL => 15,
             Expressomail_Config::REPORTPHISHINGEMAIL => '',
+            Expressomail_Config::ENABLEMAILDIREXPORT => FALSE,
         );
     }
     
index 2224f77..9fccfe3 100644 (file)
 class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstract
 {
     /**
+     * Contant for Expressomail Controller account search cache key
+     */
+    const EXPRESSOMAILCONTROLLERACCOUNTSEARCH = 'Expressomail_Controller_Account_search';
+
+    /**
      * application name (is needed in checkRight())
      *
      * @var string
@@ -68,6 +73,7 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
         $this->_doContainerACLChecks = FALSE;
         $this->_doRightChecks = TRUE;
         $this->_purgeRecords = FALSE;
+        $this->_resolveCustomFields = TRUE;
 
         $this->_backend = new Expressomail_Backend_Account();
 
@@ -97,6 +103,8 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
         return self::$_instance;
     }
 
+
+
     /**
      * get list of records
      *
@@ -113,8 +121,7 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
             $_filter = new Expressomail_Model_AccountFilter(array());
         }
 
-        $params = array('Expressomail_Controller_Account_search', Tinebase_Core::getUser()->accountId,  $_filter->toArray());
-        $cacheId = Tinebase_Helper::arrayHash($params);
+        $cacheId = $this->_createExpressomailControllerAccountSearchCacheId($_filter);
         $cache = Tinebase_Core::getCache();
         if ($cache->test($cacheId)) {
             $result = $cache->load($cacheId);
@@ -136,6 +143,9 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
             if (! $systemAccountFound) {
                 $this->_addSystemAccount($result);
             }
+            if ($this->resolveCustomfields()) {
+                Tinebase_CustomField::getInstance()->resolveMultipleCustomfields($result);
+            }
         }
 
         $cache->save($result, $cacheId);
@@ -162,6 +172,28 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
     }
 
     /**
+     * Create a Expressomail Controller account search cache id
+     *
+     * @param mixed $_filter
+     * @return string
+     */
+    protected function _createExpressomailControllerAccountSearchCacheId($_filter)
+    {
+        return Tinebase_Helper::arrayToCacheId(array(self::EXPRESSOMAILCONTROLLERACCOUNTSEARCH, Tinebase_Core::getUser()->accountId, $_filter->toArray()));
+    }
+
+    /**
+     * Create Expressomail_Model_Account cache id
+     *
+     * @param string Expressomail Model Account id
+     * @return string cache id
+     */
+    protected function _createExpressomailModelAccountCacheId($_id)
+    {
+        return Tinebase_Helper::arrayToCacheId(array(Tinebase_Core::getUser()->accountId, $_id));
+    }
+
+    /**
      * get by id
      *
      * @param string $_id
@@ -172,7 +204,7 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
     {
         Tinebase_Core::setupCache();
         $cache = Tinebase_Core::getCache();
-        $cacheId = Tinebase_Helper::arrayHash(array(Tinebase_Core::getUser()->accountId,$_id));
+        $cacheId = $this->_createExpressomailModelAccountCacheId($_id);
         $record = $cache->load($cacheId);
         if ($record === FALSE){
             $record = parent::get($_id, $_containerId);
@@ -183,7 +215,16 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
             if ($record->type == Expressomail_Model_Account::TYPE_SYSTEM) {
                 $this->_addSystemAccountConfigValues($record);
             }
-            
+
+            if ($this->_checkSharedSeenSupport($record)) {
+                $record->shared_seen_support = TRUE;
+                $record->shared_seen = $this->_getSharedSeenValue($record);
+            }
+
+            if ($this->_resolveCustomFields && $record->has('customfields')) {
+               Tinebase_CustomField::getInstance()->resolveRecordCustomFields($record);
+            }
+
             $cache->save($record, $cacheId, array('expressomailAccount'));
         }
 
@@ -378,12 +419,16 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
             Tinebase_Core::getCache()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('getMessageBody'));
         }
 
-        $expressomailSession = Expressomail_Session::getSessionNamespace();        
-        // reset capabilities if imap host / port changed
-        if (isset($expressomailSession->account) && (array_key_exists('host', $diff) || array_key_exists('port', $diff))) {
-            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
-                . ' Resetting capabilities for account ' . $_record->name);
-            unset($expressomailSession->account[$_record->getId()]);
+        try {
+            $expressomailSession = Expressomail_Session::getSessionNamespace();
+            // reset capabilities if imap host / port changed
+            if (isset($expressomailSession->account) && (array_key_exists('host', $diff) || array_key_exists('port', $diff))) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
+                    . ' Resetting capabilities for account ' . $_record->name);
+                unset($expressomailSession->account[$_record->getId()]);
+            }
+        } catch (Zend_Session_Exception $zse) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . "::" . __LINE__ . ":: It was not possible to get Expressomail Session Namespace");
         }
     }
 
@@ -398,7 +443,7 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
     {
         // get old credentials
         $credentialsBackend = Tinebase_Auth_CredentialCache::getInstance();
-        $userCredentialCache = Tinebase_Core::get(Tinebase_Core::USERCREDENTIALCACHE);
+        $userCredentialCache = Tinebase_Core::getUserCredentialCache();
 
         if ($userCredentialCache !== NULL) {
             $credentialsBackend->getCachedCredentials($userCredentialCache);
@@ -546,12 +591,17 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
      */
     public function updateCapabilities(Expressomail_Model_Account $_account, Expressomail_Backend_ImapProxy $_imapBackend = NULL)
     {
-        $expressomailSession = Expressomail_Session::getSessionNamespace();
-        if (isset($expressomailSession->account) &&
-                is_array($expressomailSession->account) && 
-                array_key_exists($_account->getId(), $expressomailSession->account)) {
-            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Getting capabilities of account ' . $_account->name . ' from SESSION.');
-            return $expressomailSession->account[$_account->getId()];
+        try {
+            $expressomailSession = Expressomail_Session::getSessionNamespace();
+            if (isset($expressomailSession->account) &&
+                    is_array($expressomailSession->account) &&
+                    array_key_exists($_account->getId(), $expressomailSession->account)) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Getting capabilities of account ' . $_account->name . ' from SESSION.');
+                return $expressomailSession->account[$_account->getId()];
+            }
+        } catch (Zend_Session_Exception $zse) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . "::" . __LINE__ .
+                    ":: It was not possible to get Expressomail Session Namespace");
         }
 
         $imapBackend = ($_imapBackend !== NULL) ? $_imapBackend : $this->_getIMAPBackend($_account, TRUE);
@@ -915,7 +965,7 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
         }
 
         if (Tinebase_Core::isRegistered(Tinebase_Core::USERCREDENTIALCACHE)) {
-            $userCredentialCache = Tinebase_Core::get(Tinebase_Core::USERCREDENTIALCACHE);
+            $userCredentialCache = Tinebase_Core::getUserCredentialCache();
             Tinebase_Auth_CredentialCache::getInstance()->getCachedCredentials($userCredentialCache);
         } else {
             Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__
@@ -1038,11 +1088,115 @@ class Expressomail_Controller_Account extends Tinebase_Controller_Record_Abstrac
     {
        Tinebase_Core::setupCache();
        $cache = Tinebase_Core::getCache();
-        $cacheId = Tinebase_Core::createCacheId(array(Tinebase_Core::getUser()->accountId,$_account->getId()));
+        $cacheId = $this->_createExpressomailModelAccountCacheId($_account->getId());
         $_filter = new Expressomail_Model_AccountFilter(array());
         //Cleans cache generate in user login, when the method seach is called with a empty filter.
-        $cacheSearch = Tinebase_Core::createCacheId(array('Expressomail_Controller_Account_search', Tinebase_Core::getUser()->accountId,  $_filter->toArray()));
+        $cacheSearch = $this->_createExpressomailControllerAccountSearchCacheId($_filter);
        $cache->remove($cacheId);
         $cache->remove($cacheSearch);
     }
+
+    /**
+     * Get cyrus murder backend hostname
+     *
+     * @param Expressomail_Model_Account $_record Account model
+     * @return mixed backend's hostaname or FALSE if not found
+     */
+    protected function _getCyrusMurderBackend(Expressomail_Model_Account $_record)
+    {
+        $imapBackend = $this->_getIMAPBackend($_record, TRUE);
+        return $imapBackend->getCyrusMurderBackend();
+    }
+
+    /**
+     * Get shared seen value
+     *
+     * @param Expressomail_Model_Account $_record
+     * @return boolean shared seen value
+     */
+    protected function _getSharedSeenValue(Expressomail_Model_Account $_record)
+    {
+        $imapBackend = $this->_getIMAPBackend($_record, TRUE);
+        return $imapBackend->getSharedSeen();
+    }
+
+    /**
+     * Set shared seen value
+     *
+     * @param Expressomail_Model_Account $_record Account model
+     * @param string $_value Shared seen value
+     * @return boolean return operation's success status
+     */
+    protected function _setSharedSeenValue(Expressomail_Model_Account $_record, $_value)
+    {
+        $imapConfig = $_record->getImapConfig();
+        $backendHostname = trim($this->_getCyrusMurderBackend($_record));
+
+        if (empty($backendHostname) || $imapConfig['host'] === $backendHostname) {
+            // Problaby we don't have load balancing/partitioning on Cyrus' infrastructure
+            $imapBackend = $this->_getIMAPBackend($_record, TRUE);
+        } else {
+            $imapConfig['host'] = $backendHostname;
+            $imapBackend = new Expressomail_Backend_Imap((object) $imapConfig);
+        }
+
+        return $imapBackend->setSharedSeen($_value);
+    }
+
+    /**
+     * Checks if imapd is cyrus and if it supports ANNOTATEMORE extension
+     *
+     * @param Expressomail_Model_Account $_record Account Model
+     * @return boolean true if imapd supports ANNOTATEMORE extension
+     */
+    protected function _checkSharedSeenSupport(Expressomail_Model_Account $_record)
+    {
+        // TODO: check cyrus imapd version
+        // ANNOTATEMORE extension is a draft that originated the METADATA extension RFC5464, maybe we
+        // should be using the later.
+        $imapConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::IMAP, new Tinebase_Config_Struct());
+        if (Tinebase_EmailUser::IMAP_CYRUS === ucfirst(strtolower($imapConfig->backend))
+            && $_record->hasCapability('ANNOTATEMORE')
+        ){
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    /**
+     * update one record
+     *
+     * @param   Tinebase_Record_Interface $_record
+     * @param   boolean $_duplicateCheck
+     * @return  Tinebase_Record_Interface
+     * @throws  Tinebase_Exception_AccessDenied
+     *
+     */
+    public function update(Tinebase_Record_Interface $_record, $_duplicateCheck = TRUE)
+    {
+        $sharedSeenValue = $_record->shared_seen;
+
+        $updatedRecord = parent::update($_record, $_duplicateCheck);
+        if ($this->_checkSharedSeenSupport($_record)) {
+            $updatedRecord->shared_seen_support = TRUE;
+            if ($this->_setSharedSeenValue($_record, $sharedSeenValue)) {
+                $updatedRecord->shared_seen = $sharedSeenValue;
+            } else {
+                Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__
+                    . ' Imap command failed when setting sharedseen value!');
+                $translate = Tinebase_Translation::getTranslation('Expressomail');
+                $message = $translate->_('Imap command failed when setting sharedseen value!');
+                throw new Expressomail_Exception_IMAPCommandFailed($message);
+            }
+        }
+
+        Tinebase_Core::setupCache();
+        $cache = Tinebase_Core::getCache();
+        $cache->save($updatedRecord,
+            $this->_createExpressomailModelAccountCacheId($updatedRecord->id),
+            array('expressomailAccount')
+        );
+
+        return $updatedRecord;
+    }
 }
index d2a00ed..f056b14 100644 (file)
@@ -480,7 +480,7 @@ class Expressomail_Controller_Folder extends Tinebase_Controller_Abstract implem
 
         if ($folder) {
             $cache = Tinebase_Core::getCache();
-            $cacheKey = 'Expressomail_Model_Folder_'.$folder->id;
+            $cacheKey = $this->_backend->getFolderCacheId($folder->id);
             $cache->remove($cacheKey);
         }
 
@@ -695,7 +695,7 @@ class Expressomail_Controller_Folder extends Tinebase_Controller_Abstract implem
 
         if ($folder) {
             $cache = Tinebase_Core::getCache();
-            $cacheKey = 'Expressomail_Model_Folder_'.$folder->id;
+            $cacheKey = $this->_backend->getFolderCacheId($folder->id);
             $cache->remove($cacheKey);
         }
 
@@ -952,10 +952,10 @@ class Expressomail_Controller_Folder extends Tinebase_Controller_Abstract implem
         }
         $result = new Tinebase_Record_RecordSet('Expressomail_Model_Folder');
         foreach ($ids as $folder) {
-            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .  ' Checking folder ' . $folder->globalname);
-
             $folder = $this->getIMAPFolderCounter($folder);
 
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .  ' Checking folder ' . $folder->globalname);
+
             // we don't have cache, checking only recent messages
             if ($folder->cache_recentcount > 0) {
                 $result->addRecord($folder);
index 3c41cb7..3bd835d 100644 (file)
@@ -1540,93 +1540,6 @@ class Expressomail_Controller_Message extends Tinebase_Controller_Record_Abstrac
     }
 
     /**
-     *
-     * @param array $source
-     * @param resource | string $inputStream
-     * @param string $flag
-     * @throws Zend_Mail_Protocol_Exception
-     */
-    public function parseAndSendMessage($source, $inputStream, $flag=NULL)
-    {
-        $originalMessage = $this->getCompleteMessage($source['itemId'], null, false);
-
-        $user = Tinebase_Core::getUser();
-
-        if (! is_resource($inputStream)) {
-            $stream = fopen("php://temp", 'r+');
-            fwrite($stream, $inputStream);
-            $inputStream = $stream;
-            rewind($inputStream);
-        }
-        $incomingMessage = new Zend_Mail_Message(
-                array(
-                        'file' => $inputStream
-                )
-        );
-
-        $headers = $incomingMessage->getHeaders();
-
-        $body = ($headers['content-transfer-encoding'] == 'base64')
-        ? base64_decode($incomingMessage->getContent())
-        : $incomingMessage->getContent();
-        $isTextPlain = strpos($headers['content-type'],'text/plain');
-        $bodyLines = preg_split('/\r\n|\r|\n/', $body);
-        $body = '';
-        if ($isTextPlain !== false) {
-            foreach ($bodyLines as &$line) {
-                $body .= htmlentities($line) . '<br>';
-            }
-        } else {
-            foreach ($bodyLines as &$line) {
-                $body .= $line . '<br>';
-            }
-        }
-        $body = '<div>'.$body.'</div>';
-
-        $bodyOrigin = $originalMessage['body'];
-        preg_match("/<body[^>]*>(.*?)<\/body>/is", $bodyOrigin, $matches);
-        $bodyOrigin = (count($matches)>1) ? $matches[1] : $bodyOrigin;
-        $body .= '<div>'.$bodyOrigin.'</div>';
-
-        $attachments = array();
-        foreach ($originalMessage['attachments'] as &$att) {
-            try {
-                $att['name'] = $att['filename'];
-                $att['type'] = $att['content-type'];
-            } catch (Exception $e) {}
-            array_push($attachments, $att);
-        }
-
-        $recordData = array();
-        $recordData['note'] = '';
-        $recordData['content_type'] = 'text/html';
-        $recordData['account_id'] = $originalMessage->account_id;
-        $recordData['to'] = is_array($headers['to']) ? $headers['to'] : array($headers['to']);
-        $recordData['cc'] = array();
-        $recordData['bcc'] = array();
-        $recordData['subject'] = $headers['subject'];
-        $recordData['body'] = $body;
-        //$recordData['flags'] = array_merge($incomingMessage->getFlags(), $originalMessage['flags']);
-        $recordData['flags'] = ($flag != NULL) ? $flag : '';
-        $recordData['original_id'] = $source['itemId'];
-        $recordData['embedded_images'] = array();
-        $recordData['attachments'] = $attachments;
-        $recordData['from_email'] = $user->accountEmailAddress;
-        $recordData['from_name'] = $user->accountFullName;
-        $recordData['customfields'] = array();
-
-        $message = new Expressomail_Model_Message();
-        $message->setFromJsonInUsersTimezone($recordData);
-
-        try {
-            Expressomail_Controller_Message_Send::getInstance()->sendMessage($message);
-        } catch (Zend_Mail_Protocol_Exception $zmpe) {
-            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not send message: ' . $zmpe->getMessage());
-            throw $zmpe;
-        }
-    }
-
-    /**
      * parse phishing notification
      *
      * @param Object $message
@@ -1691,7 +1604,7 @@ class Expressomail_Controller_Message extends Tinebase_Controller_Record_Abstrac
     private function getFormattedGmtDateTime()
     {
         // calculate timezone in "GMT-HH:MM" format
-        $dtz = new DateTimeZone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
+        $dtz = new DateTimeZone(Tinebase_Core::getUserTimezone());
         $time = new DateTime('now', $dtz);
         $offset = $dtz->getOffset( $time );
         $sign = ($offset < 0 ) ? "-" : "+";
index 1e559a2..f42e5a8 100644 (file)
@@ -744,9 +744,18 @@ class Expressomail_Controller_Message_Send extends Expressomail_Controller_Messa
             : Tinebase_Core::getUser()->accountFullName;
 
         isset($_message->from_name)?$from = $_message->from_name:$from = $from;
-
+        $user = Tinebase_Core::getUser();
+        try {
+            $allowedEmails = Expressomail_Session::getSessionNamespace()->allowedEmails[$user->accountId];
+        } catch (Zend_Session_Exception $zse) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . "::" . __LINE__ .":: It was not possible to get Expressomail Session Namespace");
+            $allowedEmails = array($user->accountEmailAddress);
+        }
         $email = ($_message !== NULL && ! empty($_message->from_email)) ? $_message->from_email : $_account->email;
-
+        if (array_search($email, $allowedEmails) === FALSE) {
+            throw new Tinebase_Exception_Record_NotAllowed('You Can\'t send a email with this FROM address: '.$email);
+            Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . 'User with id: ' .$user->accountId. 'tried to send email with address not allowed:  ' . $email);
+        }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Set from for mail: ' . $email . ' / ' . $from);
 
         $_mail->setFrom($email, $from);
diff --git a/tine20/Expressomail/Controller/Scheduler.php b/tine20/Expressomail/Controller/Scheduler.php
new file mode 100644 (file)
index 0000000..679b971
--- /dev/null
@@ -0,0 +1,242 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Expressomail
+ * @subpackage  Controller
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Fernando Alberto Reuter Wendt <fernando-alberto.wendt@serpro.gov.br>
+ * @copyright   Copyright (c) 2015 SERPRO GmbH (https://www.serpro.gov.br)
+ */
+
+/**
+ * Scheduler controller for Expressomail
+ *
+ * @package     Expressomail
+ * @subpackage  Controller
+ */
+class Expressomail_Controller_Scheduler extends Tinebase_Controller_Record_Abstract
+{
+    /**
+     * application name (is needed in checkRight())
+     *
+     * @var string
+     */
+    protected $_applicationName = 'Expressomail';
+
+    /**
+     * holds the instance of the singleton
+     *
+     * @var Expressomail_Controller_Scheduler
+     */
+    private static $_instance = NULL;
+
+    /**
+     * @var Expressomail_Backend_Scheduler
+     */
+    protected $_backend;
+
+    /**
+     * default status for new record entry
+     */
+    private $_defaultStatus = 'PENDING';
+
+    /**
+     * default priority for new record entry
+     */
+    private $_defaultPriority = 5;
+
+    /**
+     * shared folder global name base identifier
+     */
+    private $_sharedFolderPattern = 'user/';
+
+    /**
+     * the constructor
+     *
+     * don't use the constructor. use the singleton
+     */
+    private function __construct()
+    {
+        $this->_backend = new Expressomail_Backend_Scheduler();
+    }
+
+    /**
+     * don't clone. Use the singleton.
+     *
+     */
+    private function __clone()
+    {
+    }
+
+    /*
+     * abstracted method
+     */
+    public static function getInstance()
+    {
+        if (self::$_instance === NULL) {
+            self::$_instance = new Expressomail_Controller_Scheduler();
+        }
+
+        return self::$_instance;
+    }
+
+    /**
+    * Add new scheduled entry
+    *
+    * @param   string $folder
+    * @return  Tinebase_Record
+    * @throws  Tinebase_Exception_Database
+    * @throws  Tinebase_Exception
+    */
+    public function addNewScheduler($folder)
+    {
+        try{
+            $usrAccount = $this->_inspectAccountBeforeSchedule();
+            $usrMaildir = $this->_inspectFolderBeforeSchedule($usrAccount, $folder);
+
+            if((!$usrAccount) || (is_null($usrMaildir))){
+                throw new Tinebase_Exception("There are account inconsistences at your request, and it will not be scheduled.");
+            }
+
+            $newArrayData = array(
+                'account_id'     => $usrAccount,
+                'folder'         => $usrMaildir,
+                'scheduler_time' => Tinebase_DateTime::now(),
+                'status'         => $this->_defaultStatus,
+                'priority'       => $this->_defaultPriority
+            );
+
+            $newSchedule = new Expressomail_Model_Scheduler($newArrayData);
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' - The new mail dir export scheduler is ' . print_r($newSchedule, true));
+
+            $alreadyExists = $this->_ifExists($newArrayData);
+
+            if(!$alreadyExists){
+                $result = $this->_backend->create($newSchedule);
+                return $result;
+            } else{
+                throw new Tinebase_Exception("Your request for selected mail folder already exists! You must wait for your pendding request to be processed first.");
+            }
+
+        } catch (Tinebase_Exception_Backend_Database $ex) {
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . 'Failed to schedule a new mail dir export entry at database.' . print_r($ex, true));
+            $result = array('status' => 'failure', 'success' => 'false', 'msg' => $ex->getMessage());
+            return $result;
+        }
+    }
+
+    /**
+    * Check registry on database
+    *
+    * @param   array   $arrayData
+    * @return  boolean
+    * @throws  Tinebase_Exception_Database
+    */
+    private function _ifExists(array $_arrayData)
+    {
+        try{
+            $checkFilter = $this->_backend->findOne(array($_arrayData['account_id'], $_arrayData['folder'], $_arrayData['status'], $_arrayData['priority']));
+            if($checkFilter > 0){
+                return true;
+            } else{
+                return false;
+            }
+        } catch (Tinebase_Exception_Backend_Database $ex) {
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . 'Failed to schedule a new mail dir export entry at database.' . print_r($ex->getMessage()));
+            throw $ex->getMessage();
+        }
+    }
+
+    /**
+    * Check user account
+    *
+    * @throws  Tinebase_Exception $ex;
+    * @return  Tinebase_Core      $_account
+    */
+    private function _inspectAccountBeforeSchedule()
+    {
+        try{
+            $_account = Tinebase_Core::getUser()->getId();
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' - Fetched Core User ID for mail dir scheduler: ' . print_r($_account, true));
+            if($_account){
+                return $_account;
+            }
+            else {
+                Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' - Failed to get Tinebase user account id');
+                throw new Tinebase_Exception("Failed to get core user account on system!");
+            }
+        } catch (Tinebase_Exception $ex){
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' - Fetched Core User ID for mail dir scheduler: ' . print_r($_account, true));
+            throw new Tinebase_Exception("Failed to get user account on system");
+        }
+    }
+
+    /**
+    * Check folder
+    *
+    * @param   string $_usrAccountId;
+    * @param   string $_folderId;
+    * @return  string $_globalName;
+    * @throws  Tinebase_Exception;
+    *
+    */
+    private function _inspectFolderBeforeSchedule($_usrAccountId, $_folderId)
+    {
+        $_folder = Expressomail_Controller_Folder::getInstance()->get($_folderId);
+        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' - Fetched FOLDER core object: ' . print_r($_folder, true));
+        if($_folder){
+            $_globalName = $_folder->globalname;
+
+            if($this->_isSharedFolder($_globalName) !== false){
+                throw new Tinebase_Exception("Export schedule is not allowed on shared folders!");
+            }
+
+            $_accountId = $_folder->account_id;
+            $_checkAccount = $this->_checkFolderAccount($_usrAccountId, $_accountId);
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '- Fetched mail directory global name for mail dir scheduler: ' . $_globalName);
+
+            if($_checkAccount){
+                return $_globalName;
+            } else{
+                Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' - Tine user account is different from Expressomail account!');
+                throw new Tinebase_Exception("Detected account inconsistence on request operation!");
+            }
+        } else{
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' - Fetched mail directory for mail dir scheduler does not exist or is invalid: ' . print_r($_folder, true));
+            throw new Tinebase_Exception("Specified folder does not exist at mail system!");
+        }
+    }
+
+    /**
+    * Check if folder is a shared one
+    *
+    * @param   string $_globalName
+    * @return  bool
+    */
+    private function _isSharedFolder($_globalName)
+    {
+        $_match = strpos($_globalname, $this->_sharedFolderPattern);
+        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '- Checking if folder global name "' . $_globalName . '" is shared: ' . $_match);
+        return $_match;
+    }
+
+    /**
+    * Check folder account
+    *
+    * @param   string $_usrAccountId
+    * @param   string $_folderId
+    * @return  bool
+    */
+    private function _checkFolderAccount($_usrAccountId, $_folderAccount)
+    {
+        $_expressomailId = Expressomail_Controller_Account::getInstance()->get($_folderAccount);
+        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '- Fetched ACCOUNT for Expressomail account: ' . $_expressomailId);
+        if($_expressomailId->user_id === $_usrAccountId){
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+}
\ No newline at end of file
index d74aab3..67860cf 100644 (file)
@@ -99,6 +99,28 @@ class Expressomail_Controller_Sieve extends Tinebase_Controller_Abstract
     }
     
     /**
+     * Get the allowed domais to a sieve redirect
+     *
+     * @return array
+     */
+    public function getAllowedSieveRedirectDomains(){
+        $sieveConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SIEVE, new Tinebase_Config_Struct())->toArray();
+        if($sieveConfig['limitDomains'] == 1){
+            $smtpConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::SMTP, new Tinebase_Config_Struct())->toArray();
+            $domains = $smtpConfig['primarydomain'];
+            $domains .= (array_key_exists('secondarydomains', $smtpConfig))&&$smtpConfig['secondarydomains']  ? ',' . $smtpConfig['secondarydomains'] : '';
+            $domains .= (array_key_exists('obligatorydomains', $smtpConfig))&&$smtpConfig['obligatorydomains']  ? ',' . $smtpConfig['obligatorydomains'] : '';
+            $domains .= $sieveConfig['allowedDomains'] != ''?','.$sieveConfig['allowedDomains']:'';
+            $domains = strtolower($domains);
+            $domains = str_replace(' ', '', $domains);
+            //return explode(',',$domains);
+            return $domains;
+        }else{
+            return '';
+        }
+
+    }
+    /**
      * get vacation for account
      * 
      * @param string|Expressomail_Model_Account $_accountId
@@ -508,6 +530,16 @@ class Expressomail_Controller_Sieve extends Tinebase_Controller_Abstract
             if ($account->email === $_rule->action_argument) {
                 throw new Expressomail_Exception_Sieve('It is not allowed to redirect emails to self (' . $account->email . ')! Please change the recipient.');
             }
+            $domains = $this->getAllowedSieveRedirectDomains();
+            if($domains){
+                $domain = substr($_rule->action_argument, strpos($_rule->action_argument, '@')+1);
+                $domains = str_replace(' ','',$domains);
+                $domains = str_replace('.','\\.',$domains);
+                $domains = str_replace(',','|',$domains);
+                if(preg_match('/'.$domains.'/', $domain) != 1){
+                    throw new Expressomail_Exception_Sieve('It is not allowed to redirect to this domain  '.$_rule->action_argument);
+                }
+            }
         }
     }
     
@@ -591,7 +623,7 @@ class Expressomail_Controller_Sieve extends Tinebase_Controller_Abstract
      */
     protected function _doMessageSubstitutions(Expressomail_Model_Sieve_Vacation $vacation, $message)
     {
-        $timezone = Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
+        $timezone = Tinebase_Core::getUserTimezone();
         $representatives = ($vacation->contact_ids) ? Addressbook_Controller_Contact::getInstance()->getMultiple($vacation->contact_ids) : array();
         if ($vacation->contact_ids && count($representatives) > 0) {
             // sort representatives
diff --git a/tine20/Expressomail/Exception/IMAPCommandFailed.php b/tine20/Expressomail/Exception/IMAPCommandFailed.php
new file mode 100644 (file)
index 0000000..07ecf8f
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Expressomail
+ * @subpackage  Exception
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2015, SERPRO - Serviço Federal de Processamento de Dados
+ * @author      Mário César Kolling <mario.kolling@serpro.gov.br>
+ *
+ */
+
+/**
+ * Imap Command Failed Exception
+ *
+ * @package     Expressomail
+ * @subpackage  Exception
+ */
+class Expressomail_Exception_IMAPCommandFailed extends Expressomail_Exception_IMAP
+{
+    /**
+     * construct
+     *
+     * @param string $_message
+     * @param integer $_code
+     * @return void
+     */
+    public function __construct($_message = 'IMAP Command Failed.', $_code = 915) {
+        parent::__construct($_message, $_code);
+    }
+}
index 2e818ef..a609d13 100644 (file)
         {
           "text": "ReadConfirmationDetailsPanel.js",
           "path": "js/"
-        },
-        {
-          "text": "MultiWindow.js",
-          "path": "js/"
         }
       ]
     },
diff --git a/tine20/Expressomail/Frontend/ActiveSync.php b/tine20/Expressomail/Frontend/ActiveSync.php
new file mode 100644 (file)
index 0000000..36fd0d6
--- /dev/null
@@ -0,0 +1,1327 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Expressomail
+ * @subpackage  Frontend
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @copyright   Copyright (c) 2008-2014 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2014 Serpro (http://www.serpro.gov.br)
+ * @author      Flávio Gomes da Silva Lisboa <flavio.lisboa@serpro.gov.br>
+ */
+
+/**
+ * ActiveSync frontend class
+ *
+ * @package     Expressomail
+ * @subpackage  Frontend
+ */
+class Expressomail_Frontend_ActiveSync extends ActiveSync_Frontend_Abstract implements Syncroton_Data_IDataEmail, Syncroton_Data_IDataSearch
+{
+    protected $_mapping = array(
+        'body'              => 'body',
+        'cc'                => 'cc',
+        'dateReceived'      => 'received',
+        'from'              => 'from_email',
+        #'Sender'            => 'sender',
+        'subject'           => 'subject',
+        'to'                => 'to'
+    );
+
+    protected $_debugEmail = false;
+
+    /**
+     * available filters
+     *
+     * @var array
+     */
+    protected $_filterArray = array(
+        Syncroton_Command_Sync::FILTER_1_DAY_BACK,
+        Syncroton_Command_Sync::FILTER_3_DAYS_BACK,
+        Syncroton_Command_Sync::FILTER_1_WEEK_BACK,
+        Syncroton_Command_Sync::FILTER_2_WEEKS_BACK,
+        Syncroton_Command_Sync::FILTER_1_MONTH_BACK,
+    );
+
+    /**
+     * expressomail message controller
+     *
+     * @var Expressomail_Controller_Message
+     */
+    protected $_messageController;
+
+    /**
+     * expressomail account
+     *
+     * @var Expressomail_Model_Account
+     */
+    protected $_account;
+
+    /**
+     * app name (required by abstract class)
+     *
+     * @var string
+     */
+    protected $_applicationName     = 'Expressomail';
+
+    /**
+     * model name (required by abstract class)
+     *
+     * @var string
+     */
+    protected $_modelName           = 'Message';
+
+    /**
+     * type of the default folder
+     *
+     * @var int
+     */
+    protected $_defaultFolderType   = Syncroton_Command_FolderSync::FOLDERTYPE_INBOX;
+
+    /**
+     * type of user created folders
+     *
+     * @var int
+     */
+    protected $_folderType          = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED;
+
+    /**
+     * name of property which defines the filterid for different content classes
+     *
+     * @var string
+     */
+    protected $_filterProperty = 'emailfilterId';
+
+    /**
+     * field to sort search results by
+     *
+     * @var string
+     */
+    protected $_sortField = 'received';
+
+    /**
+     * @var Expressomail_Controller_Message
+     */
+    protected $_contentController;
+
+    /**
+     * Reply/Forward message with special treatment
+     *
+     * @param string $messageId
+     * @param Zend_Mail_Message $incomingMessage
+     * @param string $flag
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function parseAndSendMessage($messageId, $incomingMessage, $flag = NULL)
+    {
+        $originalMessage = Expressomail_Controller_Message::getInstance()->getCompleteMessage($messageId, null, false);
+
+        $user = Tinebase_Core::getUser();
+
+        $headers = $incomingMessage->getHeaders();
+
+        $body = ($headers['content-transfer-encoding'] == 'base64')
+            ? base64_decode($incomingMessage->getContent())
+            : $incomingMessage->getContent();
+        $isTextPlain = strpos($headers['content-type'],'text/plain');
+        $bodyLines = preg_split('/\r\n|\r|\n/', $body);
+        $body = '';
+        if ($isTextPlain !== false) {
+            foreach ($bodyLines as &$line) {
+                $body .= htmlentities($line) . '<br />';
+            }
+        } else {
+            foreach ($bodyLines as &$line) {
+                $body .= $line . '<br />';
+            }
+        }
+        $body = '<div>' . $body . '</div>';
+
+        $bodyOrigin = $originalMessage['body'];
+        preg_match("/<body[^>]*>(.*?)<\/body>/is", $bodyOrigin, $matches);
+        $bodyOrigin = (count($matches)>1) ? $matches[1] : $bodyOrigin;
+        $body .= '<div>' . $bodyOrigin . '</div>';
+
+        $attachments = array();
+        foreach ($originalMessage['attachments'] as &$att) {
+            try {
+                $att['name'] = $att['filename'];
+                $att['type'] = $att['content-type'];
+            } catch (Exception $e) {
+                Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' Could not get some attachment attributes for message: ' . $messageId);
+            }
+            array_push($attachments, $att);
+        }
+
+        $recordData = array();
+        $recordData['note'] = '';
+        $recordData['content_type'] = 'text/html';
+        $recordData['account_id'] = $originalMessage->account_id;
+        $recordData['to'] = is_array($headers['to']) ? $headers['to'] : array($headers['to']);
+        $recordData['cc'] = array();
+        $recordData['bcc'] = array();
+        $recordData['subject'] = $headers['subject'];
+        $recordData['body'] = $body;
+        //$recordData['flags'] = array_merge($incomingMessage->getFlags(), $originalMessage['flags']);
+        $recordData['flags'] = ($flag != NULL) ? $flag : '';
+        $recordData['original_id'] = $messageId;
+        $recordData['embedded_images'] = array();
+        $recordData['attachments'] = $attachments;
+        $recordData['from_email'] = $user->accountEmailAddress;
+        $recordData['from_name'] = $user->accountFullName;
+        $recordData['customfields'] = array();
+
+        $message = new Expressomail_Model_Message();
+        $message->setFromJsonInUsersTimezone($recordData);
+
+        try {
+            Expressomail_Controller_Message_Send::getInstance()->sendMessage($message);
+        } catch (Zend_Mail_Protocol_Exception $zmpe) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not send message: ' . $zmpe->getMessage());
+            throw $zmpe;
+        }
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataEmail::forwardEmail()
+     */
+    public function forwardEmail($source, $inputStream, $saveInSent, $replaceMime)
+    {
+        $messageId = $this->getMessageIdFromSource($source);
+
+        if (! is_resource($inputStream)) {
+            $stream = fopen("php://temp", 'r+');
+            fwrite($stream, $inputStream);
+            $inputStream = $stream;
+            rewind($inputStream);
+        }
+
+         if ($this->_debugEmail == true) {
+             $debugStream = fopen("php://temp", 'r+');
+             stream_copy_to_stream($inputStream, $debugStream);
+             rewind($debugStream);
+             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                 __METHOD__ . '::' . __LINE__ . " email to send:" . stream_get_contents($debugStream));
+
+             // replace original stream with debug stream, as php://input can't be rewinded
+             $inputStream = $debugStream;
+             rewind($inputStream);
+         }
+
+        $incomingMessage = new Zend_Mail_Message(
+            array(
+                'file' => $inputStream
+            )
+        );
+
+        if (! $incomingMessage->isMultipart()) {
+            $this->parseAndSendMessage($messageId, $incomingMessage, Zend_Mail_Storage::FLAG_PASSED);
+            return;
+        }
+
+        $defaultAccountId = Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT};
+
+        try {
+            $account = Expressomail_Controller_Account::getInstance()->get($defaultAccountId);
+        } catch (Tinebase_Exception_NotFound $ten) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " no email account configured");
+            throw new Syncroton_Exception('no email account configured');
+        }
+
+        if(empty(Tinebase_Core::getUser()->accountEmailAddress)) {
+            throw new Syncroton_Exception('no email address set for current user');
+        }
+
+        $fmailMessage = Expressomail_Controller_Message::getInstance()->get($messageId);
+        $fmailMessage->flags = Zend_Mail_Storage::FLAG_PASSED;
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+            __METHOD__ . '::' . __LINE__ . " source: " . $messageId . "saveInSent: " . $saveInSent);
+
+        if ($replaceMime === FALSE) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                 __METHOD__ . '::' . __LINE__ . " Adding RFC822 attachment and appending body to forward message.");
+
+            $rfc822 = Expressomail_Controller_Message::getInstance()->getMessagePart($fmailMessage);
+            $rfc822->type = Expressomail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822;
+            $rfc822->filename = 'forwarded_email.eml';
+            $rfc822->encoding = Zend_Mime::ENCODING_7BIT;
+            $replyBody = Expressomail_Controller_Message::getInstance()->getMessageBody($fmailMessage, NULL, 'text/plain');
+        } else {
+            $rfc822 = NULL;
+            $replyBody = NULL;
+        }
+
+        $mail = Tinebase_Mail::createFromZMM($incomingMessage, $replyBody);
+        if ($rfc822) {
+            $mail->addAttachment($rfc822);
+        }
+
+        Expressomail_Controller_Message_Send::getInstance()->sendZendMail($account, $mail, $saveInSent, $fmailMessage);
+    }
+
+    /**
+     * get all entries changed between to dates
+     *
+     * @param unknown_type $_field
+     * @param unknown_type $_startTimeStamp
+     * @param unknown_type $_endTimeStamp
+     * @return array
+     */
+    public function getChangedEntries($folderId, DateTime $_startTimeStamp, DateTime $_endTimeStamp = NULL, $filterType = NULL)
+    {
+        $filter = $this->_getContentFilter($filterType);
+        $this->_addContainerFilter($filter, $folderId);
+
+        $startTimeStamp = ($_startTimeStamp instanceof DateTime) ? $_startTimeStamp->format(Tinebase_Record_Abstract::ISO8601LONG) : $_startTimeStamp;
+        $endTimeStamp = ($_endTimeStamp instanceof DateTime) ? $_endTimeStamp->format(Tinebase_Record_Abstract::ISO8601LONG) : $_endTimeStamp;
+
+        // @todo filter also for create_timestamp??
+        $filter->addFilter(new Tinebase_Model_Filter_DateTime(
+            'timestamp',
+            'after',
+            $startTimeStamp
+        ));
+
+        if($endTimeStamp !== NULL) {
+            $filter->addFilter(new Tinebase_Model_Filter_DateTime(
+                'timestamp',
+                'before',
+                $endTimeStamp
+            ));
+        }
+
+        $result = $this->_contentController->search($filter, NULL, false, true, 'sync');
+
+        return $result;
+   }
+
+   /**
+   * get imap changed entries
+   *
+   * @param string $_accountId
+   * @param string $box
+   * @param string $lastmodseq
+   * @return array
+   */
+   public function getImapChangedEntries($_accountId, $box, $lastmodseq)
+   {
+       $result = array();
+       $imap = Expressomail_Backend_ImapFactory::factory($_accountId);
+       try {
+            $result = $imap->fetchIdsChangedSinceModSeq($box, $lastmodseq);
+        } catch(Exception $e) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .  ' Exception: ' . $e->getMessage());
+            return false;
+        }
+       return $result;
+   }
+
+    /**
+     * retrieve folders which were modified since last sync
+     *
+     * @param  DateTime $startTimeStamp
+     * @param  DateTime $endTimeStamp
+     * @return array
+     *
+     * @todo implement
+     *
+     * @see 0007786: changed email folder names do not sync to device
+     */
+    public function getChangedFolders(DateTime $startTimeStamp, DateTime $endTimeStamp)
+    {
+        $syncrotonFolders = array();
+
+        // @todo calculate changed folders
+
+        return $syncrotonFolders;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::getFileReference()
+     */
+    public function getFileReference($fileReference)
+    {
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(
+            __METHOD__ . '::' . __LINE__ . " fileReference " . $fileReference);
+
+        list($messageId, $partId) = explode(ActiveSync_Frontend_Abstract::LONGID_DELIMITER, $fileReference, 2);
+
+        $part = $this->_contentController->getMessagePart($messageId, $partId);
+
+        $syncrotonFileReference = new Syncroton_Model_FileReference(array(
+            'contentType' => $part->type,
+            'data'        => $part->getDecodedStream()
+        ));
+
+        return $syncrotonFileReference;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataEmail::replyEmail()
+     */
+    public function replyEmail($source, $inputStream, $saveInSent, $replaceMime)
+    {
+        $messageId = $this->getMessageIdFromSource($source);
+
+        if (! is_resource($inputStream)) {
+            $stream = fopen("php://temp", 'r+');
+            fwrite($stream, $inputStream);
+            $inputStream = $stream;
+            rewind($inputStream);
+        }
+
+        if ($this->_debugEmail == true) {
+             $debugStream = fopen("php://temp", 'r+');
+             stream_copy_to_stream($inputStream, $debugStream);
+             rewind($debugStream);
+             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                 __METHOD__ . '::' . __LINE__ . " email to send:" . stream_get_contents($debugStream));
+
+             //replace original stream wirh debug stream, as php://input can't be rewinded
+             $inputStream = $debugStream;
+             rewind($inputStream);
+        }
+
+        $incomingMessage = new Zend_Mail_Message(
+            array(
+                'file' => $inputStream
+            )
+        );
+
+        if (! $incomingMessage->isMultipart()) {
+            $this->parseAndSendMessage($messageId, $incomingMessage, Zend_Mail_Storage::FLAG_ANSWERED);
+            return;
+        }
+
+        $defaultAccountId = Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT};
+
+        try {
+            $account = Expressomail_Controller_Account::getInstance()->get($defaultAccountId);
+        } catch (Tinebase_Exception_NotFound $ten) {
+            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " no email account configured");
+            throw new Syncroton_Exception('no email account configured');
+        }
+
+        if (empty(Tinebase_Core::getUser()->accountEmailAddress)) {
+            throw new Syncroton_Exception('no email address set for current user');
+        }
+
+        $fmailMessage = Expressomail_Controller_Message::getInstance()->get($messageId);
+        $fmailMessage->flags = Zend_Mail_Storage::FLAG_ANSWERED;
+
+        if ($replaceMime === false) {
+            Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Adding RFC822 attachment and appending body to forward message.");
+
+            $rfc822 = Expressomail_Controller_Message::getInstance()->getMessagePart($fmailMessage);
+            $rfc822->type = Expressomail_Model_Message::CONTENT_TYPE_MESSAGE_RFC822;
+            $rfc822->filename = 'replied_email.eml';
+            $rfc822->encoding = Zend_Mime::ENCODING_7BIT;
+            $replyBody = Expressomail_Controller_Message::getInstance()->getMessageBody($fmailMessage, null, 'text/plain');
+        } else {
+            $rfc822 = null;
+            $replyBody = null;
+        }
+
+        $mail = Tinebase_Mail::createFromZMM($incomingMessage, $replyBody);
+        if ($rfc822) {
+            $mail->addAttachment($rfc822);
+        }
+
+        Expressomail_Controller_Message_Send::getInstance()->sendZendMail($account, $mail, (bool)$saveInSent, $fmailMessage);
+    }
+
+    /**
+     * send email
+     *
+     * @param resource $inputStream
+     * @param boolean $saveInSent
+     * @throws Syncroton_Exception
+     */
+    public function sendEmail($inputStream, $saveInSent)
+    {
+        $defaultAccountId = Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT};
+
+        try {
+            $account = Expressomail_Controller_Account::getInstance()->get($defaultAccountId);
+        } catch (Tinebase_Exception_NotFound $ten) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(
+                __METHOD__ . '::' . __LINE__ . " no email account configured");
+
+            throw new Syncroton_Exception('no email account configured');
+        }
+
+        if (empty(Tinebase_Core::getUser()->accountEmailAddress)) {
+            throw new Syncroton_Exception('no email address set for current user');
+        }
+
+        if (! is_resource($inputStream)) {
+            $stream = fopen("php://temp", 'r+');
+            fwrite($stream, $inputStream);
+            $inputStream = $stream;
+            rewind($inputStream);
+        }
+
+        if ($this->_debugEmail == true) {
+             $debugStream = fopen("php://temp", 'r+');
+             stream_copy_to_stream($inputStream, $debugStream);
+             rewind($debugStream);
+             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                 __METHOD__ . '::' . __LINE__ . " email to send:" . stream_get_contents($debugStream));
+
+             //replace original stream wirh debug stream, as php://input can't be rewinded
+             $inputStream = $debugStream;
+             rewind($inputStream);
+        }
+
+        $incomingMessage = new Zend_Mail_Message(
+            array(
+                'file' => $inputStream
+            )
+        );
+
+        $subject = $incomingMessage->headerExists('subject') ? $incomingMessage->getHeader('subject') : null;
+
+        if (Tinebase_Mail::isiMIPMail($incomingMessage)) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
+                . ' Do not send iMIP message with subject "' . $subject . '". The server should handle those.');
+        } else {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . " Send Message with subject " . $subject . " (saveInSent: " . $saveInSent . ")");
+
+            $mail = Tinebase_Mail::createFromZMM($incomingMessage);
+
+            Expressomail_Controller_Message_Send::getInstance()->sendZendMail($account, $mail, (bool)$saveInSent);
+        }
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::toSyncrotonModel()
+     */
+    public function toSyncrotonModel($entry, array $options = array())
+    {
+        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+            __METHOD__ . '::' . __LINE__ . " email data " . print_r($entry->toArray(), true));
+
+        if (! $this->_isMemoryLeft($entry->size)) {
+            throw new Syncroton_Exception_MemoryExhausted('not enough memory left for: ' . $entry->getId() . ' Needed: ' . $entry->size);
+        }
+
+        $syncrotonEmail = new Syncroton_Model_Email();
+
+        foreach ($this->_mapping as $syncrotonProperty => $tine20Property) {
+            if (empty($entry->$tine20Property) && $entry->$tine20Property != '0' || count($entry->$tine20Property) === 0) {
+                continue;
+            }
+
+            switch($tine20Property) {
+                case 'from_email':
+                    $syncrotonEmail->$syncrotonProperty = $this->_createEmailAddress($entry->from_name, $entry->from_email);
+
+                    break;
+
+                case 'to':
+                case 'cc':
+                    $syncrotonEmail->$syncrotonProperty = implode(', ', $entry->$tine20Property);
+
+                    break;
+
+                default:
+                    $syncrotonEmail->$syncrotonProperty = $entry->$tine20Property;
+                    break;
+            }
+        }
+
+        $syncrotonEmail->body = $this->_getSyncrotonBody($entry, $options);
+        if ($syncrotonEmail->body->type < 4) {
+            $syncrotonEmail->nativeBodyType = $syncrotonEmail->body->type;
+        }
+
+        if ($syncrotonEmail->body->type == Syncroton_Command_Sync::BODY_TYPE_MIME) {
+            $syncrotonEmail->messageClass = 'IPM.Note.SMIME';
+        } else {
+            $syncrotonEmail->messageClass = 'IPM.Note';
+        }
+
+        $syncrotonEmail->contentClass = 'urn:content-classes:message';
+
+        // read flag
+        $syncrotonEmail->read = in_array(Zend_Mail_Storage::FLAG_SEEN, $entry->flags) ? 1 : 0;
+
+        if (in_array(Zend_Mail_Storage::FLAG_ANSWERED, $entry->flags)) {
+            $syncrotonEmail->lastVerbExecuted = Syncroton_Model_Email::LASTVERB_REPLYTOSENDER;
+            $syncrotonEmail->lastVerbExecutionTime = new DateTime('now', new DateTimeZone('utc'));
+        #} elseif (in_array('\Forwarded', $entry->flags)) {
+        #    $syncrotonEmail->lastVerbExecuted = Syncroton_Model_Email::LASTVERB_FORWARD;
+        #    $syncrotonEmail->lastVerbExecutionTime = new DateTime('now', new DateTimeZone('utc'));
+        }
+
+        $syncrotonEmail->flag = in_array('\Flagged', $entry->flags) ?
+            new Syncroton_Model_EmailFlag(array(
+                'status'       => Syncroton_Model_EmailFlag::STATUS_ACTIVE,
+                'flagType'     => 'FollowUp',
+                'reminderSet'  => 0,
+                'startDate'    => Tinebase_DateTime::now(),
+                'utcStartDate' => Tinebase_DateTime::now(),
+                'dueDate'    => Tinebase_DateTime::now()->addWeek(1),
+                'utcDueDate' => Tinebase_DateTime::now()->addWeek(1),
+            )) :
+            new Syncroton_Model_EmailFlag(array(
+                'status' => Syncroton_Model_EmailFlag::STATUS_CLEARED
+            ));
+
+        // attachments?
+        if ($entry->has_attachment == true) {
+            $syncrotonAttachments = array();
+
+            $attachments = $this->_contentController->getAttachments($entry);
+
+            if (count($attachments) > 0) {
+                foreach ($attachments as $attachment) {
+                    $syncrotonAttachment = new Syncroton_Model_EmailAttachment(array(
+                        'displayName'       => trim($attachment['filename']),
+                        'fileReference'     => $entry->getId() . ActiveSync_Frontend_Abstract::LONGID_DELIMITER . $attachment['partId'],
+                        'method'            => 1,
+                        'estimatedDataSize' => $attachment['size']
+                    ));
+
+                    $syncrotonAttachments[] = $syncrotonAttachment;
+                }
+            }
+
+            $syncrotonEmail->attachments = $syncrotonAttachments;
+        }
+
+
+        #$syncrotonEmail->categories = array('Test');
+        $syncrotonEmail->conversationId    = $entry->getId();
+        $syncrotonEmail->conversationIndex = "\x00\x01\x02\x03\x04";
+
+        return $syncrotonEmail;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataSearch::search()
+     */
+    public function search(Syncroton_Model_StoreRequest $store)
+    {
+        $storeResponse = new Syncroton_Model_StoreResponse();
+
+        if (!isset($store->query['and']) || !isset($store->query['and']['freeText'])) {
+            $storeResponse->total = 0;
+            return $storeResponse;
+        }
+
+        $filter = new $this->_contentFilterClass(array(array(
+            'field'     => 'query',
+            'operator'  => 'contains',
+            'value'     => $store->query['and']['freeText']
+        )));
+
+        if (isset($store->query['and']['collections'])) {
+            // @todo search for multiple folders
+            $folderId = $store->query['and']['collections'][0];
+        } else {
+            $folderId = Expressomail_Controller_Folder::getInstance()->getByBackendAndGlobalName(
+                Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT},
+                'INBOX'
+            )->getId();
+        }
+        $this->_addContainerFilter($filter, $folderId);
+
+        if (isset($store->options['range'])) {
+            $pagination = new Tinebase_Model_Pagination(array(
+                'start' => $store->options['range'][0],
+                'limit' => $store->options['range'][1] - $store->options['range'][0]
+            ));
+        } else {
+            $pagination = null;
+        }
+
+        $serverIds = $this->_contentController->search($filter, $pagination, false, true, 'sync');
+        $totalCount = $this->_contentController->searchCount($filter, 'sync');
+
+        foreach ($serverIds as $serverId) {
+            $email = $this->getEntry(
+                new Syncroton_Model_SyncCollection(array(
+                    'collectionId' => $folderId,
+                    'options'      => $store->options
+                )),
+                $serverId
+            );
+
+            $storeResponse->result[] = new Syncroton_Model_StoreResponseResult(array(
+                'class'        => 'Email',
+                'longId'       => $folderId . ActiveSync_Frontend_Abstract::LONGID_DELIMITER . $serverId,
+                'collectionId' => $folderId,
+                'properties'   => $email
+            ));
+        }
+
+        $storeResponse->total = $totalCount;
+        if (count($storeResponse->result) > 0) {
+            $storeResponse->range = array($store->options['range'][0], $store->options['range'][1]);
+        }
+
+        return $storeResponse;
+    }
+
+    /**
+     *
+     * @param Expressomail_Model_Message $entry
+     * @param array $options
+     * @return void|Syncroton_Model_EmailBody
+     */
+    protected function _getSyncrotonBody(Expressomail_Model_Message $entry, $options)
+    {
+        //var_dump($options);
+
+        // get truncation
+        $truncateAt  = null;
+        $previewSize = null;
+
+        if ($options['mimeSupport'] == Syncroton_Command_Sync::MIMESUPPORT_SEND_MIME) {
+            $airSyncBaseType = Syncroton_Command_Sync::BODY_TYPE_MIME;
+
+            if (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_MIME]['truncationSize'])) {
+                $truncateAt = $options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_MIME]['truncationSize'];
+            } elseif (isset($options['mimeTruncation']) && $options['mimeTruncation'] < Syncroton_Command_Sync::TRUNCATE_NOTHING) {
+                switch($options['mimeTruncation']) {
+                    case Syncroton_Command_Sync::TRUNCATE_ALL:
+                        $truncateAt = 0;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_4096:
+                        $truncateAt = 4096;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_5120:
+                        $truncateAt = 5120;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_7168:
+                        $truncateAt = 7168;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_10240:
+                        $truncateAt = 10240;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_20480:
+                        $truncateAt = 20480;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_51200:
+                        $truncateAt = 51200;
+                        break;
+                    case Syncroton_Command_Sync::TRUNCATE_102400:
+                        $truncateAt = 102400;
+                        break;
+                }
+            }
+
+        } elseif (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_HTML])) {
+            $airSyncBaseType = Syncroton_Command_Sync::BODY_TYPE_HTML;
+
+            if (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_HTML]['truncationSize'])) {
+                $truncateAt = $options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_HTML]['truncationSize'];
+            }
+            if (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_HTML]['preview'])) {
+                $previewSize = $options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_HTML]['preview'];
+            }
+
+        } else {
+            $airSyncBaseType = Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT;
+
+            if (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT]['truncationSize'])) {
+                $truncateAt = $options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT]['truncationSize'];
+            }
+            if (isset($options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT]['preview'])) {
+                $previewSize = $options['bodyPreferences'][Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT]['preview'];
+            }
+        }
+
+        if ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) {
+            // getMessagePart will return Zend_Mime_Part
+            $messageBody = $this->_contentController->getMessagePart($entry);
+            $messageBody = stream_get_contents($messageBody->getRawStream());
+
+        } else {
+            $messageBody = $this->_contentController->getMessageBody($entry, null, $airSyncBaseType == 2 ? Zend_Mime::TYPE_HTML : Zend_Mime::TYPE_TEXT, NULL, true);
+        }
+
+        if($previewSize !== null) {
+            $preview = substr($this->_contentController->getMessageBody($entry, null, Zend_Mime::TYPE_TEXT, NULL, true), 0, $previewSize);
+
+            // strip out any non utf-8 characters
+            $preview = @iconv('utf-8', 'utf-8//IGNORE', $preview);
+        }
+
+        if($truncateAt !== null && strlen($messageBody) > $truncateAt) {
+            $messageBody  = substr($messageBody, 0, $truncateAt);
+            $isTruncacted = 1;
+        } else {
+            $isTruncacted = 0;
+        }
+
+        // strip out any non utf-8 characters
+        $messageBody  = @iconv('utf-8', 'utf-8//IGNORE', $messageBody);
+
+        $synrotonBody = new Syncroton_Model_EmailBody(array(
+            'type'              => $airSyncBaseType,
+            'estimatedDataSize' => $entry->size,
+        ));
+
+        if (strlen($messageBody) > 0) {
+            $synrotonBody->data = $messageBody;
+        }
+
+        if (isset($preview) && strlen($preview) > 0) {
+            $synrotonBody->preview = $preview;
+        }
+
+        if ($isTruncacted === 1) {
+            $synrotonBody->truncated = 1;
+        } else {
+            $synrotonBody->truncated = 0;
+        }
+
+        return $synrotonBody;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::_inspectGetCountOfChanges()
+     */
+    protected function _inspectGetCountOfChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState)
+    {
+        // TODO Remove because it was not used for Expressomail
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IData::hasChanges()
+     */
+    public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState)
+    {
+         $folderDecoded = Expressomail_Backend_Folder::decodeFolderUid($folder->bigfolderid);
+         $imapStatus = Expressomail_Controller_Folder::getFolderImapStatus($folderDecoded['accountId'], $folderDecoded['globalName']);
+         if ($imapStatus === false) return false; // Exception Raised
+         if (serialize($imapStatus) !== $folder->imapstatus) {
+             return true; // changes found
+         }
+         return false; // no changes found
+     }
+
+    /**
+     * Update folderBackend imapstatus
+     * @param Syncroton_Model_IFolder $folder
+     * @return true | false | null on exception
+     */
+    public function setFolderImapStatus(Syncroton_Model_IFolder $folder)
+    {
+         $folderDecoded = Expressomail_Backend_Folder::decodeFolderUid($folder->bigfolderid);
+         $imapStatus = Expressomail_Controller_Folder::getFolderImapStatus($folderDecoded['accountId'], $folderDecoded['globalName']);
+         if ($imapStatus === false) return null; // Exception Raised
+         if (serialize($imapStatus) !== $folder->imapstatus)
+         {
+             $folderBackend = Syncroton_Registry::getFolderBackend();
+             $folder->imapstatus = serialize($imapStatus);
+             $updateStatus = $folderBackend->update($folder);
+             return true;
+         }
+         return false;
+     }
+
+
+    /**
+     * delete entry
+     *
+     * @param  string  $_folderId
+     * @param  string  $_serverId
+     * @param  array   $_collectionData
+     */
+    public function deleteEntry($_folderId, $_serverId, $_collectionData)
+    {
+        Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " delete ColectionId: $_folderId Id: $_serverId");
+
+        $folder  = Expressomail_Controller_Folder::getInstance()->get($_collectionData->folder->bigfolderid);
+        $account = Expressomail_Controller_Account::getInstance()->get($folder->account_id);
+        $bigContentId = $this->getBigContentId($_collectionData->folder->id, $_serverId);
+
+        if ($_collectionData->deletesAsMoves === true && !empty($account->trash_folder)) {
+            // move message to trash folder
+            $trashFolder = Expressomail_Controller_Folder::getInstance()->getByBackendAndGlobalName($account, $account->trash_folder);
+            Expressomail_Controller_Message_Move::getInstance()->moveMessages($bigContentId, $trashFolder);
+            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " moved entry $bigContentId to trash folder");
+        } else {
+            // set delete flag
+            Expressomail_Controller_Message_Flags::getInstance()->addFlags($bigContentId, Zend_Mail_Storage::FLAG_DELETED);
+            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " deleted entry " . $bigContentId);
+        }
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::updateEntry()
+     */
+    public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry)
+    {
+        $folderBackend = Syncroton_Registry::get(Syncroton_Registry::FOLDERBACKEND);
+        $folder = $folderBackend->getFolder($this->_device, $folderId);
+        $bigContentId = $this->getBigContentId($folder->id, $serverId);
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(
+            __METHOD__ . '::' . __LINE__ . " CollectionId: $folderId Id: $serverId");
+
+        try {
+            $message = $this->_contentController->get($bigContentId);
+        } catch (Tinebase_Exception_NotFound $tenf) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . ' ' . $tenf);
+            throw new Syncroton_Exception_NotFound($tenf->getMessage());
+        }
+
+        if(isset($entry->read)) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . " CollectionId: $folderId Id: $bigContentId set read flag: $entry->read");
+
+            if($entry->read == 1) {
+                Expressomail_Controller_Message_Flags::getInstance()->addFlags($bigContentId, Zend_Mail_Storage::FLAG_SEEN);
+            } else {
+                Expressomail_Controller_Message_Flags::getInstance()->clearFlags($bigContentId, Zend_Mail_Storage::FLAG_SEEN);
+            }
+        }
+
+        if(isset($entry->flag)) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
+                __METHOD__ . '::' . __LINE__ . " CollectionId: $folderId Id: $bigContentId set flagged flag: {$entry->flag->status}");
+
+            if($entry->flag->status == Syncroton_Model_EmailFlag::STATUS_ACTIVE) {
+                Expressomail_Controller_Message_Flags::getInstance()->addFlags($bigContentId, Zend_Mail_Storage::FLAG_FLAGGED);
+            } else {
+                Expressomail_Controller_Message_Flags::getInstance()->clearFlags($bigContentId, Zend_Mail_Storage::FLAG_FLAGGED);
+            }
+        }
+
+        $message->timestamp = $this->_syncTimeStamp;
+        $this->_contentController->update($message);
+
+        return;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IData::updateFolder()
+     */
+    public function updateFolder(Syncroton_Model_IFolder $folder)
+    {
+        $fmailFolder = Expressomail_Controller_Folder::getInstance()->get($folder->serverId);
+        Expressomail_Controller_Folder::getInstance()->rename($fmailFolder->account_id, $folder->displayName, $fmailFolder->globalname);
+        return $folder;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::toTineModel()
+     */
+    public function toTineModel(Syncroton_Model_IEntry $data, $entry = null)
+    {
+        // does nothing => you can't add emails via ActiveSync
+    }
+
+    /**
+     * create rfc email address
+     *
+     * @param  string  $_realName
+     * @param  string  $_address
+     * @return string
+     */
+    protected function _createEmailAddress($_realName, $_address)
+    {
+        return !empty($_realName) ? sprintf('"%s" <%s>', str_replace('"', '\\"', $_realName), $_address) : $_address;
+    }
+
+    /**
+     * return list of supported folders for this backend
+     *
+     * @return array
+     */
+    public function getAllFolders()
+    {
+        if (!Tinebase_Core::getUser()->hasRight('Expressomail', Tinebase_Acl_Rights::RUN)) {
+            // no folders
+            return array();
+        }
+
+        $result = $this->_getFolders();
+        if (strtolower($this->_device->devicetype) == 'android') {
+            $this->_addFakedFolders($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * get expressomail account
+     *
+     * @return Expressomail_Model_Account|NULL
+     */
+    protected function _getAccount()
+    {
+        if ($this->_account === NULL) {
+            $defaultAccountId = Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT};
+
+            if (empty($defaultAccountId)) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(
+                    __METHOD__ . '::' . __LINE__ . " no default account set. Can't sync any folders.");
+                return NULL;
+            }
+
+            try {
+                $this->_account = Expressomail_Controller_Account::getInstance()->get($defaultAccountId);
+            } catch (Tinebase_Exception_NotFound $ten) {
+                return NULL;
+            }
+        }
+
+        return $this->_account;
+    }
+
+    /**
+     * get Syncroton_Model_Folder folders recursively by parentFolder
+     *
+     * @param Expressomail_Model_Folder $parentFolder
+     * @param array $result
+     * @return array of Syncroton_Model_Folder
+     */
+    protected function _getFolders($parentFolder = NULL, &$result = array())
+    {
+        $globalname = ($parentFolder) ? $parentFolder->globalname : '';
+        $account = $this->_getAccount();
+        if (! $account) {
+            return array();
+        }
+
+        $filter = new Expressomail_Model_FolderFilter(array(
+            array('field' => 'globalname', 'operator' => 'startswith',  'value' => $globalname),
+            array('field' => 'account_id', 'operator' => 'equals',      'value' => $account->getId()),
+        ));
+
+        try {
+            $folders = Expressomail_Controller_Folder::getInstance()->search($filter);
+        } catch (Expressomail_Exception_IMAPInvalidCredentials $feiic) {
+            Tinebase_Exception::log($feiic, null, array(
+                'accountname' => $account->name
+            ));
+            return array();
+        }
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
+            . " Found " . count($folders) . ' subfolders of folder "' . $globalname . '"');
+
+        foreach ($folders as $folder) {
+            if (! $folder->is_selectable) {
+                continue;
+            }
+
+            $serverId = md5($folder->getId());
+            $result[$serverId] = new Syncroton_Model_Folder(array(
+                'serverId'      => $serverId,
+                'parentId'      => ($parentFolder) ? md5($parentFolder->getId()) : 0,
+                'displayName'   => substr($folder->localname, 0,254),
+                'type'          => $this->_getFolderType($folder),
+                'bigfolderid'   => $folder->getId()
+            ));
+
+            if ($folder->has_children) {
+                $this->_getFolders($folder, $result);
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::moveItem()
+     */
+    public function moveItem($srcFolderId, $serverId, $dstFolderId)
+    {
+        $folderBackend = Syncroton_Registry::get(Syncroton_Registry::FOLDERBACKEND);
+        $srcFolder = $folderBackend->getFolder($this->_device, $srcFolderId);
+        $dstFolder = $folderBackend->getFolder($this->_device, $dstFolderId);
+        $bigContentId = $this->getBigContentId($srcFolder->id, $serverId);
+
+        $filter = new Expressomail_Model_MessageFilter(array(
+            array(
+                'field'     => 'id',
+                'operator'  => 'equals',
+                'value'     => $bigContentId
+            )
+        ));
+
+        Expressomail_Controller_Message_Move::getInstance()->moveMessages($filter, $dstFolder->bigfolderid);
+
+        return $serverId;
+    }
+
+    /**
+     * used by the mail backend only. Used to update the folder cache
+     *
+     * @param  string  $_folderId
+     */
+    public function updateCache($_folderId)
+    {
+        try {
+            Expressomail_Controller_Message::getInstance()->updateCache($_folderId, 5);
+        } catch (Exception $e) {
+            if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
+                Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " catched exception " . get_class($e));
+            if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
+                Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage());
+            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG))
+                Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getTraceAsString());
+        }
+    }
+
+    /**
+     * set activesync foldertype
+     *
+     * @param Expressomail_Model_Folder $folder
+     * @return string
+     */
+    protected function _getFolderType(Expressomail_Model_Folder $folder)
+    {
+        $personalNameSpaceSuffix = null;
+
+        $account = $this->_getAccount();
+
+        // first lookup folder type by account settings ...
+        if ($account && !empty($account->ns_personal)) {
+            $personalNameSpaceSuffix = $account->ns_personal . $account->delimiter;
+        }
+
+        switch (strtoupper($folder->localname)) {
+            case 'INBOX':
+                if (($personalNameSpaceSuffix . 'INBOX' === $folder->globalname) ||
+                    (substr($personalNameSpaceSuffix, 0, 5) === 'INBOX' && $folder->globalname === 'INBOX') // Cyrus Prvate Namespace == 'INBOX.'
+                ) {
+                    return Syncroton_Command_FolderSync::FOLDERTYPE_INBOX;
+                }
+
+                break;
+
+            case 'TRASH':
+                // either use configured trash folder or detect by name
+                if (($account && $account->trash_folder === $folder->globalname) ||
+                    ($personalNameSpaceSuffix . $folder->localname === $folder->globalname)
+                ) {
+                    return Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS;
+                }
+
+                break;
+
+            case 'SENT':
+                // either use configured sent folder or detect by name
+                if (($account && $account->sent_folder === $folder->globalname) ||
+                    ($personalNameSpaceSuffix . $folder->localname === $folder->globalname)
+                ) {
+                    return Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL;
+                }
+
+                break;
+
+            case 'DRAFTS':
+                // either use configured drafts folder or detect by name
+                if (($account && $account->drafts_folder === $folder->globalname) ||
+                    ($personalNameSpaceSuffix . $folder->localname === $folder->globalname)
+                ) {
+                    return Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS;
+                }
+
+                break;
+
+            case 'OUTBOX':
+                // detect by name
+                if ($personalNameSpaceSuffix . $folder->localname === $folder->globalname) {
+                    return Syncroton_Command_FolderSync::FOLDERTYPE_OUTBOX;
+                }
+
+                break;
+        }
+
+        return Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED;
+    }
+
+    /**
+     * get folder identified by $_folderId
+     *
+     * @param string $_folderId
+     * @return string
+     */
+    private function getFolder($_folderId)
+    {
+        $folders = $this->getSupportedFolders();
+
+        if(!(isset($folders[$_folderId]) || array_key_exists($_folderId, $folders))) {
+            throw new ActiveSync_Exception_FolderNotFound('folder not found. ' . $_folderId);
+        }
+
+        return $folders[$_folderId];
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::_getContentFilter()
+     */
+    protected function _getContentFilter($_filterType)
+    {
+        $filter = parent::_getContentFilter($_filterType);
+
+        if(in_array($_filterType, $this->_filterArray)) {
+            $today = Tinebase_DateTime::now()->setTime(0,0,0);
+
+            switch($_filterType) {
+                case Syncroton_Command_Sync::FILTER_1_DAY_BACK:
+                    $received = $today->subDay(1);
+                    break;
+                case Syncroton_Command_Sync::FILTER_3_DAYS_BACK:
+                    $received = $today->subDay(3);
+                    break;
+                case Syncroton_Command_Sync::FILTER_1_WEEK_BACK:
+                    $received = $today->subWeek(1);
+                    break;
+                case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK:
+                    $received = $today->subWeek(2);
+                    break;
+                case Syncroton_Command_Sync::FILTER_1_MONTH_BACK:
+                    $received = $today->subMonth(1);
+                    break;
+            }
+
+            // add period filter
+            $filter->addFilter(new Expressomail_Model_Filter_DateTime('received', 'after', $received->get(Tinebase_Record_Abstract::ISO8601LONG)));
+        }
+
+        return $filter;
+    }
+
+    /**
+     * (non-PHPdoc)
+     * @see ActiveSync_Frontend_Abstract::_addContainerFilter()
+     */
+    protected function _addContainerFilter(Tinebase_Model_Filter_FilterGroup $_filter, $_containerId)
+    {
+        // custom filter gets added when created
+        $_filter->createFilter(
+            'account_id',
+            'equals',
+            Tinebase_Core::getPreference('Expressomail')->{Expressomail_Preference::DEFAULTACCOUNT}
+        );
+
+        $_filter->addFilter($_filter->createFilter(
+            'folder_id',
+            'equals',
+            $_containerId
+        ));
+    }
+
+    /**
+     *
+     * @return int Syncroton_Command_Sync::FILTER...
+     *
+     */
+    public function getMaxFilterType()
+    {
+        return ActiveSync_Config::getInstance()->get(ActiveSync_Config::MAX_FILTER_TYPE_EMAIL);
+    }
+
+    /**
+     * It creates faked folders that is required by Android 5 (Lollipop),
+     * when it doesn't exists in IMAP
+     *
+     * @param array $folders
+     */
+    private function _addFakedFolders(&$folders)
+    {
+        $folderTypes = array();
+        $inboxServerId = null;
+
+        foreach ($folders as $folder) {
+            $folderTypes[] = $folder->type;
+
+            if ($folder->type == Syncroton_Command_FolderSync::FOLDERTYPE_INBOX) {
+                $inboxServerId = $folder->serverId;
+            }
+        }
+
+        if (! (in_array(Syncroton_Command_FolderSync::FOLDERTYPE_OUTBOX, $folderTypes))) {
+           $fakedServerId = $inboxServerId . 'FAKEDOUTBOX';
+           $folders[$fakedServerId] = new Syncroton_Model_Folder(array(
+                'serverId'      => $fakedServerId,
+                'parentId'      => $inboxServerId,
+                'displayName'   => 'Outbox',
+                'type'          => Syncroton_Command_FolderSync::FOLDERTYPE_OUTBOX
+            ));
+        }
+    }
+
+    /**
+     *
+     * @param  string  $folderId
+     * @param  int     $filterType
+     * @return Tinebase_Record_RecordSet
+     */
+    public function getServerEntries($folderId, $filterType)
+    {
+        $folderBackend = Syncroton_Registry::get(Syncroton_Registry::FOLDERBACKEND);
+        $folder = $folderBackend->getFolder($this->_device, $folderId);
+
+        $bigContentIds =  parent::getServerEntries($folder->bigfolderid, $filterType);
+
+        foreach($bigContentIds as $bigContentId)
+        {
+            $contentId = md5($bigContentId);
+            $contents[$bigContentId] = $contentId;
+        }
+
+        return $contents;
+    }
+
+   /**
+    * Obtain big Email message ID used by Expressomail from small ID used by ActiveSync
+    *
+    * @param string $folderId
+    * @param string $serverId
+    *
+    * @return string $mailServerContentId
+    */
+    public function getBigContentId($folderId, $serverId)
+    {
+        $contentBackend = Syncroton_Registry::get(Syncroton_Registry::CONTENTSTATEBACKEND);
+        $contentState = $contentBackend->getContentState($this->_device->id, $folderId, $serverId);
+        return $contentState->bigcontentid;
+    }
+
+    /**
+     * Get Expressomail message id from source structure
+     *
+     * @param array|string $source
+     * @return string
+     */
+    protected function getMessageIdFromSource($source)
+    {
+        $serverId = is_array($source) ? $source['itemId'] : $source;
+        $folderId = is_array($source) ? $source['collectionId'] : NULL;
+
+        // is $serverId a LongId?
+        if (strpos($serverId, ActiveSync_Frontend_Abstract::LONGID_DELIMITER) !== false) {
+            list($folderId, $serverId) = explode(ActiveSync_Frontend_Abstract::LONGID_DELIMITER, $serverId, 2);
+        }
+
+        $folderBackend = Syncroton_Registry::get(Syncroton_Registry::FOLDERBACKEND);
+        $folder = $folderBackend->getFolder($this->_device, $folderId);
+        return $this->getBigContentId($folder->id, $serverId);
+
+    }
+}
index 046e095..f8a8208 100644 (file)
@@ -31,7 +31,7 @@ class Expressomail_Frontend_Http extends Tinebase_Frontend_Http_Abstract
         $file = new Zend_Form_Element_File('file');
         $maxsize = $file->getMaxFileSize();
 
-        $sessionId = Tinebase_Core::getSessionId();
+        $sessionId = Tinebase_Core::get(Tinebase_Session::SESSIONID);
         if(move_uploaded_file($_FILES['upload']['tmp_name'], $tmpFile)) {
             $image_id = str_replace(Tinebase_Core::getTempDir().'/','',$tmpFile);
             $image_size = filesize($tmpFile);
@@ -83,7 +83,7 @@ class Expressomail_Frontend_Http extends Tinebase_Frontend_Http_Abstract
         $contentType = mime_content_type(Tinebase_Core::getTempDir().'/'.$tempImageId);
         $image = file_get_contents(Tinebase_Core::getTempDir().'/'.$tempImageId);
         
-        $serverETag = sha1($fileData);
+        $serverETag = sha1($image);
 
         // cache for 3600 seconds
         $maxAge = 3600;
index d63830f..3128ea5 100644 (file)
@@ -360,11 +360,16 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
      */
     public function saveMessage($recordData)
     {
+        $recordData = $this->updateRecordIds($recordData);
+
         $message = new Expressomail_Model_Message();
         $message->setFromJsonInUsersTimezone($recordData);
         
         //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . print_r(Zend_Json::decode($recordData), TRUE));
 
+        if (! $message->original_id) {
+            $message->original_id = $message->draft_id;
+        }
         try {
             $result = Expressomail_Controller_Message_Send::getInstance()->sendMessage($message);
             $result = $this->_recordToJson($result);
@@ -407,10 +412,15 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
      */
     public function saveDraftInFolder($folderName, $recordData)
     {
+        $recordData = $this->updateRecordIds($recordData);
+
         $message = new Expressomail_Model_Message();
         $message->setFromJsonInUsersTimezone($recordData);
 
         $draft_id = ($message->draft_id);
+        if (! $message->original_id) {
+            $message->original_id = $draft_id;
+        }
         $message = Expressomail_Controller_Message_Send::getInstance()->saveMessageInFolder($folderName, $message);
 
         if ($draft_id) {
@@ -423,6 +433,36 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
     }
 
     /**
+     * update recorddata ids that maybe are outdated after last draft save
+     *
+     * @param  array $recordData
+     * @return array
+     */
+    private function updateRecordIds($recordData)
+    {
+        if ($recordData['initial_id']) {
+            $replaceIds = array();
+            if(count($recordData['embedded_images'])>0)
+            {
+                for ($index = 0; $index < count($recordData['embedded_images']); $index++)
+                {
+                    try {
+                        $replaceIds[$index] = $recordData['embedded_images'][$index]['id'];
+                        $recordData['embedded_images'][$index]['id'] = $recordData['draft_id'];
+                    } catch (Exception $exc) {
+                    }
+                }
+            }
+            foreach($replaceIds as $id) {
+                $recordData['body'] = str_replace('src="index.php?method=Expressomail.downloadAttachment&amp;messageId='.$id, 'src="index.php?method=Expressomail.downloadAttachment&amp;messageId='.$recordData['draft_id'], $recordData['body']);
+            }
+            // update content
+            $recordData['body'] = str_replace($recordData['initial_id'], $recordData['draft_id'], $recordData['body']);
+        }
+        return $recordData;
+    }
+
+    /**
      * report message(s) as phishing
      *
      * @param  array $msgIds
@@ -821,6 +861,7 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
         
         $supportedFlags = Expressomail_Controller_Message_Flags::getInstance()->getSupportedFlags();
         $extraSenderAccounts = array();
+        $allowedEmails = array();
         foreach ($accounts['results'] as $key => $account) {
             try {
                 // build a imap backend so the system folder can be created if necessary
@@ -850,6 +891,7 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
                             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $zdse->getTraceAsString());
                     }
                 }
+                $allowedEmails[] = $accountModel->email;
             } catch (Exception $e) {
                 if (Tinebase_Core::isLogLevel(Zend_Log::ERR))
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Exception: ' . $e->getMessage());
@@ -873,7 +915,14 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
             unset($account['smtp_auth']);
             $accounts['results'][$key] = $account;
         }
-        
+
+        $user = Tinebase_Core::getUser();
+        $allowedEmails = is_array($user->smtpUser->emailAliases)?array_merge($allowedEmails, $user->smtpUser->emailAliases):$allowedEmails;
+        foreach ($extraSenderAccounts['results'] as $account) {
+            $allowedEmails[] = $account['accountEmailAddress'];
+        }
+
+        Expressomail_Session::getSessionNamespace()->allowedEmails[$user->accountId] = $allowedEmails;
         $result = array(
                 'extraSenderAccounts' => $extraSenderAccounts,
                 'accounts' => $accounts,
@@ -892,21 +941,54 @@ class Expressomail_Frontend_Json extends Tinebase_Frontend_Json_Abstract
                     'cookieValue' => $_COOKIE[$balanceIdCookieName] 
             );
         }
+        $result['allowedDomais'] = Expressomail_Controller_Sieve::getInstance()->getAllowedSieveRedirectDomains();
+
         $result['vacationTemplates'] = $this->getVacationMessageTemplates();
 
         $config = Tinebase_Core::getConfig();
-        $result['useKeyEscrow'] = $config->certificate->active && $config->certificate->useKeyEscrow;
+        if(isset($config->certificate)
+                && is_object($config->certificate)) {
+            $result['useKeyEscrow'] = $config->certificate->active && $config->certificate->useKeyEscrow;
+        } else {
+            $result['useKeyEscrow'] = false;
+        }
+
 
         $config = Expressomail_Controller::getInstance()->getConfigSettings(false);
         // add autoSaveDraftsInterval to client registry
         $result['autoSaveDraftsInterval'] = $config->autoSaveDraftsInterval;
         // add reportPhishingEmail to client registry
         $result['reportPhishingEmail'] = $config->reportPhishingEmail;
+        // add mail folders export feature to client registry
+        $result['enableMailDirExport'] = $config->enableMailDirExport;
 
         return $result;
     }
 
-    
+    /*
+     * Returns export mail folder scheduler action forr expressomail.
+     *
+     * @param string $account
+     * @param string $folder
+     *
+     * @return array
+     */
+    public function schedulerFolder($folder){
+
+        $result = Expressomail_Controller_Scheduler::getInstance()->addNewScheduler($folder);
+        Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . print_r($result, true));
+        if(!$result['msg']){
+            return array(
+                'status'    => 'success'
+            );
+        } else{
+            return array(
+                'error'     => 0,
+                'status'    => 'failure',
+                'message'   => $result['msg']
+            );
+        }
+    }
 
     /**
      * check spelling
diff --git a/tine20/Expressomail/Java/ExpressoCertMail-all.jar b/tine20/Expressomail/Java/ExpressoCertMail-all.jar
new file mode 100644 (file)
index 0000000..4a86f56
Binary files /dev/null and b/tine20/Expressomail/Java/ExpressoCertMail-all.jar differ
index fdb3486..4f3013d 100644 (file)
@@ -5,7 +5,7 @@
  * @package     Expressomail
  * @subpackage  Mail
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2008-2013 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2013-2015 Serpro (http://www.serpro.gov.br)
  * @author      Bruno Vieira Costa <bruno.vieira-costa@serpro.gov.br>
  */
 
  */
 class Expressomail_Mail extends Tinebase_Mail
 {
-    protected $_htmlRelatedAttachments = null;
-
-
-     /**
-     * Public constructor
-     *
-     * @param string $charset
-     */
-    public function __construct($charset = 'iso-8859-1')
-    {
-        $this->_charset = $charset;
-        $this->_htmlRelatedAttachments = new Zend_Mime_Message();
-    }
-
      /**
      * create Tinebase_Mail from Zend_Mail_Message
      * 
@@ -167,85 +153,4 @@ class Expressomail_Mail extends Tinebase_Mail
         
         return $result;
     }
-
-    /**
-     * Adds an existing attachment related to the HTML part of the message
-     *
-     * @param  Zend_Mime_Part $attachment
-     * @return Zend_Mail Provides fluent interface
-     */
-    public function addHtmlRelatedAttachment(Zend_Mime_Part $attachment)
-    {
-        if (!$this->_bodyHtml) {
-            /**
-             * @see Zend_Mail_Exception
-             */
-            require_once 'Zend/Mail/Exception.php';
-            throw new Zend_Mail_Exception('No HTML Body defined');
-        }
-        $this->_htmlRelatedAttachments->addPart($attachment);
-        return $this;
-    }
-
-        /**
-     * Creates a Zend_Mime_Part attachment related to the HTML part of the message
-     *
-     * Attachment is automatically added to the mail object after creation. The
-     * attachment object is returned to allow for further manipulation.
-     *
-     * @param  string         $body
-     * @param  string         $cid The Content Id
-     * @param  string         $mimeType
-     * @param  string         $disposition
-     * @param  string         $encoding
-     * @param  string         $filename OPTIONAL A filename for the attachment
-     * @return Zend_Mime_Part Newly created Zend_Mime_Part object (to allow
-     * advanced settings)
-     */
-    public function createHtmlRelatedAttachment($body, $cid = null,
-                                     $mimeType    = Zend_Mime::TYPE_OCTETSTREAM,
-                                     $disposition = Zend_Mime::DISPOSITION_INLINE,
-                                     $encoding    = Zend_Mime::ENCODING_BASE64,
-                                     $filename    = null)
-    {
-
-        if (null === $cid) {
-            $cid = $this->createCid($body);
-        }
-        $mp = new Zend_Mime_Part($body);
-        $mp->id = $cid;
-        $mp->encoding = $encoding;
-        $mp->type = $mimeType;
-        $mp->disposition = $disposition;
-        $mp->filename = $filename;
-
-        $this->addHtmlRelatedAttachment($mp);
-
-        return $mp;
-    }
-
-
-    /**
-     * Generates and returns a new cid
-     *
-     * @return
-     */
-    public function createCid($body)
-    {
-        static $unique = 0;
-        return md5($body . ($unique++));
-    }
-
-    /**
-     * Returns the list of all Zend_Mime_Parts related to the HTML part of the message
-     *
-     * @return array of Zend_Mime_Part
-     */
-    public function getHtmlRelatedAttachments()
-    {
-      return $this->_htmlRelatedAttachments;
-    }
-
-
-
-}
+}
\ No newline at end of file
index 5a23b65..5d723d6 100644 (file)
@@ -151,6 +151,9 @@ class Expressomail_Model_Account extends Tinebase_Record_Abstract
         'ns_personal'           => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'ns_other'              => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'ns_shared'             => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+    // shared seen flags
+        'shared_seen'           => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
+        'shared_seen_support'   => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
     // user data
         'email'                 => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'from'                  => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => ''),
@@ -416,7 +419,7 @@ class Expressomail_Model_Account extends Tinebase_Record_Abstract
         if (! $this->{$userField} || ! ($this->{$passwordField} && ! $_onlyUsername)) {
             
             $credentialsBackend = Tinebase_Auth_CredentialCache::getInstance();
-            $userCredentialCache = Tinebase_Core::get(Tinebase_Core::USERCREDENTIALCACHE);
+            $userCredentialCache = Tinebase_Core::getUserCredentialCache();
             
             if ($userCredentialCache !== NULL) {
                 try {
index 7c775d8..785965e 100644 (file)
@@ -426,11 +426,11 @@ class Expressomail_Model_DeliveryStatusNotificationMessagePart
         $html .= '<br /><br />';
 
         // Per Recipient Notification Status
-        foreach ($this->_recipients as $finalRecipient => $recipient) {
+        foreach ($this->_recipients as $recipient) {
             // Recipient Address
             $html .= '<b>' . $translate->_('Recipient') . ':</b> ';
             $html .= isset($recipient['originalRecipient']) ? $recipient['originalRecipient']
-                        : $finalRecipient;
+                        : $recipient['finalRecipient'];
             $html .= '<br />';
 
             // Delivery Status Notification Class
index 350549a..9eeb9de 100644 (file)
@@ -32,7 +32,7 @@ class Expressomail_Model_Filter_DateTime extends Tinebase_Model_Filter_DateTime
         // prepare value
         $value = (array) $this->_getDateValues($this->_operator, $this->_value);
         $timezone = Tinebase_Helper::array_value('timezone', $this->_options);
-        $timezone = $timezone ? $timezone : Tinebase_Core::get('userTimeZone');
+        $timezone = $timezone ? $timezone : Tinebase_Core::getUserTimezone();
         foreach ($value as &$date)
         {
             $date = new Tinebase_DateTime($date); // should be in user timezone
index 52291a4..1164cd0 100644 (file)
@@ -129,6 +129,8 @@ class Expressomail_Model_Folder extends Tinebase_Record_Abstract
         'imap_uidvalidity'       => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
         'imap_totalcount'        => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
         'imap_timestamp'         => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'can_share'              => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'sharing_with'             => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => array()),
     // cache values 
         'cache_status'           => array(
             Zend_Filter_Input::ALLOW_EMPTY => true, 
@@ -223,4 +225,29 @@ class Expressomail_Model_Folder extends Tinebase_Record_Abstract
             'parent'    => $parent,
         );
     }
+
+    /**
+     * Set can_share and is_sharing attributes from folder's ACLs
+     * @param boolean|array $acls folder's acls or false if coudn't get folder's acls
+     */
+    public function setSharingValues($acls)
+    {
+        $userAclIndex = FALSE;
+        $sharingWith = array();
+
+        if ($acls !== FALSE && is_array($acls) && isset($acls['results'])) {
+            $accountLoginName = Tinebase_Core::getUser()->accountLoginName;
+            $index = 0;
+            foreach ($acls['results'] as $index => $acl) {
+                if (isset($acl['account_id']) && $acl['account_id'] === $accountLoginName) {
+                    $userAclIndex = $index;
+                } else if (isset($acl['account_id'])) {
+                    $sharingWith[] = $acl['account_id'];
+                }
+            }
+        }
+
+        $this->can_share = $userAclIndex === FALSE ? FALSE : $acls['results'][$userAclIndex]['administer'];
+        $this->sharing_with = $sharingWith;
+    }
 }
index 7398552..16d2ae8 100644 (file)
@@ -136,6 +136,7 @@ class Expressomail_Model_Message extends Tinebase_Record_Abstract implements Tin
         'original_id'           => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'original_part_id'      => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'messageuid'            => array(Zend_Filter_Input::ALLOW_EMPTY => false),
+        'initial_id'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'draft_id'              => array(Zend_Filter_Input::ALLOW_EMPTY => true),
         'folder_id'             => array(Zend_Filter_Input::ALLOW_EMPTY => false),
         'subject'               => array(Zend_Filter_Input::ALLOW_EMPTY => true),
@@ -334,7 +335,7 @@ class Expressomail_Model_Message extends Tinebase_Record_Abstract implements Tin
                 return;
 
             // calculate timezone in "GMT-HH:MM" format
-            $dtz = new DateTimeZone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
+            $dtz = new DateTimeZone(Tinebase_Core::getUserTimezone());
             $time= new DateTime('now', $dtz);
             $offset = $dtz->getOffset( $time );
             $sign = ($offset < 0 ) ? "-" : "+";
diff --git a/tine20/Expressomail/Model/Scheduler.php b/tine20/Expressomail/Model/Scheduler.php
new file mode 100644 (file)
index 0000000..8cda7be
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+/**
+ * class to hold Account data
+ *
+ * @package     Expressomail
+ * @subpackage  Model
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Fernando Alberto Reuter Wendt
+ * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ *              Copyright (c) 2015 SERPRO GmbH (https://www.serpro.gov.br)
+ *
+ */
+
+/**
+ * class to hold folder export scheduler data
+ *
+ * @property  string    _identifier
+ * @property  string    _application
+ * @property  array     _validators
+ * @property  array     _datetimeFields
+ * @package   Expressomail
+ * @subpackage    Model
+ */
+class Expressomail_Model_Scheduler extends Tinebase_Record_Abstract
+{
+    /**
+     * key in $_validators/$_properties array for the field which
+     * represents the identifier
+     *
+     * @var string
+     */
+    protected $_identifier = 'id';
+
+    /**
+     * application the record belongs to
+     *
+     * @var string
+     */
+    protected $_application = 'Expressomail';
+
+    /**
+     * list of zend validator
+     *
+     * this validators get used when validating user generated content with Zend_Input_Filter
+     *
+     * @var array
+     */
+    protected $_validators = array(
+        'id'                => array(Zend_Filter_Input::ALLOW_EMPTY => false),
+        'account_id'        => array(Zend_Filter_Input::ALLOW_EMPTY => false),
+        'folder'            => array(Zend_Filter_Input::ALLOW_EMPTY => false),
+        'scheduler_time'    => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'start_time'        => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'end_time'          => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'status'            => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'is_deleted'        => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'deleted_time'      => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'deleted_by'        => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'priority'          => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+        'expunged_time'     => array(Zend_Filter_Input::ALLOW_EMPTY => true)
+    );
+
+    /**
+     * name of fields containing datetime or an array of datetime information
+     *
+     * @var array list of datetime fields
+     */
+    protected $_datetimeFields = array(
+        'scheduler_time',
+        'start_time',
+        'end_time',
+        'deleted_time',
+        'expunged_time'
+    );
+
+    /**
+     * if foreign Id fields should be resolved on search and get from json
+     * should have this format:
+     *     array('Calendar_Model_Contact' => 'contact_id', ...)
+     * or for more fields:
+     *     array('Calendar_Model_Contact' => array('contact_id', 'customer_id), ...)
+     * (e.g. resolves contact_id with the corresponding Model)
+     *
+     * @var array
+     */
+    protected static $_resolveForeignIdFields = array(
+        'Tinebase_Model_User' => array('account_id')
+    );
+}
\ No newline at end of file
index cbe8325..7a26eed 100644 (file)
@@ -102,7 +102,7 @@ class Expressomail_Model_Sieve_Vacation extends Tinebase_Record_Abstract
             ->setReason($this->reason)
             ->setDateEnabled($this->date_enabled);
         
-        $this->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
+        $this->setTimezone(Tinebase_Core::getUserTimezone());
         if ($this->start_date instanceof Tinebase_DateTime) {
             $fsv->setStartdate($this->start_date->format('Y-m-d'));
         }
index 2140207..4eb00bf 100644 (file)
@@ -152,10 +152,11 @@ class Expressomail_Protocol_Imap extends Zend_Mail_Protocol_Imap
      * get acls for a folder
      *
      * @param  string $box which folder to get the acls
+     * @param  bool $returnOwnerACL true if it will return owner's ACL
      * @return bool|array false if error, array with all users and the acls of this user for this folder.
      * @throws Zend_Mail_Protocol_Exception
      */
-    public function getFolderAcls($box = 'INBOX'){
+    public function getFolderAcls($box = 'INBOX', $returnOwnerACL = FALSE){
 
         $this->sendRequest("GETACL", array($this->escapeString($box)), $tag);
 
@@ -172,6 +173,7 @@ class Expressomail_Protocol_Imap extends Zend_Mail_Protocol_Imap
                 $writeacl = false;
                 $readacl = false;
                 $sendacl = false;
+                $administer = false;
 
                 if(stristr($result[$i+1],'w')){
                     $writeacl = true;
@@ -182,26 +184,38 @@ class Expressomail_Protocol_Imap extends Zend_Mail_Protocol_Imap
                 if(stristr($result[$i+1],'p')){
                     $sendacl = true;
                 }
-                try{
-                if($this->_useUidAsLogin()){
-                    $user = Tinebase_User::getInstance()->getFullUserByLoginName($result[$i])->toArray();
-                }else{
-                    $user = Tinebase_User::getInstance()->getFullUserByEmailAddress($result[$i])->toArray();
+                if (stristr($result[$i+1],'a')) {
+                    $administer = true;
                 }
-                $current = Tinebase_Core::getUser()->toArray();
-
-                if($current['accountId'] == $user['accountId'])
-                    continue;
-
-                $account_name = Array('accountId' => $user['accountId'],
-                                     'accountDisplayName' => $user['accountDisplayName'],
-                                     'accountFullName' => $user['accountFullName'],
-                                     'accountFirstName' => $user['accountFirstName'],
-                                     'accountLastName' => $user['accountLastName'],
-                                     'contact_id' => $user['contact_id']);
+                try{
+                    if($this->_useUidAsLogin()){
+                        $user = Tinebase_User::getInstance()->getFullUserByLoginName($result[$i])->toArray();
+                    }else{
+                        $user = Tinebase_User::getInstance()->getFullUserByEmailAddress($result[$i])->toArray();
+                    }
+                    $current = Tinebase_Core::getUser()->toArray();
 
+                    if(!$returnOwnerACL && $current['accountId'] === $user['accountId']) {
+                        continue;
+                    }
 
-                $results[] = Array('account_name' => $account_name, 'account_id' => $user['accountLoginName'], 'readacl' => $readacl, 'writeacl' => $writeacl, 'sendacl' => $sendacl);
+                    $account_name = Array('accountId' => $user['accountId'],
+                                         'accountLoginName' => $user['accountLoginName'],
+                                         'accountDisplayName' => $user['accountDisplayName'],
+                                         'accountFullName' => $user['accountFullName'],
+                                         'accountFirstName' => $user['accountFirstName'],
+                                         'accountLastName' => $user['accountLastName'],
+                                         'contact_id' => $user['contact_id']);
+
+
+                    $results[] = Array(
+                        'account_name' => $account_name,
+                        'account_id' => $user['accountLoginName'],
+                        'readacl' => $readacl,
+                        'writeacl' => $writeacl,
+                        'sendacl' => $sendacl,
+                        'administer' => $administer,
+                    );
                 }catch(Exception $e){
 
                 }
@@ -291,8 +305,8 @@ class Expressomail_Protocol_Imap extends Zend_Mail_Protocol_Imap
     public function setFolderAcls($box, $acls)
     {
 
-        $folderList = $this->listMailbox('INBOX');
-        $currentAcls = $this->getFolderAcls('INBOX');
+        $folderList = $this->listMailbox($box);
+        $currentAcls = $this->getFolderAcls($box);
         $currentAcls = $currentAcls['results'];
 
         foreach($currentAcls as $index => $currentAcl){
@@ -320,7 +334,7 @@ class Expressomail_Protocol_Imap extends Zend_Mail_Protocol_Imap
                     $login = $tmpUser['accountEmailAddress'];
                 }
             }else{
-                $tmpUser =  Tinebase_User::getInstance()->getFullUserById($user[account_name]['accountId'])->toArray();
+                $tmpUser =  Tinebase_User::getInstance()->getFullUserById($user['account_name']['accountId'])->toArray();
                 if($this->_useUidAsLogin()){
                     $login = $tmpUser['accountLoginName'];
                 }else{
index 776c37d..ab57f36 100644 (file)
  * @package     Expressomail
  * @subpackage  Session
  */
-class Expressomail_Session extends Tinebase_Session_Abstract {    
-    
-    /**
-     * Session namespace for Expressomail
-     */
-    const EXPRESSOMAIL_SESSION_NAMESPACE = 'Expressomail_Session_Namespace';
-    
-       /**
-        * Gets Expressomail session namespace
-        * 
-        * @throws Exception
-        * @return Ambigous <Zend_Session_Namespace, NULL, mixed>
-        */
-       public static function getSessionNamespace()
-       {           
-           try {
-                  return self::_getSessionNamespace(self::EXPRESSOMAIL_SESSION_NAMESPACE);
-           } catch(Exception $e) {             
-               Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Session error: ' . $e->getMessage());
-               Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $e->getTraceAsString());         
-               throw $e;
-           }       
-       }    
-}
\ No newline at end of file
+class Expressomail_Session extends Tinebase_Session_Abstract
+{
+}
index 78c1cd0..6962211 100644 (file)
@@ -118,6 +118,9 @@ class Expressomail_Setup_Initialize extends Setup_Initialize
         $property_reportPhishingEmail = $properties[Expressomail_Config::REPORTPHISHINGEMAIL];
         $default_value_reportPhishingEmail = $property_reportPhishingEmail['default'];
         $config[Expressomail_Config::REPORTPHISHINGEMAIL] = $default_value_reportPhishingEmail;
+        $property_enableMailDirExport = $properties[Expressomail_Config::ENABLEMAILDIREXPORT];
+        $default_value_enableMailDirExport = $property_enableMailDirExport['default'];
+        $config[Expressomail_Config::ENABLEMAILDIREXPORT] = $default_value_enableMailDirExport;
        Expressomail_Controller::getInstance()->saveConfigSettings($config);
     }
 
index 7eea6e6..5e85d2f 100644 (file)
@@ -118,4 +118,260 @@ class Expressomail_Setup_Update_Release0 extends Setup_Update_Abstract
 
         $this->setApplicationVersion('Expressomail', '0.5');
     }
+
+    /**
+     * update to 0.6
+     * add Expressomail domain config file parameter ENABLEMAILDIREXPORT
+     * add Expressomail table 'expressomail_maildirexport_queue'
+     * insert Expressomail applications table new record
+     *
+     * @return void
+     * @throws Tinebase_Exception_NotFound|Tinebase_Exception_Backend_Database|Tinebase_Exception
+     */
+    public function update_5()
+    {
+        //Add new setup entry at domain setup configuration file
+        $settings = Expressomail_Config::getInstance()->get(Expressomail_Config::EXPRESSOMAIL_SETTINGS);
+        if (!array_key_exists(Expressomail_Config::ENABLEMAILDIREXPORT, $settings)) {
+            try {
+                $properties = Expressomail_Config::getProperties();
+                $property = $properties[Expressomail_Config::ENABLEMAILDIREXPORT];
+                $defaultValue = $property['default'];
+                $settings[Expressomail_Config::ENABLEMAILDIREXPORT] = $defaultValue;
+                Expressomail_Controller::getInstance()->saveConfigSettings($settings);
+                Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 successfully added new entry at domain configuration file: "' . $settings[Expressomail_Config::ENABLEMAILDIREXPORT] . '"');
+            } catch (Tinebase_Exception_NotFound $tenf) {
+                Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 fails to add new domain entry: "' . $settings[Expressomail_Config::ENABLEMAILDIREXPORT] . '"');
+            }
+        } else{
+            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 attempted to created a new domain config file entry, but it already exists! "' . Expressomail_Config::ENABLEMAILDIREXPORT .'"');
+        }
+
+        //Add table used by queue script for export mail dir data
+        $newTable = 'expressomail_backup_scheduler';
+        if(!$this->_backend->tableExists($newTable)) {
+            try{
+                $table = Setup_Backend_Schema_Table_Factory::factory('String', '
+                    <table>
+                        <name>'.$newTable.'</name>
+                        <version>1</version>
+                        <declaration>
+                            <field>
+                                <name>id</name>
+                                <type>text</type>
+                                <length>40</length>
+                                <notnull>true</notnull>
+                            </field>
+                            <field>
+                                <name>account_id</name>
+                                <type>text</type>
+                                <length>40</length>
+                                <notnull>true</notnull>
+                            </field>
+                            <field>
+                                <name>folder</name>
+                                <type>text</type>
+                                <length>250</length>
+                                <notnull>true</notnull>
+                            </field>
+                            <field>
+                                <name>scheduler_time</name>
+                                <type>datetime</type>
+                                <notnull>true</notnull>
+                            </field>
+                            <field>
+                                <name>start_time</name>
+                                <type>datetime</type>
+                            </field>
+                            <field>
+                                <name>end_time</name>
+                                <type>datetime</type>
+                            </field>
+                            <field>
+                                <name>status</name>
+                                <type>text</type>
+                                <length>40</length>
+                                <notnull>true</notnull>
+                                <default>PENDING</default>
+                            </field>
+                            <field>
+                                <name>is_deleted</name>
+                                <type>boolean</type>
+                                <default>false</default>
+                            </field>
+                            <field>
+                                <name>deleted_time</name>
+                                <type>datetime</type>
+                            </field>
+                            <field>
+                                <name>deleted_by</name>
+                                <type>text</type>
+                                <length>40</length>
+                            </field>
+                            <field>
+                                <name>priority</name>
+                                <type>integer</type>
+                                <notnull>true</notnull>
+                                <default>5</default>
+                            </field>
+                            <field>
+                                <name>expunged_time</name>
+                                <type>datetime</type>
+                            </field>
+                            <index>
+                                <name>id</name>
+                                <field>
+                                    <name>id</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>account_id</name>
+                                <field>
+                                    <name>account_id</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>folder</name>
+                                <field>
+                                    <name>folder</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>status</name>
+                                <field>
+                                    <name>status</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>scheduler_time</name>
+                                <field>
+                                    <name>scheduler_time</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>is_deleted</name>
+                                <field>
+                                    <name>is_deleted</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>priority</name>
+                                <field>
+                                    <name>priority</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>id</name>
+                                <primary>true</primary>
+                                <field>
+                                    <name>id</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>account_id--folder--status--is_deleted</name>
+                                <unique>true</unique>
+                                <field>
+                                    <name>account_id</name>
+                                </field>
+                                <field>
+                                    <name>folder</name>
+                                </field>
+                                <field>
+                                    <name>status</name>
+                                </field>
+                                <field>
+                                    <name>is_deleted</name>
+                                </field>
+                            </index>
+                            <index>
+                                <name>'.$newTable.'::account_id--accounts::id</name>
+                                <field>
+                                    <name>account_id</name>
+                                </field>
+                                <foreign>true</foreign>
+                                <reference>
+                                    <table>accounts</table>
+                                    <field>id</field>
+                                    <ondelete>CASCADE</ondelete>
+                                </reference>
+                            </index>
+                        </declaration>
+                    </table>
+                ');
+                $this->_backend->createTable($table);
+                Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade 0.6 successfully created a new table at data base schema: "' . $newTable . '"');
+
+                //Insert new Expressomail application table record
+                try{
+                    //Fetch application id to perform insert operation
+                    $selectId = $this->_db->select()
+                        ->from(SQL_TABLE_PREFIX . 'applications', 'id')
+                            ->where($this->_db->quoteIdentifier('name') . ' = ?', 'Expressomail');
+
+                    $resultId = $this->_db->fetchAll($selectId);
+                    $appId = $resultId[0]["id"];
+
+                    //Check basic data consistence at table application
+                    if(count($resultId) != 1){
+                        Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 inconsistent data at applications table for appName "ExpressoMail"');
+                        throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' inconsistent data at applications table!"));
+                    }
+
+                    //Try to find out if some corrupted event have already iserted this data before
+                    $selectAppTable = $this->_db->select()
+                        ->from(SQL_TABLE_PREFIX . 'application_tables', 'name')
+                            ->where($this->_db->quoteIdentifier('name') . ' = ?', $newTable);
+
+                    $resultAppTable = $this->_db->fetchAll($selectAppTable);
+                    if(count($resultAppTable) != 0){
+                        Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 inconsistent data at applications table for appName "ExpressoMail": the new table "'.$newTable.'" already is there!');
+                        throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' inconsistent data at applications table: new table '$newTable' relationship already exists at 'application_tables'!"));
+                    }
+
+                    //Follows to add new record
+                    $appRecord = new SimpleXMLElement("
+                                <record>
+                                    <table>
+                                        <name>application_tables</name>
+                                    </table>
+                                    <field>
+                                        <name>application_id</name>
+                                        <value>$appId</value>
+                                    </field>
+                                    <field>
+                                        <name>name</name>
+                                        <value>$newTable</value>
+                                    </field>
+                                    <field>
+                                        <name>version</name>
+                                        <value>1</value>
+                                    </field>
+                                </record>
+                    ");
+
+                     //Performs insert new record
+                     $this->_backend->execInsertStatement($appRecord);
+                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 successfully inserted a new record at "application_tables" table: "' . $newTable . '"');
+
+                     try{
+                        //Fetch update action
+                        $this->setApplicationVersion('Expressomail', '0.6');
+                        Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 successfully finished.');
+                     } catch (Tinebase_Exception $updateException){
+                        Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 fails to be up to dated: ' . $updateException->getMessage());
+                        throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' fails to update to 0.6 at 'setApplicationVersion':" . $updateException->getMessage()));
+                     }
+                } catch (Tinebase_Exception_Backend_Database $insertAppException) {
+                    Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 fails to insert new applications table: ' . $insertAppException->getMessage());
+                    throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' fails to update to 0.6 at insert applicatons table new record:" . $insertAppException->getMessage()));
+                }
+            } catch (Tinebase_Exception_Backend_Database $createException){
+                Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 fails to create new table: ' . $createException->getMessage());
+                throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' fails to update to 0.6 at create new table:" . $createException->getMessage()));
+            }
+        } else{
+            Tinebase_Core::getLogger()->error(__METHOD__ . '::' . __LINE__ . ' ExpressoMail upgrade to 0.6 fails to process new table creation: table "' .$newTable . '" already exists at application schema database!');
+            throw(new Tinebase_Exception_Backend_Database("Application 'Expressomail' fails to update to 0.6: base table '$newTable' already exists at database schema!"));
+        }
+    }
 }
\ No newline at end of file
index bc76f92..25a938a 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <application>
     <name>Expressomail</name>
-    <version>0.5</version>
+    <version>0.6</version>
     <order>50</order>
     <status>disabled</status>
     <tables>
                 </index>
             </declaration>
         </table>
+        <table>
+            <name>expressomail_backup_scheduler</name>
+            <version>1</version>
+            <declaration>
+                <field>
+                    <name>id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>account_id</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>folder</name>
+                    <type>text</type>
+                    <length>250</length>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>scheduler_time</name>
+                    <type>datetime</type>
+                    <notnull>true</notnull>
+                </field>
+                <field>
+                    <name>start_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>end_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>status</name>
+                    <type>text</type>
+                    <length>40</length>
+                    <notnull>true</notnull>
+                    <default>PENDING</default>
+                </field>
+                <field>
+                    <name>is_deleted</name>
+                    <type>boolean</type>
+                    <default>false</default>
+                </field>
+                <field>
+                    <name>deleted_time</name>
+                    <type>datetime</type>
+                </field>
+                <field>
+                    <name>deleted_by</name>
+                    <type>text</type>
+                    <length>40</length>
+                </field>
+                <field>
+                    <name>priority</name>
+                    <type>integer</type>
+                    <notnull>true</notnull>
+                    <default>5</default>
+                </field>
+                <field>
+                    <name>expunged_time</name>
+                    <type>datetime</type>
+                </field>
+                <index>
+                    <name>id</name>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>account_id</name>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>folder</name>
+                    <field>
+                        <name>folder</name>
+                    </field>
+                </index>
+                <index>
+                    <name>status</name>
+                    <field>
+                        <name>status</name>
+                    </field>
+                </index>
+                <index>
+                    <name>scheduler_time</name>
+                    <field>
+                        <name>scheduler_time</name>
+                    </field>
+                </index>
+                <index>
+                    <name>is_deleted</name>
+                    <field>
+                        <name>is_deleted</name>
+                    </field>
+                </index>
+                <index>
+                    <name>priority</name>
+                    <field>
+                        <name>priority</name>
+                    </field>
+                </index>
+                <index>
+                    <name>id</name>
+                    <primary>true</primary>
+                    <field>
+                        <name>id</name>
+                    </field>
+                </index>
+                <index>
+                    <name>account_id--folder--status--is_deleted</name>
+                    <unique>true</unique>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <field>
+                        <name>folder</name>
+                    </field>
+                    <field>
+                        <name>status</name>
+                    </field>
+                    <field>
+                        <name>is_deleted</name>
+                    </field>
+                </index>
+                <index>
+                    <name>expressomail_backup_scheduler::account_id--accounts::id</name>
+                    <field>
+                        <name>account_id</name>
+                    </field>
+                    <foreign>true</foreign>
+                    <reference>
+                        <table>accounts</table>
+                        <field>id</field>
+                        <ondelete>CASCADE</ondelete>
+                    </reference>
+                </index>
+            </declaration>
+        </table>
     </tables>
 </application>
index 2b19dcc..aa5de93 100644 (file)
@@ -5,8 +5,9 @@
  * @package     Expressomail
  * @subpackage  Transport
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schüle <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Bruno Vieira Costa <bruno.vieira-costa@serpro.gov.br>
+ * @author      Cassiano Dal Pizzol <cassiano.dalpizzol@serpro.gov.br>
+ * @copyright   Copyright (c) 2013-2015 Serpro (http://www.serpro.gov.br)
  * 
  */
 
@@ -136,10 +137,6 @@ class Expressomail_Transport extends Zend_Mail_Transport_Smtp
      */
     protected function _buildBody()
     {
-//        if (($text = $this->_mail->getBodyText())
-//            && ($html = $this->_mail->getBodyHtml()))
-      
-//        
         $text = $this->_mail->getBodyText();
         $html = $this->_mail->getBodyHtml();
 
@@ -155,17 +152,8 @@ class Expressomail_Transport extends Zend_Mail_Transport_Smtp
             $boundaryLine = $mime->boundaryLine($this->EOL);
             $boundaryEnd  = $mime->mimeEnd($this->EOL);
 
-//            $text->disposition = false;
             $html->disposition = false;
 
-//            $body = $boundaryLine
-//                  . $text->getHeaders($this->EOL)
-//                  . $this->EOL
-//                  . $text->getContent($this->EOL)
-//                  . $this->EOL
-//                  . $boundaryLine
-//                  . $html->getHeaders($this->EOL)
-            
             if ($hasHtmlRelatedParts) {
                 $message = new Zend_Mime_Message();
                 array_unshift($htmlAttachmentParts, $html);
index 3f7c0ff..9e4847b 100644 (file)
     background-image:url(../../images/remote-folder-open.gif);
 }
 
+.x-tree-node-expanded-overlay-share img.x-tree-node-icon{
+    background-image:url(../../images/shared.png), url(../../images/folder-open.gif);
+}
+
+.x-tree-node-collapsed-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/folder.gif);
+}
+
+.expressomail-node-trash-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/user-trash.png);
+}
+
+.expressomail-node-trash-full-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/user-trash-full.png);
+}
+
+.expressomail-node-sent-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/mail-folder-sent.png);
+}
+
+.expressomail-node-inbox-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/mail-folder-inbox.png);
+}
+
+.expressomail-node-drafts-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/folder-txt.png);
+}
+
+.expressomail-node-templates-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/folder-tar.png);
+}
+
+.expressomail-node-junk-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/oxygen/16x16/places/trashcan-empty-alt.png);
+}
+
+.expressomail-node-remote-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/remote-folder.gif);
+}
+
+.expressomail-node-remote-open-overlay-share img.x-tree-node-icon {
+    background-image:url(../../images/shared.png), url(../../images/remote-folder-open.gif);
+}
 
 .expressomail-node-statusbox {
        padding-right: 5px;
index 56f905a..26dd1bb 100644 (file)
@@ -58,19 +58,25 @@ Tine.Expressomail.AccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog,
         Tine.Expressomail.AccountEditDialog.superclass.onRecordLoad.call(this);
 
         // if account type == system disable most of the input fields
-        if (this.record.get('type') == 'system') {
-            this.getForm().items.each(function(item) {
-                // only enable some fields
-                switch(item.name) {
-                    case 'signature':
-                    case 'signature_position':
-                    case 'display_format':
+        this.getForm().items.each(function(item) {
+            // only enable some fields
+            switch(item.name) {
+                case 'shared_seen':
+                    item.setDisabled(!this.record.get('shared_seen_support'));
+                    break;
+                case 'signature':
+                case 'signature_position':
+                case 'display_format':
+                    if (this.record.get('type') === 'system') {
                         break;
-                    default:
+                    }// else it gets into default
+                default:
+                    if (!item.name.match(/^customfield*/)
+                            && this.record.get('type') === 'system') {
                         item.setDisabled(true);
-                }
-            }, this);
-        }
+                    }
+            }
+        }, this);
     },    
        
     /**
@@ -169,6 +175,19 @@ Tine.Expressomail.AccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog,
                 }, {
                     fieldLabel: this.app.i18n._('Organization'),
                     name: 'organization'
+                }, {
+                    fieldLabel: this.app.i18n._('Enable Shared Seen Flags'),
+                    name: 'shared_seen',
+                    editable: false,
+                    lazyRender: true,
+                    mode: 'local',
+                    forceSelection: true,
+                    value: false,
+                    xtype: 'combo',
+                    store: [
+                        [true, this.app.i18n._('Yes')],
+                        [false, this.app.i18n._('No')]
+                    ]
                 }, this.signatureEditor,
                 {
                     fieldLabel: this.app.i18n._('Signature position'),
@@ -411,7 +430,7 @@ Tine.Expressomail.AccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog,
  Tine.Expressomail.AccountEditDialog.openWindow = function (config) {
     var window = Tine.WindowFactory.getWindow({
         width: 620,
-        height: 550,
+        height: 570,
         name: Tine.Expressomail.AccountEditDialog.prototype.windowNamePrefix + Ext.id(),
         contentPanelConstructor: 'Tine.Expressomail.AccountEditDialog',
         contentPanelConstructorConfig: config
index 738f822..fe7a070 100644 (file)
@@ -42,6 +42,9 @@ Tine.Expressomail.AclsEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
     loadRecord: false,
     tbarItems: [],
     evalAcls: false,
+    enableSendAs: false,
+
+    node: null,
 
     /**
      * @private
@@ -96,7 +99,8 @@ Tine.Expressomail.AclsEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
      */
     getFormItems: function() {
         this.aclsGrid = new  Tine.Expressomail.AclsGrid({
-            store: this.aclStore
+            store: this.aclStore,
+            enableSendAs: this.enableSendAs
         });
 
         return this.aclsGrid;
@@ -110,8 +114,12 @@ Tine.Expressomail.AclsEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
 
         var acls = [];
         this.aclStore.each(function(_record){
+            // sendacl only makes sense with INBOX
+            if (!this.enableSendAs) {
+                _record.data.sendacl = false;
+            }
             acls.push(_record.data);
-        });
+        }, this);
 
         Ext.Ajax.request({
             params: {
@@ -151,6 +159,7 @@ Tine.Expressomail.AclsEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
                 }
             }
         });
+        this.fireEvent('save', this.aclStore);
     }
 });
 
index a92c998..d155c25 100644 (file)
@@ -37,6 +37,7 @@ Tine.Expressomail.AclsGrid = Ext.extend(Tine.widgets.account.PickerGridPanel, {
     selectTypeDefault: 'user',
     hasAccountPrefix: true,
     recordClass: Tine.Expressomail.Model.Acl,
+    enableSendAs: false,
     
     /**
      * @private
@@ -60,13 +61,15 @@ Tine.Expressomail.AclsGrid = Ext.extend(Tine.widgets.account.PickerGridPanel, {
                 tooltip: _('Write and delete messages from folders'),
                 dataIndex: 'writeacl',
                 width: 55
-            }),
-            new Ext.ux.grid.CheckColumn({
+            })
+        ];
+        if (this.enableSendAs) {
+            this.configColumns.push(new Ext.ux.grid.CheckColumn({
                 header: _('Send as'),
                 tooltip: _('Send as folder owner'),
                 dataIndex: 'sendacl',
-                width: 55
-            })            
-        ];
+                width: 55,
+            }));
+        }
     }
 });
\ No newline at end of file
index 493fb4f..a9e68c5 100644 (file)
@@ -67,6 +67,22 @@ Tine.Expressomail.AdminPanel = Ext.extend(Tine.widgets.dialog.AdminPanel, {
                 value: null,
                 maxLength: 64,
                 allowBlank: true
+            },
+            {
+                name: 'enableMailDirExport',
+                fieldLabel: this.app.i18n._('Enable mail folders for exportation (compressed)'),
+                typeAhead     : false,
+                triggerAction : 'all',
+                lazyRender    : true,
+                editable      : false,
+                mode          : 'local',
+                forceSelection: true,
+                value: null,
+                xtype: 'combo',
+                store: [
+                    [false, this.app.i18n._('No')],
+                    [true,  this.app.i18n._('Yes')]
+                ]
             }
         ]];
     }
index 5e8138b..1af10d0 100644 (file)
@@ -127,7 +127,8 @@ Tine.Expressomail.ContactGridPanel = Ext.extend(Tine.Addressbook.ContactGridPane
                 dataIndex: Ext.util.Format.lowercase(type),
                 width: 50,
                 hidden: false,
-                renderer: this.typeRadioRenderer.createDelegate(this, [type], 0)
+                renderer: this.typeRadioRenderer.createDelegate(this, [type], 0),
+                searchable: false
             });
             
         }, this);
index 1a3c9f7..8e66b03 100644 (file)
@@ -601,7 +601,17 @@ Tine.Expressomail.Application = Ext.extend(Tine.Tinebase.Application, {
      * @param {value} newValue
      */
     onPreferenceChange: function (key, oldValue, newValue) {
+        if (Tine.Tinebase.tineInit.isReloading || oldValue === "") { // Fix for IE errors on preferences initialization
+            return;
+        }
         switch (key) {
+            case 'emailsPerPage':
+                app = Tine.Tinebase.appMgr.get('Expressomail');
+                centerPanel = app.getMainScreen().getCenterPanel();
+                centerPanel.defaultPaging.limit = newValue;
+                centerPanel.filterToolbar.onFilterChange();
+
+                break;
             case 'enableEncryptedMessage':
                 // reload mainscreen
                 var reload = new Ext.util.DelayedTask(function(){window.location.reload(false);},this);
@@ -1067,6 +1077,15 @@ Tine.Expressomail.handleRequestException = function(exception) {
             }
             break;
 
+        case 915: // Expressomail_Exception_IMAPCommandFailed
+            Ext.Msg.show({
+               title:   app.i18n._('Imap Command Failed'),
+               msg:     exception.message ? exception.message : app.i18n._('Imap Command Failed.'),
+               icon:    Ext.MessageBox.ERROR,
+               buttons: Ext.Msg.OK
+            });
+            break;
+
         case 920: // Expressomail_Exception_SMTP
             Ext.Msg.show({
                title:   app.i18n._('SMTP Error'),
@@ -1129,11 +1148,26 @@ Tine.Expressomail.fixIEUserAgent = function()
             result = re.exec(navigator.userAgent)[0],
             original = result.substring(1, result.length -1),
             elements = original.split('; '),
-            newUserAgent = '';
-        for(var i = 0; i < 4; i++){
-            newUserAgent = newUserAgent+elements[i]+'; ';
-        }
-        return navigator.userAgent.replace(original,newUserAgent.substr(0,newUserAgent.length -2));
+            newUserAgent = '(',
+            selectionItems = [
+                'compatible',
+                'Trident\\/\\d+\\.\\d+',
+                'MSIE \\d+\\.\\d+',
+                'Windows NT \\d+\\.\\d+',
+                'rv:\\d+\\.\\d+',
+                'WOW64',
+                'Win64',
+                'IA64',
+                'x64'
+            ],
+            ieRegexp = new RegExp('('+selectionItems.join('|')+')');
+        Ext.each(elements, function(element){
+            if (ieRegexp.test(element)){
+                newUserAgent = newUserAgent+element+'; ';
+            }
+        });
+        newUserAgent = newUserAgent.replace(/;\s$/, ')');
+        return navigator.userAgent.replace(re, newUserAgent);
     }
 }
 
index 9f613bf..02ce3bb 100644 (file)
@@ -172,6 +172,26 @@ Tine.Expressomail.GridDetailsPanel = Ext.extend(Tine.widgets.grid.DetailsPanel,
     },
 
     /**
+     * update details panel
+     *
+     * @param {Ext.grid.RowSelectionModel} sm
+     */
+    onDetailsUpdate: function(sm) {
+        Tine.Expressomail.GridDetailsPanel.superclass.onDetailsUpdate.call(this, sm);
+        this.scrollPreviewToTop();
+    },
+
+    /**
+     * scroll preview panel to top
+     */
+    scrollPreviewToTop: function() {
+        var els = this.getMessageRecordPanel().getEl().query('div[class=preview-panel-expressomail]');
+        if (els) {
+            els[0].parentElement.scrollTop = 0;
+        }
+    },
+
+    /**
      * (on) update details
      *
      * @param {Tine.Expressomail.Model.Message} record
@@ -196,11 +216,13 @@ Tine.Expressomail.GridDetailsPanel = Ext.extend(Tine.widgets.grid.DetailsPanel,
                 // TODO: set signature, attachments, etc
                 this.setTemplateContent(record, this.getMessageRecordPanel().body);
                 this.fireEvent('dblwindow');
+                this.scrollPreviewToTop();
             }
             this.isNavKey = false;
         } else if (record === this.record) {
             this.setTemplateContent(record, this.getMessageRecordPanel().body);
             this.fireEvent('dblwindow');
+            this.scrollPreviewToTop();
         }
     },
 
index e526a44..00ca4ba 100644 (file)
@@ -68,6 +68,7 @@ Tine.Expressomail.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
     fetchtry: 0,
 
     saveOnDestroy: {},
+    updateDetailsDelay: 500,
 
     /**
      * @private grid cfg
@@ -134,14 +135,57 @@ Tine.Expressomail.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
 
         Tine.Expressomail.GridPanel.superclass.initComponent.call(this)
 
-        this.grid.getSelectionModel().on('rowselect', this.onRowSelection, this);
+        this.grid.getSelectionModel().on('rowselect', this.onRowSelectionDelay, this);
         this.app.getFolderStore().on('update', this.onUpdateFolderStore, this);
 
         this.initPagingToolbar();
 
         this.saveOnDestroy = {};
     },
-    
+
+    /**
+     * init grid
+     * @private
+     */
+    initGrid: function() {
+        Tine.Expressomail.GridPanel.superclass.initGrid.call(this);
+        this.selectionModel.events.selectionchange.clearListeners();
+        this.selectionModel.on('selectionchange', this.onSelectionChangeDelay, this);
+    },
+
+    /**
+     * called when a selection gets changed
+     *
+     * @param {SelectionModel} sm
+     */
+    onSelectionChangeDelay: function(sm) {
+        this.actionUpdater.updateActions(sm);
+        this.ctxNode = this.selectionModel.getSelections();
+        if (this.updateOnSelectionChange && this.detailsPanel) {
+            if (this.selectionChangeDelayedTask) {
+                this.selectionChangeDelayedTask.cancel();
+            }
+            this.selectionChangeDelayedTask = new Ext.util.DelayedTask(this.detailsPanel.onDetailsUpdate, this.detailsPanel, [sm]);
+            this.selectionChangeDelayedTask.delay(this.updateDetailsDelay);
+        }
+    },
+
+    /**
+     * called when a row gets selected
+     *
+     * @param {SelectionModel} sm
+     * @param {Number} rowIndex
+     * @param {Tine.Expressomail.Model.Message} record
+     * @param {Number} retryCount
+     */
+    onRowSelectionDelay: function(sm, rowIndex, record, retryCount) {
+        if (this.rowSelectionDelayedTask) {
+            this.rowSelectionDelayedTask.cancel();
+        }
+        this.rowSelectionDelayedTask = new Ext.util.DelayedTask(this.onRowSelection, this, [sm, rowIndex, record, retryCount]);
+        this.rowSelectionDelayedTask.delay(this.updateDetailsDelay);
+    },
+
     /**
      * get load mask
      * 
@@ -243,18 +287,6 @@ Tine.Expressomail.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
      * skip initial till we know the INBOX id
      */
     initialLoad: function() {
-        var account = this.app.getActiveAccount(),
-            accountId = account ? account.id : null,
-            inbox = accountId ? this.app.getFolderStore().queryBy(function(record) {
-                return record.get('account_id') === accountId && record.get('localname').match(/^inbox$/i);
-            }, this).first() : null;
-
-        if (! inbox) {
-            this.initialLoad.defer(100, this, arguments);
-            return;
-        }
-
-        return Tine.Expressomail.GridPanel.superclass.initialLoad.apply(this, arguments);
     },
 
     /**
@@ -1622,13 +1654,7 @@ Tine.Expressomail.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
             this.detailsPanel.addListener('dblwindow', this.openDblClickWindow, this);
         }
         else {
-            if(this.detailsPanel.record.bodyIsFetched()){
-                this.openDblClickWindow(grid, row, e);
-            }else{
-                this.detailsPanel.getLoadMask().hide();
-                this.getLoadMask().show();
-                this.detailsPanel.addListener('dblwindow', this.openDblClickWindow, this);
-            }
+            this.openDblClickWindow(grid, row, e);
         }
     },
     
@@ -1797,6 +1823,9 @@ Tine.Expressomail.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
         }
         try { // because editwindow could be closed yet
             editwindow.record.commit(true);
+            if (!editwindow.record.get('initial_id')) {
+                editwindow.record.set('initial_id', record.get('draft_id'));
+            }
             editwindow.record.set('draft_id', record.get('original_id'));
             editwindow.setMessageOnTitle(editwindow.notifyClear);
             editwindow.setSaveDraftsDelayedTask();
index 2b14717..a4e1fa7 100644 (file)
@@ -387,8 +387,9 @@ Tine.Expressomail.MessageDisplayDialog.openWindow = function (config) {
     var record = (Ext.isString(config.record)) ? Ext.util.JSON.decode(config.record) : config.record,
         id = (record && record.id) ? record.id : 0,
         window = Tine.WindowFactory.getWindow({
-            width: 800,
-            height: 700,
+            width: 700,
+            height: 650,
+            multiple: true,
             name: 'TineExpressomailMessageDisplayDialog_' + id,
             contentPanelConstructor: 'Tine.Expressomail.MessageDisplayDialog',
             contentPanelConstructorConfig: config
index 60ef718..6aab4fa 100644 (file)
@@ -856,9 +856,8 @@ Tine.Expressomail.MessageEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog,
         } else if (this.forwardMsgs) {
             this.record.set('flags', 'Passed');
             this.record.set('original_id', this.forwardMsgs[0].id);
-        } else if (this.draftOrTemplate) {
-            this.record.set('draft_id', this.draftOrTemplate.id);
         }
+
         this.record.set('add_contacts', true);
 
         Tine.log.debug('Tine.Expressomail.MessageEditDialog::initRecord() -> record:');
@@ -2243,6 +2242,8 @@ Tine.Expressomail.MessageEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog,
 Tine.Expressomail.MessageEditDialog.openWindow = function (config) {
     var window = Tine.WindowFactory.getWindow({
         notifiable: true,
+        multiple: true,
+        limit: 1,
         width: 829,
         height: 700,
         ref: Tine.Tinebase.appMgr.get('Expressomail'),
index ce32b32..4b85cbe 100644 (file)
@@ -74,6 +74,7 @@ Tine.Expressomail.Model.Message = Tine.Tinebase.data.Record.create([
       { name: 'attachments' },
       { name: 'has_attachment', type: 'bool' },
       { name: 'original_id' },
+      { name: 'initial_id' }, // contains the initial id of edited message
       { name: 'draft_id' },
       { name: 'folder_id' },
       { name: 'note' },
@@ -527,6 +528,8 @@ Tine.Expressomail.Model.Account = Tine.Tinebase.data.Record.create(Tine.Tinebase
     { name: 'ns_personal' },
     { name: 'ns_other' },
     { name: 'ns_shared' },
+    { name: 'shared_seen' },
+    { name: 'shared_seen_support' },
     { name: 'signature' },
     { name: 'signature_position' },
     { name: 'smtp_port' },
@@ -671,6 +674,8 @@ Tine.Expressomail.Model.Folder = Tine.Tinebase.data.Record.create([
       { name: 'imap_timestamp',     type: 'date', dateFormat: Date.patterns.ISO8601Long },
       { name: 'imap_uidvalidity',   type: 'int' },
       { name: 'imap_totalcount',    type: 'int' },
+      { name: 'can_share',          type: 'bool' },
+      { name: 'sharing_with',       type: 'Array' },
       { name: 'cache_status' },
       { name: 'cache_recentcount',  type: 'int' },
       { name: 'cache_totalcount',   type: 'int' },
index 9b357b7..ebc18eb 100644 (file)
@@ -185,8 +185,24 @@ Tine.Expressomail.setTreeContextMenus = function() {
                     var window = Tine.Expressomail.AclsEditDialog.openWindow({
                         title: String.format(this.app.i18n._('Share mailbox')),
                         accountId: account,
-                        // Using 'INBOX', can use folderId
-                        globalName: 'INBOX'
+                        globalName: folderId,
+                        enableSendAs: folderId === "INBOX" ? true : false,
+                        listeners: {
+                            // NOTE: scope has to be first item in listeners! @see Ext.ux.WindowFactory
+                            scope: this,
+                            'save': function(data) {
+                                var shares = [];
+                                data.each(function(_record){
+                                    if (_record.get('readacl')
+                                        || _record.get('writeacl')
+                                        || _record.get('sendacl')
+                                    ){
+                                        shares.push(_record.get('account_id'));
+                                    }
+                                });
+                                this.ctxNode.getOwnerTree().onSharingUpdate(this.ctxNode, shares, true);
+                            }
+                        }
                     });
                 }
             }
@@ -294,6 +310,64 @@ Tine.Expressomail.setTreeContextMenus = function() {
         }
     };
 
+    //export mail dir scheduler
+    var scheduleFolderExportAction = {
+        text: this.app.i18n._('Export Folder'),
+        iconCls: 'action_export',
+        scope: this,
+        handler: function() {
+            if (this.ctxNode) {
+                var folderId = this.ctxNode.attributes.folder_id,
+                    folder = this.app.getFolderStore().getById(folderId),
+                    folderName = folder.get('globalname');
+
+                var baseStyle = 'border:1px solid rgb(214,133,2);padding:4px;margin:5px;background-color: rgb(250,239,165);';
+                var confirmQuestion = this.app.i18n._('Please, do you confirm your request to schedule a task to export all mail data contained in the following folder?')
+                                                    + '<div style="' + baseStyle + '">' + setFolderName(folderName) + '</div><p>'
+                                                    + this.app.i18n._('<b>NOTE:</b> if you choose a folder root, all child folders will be included too.<br/>')
+                                                    + this.app.i18n._('<b>IMPORTANT:</b> all events related to this action will be comunicated to your e-mail address.')
+                                                    + '</p>';
+
+                Ext.MessageBox.confirm(this.app.i18n._('Scheduler confirm'), confirmQuestion, function (btn) {
+                    if (btn == 'yes') {
+                        Ext.MessageBox.wait(this.app.i18n.gettext('Please wait'), this.app.i18n.gettext('Scheduling your request...'));
+
+                        var params = {
+                            method: 'Expressomail.schedulerFolder',
+                            folder: folderId
+                        };
+
+                        Ext.Ajax.request({
+                            params: params,
+                            scope: this,
+                            timeout: 15000, // 15s
+                            success: function(_result, _request){
+                                var scheduled = Ext.util.JSON.decode(_result.responseText);
+                                if(scheduled.status === 'failure'){
+                                    Ext.MessageBox.alert(
+                                            this.app.i18n._('Failed'),
+                                            this.app.i18n._(scheduled.message)
+                                    );
+                                } else{
+                                    Ext.MessageBox.show({
+                                        buttons: Ext.Msg.OK,
+                                        icon: Ext.MessageBox.INFO,
+                                        title: this.app.i18n._('Export Folder'),
+                                        msg: this.app.i18n._('Your scheduler was successfully done! Pay attention at you mail box for notifications.')
+                                    });
+                                }
+                            },
+                            failure: function (_result, _request) {
+                                var msgError = Ext.util.JSON.decode(_result.responseText);
+                                Ext.MessageBox.alert(this.app.i18n._('Failed'), this.app.i18n._(msgError.message));
+                            }
+                        });
+                    }
+                }, this);
+            }
+        }
+    };
+
     // mutual config options
     var config = {
         nodeName: _('Folder'),
@@ -303,30 +377,89 @@ Tine.Expressomail.setTreeContextMenus = function() {
     };
 
     // system folder ctx menu
-    config.actions = [markFolderSeenAction, 'add',manageEmlImportAction];
+    config.actions = [markFolderSeenAction, 'add',manageEmlImportAction, manageAclsAction];
     this.contextMenuSystemFolder = Tine.widgets.tree.ContextMenu.getMenu(config);
 
+    config.actions = [markFolderSeenAction, 'add',manageEmlImportAction, manageAclsAction,
+                        scheduleFolderExportAction];
+    this.contextMenuSystemFolderExp = Tine.widgets.tree.ContextMenu.getMenu(config);
+
     // user folder ctx menu
-    config.actions = [markFolderSeenAction, 'add', 'rename', 'delete',manageEmlImportAction];
+    config.actions = [markFolderSeenAction, 'add', 'rename', 'delete',manageEmlImportAction,
+                        manageAclsAction];
     this.contextMenuUserFolder = Tine.widgets.tree.ContextMenu.getMenu(config);
 
+    // user folder ctx menu
+    config.actions = [markFolderSeenAction, 'add', 'rename', 'delete',manageEmlImportAction,
+                        manageAclsAction, scheduleFolderExportAction];
+    this.contextMenuUserFolderExp = Tine.widgets.tree.ContextMenu.getMenu(config);
+
     // trash ctx menu
-    config.actions = [markFolderSeenAction, 'add', emptyFolderAction];
+    config.actions = [markFolderSeenAction, 'add', emptyFolderAction, manageAclsAction];
     this.contextMenuTrash = Tine.widgets.tree.ContextMenu.getMenu(config);
 
+    // trash ctx menu
+    config.actions = [markFolderSeenAction, 'add', emptyFolderAction, manageAclsAction,
+                        scheduleFolderExportAction];
+    this.contextMenuTrashExp = Tine.widgets.tree.ContextMenu.getMenu(config);
+
     // account ctx menu
     this.contextMenuAccount = Tine.widgets.tree.ContextMenu.getMenu({
         nodeName: this.app.i18n.n_('Account', 'Accounts', 1),
-        actions: [addFolderToRootAction, manageAclsAction, updateFolderCacheAction, editVacationAction, editRulesAction, editAccountAction],
+        actions: [addFolderToRootAction, updateFolderCacheAction, editVacationAction, editRulesAction, editAccountAction],
         scope: this,
         backend: 'Expressomail',
         backendModel: 'Account'
     });
-    
-    config.actions = [markFolderSeenAction, 'add', 'rename', deleteFolderChildAction , manageEmlImportAction];
+
+    config.actions = [markFolderSeenAction, 'add', 'rename', deleteFolderChildAction ,
+                        manageEmlImportAction, manageAclsAction];
     this.contextMenuUserFolderChildren = Tine.widgets.tree.ContextMenu.getMenu(config);
 
+    config.actions = [markFolderSeenAction, 'add', 'rename', deleteFolderChildAction ,
+                        manageEmlImportAction, manageAclsAction, scheduleFolderExportAction];
+    this.contextMenuUserFolderChildrenExp = Tine.widgets.tree.ContextMenu.getMenu(config);
+
     // context menu for unselectable folders (like public/shared namespace)
     config.actions = ['add'];
     this.unselectableFolder = Tine.widgets.tree.ContextMenu.getMenu(config);
 };
+
+/*
+ * function do split folder global name for translation parts
+ * @param String folder
+ * @returns String setname
+ */
+function setFolderName(folder) {
+    var charIndex = '/';
+    var splitData = folder.split(charIndex);
+    if (splitData.lenght <= 0){
+        return folder;
+    } else{
+        var setname = "";
+        for(var i=0; i < splitData.length; i++){
+            var adjusted = doTranslateName((splitData[i]));
+            setname =  setname + adjusted + '\\';
+        }
+        setname = setname.substring(0, setname.length -1);
+        return(setname);
+    }
+}
+
+/*
+ * function to process translation partial path
+ * @param String name
+ * @returns String
+ */
+function doTranslateName(name) {
+    this.app = Tine.Tinebase.appMgr.get('Expressomail');
+    this.i18n = this.app.i18n;
+
+    switch(name){
+        case 'user':
+            return (this.app.i18n._('Shared'));
+            break;
+        default:
+            return (this.app.i18n._(name));
+    }
+}
index fb86255..78c8994 100644 (file)
@@ -81,7 +81,8 @@ Tine.Expressomail.TreeLoader = Ext.extend(Tine.widgets.tree.Loader, {
         Ext.apply(attr, {
             leaf: !attr.has_children,
             expandable: attr.has_children,
-            cls: 'x-tree-node-collapsed',
+            cls: Boolean(attr.sharing_with.length) ? 'x-tree-node-collapsed-overlay-share'
+                                    : 'x-tree-node-collapsed',
             folder_id: attr.id,
             folderNode: true,
             allowDrop: true,
@@ -91,31 +92,39 @@ Tine.Expressomail.TreeLoader = Ext.extend(Tine.widgets.tree.Loader, {
         // show standard folders icons 
         if (account) {
             if (account.get('trash_folder') === attr.globalname) {
-                if (attr.cache_totalcount > 0) {
-                    attr.cls = 'expressomail-node-trash-full';
+                if (attr.cache_totalcount > 1) {
+                    attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-trash-full-overlay-share'
+                                                : 'expressomail-node-trash-full';
                 } else {
-                    attr.cls = 'expressomail-node-trash';
+                    attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-trash-overlay-share'
+                                                : 'expressomail-node-trash';
                 }
             }
             if (account.get('sent_folder') === attr.globalname) {
-                attr.cls = 'expressomail-node-sent';
+                attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-sent-overlay-share'
+                                            : 'expressomail-node-sent';
             }
             if (account.get('drafts_folder') === attr.globalname) {
-                attr.cls = 'expressomail-node-drafts';
+                attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-drafts-overlay-share'
+                                            : 'expressomail-node-drafts';
             }
             if (account.get('templates_folder') === attr.globalname) {
-                attr.cls = 'expressomail-node-templates';
+                attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-templates-overlay-share'
+                                            : 'expressomail-node-templates';
             }
         }
         if (attr.globalname.match(/^inbox$/i)) {
-            attr.cls = 'expressomail-node-inbox';
+            attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-inbox-overlay-share'
+                                        : 'expressomail-node-inbox';
             attr.text = this.app.i18n._hidden('INBOX');
         }
         if (attr.globalname.match(/^junk$/i)) {
-            attr.cls = 'expressomail-node-junk';
+            attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-junk-overlay-share'
+                                        : 'expressomail-node-junk';
         }
         if (attr.globalname.match(/^inbox\/arquivo remoto$/i) || attr.globalname.match(/^inbox\/arquivo remoto\//i)) {
-            attr.cls = 'expressomail-node-remote';
+            attr.cls = Boolean(attr.sharing_with.length) ? 'expressomail-node-remote-overlay-share'
+                                        : 'expressomail-node-remote';
         }
 
         if (! attr.is_selectable) {
@@ -133,35 +142,48 @@ Ext.override(Ext.tree.TreeNodeUI, {
                 rc1,
                 rc2,
                 cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow",
-                hasChild = n.hasChildNodes();
+                hasChild = n.hasChildNodes(),
+                is_sharing = Boolean(Ext.isEmpty(n.attributes.sharing_with)
+                            ? 0 : n.attributes.sharing_with.length);
             if(hasChild || n.attributes.expandable){
                 if(n.expanded){
                     cls += "-minus";
-                    c1 = "x-tree-node-collapsed";
-                    c2 = "x-tree-node-expanded";
-                    rc1 = "expressomail-node-remote";
-                    rc2 = "expressomail-node-remote-open";
+                    c1 = is_sharing ? "x-tree-node-collapsed-overlay-share" : "x-tree-node-collapsed";
+                    c2 = is_sharing ? "x-tree-node-expanded-overlay-share" : "x-tree-node-expanded";
+                    rc1 = is_sharing ? "expressomail-node-remote-overlay-share" : "expressomail-node-remote";
+                    rc2 = is_sharing ? "expressomail-node-remote-open-overlay-share" : "expressomail-node-remote-open";
                 }else{
                     cls += "-plus";
-                    c1 = "x-tree-node-expanded";
-                    c2 = "x-tree-node-collapsed";
-                    rc1 = "expressomail-node-remote-open";
-                    rc2 = "expressomail-node-remote";
+                    c1 = is_sharing ? "x-tree-node-expanded-overlay-share" : "x-tree-node-expanded";
+                    c2 = is_sharing ? "x-tree-node-collapsed-overlay-share" : "x-tree-node-collapsed";
+                    rc1 = is_sharing ? "expressomail-node-remote-open-overlay-share" : "expressomail-node-remote-open";
+                    rc2 = is_sharing ? "expressomail-node-remote-overlay-share" : "expressomail-node-remote";
                 }
+
                 if(this.wasLeaf){
-                    this.removeClass("x-tree-node-leaf");
+                    if (!is_sharing) {
+                        Ext.fly(this.elNode).removeClass("x-tree-node-leaf");
+                    }
                     this.wasLeaf = false;
+                } else {
+                    if (is_sharing && !Ext.fly(this.elNode).hasClass("x-tree-node-leaf")) {
+                        Ext.fly(this.elNode).addClass("x-tree-node-leaf");
+                    } else if (!is_sharing && Ext.fly(this.elNode).hasClass("x-tree-node-leaf")) {
+                        Ext.fly(this.elNode).removeClass("x-tree-node-leaf");
+                    }
                 }
                 if(this.c1 != c1 || this.c2 != c2){
-                    Ext.fly(this.elNode).replaceClass(c1, c2);
-                    if (Ext.fly(this.elNode).hasClass(rc1)) {
-                        Ext.fly(this.elNode).replaceClass(rc1, rc2);
+                        Ext.fly(this.elNode).replaceClass(c1, c2);
+                        if (Ext.fly(this.elNode).hasClass(rc1)) {
+                            Ext.fly(this.elNode).replaceClass(rc1, rc2);
+                        }
+                        this.c1 = c1; this.c2 = c2;
                     }
-                    this.c1 = c1; this.c2 = c2;
-                }
             }else{
                 if(!this.wasLeaf){
-                    Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-collapsed");
+                    Ext.fly(this.elNode).replaceClass(
+                        is_sharing ? "x-tree-node-expanded-overlay-share" : "x-tree-node-expanded",
+                        is_sharing ? "x-tree-node-collapsed-overlay-share" : "x-tree-node-collapsed");
                     delete this.c1;
                     delete this.c2;
                     this.wasLeaf = true;
index 1f6d559..b91b6ed 100644 (file)
@@ -130,6 +130,7 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
      * is needed by Tine.widgets.mainscreen.WestPanel to fake container tree panel
      */
     selectContainerPath: Ext.emptyFn,
+    updateGridDelay: 500,
 
     /**
      * init
@@ -197,7 +198,7 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
         this.on('containerrename', this.onFolderRename, this);
         this.on('beforecontainerrename', this.onBeforeFolderRename, this);
         this.on('containerdelete', this.onFolderDelete, this);
-        this.selModel.on('selectionchange', this.onSelectionChange, this);
+        this.selModel.on('selectionchange', this.onSelectionChangeDelay, this);
         this.folderStore.on('update', this.onUpdateFolderStore, this);
 
         // call parent::initComponent
@@ -240,6 +241,66 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
         });
     },
 
+    onSharingUpdate: function(node, shares, recursive) {
+        var added = [],
+            removed = [],
+            path = node.attributes.path,
+            record = this.folderStore.getAt(this.folderStore.findExact(
+                    'path', path));
+
+        Ext.each(shares, function(share){
+            if (node.attributes.sharing_with.indexOf(share) === -1) {
+                added.push(share);
+            }
+        }, this);
+        Ext.each(node.attributes.sharing_with, function(share){
+            if (shares.indexOf(share) === -1) {
+                removed.push(share);
+            }
+        }, this);
+
+        var editValue = function(_record){
+            if (_record.get('can_share') && (!Ext.isEmpty(added) || !Ext.isEmpty(removed))) {
+                var currentShares = _record.get('sharing_with').slice(0); // Cloning array
+                _record.beginEdit();
+                Ext.each(added, function(share){
+                    if (currentShares.indexOf(share) === -1){
+                        currentShares.push(share);
+                    }
+                }, this);
+                Ext.each(removed, function(share){
+                    var index = currentShares.indexOf(share);
+                    if (index !== -1){
+                        currentShares.splice(index, 1);
+                    }
+                }, this);
+                _record.set('sharing_with', currentShares);
+                _record.endEdit();
+            }
+        };
+        if (recursive && !node.isLeaf()) {
+            var records = this.folderStore.query('parent_path', path);
+            records.add(record);
+            records.each(editValue);
+        } else {
+            editValue.call(this, record);
+        }
+    },
+
+    /**
+     * called when a selection gets changed
+     *
+     * @param {SelectionModel} sm
+     * @param {Object} node
+     */
+    onSelectionChangeDelay: function(sm, nodes) {
+        if (this.selectionChangeDelayedTask) {
+            this.selectionChangeDelayedTask.cancel();
+        }
+        this.selectionChangeDelayedTask = new Ext.util.DelayedTask(this.onSelectionChange, this, [sm, nodes]);
+        this.selectionChangeDelayedTask.delay(this.updateGridDelay);
+    },
+
     /**
      * called when tree selection changes
      *
@@ -288,7 +349,12 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
             
             // set ftb filters according to tree selection
             ftb.addFilter(new ftb.record(filter));
-            
+
+            // prevent unnecessary loading of nodes that aren't selected anymore
+            if (!(sm.selNodes==nodes)) {
+                return;
+            }
+
             // Prevent empty path filters from trigger searchMessage
             if (Ext.isEmpty(filter.value)){
                 ftb.supressEvents = true;
@@ -321,6 +387,23 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
             });
         }
 
+        this.filterPlugin.override( {
+            setValue: function(filters) {
+                if (! this.selectNodes) {
+                    return null;
+                }
+
+                var sm = this.treePanel.getSelectionModel();
+
+                // prevent unnecessary loading of nodes that aren't selected anymore
+                if (!(sm.selNodes==this.selectNodes)) {
+                    return;
+                }
+
+                Tine.widgets.tree.FilterPlugin.superclass.setValue.call(this, filters);
+            }
+        });
+
         return this.filterPlugin;
     },
 
@@ -450,6 +533,14 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
         }
     },
 
+    setDisabledContextMenuItem: function(menu, iconClsName, disable) {
+        menu.items.each(function(item) {
+            if (item.iconCls === iconClsName) {
+                item.setDisabled(disable);
+            }
+        });
+    },
+
     /**
      * show context menu for folder tree
      *
@@ -491,16 +582,43 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
                 this.contextMenuAccount.showAt(event.getXY());
             }
         } else {
-            if (folder.get('globalname') === account.get('trash_folder')) {
-                this.contextMenuTrash.showAt(event.getXY());
-            } else if (! folder.get('is_selectable')){
-                this.unselectableFolder.showAt(event.getXY());
-            } else if (folder.get('system_folder')) {
-                this.contextMenuSystemFolder.showAt(event.getXY());
-            } else if(folder.get('has_children')){
-                this.contextMenuUserFolderChildren.showAt(event.getXY());
-            } else {
-                this.contextMenuUserFolder.showAt(event.getXY());
+            var is_shared = folder.get('parent').indexOf('user'),
+                export_folder_enabled = Tine.Expressomail.registry.get('enableMailDirExport'),
+                can_share = folder.get('can_share'),
+                action = 'action_managePermissions';
+            if ((is_shared < 0) && (export_folder_enabled)){
+                if (folder.get('globalname') === account.get('trash_folder')) {
+                    this.setDisabledContextMenuItem(this.contextMenuTrashExp, action, !can_share);
+                    this.contextMenuTrashExp.showAt(event.getXY());
+                } else if (! folder.get('is_selectable')){
+                    this.unselectableFolder.showAt(event.getXY());
+                } else if (folder.get('system_folder')) {
+                    this.setDisabledContextMenuItem(this.contextMenuSystemFolderExp, action, !can_share);
+                    this.contextMenuSystemFolderExp.showAt(event.getXY());
+                } else if(folder.get('has_children')){
+                    this.setDisabledContextMenuItem(this.contextMenuUserFolderChildrenExp, action, !can_share);
+                    this.contextMenuUserFolderChildrenExp.showAt(event.getXY());
+                } else {
+                    this.setDisabledContextMenuItem(this.contextMenuUserFolderExp, action, !can_share);
+                    this.contextMenuUserFolderExp.showAt(event.getXY());
+                }
+            }
+            else{
+                if (folder.get('globalname') === account.get('trash_folder')) {
+                    this.setDisabledContextMenuItem(this.contextMenuTrash, action, !can_share);
+                    this.contextMenuTrash.showAt(event.getXY());
+                } else if (! folder.get('is_selectable')){
+                    this.unselectableFolder.showAt(event.getXY());
+                } else if (folder.get('system_folder')) {
+                    this.setDisabledContextMenuItem(this.contextMenuSystemFolder, action, !can_share);
+                    this.contextMenuSystemFolder.showAt(event.getXY());
+                } else if(folder.get('has_children')){
+                    this.setDisabledContextMenuItem(this.contextMenuUserFolderChildren, action, !can_share);
+                    this.contextMenuUserFolderChildren.showAt(event.getXY());
+                } else {
+                    this.setDisabledContextMenuItem(this.contextMenuUserFolder, action, !can_share);
+                    this.contextMenuUserFolder.showAt(event.getXY());
+                }
             }
         }
     },
@@ -814,6 +932,53 @@ Ext.extend(Tine.Expressomail.TreePanel, Ext.tree.TreePanel, {
                 progressEl.setVisible(isSelected && cacheStatus !== 'complete' && cacheStatus !== 'disconnect' && progress !== 100 && lastCacheStatus !== 'complete');
             }
         }
+        if (node) {
+            if (Boolean(folder.get('sharing_with').length) !== Boolean(node.attributes.sharing_with.length)) {
+                var classesMap = [
+                    'x-tree-node-expanded',
+                    'x-tree-node-collapsed',
+                    'expressomail-node-trash',
+                    'expressomail-node-trash-full',
+                    'expressomail-node-sent',
+                    'expressomail-node-inbox',
+                    'expressomail-node-drafts',
+                    'expressomail-node-templates',
+                    'expressomail-node-junk',
+                    'expressomail-node-remote',
+                    'expressomail-node-remote-open'
+                ];
+
+                // Find classes to change
+                var foundClasses = new Array();
+                Ext.each(classesMap, function(item){
+                    if (Ext.fly(node.getUI().elNode).hasClass(item)){
+                        foundClasses.push(item);
+                    } else if (Ext.fly(node.getUI().elNode).hasClass(item + '-overlay-share')) {
+                        foundClasses.push(item + '-overlay-share');
+                    }
+                });
+
+                Ext.each(foundClasses, function(oldCls){
+                    var newCls = Boolean(folder.get('sharing_with').length) ? oldCls + '-overlay-share'
+                                                                    : oldCls.replace('-overlay-share', '');
+
+                    if (Boolean(folder.get('sharing_with').length)
+                        && !Ext.fly(node.getUI().elNode).hasClass("x-tree-node-leaf"))
+                    {
+                        Ext.fly(node.getUI().elNode).addClass("x-tree-node-leaf");
+                    } else if (!Boolean(folder.get('sharing_with').length)
+                                && Ext.fly(node.getUI().elNode).hasClass("x-tree-node-leaf"))
+                    {
+                        if (!node.getUI().wasLeaf) {
+                            Ext.fly(node.getUI().elNode).removeClass("x-tree-node-leaf");
+                        }
+                    }
+                    Ext.fly(node.getUI().elNode).replaceClass(oldCls, newCls);
+                }, this);
+            }
+            node.attributes.sharing_with = folder.get('sharing_with');
+        }
+
     },
 
     /**
index f87865d..5fa5dba 100644 (file)
@@ -375,7 +375,17 @@ Tine.Expressomail.sieve.RuleEditDialog = Ext.extend(Tine.widgets.dialog.EditDial
                             allowBlank: false,
                             emptyText: 'test@example.org',
                             width: 200,
-                            hideLabel: true
+                            hideLabel: true,
+                            validator: function(text){
+                                allowedDomais = Tine.Expressomail.registry.get("allowedDomais");
+                                if(allowedDomais){
+                                    domains = allowedDomais.replace(/\s/g, "").replace(/\./g, "\\.").replace(/,/g, "|");
+                                    domainRegexp = new RegExp("(" + domains +")$");
+                                    return domainRegexp.test(text)?true:Tine.Tinebase.appMgr.get('Expressomail').i18n._('Redirect to this address not allowed.');;
+                                }else{
+                                    return true
+                                }
+                            }
                         }]
                     }, {
                         id: this.idPrefix + 'reject',
index 0a06328..b9f6f1d 100644 (file)
@@ -9,18 +9,17 @@
 #   <p.schuele@metaways.de>, 2012.
 msgid ""
 msgstr ""
-"Project-Id-Version: Tine 2.0\n"
+"Project-Id-Version: ExpressoBr - Expressomail\n"
 "POT-Creation-Date: 2008-05-17 22:12+0100\n"
-"PO-Revision-Date: 2015-08-24 10:49-0300\n"
-"Last-Translator: Rommel Cysne <rommel.cysne@serpro.gov.br>\n"
-"Language-Team: German (http://www.transifex.com/projects/p/tine20/language/"
-"de/)\n"
+"PO-Revision-Date: 2015-08-24 15:07-0300\n"
+"Last-Translator: Cassiano Dal Pizzol <cassiano.dalpizzol@serpro.gov.br>\n"
+"Language-Team: ExpressoBr Translators\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Language: de\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SourceCharset: UTF-8\n"
 "X-Generator: Poedit 1.5.4\n"
 
 #: Acl/Rights.php:106
index d349938..4f691a3 100644 (file)
@@ -1,11 +1,12 @@
 msgid ""
 msgstr ""
-"Project-Id-Version: Tine 2.0 - Expressomail\n"
+"Project-Id-Version: ExpressoBr - Expressomail\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2008-05-17 22:12+0100\n"
-"PO-Revision-Date: 2015-08-24 10:49-0300\n"
-"Last-Translator: Rommel Cysne <rommel.cysne@serpro.gov.br>\n"
-"Language-Team: Tine 2.0 Translators\n"
+"PO-Revision-Date: 2015-08-24 15:07-0300\n"
+"Last-Translator: Cassiano Dal Pizzol <cassiano.dalpizzol@serpro.gov.br>\n"
+"Language-Team: ExpressoBr Translators\n"
+"Language: en\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -13,7 +14,6 @@ msgstr ""
 "X-Launchpad-Export-Date: 2012-03-02 09:32+0000\n"
 "X-Generator: Poedit 1.5.4\n"
 "X-Poedit-SourceCharset: UTF-8\n"
-"Language: en\n"
 
 #: Acl/Rights.php:106
 msgid "manage email accounts"
@@ -1014,59 +1014,59 @@ msgstr "All drafts"
 msgid "All mails with the draft flag"
 msgstr "All mails with the draft flag"
 
-#: js/GridDetailsPanel.js:255
+#: js/GridDetailsPanel.js: 255
 msgid "Verification Failed!"
 msgstr "Verification Failed!"
 
-#: js/GridDetailsPanel.js:251
+#: js/GridDetailsPanel.js: 251
 msgid "Verification Successful!"
 msgstr "Verification Successful!"
 
-#: js/GridDetailsPanel.js:245
+#: js/GridDetailsPanel.js: 245
 msgid "Digital Signature"
 msgstr "Digital Signature"
 
-#: js/GridDetailsPanel.js:547
+#: js/GridDetailsPanel.js: 547
 msgid "Verification Details"
 msgstr "Verification Details"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js: 542
 msgid "Serial Number"
 msgstr "Serial Number"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js: 542
 msgid "Issuer"
 msgstr "Issuer"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js: 542
 msgid "Owner"
 msgstr "Owner"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js: 542
 msgid "Valid From"
 msgstr "Valid From"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js: 542
 msgid "Valid To"
 msgstr "Valid To"
 
-#: Smime.php:129
+#: Smime.php: 129
 msgid "Message Integrity Verification Failure"
 msgstr "Message Integrity Verification Failure"
 
-#: js/GridDetailsPanel.js:561
+#: js/GridDetailsPanel.js: 561
 msgid "Sender's email is different from Digital Certificate's email"
 msgstr "Sender's email is different from Digital Certificate's email"
 
-#: js/GridDetailsPanel.js:392
+#: js/GridDetailsPanel.js: 392
 msgid "show details of digitial signature verification"
 msgstr "show details of digitial signature verification"
 
-#: Preference.php:166
+#: Preference.php: 166
 msgid "Sign messages by default when sending mail"
 msgstr "Sign messages by default when sending mail"
 
-#: Preference.php:166
+#: Preference.php: 166
 msgid ""
 "Choose yes, to open message editor with toggle button \"Sign Message\" "
 "pressed"
@@ -1074,11 +1074,11 @@ msgstr ""
 "Choose yes, to open message editor with toggle button \"Sign Message\" "
 "pressed"
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js: 199
 msgid "Digitally Sign Mail"
 msgstr "Digitally Sign Mail"
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js: 199
 msgid "Activate this toggle button to sign a message on send"
 msgstr "Activate this toggle button to sign a message on send"
 
index d490d58..438de70 100644 (file)
@@ -2,18 +2,18 @@
 # Translators:
 msgid ""
 msgstr ""
-"Project-Id-Version: Tine 2.0 - Expresso Mail\n"
+"Project-Id-Version: ExpressoBr - Expressomail\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2014-04-09 17:14-0300\n"
-"PO-Revision-Date: 2015-08-24 10:49-0300\n"
-"Last-Translator: Rommel Cysne <rommel.cysne@serpro.gov.br>\n"
-"Language-Team: Expresso Castilian Translators\n"
+"PO-Revision-Date: 2015-08-24 15:07-0300\n"
+"Last-Translator: Cassiano Dal Pizzol <cassiano.dalpizzol@serpro.gov.br>\n"
+"Language-Team: ExpressoBr Translators\n"
 "Language: es\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SourceCharset: UTF-8\n"
 "X-Poedit-KeywordsList: _\n"
 "X-Poedit-Basepath: ..\n"
 "X-Generator: Poedit 1.5.4\n"
index 6400d00..1418b03 100644 (file)
@@ -6,18 +6,17 @@
 # gustavotonini <GUSTAVOTONINI@gmail.com>, 2012
 msgid ""
 msgstr ""
-"Project-Id-Version: Tine 2.0\n"
+"Project-Id-Version: ExpressoBr - Expressomail\n"
 "POT-Creation-Date: 2008-05-17 22:12+0100\n"
-"PO-Revision-Date: 2015-08-24 10:50-0300\n"
-"Last-Translator: Rommel Cysne <rommel.cysne@serpro.gov.br>\n"
-"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/"
-"tine20/language/pt_BR/)\n"
+"PO-Revision-Date: 2015-08-31 17:04-0300\n"
+"Last-Translator: Fernando Alberto Reuter Wendt <fernando-alberto.wendt@serpro.gov.br>\n"
+"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/tine20/language/pt_BR/)\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Language: pt_BR\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SourceCharset: UTF-8\n"
 "X-Generator: Poedit 1.5.4\n"
 
 #: Exception/PasswordPolicyViolation.php:22
@@ -42,8 +41,7 @@ msgstr "Reportar erros"
 
 #: Acl/Rights.php:148
 msgid "Report bugs to the software vendor directly when they occur."
-msgstr ""
-"Reportar problemas para o desenvolvedor diretamente quando eles ocorrerem"
+msgstr "Reportar problemas para o desenvolvedor diretamente quando eles ocorrerem"
 
 #: Acl/Rights.php:151
 msgid "Check version"
@@ -59,9 +57,7 @@ msgstr "Administrar seu perfil"
 
 #: Acl/Rights.php:156
 msgid "The right to manage the own profile (selected contact data)."
-msgstr ""
-"O direito para gerenciar o próprio perfil (informação de contato "
-"selecionada)."
+msgstr "O direito para gerenciar o próprio perfil (informação de contato selecionada)."
 
 #: Acl/Rights.php:159
 msgid "Manage own client state"
@@ -91,7 +87,8 @@ msgstr "descrição de direitos de execução"
 msgid "default"
 msgstr "padrão"
 
-#: Frontend/Http.php:396 js/ExceptionHandler.js:149
+#: Frontend/Http.php:396
+#: js/ExceptionHandler.js:149
 msgid "Authorisation Required"
 msgstr "Autorização necessária"
 
@@ -99,11 +96,13 @@ msgstr "Autorização necessária"
 msgid "Your session is not valid. You need to login again."
 msgstr "Sua sessão não é válida.  Você precisa logar-se de novo."
 
-#: Frontend/Http.php:422 js/ExceptionDialog.js:62
+#: Frontend/Http.php:422
+#: js/ExceptionDialog.js:62
 msgid "Abnormal End"
 msgstr "Fim Anormal"
 
-#: Frontend/Http.php:423 js/ExceptionDialog.js:134
+#: Frontend/Http.php:423
+#: js/ExceptionDialog.js:134
 msgid "An error occurred, the program ended abnormal."
 msgstr "Ocorreu um erro, o programa terminou de maneira anormal."
 
@@ -115,8 +114,12 @@ msgstr "por"
 msgid "Changed fields:"
 msgstr "Campos modificados:"
 
-#: User/Abstract.php:281 User/Abstract.php:282 User/Abstract.php:283
-#: User/Abstract.php:284 User/Abstract.php:285 js/ux/ConnectionStatus.js:58
+#: User/Abstract.php:281
+#: User/Abstract.php:282
+#: User/Abstract.php:283
+#: User/Abstract.php:284
+#: User/Abstract.php:285
+#: js/ux/ConnectionStatus.js:58
 #: Group/Abstract.php:191
 msgid "unknown"
 msgstr "desconhecido"
@@ -264,8 +267,7 @@ msgstr "Validador da Sessão UA"
 
 #: Config.php:434
 msgid "Destroy session if the users user agent string changes."
-msgstr ""
-"Extinguir a sessão se os usuários usuarem agente de mudança de seqüência."
+msgstr "Extinguir a sessão se os usuários usuarem agente de mudança de seqüência."
 
 #: Config.php:442
 msgid "Files Directory"
@@ -273,14 +275,15 @@ msgstr "Diretório de arquivos"
 
 #: Config.php:444
 msgid "Directory with web server write access for user files."
-msgstr ""
-"Diretório com direito de escrita no servidor web para os arquivos do usuário"
+msgstr "Diretório com direito de escrita no servidor web para os arquivos do usuário"
 
-#: Config.php:452 Config.php:454
+#: Config.php:452
+#: Config.php:454
 msgid "User may change password"
 msgstr "Usuário pode modificar a senha"
 
-#: Config.php:462 Config.php:464
+#: Config.php:462
+#: Config.php:464
 msgid "Enable password policy"
 msgstr "Política de senha disponível"
 
@@ -345,11 +348,8 @@ msgid "Automatic bugreports"
 msgstr "Relatórios de erros automáticos"
 
 #: Config.php:544
-msgid ""
-"Always send bugreports, even on timeouts and other exceptions / failures."
-msgstr ""
-"Enviar sempre relatórios de erros, mesmo após tempo limite ou outras "
-"exceções / falhas."
+msgid "Always send bugreports, even on timeouts and other exceptions / failures."
+msgstr "Enviar sempre relatórios de erros, mesmo após tempo limite ou outras exceções / falhas."
 
 #: Config.php:552
 msgid "Last sessions cleanup run"
@@ -415,7 +415,8 @@ msgstr "modificado"
 msgid "record changed"
 msgstr "registros modificado"
 
-#: Preference.php:87 js/widgets/TimezoneChooser.js:37
+#: Preference.php:87
+#: js/widgets/TimezoneChooser.js:37
 msgid "Timezone"
 msgstr "Fuso horário"
 
@@ -423,7 +424,8 @@ msgstr "Fuso horário"
 msgid "The timezone in which dates are shown in Tine 2.0."
 msgstr "O fuso horário no qual as datas são exibidas no Tine 2.0."
 
-#: Preference.php:91 js/widgets/LangChooser.js:35
+#: Preference.php:91
+#: js/widgets/LangChooser.js:35
 msgid "Language"
 msgstr "Idioma"
 
@@ -445,9 +447,7 @@ msgstr "Tipo de Janela"
 
 #: Preference.php:100
 msgid "You can choose between modal windows or normal browser popup windows."
-msgstr ""
-"Você pode escolher entre janelas modais ou janelas normais que surgem no "
-"navegador"
+msgstr "Você pode escolher entre janelas modais ou janelas normais que surgem no navegador"
 
 #: Preference.php:103
 msgid "Confirm Logout"
@@ -461,7 +461,8 @@ msgstr "Mostrar diálogo de confiramação na saída"
 msgid "Data"
 msgstr "Dados"
 
-#: Export/Pdf.php:216 js/widgets/tags/TagsPanel.js:57
+#: Export/Pdf.php:216
+#: js/widgets/tags/TagsPanel.js:57
 msgid "Tags"
 msgstr "Rótulos"
 
@@ -477,17 +478,21 @@ msgstr "Atividades"
 msgid "Profile Information"
 msgstr "Informações de Perfil"
 
-#: js/AdminPanel.js:79 js/widgets/EditRecord.js:168
+#: js/AdminPanel.js:79
+#: js/widgets/EditRecord.js:168
 #: js/widgets/dialog/EditDialog.js:309
 msgid "Apply"
 msgstr "Aplicar"
 
-#: js/AdminPanel.js:94 js/widgets/TimezoneChooser.js:77
+#: js/AdminPanel.js:94
+#: js/widgets/TimezoneChooser.js:77
 #: js/widgets/LangChooser.js:68
+#: js/TreeContextMenu.js:317
 msgid "Please Wait"
 msgstr "Por favor, aguarde"
 
-#: js/AdminPanel.js:156 js/widgets/container/GrantsGrid.js:43
+#: js/AdminPanel.js:156
+#: js/widgets/container/GrantsGrid.js:43
 msgid "Read"
 msgstr "Ler"
 
@@ -495,7 +500,8 @@ msgstr "Ler"
 msgid "The field is readable part of the profile"
 msgstr "O campo é parte legível do perfil"
 
-#: js/AdminPanel.js:161 js/widgets/container/GrantsGrid.js:47
+#: js/AdminPanel.js:161
+#: js/widgets/container/GrantsGrid.js:47
 msgid "Edit"
 msgstr "Editar"
 
@@ -503,22 +509,29 @@ msgstr "Editar"
 msgid "The field is editable part of the profile"
 msgstr "O campo é parte legível do perfil"
 
-#: js/AdminPanel.js:175 js/widgets/dialog/DuplicateResolveGridPanel.js:139
+#: js/AdminPanel.js:175
+#: js/widgets/dialog/DuplicateResolveGridPanel.js:139
 msgid "Field Name"
 msgstr "Nome do campo"
 
-#: js/AboutDialog.js:41 js/MainMenu.js:112
+#: js/AboutDialog.js:41
+#: js/MainMenu.js:112
 msgid "About {0}"
 msgstr "Sobre {0}"
 
-#: js/AboutDialog.js:60 js/CreditsScreen.js:53 js/LicenseScreen.js:51
-#: js/PasswordChangeDialog.js:66 js/widgets/EditRecord.js:157
+#: js/AboutDialog.js:60
+#: js/CreditsScreen.js:53
+#: js/LicenseScreen.js:51
+#: js/PasswordChangeDialog.js:66
+#: js/widgets/EditRecord.js:157
 #: js/widgets/tags/TagsMassAttachAction.js:84
 #: js/widgets/dialog/MultiOptionsDialog.js:102
 #: js/widgets/dialog/AddToRecordPanel.js:111
 #: js/widgets/dialog/PreferencesDialog.js:109
-#: js/widgets/dialog/EditDialog.js:298 js/widgets/ActivitiesPanel.js:311
-#: js/widgets/container/ContainerSelect.js:490 js/ux/form/LayerCombo.js:186
+#: js/widgets/dialog/EditDialog.js:298
+#: js/widgets/ActivitiesPanel.js:311
+#: js/widgets/container/ContainerSelect.js:490
+#: js/ux/form/LayerCombo.js:186
 msgid "Ok"
 msgstr "OK"
 
@@ -539,23 +552,16 @@ msgid "Contributors"
 msgstr "Contribuidores"
 
 #: js/tineInit.js:603
-msgid ""
-"Fatal Error: Client self-update failed, please contact your administrator "
-"and/or restart/reload your browser."
-msgstr ""
-"Erro Fatal: a auto-atualização do Cliente falhou, favor contactar o "
-"administrador e/ou reiniciar/recarregar seu navegador."
+msgid "Fatal Error: Client self-update failed, please contact your administrator and/or restart/reload your browser."
+msgstr "Erro Fatal: a auto-atualização do Cliente falhou, favor contactar o administrador e/ou reiniciar/recarregar seu navegador."
 
 #: js/AppManager.js:208
 msgid "Missing Applications"
 msgstr "Faltando Aplicativos"
 
 #: js/AppManager.js:209
-msgid ""
-"There are no applications enabled for you. Please contact your administrator."
-msgstr ""
-"Não existem aplicativos disponíveis para você.  Por favor contacte o "
-"administrador do sistema."
+msgid "There are no applications enabled for you. Please contact your administrator."
+msgstr "Não existem aplicativos disponíveis para você.  Por favor contacte o administrador do sistema."
 
 #: js/CreditsScreen.js:36
 msgid "Credits"
@@ -565,13 +571,18 @@ msgstr "Créditos"
 msgid "Usage:&#160;"
 msgstr "Uso:&#160;"
 
-#: js/common.js:255 js/common.js:260 js/widgets/tags/TagToggleBox.js:112
-#: js/widgets/tags/TagToggleBox.js:117 js/widgets/tags/TagsPanel.js:128
-#: js/widgets/tags/TagCombo.js:134 js/widgets/tags/TagCombo.js:139
+#: js/common.js:255
+#: js/common.js:260
+#: js/widgets/tags/TagToggleBox.js:112
+#: js/widgets/tags/TagToggleBox.js:117
+#: js/widgets/tags/TagsPanel.js:128
+#: js/widgets/tags/TagCombo.js:134
+#: js/widgets/tags/TagCombo.js:139
 msgid "personal"
 msgstr "pessoal"
 
-#: js/common.js:273 js/common.js:311
+#: js/common.js:273
+#: js/common.js:311
 msgid "No Information"
 msgstr "Nenhuma Informação"
 
@@ -599,15 +610,18 @@ msgid_plural "{0} seconds"
 msgstr[0] "segundo"
 msgstr[1] "segunedos"
 
-#: js/LoginPanel.js:80 js/LoginPanel.js:118
+#: js/LoginPanel.js:80
+#: js/LoginPanel.js:118
 msgid "Login"
 msgstr "Login"
 
-#: js/LoginPanel.js:90 js/widgets/dialog/CredentialsDialog.js:61
+#: js/LoginPanel.js:90
+#: js/widgets/dialog/CredentialsDialog.js:61
 msgid "Username"
 msgstr "Usuário"
 
-#: js/LoginPanel.js:107 js/widgets/dialog/CredentialsDialog.js:65
+#: js/LoginPanel.js:107
+#: js/widgets/dialog/CredentialsDialog.js:65
 msgid "Password"
 msgstr "Senha"
 
@@ -616,14 +630,8 @@ msgid "Tine 2.0 is made for you"
 msgstr "Tine 2.0 é feito para você"
 
 #: js/LoginPanel.js:139
-msgid ""
-"Tine 2.0 wants to make business collaboration easier and more enjoyable - "
-"for your needs! So you are warmly welcome to discuss with us, bring in ideas "
-"and get help."
-msgstr ""
-"Tine 2.0 quer tornar a colaboração nos negócios mais fácil e mais amigável - "
-"para as suas necessidades! Então você é bem vindo para discutir conosco, "
-"trazer idéias e obter ajuda."
+msgid "Tine 2.0 wants to make business collaboration easier and more enjoyable - for your needs! So you are warmly welcome to discuss with us, bring in ideas and get help."
+msgstr "Tine 2.0 quer tornar a colaboração nos negócios mais fácil e mais amigável - para as suas necessidades! Então você é bem vindo para discutir conosco, trazer idéias e obter ajuda."
 
 #: js/LoginPanel.js:145
 msgid "Tine 2.0 Homepage"
@@ -638,12 +646,8 @@ msgid "Translations"
 msgstr "Traduções"
 
 #: js/LoginPanel.js:152
-msgid ""
-"If you miss a language, or your language is not supported completely, you "
-"can help our translation teams at transifex."
-msgstr ""
-"Se você omitir o idioma ou seu idioma não é suportado completamente, você "
-"pode pedir ajuda à nossa equipe de tradução na Transifex."
+msgid "If you miss a language, or your language is not supported completely, you can help our translation teams at transifex."
+msgstr "Se você omitir o idioma ou seu idioma não é suportado completamente, você pode pedir ajuda à nossa equipe de tradução na Transifex."
 
 #: js/LoginPanel.js:155
 msgid "Tine 2.0 Translation Portal"
@@ -653,18 +657,15 @@ msgstr "Portal de Tradução do Tine 2.0"
 msgid "about {0} minutes"
 msgstr "sobre {0} minutos"
 
-#: js/LoginPanel.js:205 js/LoginPanel.js:430
+#: js/LoginPanel.js:205
+#: js/LoginPanel.js:430
 msgid "Tine 2.0 needs your help"
 msgstr "Tine 2.0 precisa da sua ajuda"
 
-#: js/LoginPanel.js:207 js/LoginPanel.js:432
-msgid ""
-"We regularly need your feedback to make the next Tine 2.0 releases fit your "
-"needs even better. Help us and yourself by participating:"
-msgstr ""
-"Nós necessitamos ter o seu retorno regularmente para que os próximos "
-"lançamentos do Tine 2.0 para atender cada vez melhor suas necessidades.  "
-"Ajude-nos e a você mesmo participando:"
+#: js/LoginPanel.js:207
+#: js/LoginPanel.js:432
+msgid "We regularly need your feedback to make the next Tine 2.0 releases fit your needs even better. Help us and yourself by participating:"
+msgstr "Nós necessitamos ter o seu retorno regularmente para que os próximos lançamentos do Tine 2.0 para atender cada vez melhor suas necessidades.  Ajude-nos e a você mesmo participando:"
 
 #: js/LoginPanel.js:213
 msgid "participate!"
@@ -691,12 +692,8 @@ msgid "Browser incompatible?"
 msgstr "Navegador incompatível ?"
 
 #: js/LoginPanel.js:286
-msgid ""
-"You are using an unrecognized browser. This could result in unexpected "
-"behaviour."
-msgstr ""
-"Você está usando um navegador desconhecido.  Isso pode resultar num "
-"comportamento inesperado."
+msgid "You are using an unrecognized browser. This could result in unexpected behaviour."
+msgstr "Você está usando um navegador desconhecido.  Isso pode resultar num comportamento inesperado."
 
 #: js/LoginPanel.js:292
 msgid "You might try one of these browsers:"
@@ -706,7 +703,8 @@ msgstr "Você poderia tentar um desses navegadores:"
 msgid "Logging you in..."
 msgstr "Autenticando você no..."
 
-#: js/LoginPanel.js:350 js/widgets/tree/ContextMenu.js:191
+#: js/LoginPanel.js:350
+#: js/widgets/tree/ContextMenu.js:191
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:641
 #: js/widgets/persistentfilter/PickerPanel.js:317
 #: js/widgets/persistentfilter/PickerPanel.js:355
@@ -719,11 +717,13 @@ msgstr "Por favor aguarde"
 msgid "Login successful. Loading {0}..."
 msgstr "Login bem sucedido.  Carregando {0}..."
 
-#: js/LoginPanel.js:363 js/MainMenu.js:227
+#: js/LoginPanel.js:363
+#: js/MainMenu.js:227
 msgid "Please wait!"
 msgstr "Favor aguardar!"
 
-#: js/LoginPanel.js:371 js/ExceptionHandler.js:214
+#: js/LoginPanel.js:371
+#: js/ExceptionHandler.js:214
 msgid "Connection lost, please check your network!"
 msgstr "Conexão perdida, favor verificar sua rede!"
 
@@ -735,16 +735,20 @@ msgstr "Falha na autenticação"
 msgid "Your username and/or your password are wrong!!!"
 msgstr "Seu nome de usuário e/ou sua senha estão errados"
 
-#: js/LoginPanel.js:388 js/widgets/dialog/CredentialsDialog.js:126
+#: js/LoginPanel.js:388
+#: js/widgets/dialog/CredentialsDialog.js:126
 #: js/widgets/dialog/PreferencesDialog.js:245
 #: js/widgets/dialog/PreferencesDialog.js:274
-#: js/widgets/dialog/EditDialog.js:671 js/widgets/dialog/ExportDialog.js:150
+#: js/widgets/dialog/EditDialog.js:671
+#: js/widgets/dialog/ExportDialog.js:150
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:603
 msgid "Errors"
 msgstr "Erros"
 
-#: js/LoginPanel.js:388 js/widgets/dialog/CredentialsDialog.js:126
-#: js/widgets/dialog/EditDialog.js:691 js/widgets/dialog/ExportDialog.js:150
+#: js/LoginPanel.js:388
+#: js/widgets/dialog/CredentialsDialog.js:126
+#: js/widgets/dialog/EditDialog.js:691
+#: js/widgets/dialog/ExportDialog.js:150
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:603
 msgid "Please fix the errors noted."
 msgstr "Favor corrigir os erros observados"
@@ -773,17 +777,20 @@ msgstr "Nova Senha"
 msgid "Repeat new Password"
 msgstr "Repeta a nova Senha"
 
-#: js/PasswordChangeDialog.js:60 js/widgets/EditRecord.js:178
+#: js/PasswordChangeDialog.js:60
+#: js/widgets/EditRecord.js:178
 #: js/widgets/tags/TagToggleBox.js:59
 #: js/widgets/tags/TagsMassAttachAction.js:105
 #: js/widgets/dialog/DuplicateMergeDialog.js:79
 #: js/widgets/dialog/MultiOptionsDialog.js:109
 #: js/widgets/dialog/AddToRecordPanel.js:103
 #: js/widgets/dialog/PreferencesDialog.js:117
-#: js/widgets/dialog/EditDialog.js:318 js/widgets/dialog/WizardPanel.js:187
+#: js/widgets/dialog/EditDialog.js:318
+#: js/widgets/dialog/WizardPanel.js:187
 #: js/widgets/ActivitiesPanel.js:303
 #: js/widgets/persistentfilter/EditPersistentFilterPanel.js:76
-#: js/widgets/container/ContainerSelect.js:481 js/ExceptionDialog.js:100
+#: js/widgets/container/ContainerSelect.js:481
+#: js/ExceptionDialog.js:100
 #: js/ux/form/LayerCombo.js:193
 msgid "Cancel"
 msgstr "Cancelar"
@@ -804,7 +811,8 @@ msgstr "Sucesso"
 msgid "Your password has been changed."
 msgstr "Sua senha foi alterada."
 
-#: js/PasswordChangeDialog.js:100 js/PasswordChangeDialog.js:110
+#: js/PasswordChangeDialog.js:100
+#: js/PasswordChangeDialog.js:110
 #: js/widgets/relation/GenericPickerGridPanel.js:707
 #: js/widgets/relation/GenericPickerGridPanel.js:720
 #: js/widgets/dialog/ImportDialog.js:654
@@ -825,7 +833,8 @@ msgstr "Usuário: {0}"
 msgid "Debug Console (Ctrl + F11)"
 msgstr "Console de Depuração (Ctrl + F11)"
 
-#: js/MainMenu.js:124 js/widgets/dialog/PreferencesPanel.js:36
+#: js/MainMenu.js:124
+#: js/widgets/dialog/PreferencesPanel.js:36
 msgid "Preferences"
 msgstr "Preferências"
 
@@ -851,8 +860,7 @@ msgstr "Permitir notificações na Área de Trabalho"
 
 #: js/MainMenu.js:154
 msgid "Request permissions for webkit desktop notifications."
-msgstr ""
-"Solicitação de permissão para notificações do webkit na área de trabalho."
+msgstr "Solicitação de permissão para notificações do webkit na área de trabalho."
 
 #: js/MainMenu.js:164
 msgid "Install web app"
@@ -862,8 +870,10 @@ msgstr "Instalar applicação web"
 msgid "Install Tine 2.0 as web app in your browser."
 msgstr "Instalar Tine 2.0 como uma aplicação web no seu navegador."
 
-#: js/MainMenu.js:213 js/widgets/grid/GridPanel.js:1667
-#: js/widgets/tree/ContextMenu.js:346 js/widgets/dialog/EditDialog.js:698
+#: js/MainMenu.js:213
+#: js/widgets/grid/GridPanel.js:1667
+#: js/widgets/tree/ContextMenu.js:346
+#: js/widgets/dialog/EditDialog.js:698
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:638
 #: js/widgets/persistentfilter/PickerPanel.js:315
 msgid "Confirm"
@@ -906,40 +916,24 @@ msgid "Not Found"
 msgstr "Não encontrado"
 
 #: js/ExceptionHandler.js:175
-msgid ""
-"Sorry, your request could not be completed because the required data could "
-"not be found. In most cases this means that someone already deleted the "
-"data. Please refresh your current view."
-msgstr ""
-"Desculpe, sua solicitação não pode ser completada porque a informação "
-"requisitada não pode ser encontrada.  Em muitos casos isso parece que alguém "
-"já apagou a informação.  Por favor, atualize sua visão atual."
+msgid "Sorry, your request could not be completed because the required data could not be found. In most cases this means that someone already deleted the data. Please refresh your current view."
+msgstr "Desculpe, sua solicitação não pode ser completada porque a informação requisitada não pode ser encontrada.  Em muitos casos isso parece que alguém já apagou a informação.  Por favor, atualize sua visão atual."
 
 #: js/ExceptionHandler.js:183
 msgid "Concurrent Updates"
 msgstr "Atualizações Concorrentes"
 
 #: js/ExceptionHandler.js:184
-msgid ""
-"Someone else saved this record while you where editing the data. You need to "
-"reload and make your changes again."
-msgstr ""
-"Alguém salvou este registro enquanto você estava editando a informação.  "
-"Você deverecarregar e fazer suas modificações de novo."
+msgid "Someone else saved this record while you where editing the data. You need to reload and make your changes again."
+msgstr "Alguém salvou este registro enquanto você estava editando a informação.  Você deverecarregar e fazer suas modificações de novo."
 
 #: js/ExceptionHandler.js:192
 msgid "Service Unavailable"
 msgstr "Serviço Indisponível"
 
 #: js/ExceptionHandler.js:193
-msgid ""
-"The server is currently unable to handle the request due to a temporary "
-"overloading, maintenance or misconfiguration of the server. Please try again "
-"or contact your administrator."
-msgstr ""
-"O servidor não está disponível para processar sua solicitação devido a uma "
-"sobrecarga temporária, manutenção ou reconfiguração do servidor.  Favor "
-"tente de novoou contacte o administrador do sistema."
+msgid "The server is currently unable to handle the request due to a temporary overloading, maintenance or misconfiguration of the server. Please try again or contact your administrator."
+msgstr "O servidor não está disponível para processar sua solicitação devido a uma sobrecarga temporária, manutenção ou reconfiguração do servidor.  Favor tente de novoou contacte o administrador do sistema."
 
 #: js/ExceptionHandler.js:199
 msgid "Server Message:"
@@ -951,56 +945,39 @@ msgstr "Informação inválida"
 
 #: js/ExceptionHandler.js:202
 msgid "Your input data is not valid. Please provide valid data."
-msgstr ""
-"O dado informado não é válido.  Favor providenciar uma informação válida."
+msgstr "O dado informado não é válido.  Favor providenciar uma informação válida."
 
 #: js/ExceptionHandler.js:220
 msgid "Timeout"
 msgstr "Tempo limite"
 
 #: js/ExceptionHandler.js:221
-msgid ""
-"Sorry, some timeout occured while processing your request. Please reload "
-"your browser, try again or contact your administrator."
-msgstr ""
-"Desculpe, o limite de tempo foi excedido enquanto processava sua "
-"solicitação.  Favor recarregar seu navegador, tente de novo ou contacte o "
-"administrador do sistema."
+msgid "Sorry, some timeout occured while processing your request. Please reload your browser, try again or contact your administrator."
+msgstr "Desculpe, o limite de tempo foi excedido enquanto processava sua solicitação.  Favor recarregar seu navegador, tente de novo ou contacte o administrador do sistema."
 
 #: js/ExceptionHandler.js:229
 msgid "No Response"
 msgstr "Sem resposta"
 
 #: js/ExceptionHandler.js:230
-msgid ""
-"Sorry, the Server did not respond any data. Please reload your browser, try "
-"again or contact your administrator."
-msgstr ""
-"Desculpe, o Servidor não retornou nenhuma informação.  Favor recarregar seu "
-"navegador, tente de novo ou contacte o administrador do sistema"
+msgid "Sorry, the Server did not respond any data. Please reload your browser, try again or contact your administrator."
+msgstr "Desculpe, o Servidor não retornou nenhuma informação.  Favor recarregar seu navegador, tente de novo ou contacte o administrador do sistema"
 
 #: js/ExceptionHandler.js:237
 msgid "Out of Resources"
 msgstr "Fora de Recursos"
 
 #: js/ExceptionHandler.js:238
-msgid ""
-"Sorry, the Server stated a \"memory exhausted\" condition. Please contact "
-"your administrator."
-msgstr ""
-"Desculpe, o Servidor apresenta \"memória esgotada\".  Favor contactar o "
-"administrador do sistema."
+msgid "Sorry, the Server stated a \"memory exhausted\" condition. Please contact your administrator."
+msgstr "Desculpe, o Servidor apresenta \"memória esgotada\".  Favor contactar o administrador do sistema."
 
 #: js/ExceptionHandler.js:254
 msgid "No Role Memberships"
 msgstr "Sem funções associadas"
 
 #: js/ExceptionHandler.js:255
-msgid ""
-"Your user account has no role memberships. Please contact your administrator."
-msgstr ""
-"Sua conta não tem funcões associadas.  Favor contactar o administrador do "
-"sistema."
+msgid "Your user account has no role memberships. Please contact your administrator."
+msgstr "Sua conta não tem funcões associadas.  Favor contactar o administrador do sistema."
 
 #: js/Container.js:123
 msgid "All {0}"
@@ -1018,12 +995,14 @@ msgstr "Outros usuários {0}"
 msgid "My {0}"
 msgstr "Meu {0}"
 
-#: js/widgets/EditRecord.js:131 js/widgets/dialog/EditDialog.js:360
+#: js/widgets/EditRecord.js:131
+#: js/widgets/dialog/EditDialog.js:360
 #: js/widgets/dialog/EditDialog.js:388
 msgid "Saved in"
 msgstr "Salvo em"
 
-#: js/widgets/EditRecord.js:188 js/widgets/dialog/EditDialog.js:327
+#: js/widgets/EditRecord.js:188
+#: js/widgets/dialog/EditDialog.js:327
 msgid "delete"
 msgstr "apagar"
 
@@ -1037,8 +1016,7 @@ msgstr "Vincular Identificações"
 
 #: js/widgets/tags/TagToggleBox.js:140
 msgid "No Tags to detach found in the selected records"
-msgstr ""
-"Não existem identificações para separar os registros selecionados encontrados"
+msgstr "Não existem identificações para separar os registros selecionados encontrados"
 
 #: js/widgets/tags/TagToggleBox.js:141
 msgid "Please Wait..."
@@ -1058,8 +1036,7 @@ msgstr "Adicionar nova identificação pessoal"
 
 #: js/widgets/tags/TagsPanel.js:109
 msgid "Please note: You create a personal tag. Only you can see it!"
-msgstr ""
-"Favor observar: você cria uma identificação pessoal. Somente você pode vê-la!"
+msgstr "Favor observar: você cria uma identificação pessoal. Somente você pode vê-la!"
 
 #: js/widgets/tags/TagsPanel.js:109
 msgid "Enter tag name:"
@@ -1079,7 +1056,8 @@ msgstr[1] "Desvincular identificações"
 msgid "Edit tag"
 msgstr "Editar identificação"
 
-#: js/widgets/tags/TagsPanel.js:188 js/widgets/tags/TagsPanel.js:193
+#: js/widgets/tags/TagsPanel.js:188
+#: js/widgets/tags/TagsPanel.js:193
 msgid "Rename Tag"
 msgstr "Renomear identificação"
 
@@ -1118,11 +1096,8 @@ msgstr[1] "Apagar realmente as Identificações selecionadas?"
 #: js/widgets/tags/TagsPanel.js:259
 msgid "the selected tag will be deleted and disapear for all entries"
 msgid_plural "The selected tags will be removed and disapear for all entries"
-msgstr[0] ""
-"a identificação selecionada será apagada e desaparecerá de todas as entradas"
-msgstr[1] ""
-"As identificações selecionadas serão apagadas e desaparecerão de todas as "
-"entradas"
+msgstr[0] "a identificação selecionada será apagada e desaparecerá de todas as entradas"
+msgstr[1] "As identificações selecionadas serão apagadas e desaparecerão de todas as entradas"
 
 #: js/widgets/tags/TagsPanel.js:263
 msgid "Please wait a moment..."
@@ -1134,8 +1109,10 @@ msgid_plural "Deleting Tags"
 msgstr[0] "Apagando Identificação"
 msgstr[1] "Apagando Identificações"
 
-#: js/widgets/tags/TagsPanel.js:279 js/widgets/tags/TagsPanel.js:371
-#: js/widgets/tags/TagsPanel.js:404 js/widgets/dialog/EditDialog.js:710
+#: js/widgets/tags/TagsPanel.js:279
+#: js/widgets/tags/TagsPanel.js:371
+#: js/widgets/tags/TagsPanel.js:404
+#: js/widgets/dialog/EditDialog.js:710
 msgid "Failed"
 msgstr "Falhou"
 
@@ -1143,11 +1120,13 @@ msgstr "Falhou"
 msgid "Could not delete Tag(s)."
 msgstr "Não é possível apagar Identificação(ões)"
 
-#: js/widgets/tags/TagsPanel.js:323 js/widgets/tags/TagsPanel.js:385
+#: js/widgets/tags/TagsPanel.js:323
+#: js/widgets/tags/TagsPanel.js:385
 msgid "Notice"
 msgstr "Observação"
 
-#: js/widgets/tags/TagsPanel.js:324 js/widgets/tags/TagsPanel.js:386
+#: js/widgets/tags/TagsPanel.js:324
+#: js/widgets/tags/TagsPanel.js:386
 msgid "The minimum tag length is three."
 msgstr "O tamanho mínimo da identificação é três"
 
@@ -1187,7 +1166,8 @@ msgstr "Selecionar Identificação"
 msgid "Attaching Tag"
 msgstr "Vinculando Identificação"
 
-#: js/widgets/tags/TagFilter.js:30 js/Models.js:141
+#: js/widgets/tags/TagFilter.js:30
+#: js/Models.js:141
 msgid "Tag"
 msgid_plural "Tags"
 msgstr[0] "Identificação"
@@ -1205,11 +1185,13 @@ msgstr "Selecione identificação(ões) a desvincular"
 msgid "tag name"
 msgstr "nome da identificação"
 
-#: js/widgets/VersionCheck.js:44 js/widgets/VersionCheck.js:53
+#: js/widgets/VersionCheck.js:44
+#: js/widgets/VersionCheck.js:53
 msgid "New version of Tine 2.0 available"
 msgstr "Nova versão do Tine 2.0 está disponível"
 
-#: js/widgets/VersionCheck.js:45 js/widgets/VersionCheck.js:54
+#: js/widgets/VersionCheck.js:45
+#: js/widgets/VersionCheck.js:54
 msgid "Version \"{0}\" of Tine 2.0 is available."
 msgstr "Versão \"{0}\" do Tine 2.0 está disponível."
 
@@ -1225,7 +1207,8 @@ msgstr "Favor considerar a atualização!"
 msgid "Remove record"
 msgstr "Remover registro"
 
-#: js/widgets/grid/PickerGridPanel.js:255 js/widgets/grid/PickerFilter.js:310
+#: js/widgets/grid/PickerGridPanel.js:255
+#: js/widgets/grid/PickerFilter.js:310
 #: js/widgets/grid/FilterModelMultiSelect.js:214
 #: js/widgets/container/FilterModel.js:249
 msgid "Selected  {0}"
@@ -1243,7 +1226,8 @@ msgstr "contém"
 msgid "reg. exp."
 msgstr "reg. exp."
 
-#: js/widgets/grid/FilterModel.js:170 js/widgets/container/FilterModel.js:142
+#: js/widgets/grid/FilterModel.js:170
+#: js/widgets/container/FilterModel.js:142
 #: js/widgets/container/FilterModel.js:146
 msgid "is equal to"
 msgstr "é igual a"
@@ -1374,7 +1358,8 @@ msgstr "próximo ano"
 msgid "Attention: There are more filters active!"
 msgstr "Atenção: Existem mais filtros ativos!"
 
-#: js/widgets/grid/FilterPanel.js:175 js/widgets/grid/FilterPanel.js:485
+#: js/widgets/grid/FilterPanel.js:175
+#: js/widgets/grid/FilterPanel.js:485
 msgid "Criteria {0}"
 msgstr "Critério {0}"
 
@@ -1394,23 +1379,21 @@ msgid_plural "Your view is limited by {0} criterias:"
 msgstr[0] "Sua visão está limitada pelo {0} critério:"
 msgstr[1] "Sua visão está limitada pelos {0} critérios:"
 
-#: js/widgets/grid/FileUploadGrid.js:115 js/ux/form/ImageField.js:211
+#: js/widgets/grid/FileUploadGrid.js:115
+#: js/ux/form/ImageField.js:211
 msgid "Upload Failed"
 msgstr "Carregamento falhou"
 
 #: js/widgets/grid/FileUploadGrid.js:116
-msgid ""
-"Could not upload file. Filesize could be too big. Please notify your "
-"Administrator. Max upload size: "
-msgstr ""
-"Não foi possível carregar o arquivo.  O tamanho pode ser muito grande. Favor "
-"notificar o Administrador.  Tamanho máximo de carregamento: "
+msgid "Could not upload file. Filesize could be too big. Please notify your Administrator. Max upload size: "
+msgstr "Não foi possível carregar o arquivo.  O tamanho pode ser muito grande. Favor notificar o Administrador.  Tamanho máximo de carregamento: "
 
 #: js/widgets/grid/FileUploadGrid.js:180
 msgid "Remove file"
 msgstr "Remover arquivo"
 
-#: js/widgets/grid/FileUploadGrid.js:188 js/widgets/tree/ContextMenu.js:116
+#: js/widgets/grid/FileUploadGrid.js:188
+#: js/widgets/tree/ContextMenu.js:116
 msgid "Pause upload"
 msgstr "Pausar carregamento"
 
@@ -1434,7 +1417,8 @@ msgstr "tipo"
 msgid "Remove"
 msgstr "Remover"
 
-#: js/widgets/grid/FilterToolbar.js:85 js/widgets/grid/FilterToolbar.js:571
+#: js/widgets/grid/FilterToolbar.js:85
+#: js/widgets/grid/FilterToolbar.js:571
 msgid "Show"
 msgstr "Exibir"
 
@@ -1480,13 +1464,15 @@ msgstr "existem relações"
 
 #: js/widgets/grid/LinkGridPanel.js:103
 #: js/widgets/account/PickerGridPanel.js:267
-#: js/widgets/container/PropertiesDialog.js:107 js/Models.js:428
+#: js/widgets/container/PropertiesDialog.js:107
+#: js/Models.js:428
 msgid "Name"
 msgstr "Nome"
 
 #: js/widgets/grid/LinkGridPanel.js:105
 #: js/widgets/relation/GenericPickerGridPanel.js:430
-#: js/widgets/ActivitiesPanel.js:461 js/widgets/ActivitiesPanel.js:598
+#: js/widgets/ActivitiesPanel.js:461
+#: js/widgets/ActivitiesPanel.js:598
 msgid "Type"
 msgstr "Tipo"
 
@@ -1509,27 +1495,27 @@ msgid "Remove Filter"
 msgstr "Remover Filtro"
 
 #: js/widgets/grid/GridPanel.js:286
-msgid ""
-"There could not be found any {0}. Please try to change your filter-criteria, "
-"view-options or the {1} you search in."
-msgstr ""
-"Não foram encontrados qualquer {0}.  Favor tentar modificar seu critério de "
-"pesquisa,ver opções ou o {1} sua pesquisa em."
+msgid "There could not be found any {0}. Please try to change your filter-criteria, view-options or the {1} you search in."
+msgstr "Não foram encontrados qualquer {0}.  Favor tentar modificar seu critério de pesquisa,ver opções ou o {1} sua pesquisa em."
 
-#: js/widgets/grid/GridPanel.js:288 js/widgets/grid/GridPanel.js:474
-#: js/widgets/grid/GridPanel.js:475 js/widgets/grid/GridPanel.js:476
+#: js/widgets/grid/GridPanel.js:288
+#: js/widgets/grid/GridPanel.js:474
+#: js/widgets/grid/GridPanel.js:475
+#: js/widgets/grid/GridPanel.js:476
 msgid "Edit {0}"
 msgid_plural "Edit {0}"
 msgstr[0] "Editar {0}"
 msgstr[1] "Editar {0}"
 
-#: js/widgets/grid/GridPanel.js:489 js/widgets/dialog/EditDialog.js:484
+#: js/widgets/grid/GridPanel.js:489
+#: js/widgets/dialog/EditDialog.js:484
 msgid "Copy {0}"
 msgstr "Copiar {0}"
 
 # msgid "Add {0}"
 # msgstr "Adicionar {0}"
-#: js/widgets/grid/GridPanel.js:500 js/widgets/tree/ContextMenu.js:35
+#: js/widgets/grid/GridPanel.js:500
+#: js/widgets/tree/ContextMenu.js:35
 #: js/widgets/grid/GridPanel.js:508
 msgid "Print Page"
 msgstr "Imprimir Página"
@@ -1560,7 +1546,8 @@ msgstr "Adicionar para..."
 msgid "Creation Time"
 msgstr "Hora da criação"
 
-#: js/widgets/grid/GridPanel.js:1270 js/widgets/ActivitiesPanel.js:464
+#: js/widgets/grid/GridPanel.js:1270
+#: js/widgets/ActivitiesPanel.js:464
 msgid "Created By"
 msgstr "Criado Por"
 
@@ -1593,7 +1580,8 @@ msgid "Related to"
 msgstr "Relacionado com"
 
 #: js/widgets/relation/FilterModel.js:32
-#: js/widgets/relation/GenericPickerGridPanel.js:133 js/Models.js:400
+#: js/widgets/relation/GenericPickerGridPanel.js:133
+#: js/Models.js:400
 msgid "Relation"
 msgid_plural "Relations"
 msgstr[0] "Relação"
@@ -1632,11 +1620,8 @@ msgid "There are invalid relations. Please check before saving."
 msgstr "Existem relações inválidas.  Favor verifique antes de salvar."
 
 #: js/widgets/relation/GenericPickerGridPanel.js:252
-msgid ""
-"The maximum number of {0} with the type {1} is reached. Please change the "
-"type of this relation"
-msgstr ""
-"O número máximo de {0} com o tipo {1} foi atingido.  Favor modifique o "
+msgid "The maximum number of {0} with the type {1} is reached. Please change the type of this relation"
+msgstr "O número máximo de {0} com o tipo {1} foi atingido.  Favor modifique o "
 
 #: js/widgets/relation/GenericPickerGridPanel.js:426
 msgid "Record"
@@ -1651,11 +1636,8 @@ msgid "Dependency"
 msgstr "Dependencia"
 
 #: js/widgets/relation/GenericPickerGridPanel.js:708
-msgid ""
-"The record you tried to link is already linked. Please edit the existing "
-"link."
-msgstr ""
-"O registro que você tentou ligar já está ligado.  Favor editar a ligação."
+msgid "The record you tried to link is already linked. Please edit the existing link."
+msgstr "O registro que você tentou ligar já está ligado.  Favor editar a ligação."
 
 #: js/widgets/relation/GenericPickerGridPanel.js:721
 #: js/widgets/form/RecordPickerComboBox.js:268
@@ -1663,12 +1645,8 @@ msgid "You tried to link a record with itself. This is not allowed!"
 msgstr "você tentou ligar um registro a ele mesmo.  Isso não é permitido"
 
 #: js/widgets/relation/PickerCombo.js:93
-msgid ""
-"The {1} \"{2}\" is already used in the Field \"{0}\" and can be linked only "
-"once!"
-msgstr ""
-"O {1} \"{2}\" já está em uso no Campo \"{0}\" e pode ser vinculado somente "
-"uma vez!"
+msgid "The {1} \"{2}\" is already used in the Field \"{0}\" and can be linked only once!"
+msgstr "O {1} \"{2}\" já está em uso no Campo \"{0}\" e pode ser vinculado somente uma vez!"
 
 #: js/widgets/tree/ContextMenu.js:185
 msgid "Please enter the name of the new {0}:"
@@ -1678,7 +1656,8 @@ msgstr "Favor entrar o nome do novo {0}:"
 msgid "No {0} added"
 msgstr "Nenhum {0} adicionado"
 
-#: js/widgets/tree/ContextMenu.js:188 js/widgets/tree/ContextMenu.js:272
+#: js/widgets/tree/ContextMenu.js:188
+#: js/widgets/tree/ContextMenu.js:272
 msgid "You have to supply a {0} name!"
 msgstr "Vocẽ deve fornecer o nome {0}!"
 
@@ -1715,44 +1694,32 @@ msgid "Choose Import File"
 msgstr "Escolha o arquivo a importar"
 
 #: js/widgets/dialog/ImportDialog.js:236
-msgid ""
-"Please choose the file that contains the records you want to add to Tine 2.0"
-msgstr ""
-"Favor escolher o arquivo que contém os registros que você quer adicionar ao "
-"Tine 2.0"
+msgid "Please choose the file that contains the records you want to add to Tine 2.0"
+msgstr "Favor escolher o arquivo que contém os registros que você quer adicionar ao Tine 2.0"
 
 #: js/widgets/dialog/ImportDialog.js:240
 msgid "Select file containing your {0}"
 msgstr "Selecione o arquivo contendo seu {0}"
 
-#: js/widgets/dialog/ImportDialog.js:248 js/widgets/dialog/ImportDialog.js:253
+#: js/widgets/dialog/ImportDialog.js:248
+#: js/widgets/dialog/ImportDialog.js:253
 msgid "What should the file you upload look like?"
 msgstr "Que arquivo você gostaria de carregar?"
 
 #: js/widgets/dialog/ImportDialog.js:256
-msgid ""
-"Tine 2.0 does not understand all kind of files you might want to upload. You "
-"will have to manually adjust your file so Tine 2.0 can handle it."
-msgstr ""
-"Tine 2.0 não reconhece todos os tipos de arquivos que você gostaria de "
-"carregar.  Você terá que ajustar manualmente seu arquivo para que o Tine 2.0 "
-"possa manuseá-lo."
+msgid "Tine 2.0 does not understand all kind of files you might want to upload. You will have to manually adjust your file so Tine 2.0 can handle it."
+msgstr "Tine 2.0 não reconhece todos os tipos de arquivos que você gostaria de carregar.  Você terá que ajustar manualmente seu arquivo para que o Tine 2.0 possa manuseá-lo."
 
 #: js/widgets/dialog/ImportDialog.js:259
-msgid ""
-"Following you find a list of all supported import formats and a sample file, "
-"how Tine 2.0 expects your file to look like."
-msgstr ""
-"A seguir você encontrará uma lista de todos os formatos de importação "
-"suportados e um arquivo de exemplo, como o Tine 2.0 espera que o seu arquivo "
-"se pareça."
+msgid "Following you find a list of all supported import formats and a sample file, how Tine 2.0 expects your file to look like."
+msgstr "A seguir você encontrará uma lista de todos os formatos de importação suportados e um arquivo de exemplo, como o Tine 2.0 espera que o seu arquivo se pareça."
 
 #: js/widgets/dialog/ImportDialog.js:262
 msgid "Please select the import format of the file you want to upload"
-msgstr ""
-"Favor selecionar o formato de importação do arquivo que você quer carregar"
+msgstr "Favor selecionar o formato de importação do arquivo que você quer carregar"
 
-#: js/widgets/dialog/ImportDialog.js:283 js/widgets/dialog/ImportDialog.js:315
+#: js/widgets/dialog/ImportDialog.js:283
+#: js/widgets/dialog/ImportDialog.js:315
 msgid "Download example file"
 msgstr "Baixando o arquivo de exemplo"
 
@@ -1812,7 +1779,8 @@ msgstr "Resolver todos os conflitos"
 msgid "Processing Conflict Data"
 msgstr "Processando Conflito de Dado"
 
-#: js/widgets/dialog/ImportDialog.js:575 js/widgets/dialog/ImportDialog.js:595
+#: js/widgets/dialog/ImportDialog.js:575
+#: js/widgets/dialog/ImportDialog.js:595
 msgid "No conflict to resolve"
 msgstr "Nenhum conflito a resolver"
 
@@ -1851,10 +1819,8 @@ msgid "{0} of them where identified as duplicates."
 msgstr "{0} deles foram identificados como duplicatas."
 
 #: js/widgets/dialog/ImportDialog.js:755
-msgid ""
-"From the identified duplicates {0} will be merged into the existing records."
-msgstr ""
-"Das duplicatas identificadas {0} serão juntadas aos registros existentes."
+msgid "From the identified duplicates {0} will be merged into the existing records."
+msgstr "Das duplicatas identificadas {0} serão juntadas aos registros existentes."
 
 #: js/widgets/dialog/ImportDialog.js:759
 msgid "From the identified duplicates {0} will be discarded."
@@ -2017,8 +1983,7 @@ msgstr "Carregando ..."
 #: js/widgets/dialog/PreferencesDialog.js:245
 #: js/widgets/form/ConfigPanel.js:134
 msgid "You need to correct the red marked fields before config could be saved"
-msgstr ""
-"Você precisa corrigir os campos em vermelho antes da configuração ser salva"
+msgstr "Você precisa corrigir os campos em vermelho antes da configuração ser salva"
 
 #: js/widgets/dialog/PreferencesDialog.js:274
 msgid "Saving of preferences failed."
@@ -2061,17 +2026,12 @@ msgid "{0} {1} has been updated properly."
 msgstr "{0} {1} atualizou corretamente."
 
 #: js/widgets/dialog/MultipleEditResultSummary.js:152
-msgid ""
-"{0} {1} have invalid data after updating. These {1} have not been changed."
-msgstr ""
-"{0} {1} tem informação inválida após a atualização. Este {1} não foi "
-"modificado."
+msgid "{0} {1} have invalid data after updating. These {1} have not been changed."
+msgstr "{0} {1} tem informação inválida após a atualização. Este {1} não foi modificado."
 
 #: js/widgets/dialog/MultipleEditResultSummary.js:152
 msgid "{0} {1} has invalid data after updating. This {1} has not been changed."
-msgstr ""
-"{0} {1} tem informação inválida após a atualização. Este {1} não foi "
-"modificado."
+msgstr "{0} {1} tem informação inválida após a atualização. Este {1} não foi modificado."
 
 #: js/widgets/dialog/ExportDialog.js:84
 msgid "Export {0} {1}"
@@ -2103,12 +2063,8 @@ msgid "Different Values"
 msgstr "Valores Diferentes"
 
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:541
-msgid ""
-"This field has different values. Editing this field will overwrite the old "
-"values."
-msgstr ""
-"Este campo tem valores diferentes.  Editando este campo os valores antigos "
-"serão subrescritos."
+msgid "This field has different values. Editing this field will overwrite the old values."
+msgstr "Este campo tem valores diferentes.  Editando este campo os valores antigos serão subrescritos."
 
 #: js/widgets/dialog/MultipleEditDialogPlugin.js:638
 msgid "Do you really want to change these {0} records?"
@@ -2194,16 +2150,19 @@ msgstr "Campos Customizados"
 msgid "Add a Note..."
 msgstr "Adicionar Nota..."
 
-#: js/widgets/ActivitiesPanel.js:162 js/widgets/ActivitiesPanel.js:174
+#: js/widgets/ActivitiesPanel.js:162
+#: js/widgets/ActivitiesPanel.js:174
 #: js/widgets/container/GrantsGrid.js:45
 msgid "Add"
 msgstr "Adicionar"
 
-#: js/widgets/ActivitiesPanel.js:162 js/widgets/ActivitiesPanel.js:463
+#: js/widgets/ActivitiesPanel.js:162
+#: js/widgets/ActivitiesPanel.js:463
 msgid "Note"
 msgstr "Nota"
 
-#: js/widgets/ActivitiesPanel.js:175 js/widgets/ActivitiesPanel.js:385
+#: js/widgets/ActivitiesPanel.js:175
+#: js/widgets/ActivitiesPanel.js:385
 msgid "Add new note"
 msgstr "Adicionar nova nota"
 
@@ -2215,7 +2174,8 @@ msgstr "Notas"
 msgid "Enter new note:"
 msgstr "Incluir nova nota"
 
-#: js/widgets/ActivitiesPanel.js:319 js/widgets/ActivitiesPanel.js:384
+#: js/widgets/ActivitiesPanel.js:319
+#: js/widgets/ActivitiesPanel.js:384
 msgid "Add Note"
 msgstr "Adicionar Nota"
 
@@ -2239,11 +2199,13 @@ msgstr "Nenhum histórico a exibir"
 msgid "History"
 msgstr "Histórico"
 
-#: js/widgets/ActivitiesPanel.js:592 js/ApplicationStarter.js:222
+#: js/widgets/ActivitiesPanel.js:592
+#: js/ApplicationStarter.js:222
 msgid "Quick search"
 msgstr "Pesquisa rápida"
 
-#: js/widgets/ActivitiesPanel.js:593 js/widgets/ActivitiesPanel.js:594
+#: js/widgets/ActivitiesPanel.js:593
+#: js/widgets/ActivitiesPanel.js:594
 msgid "Time"
 msgstr "Hora"
 
@@ -2314,12 +2276,8 @@ msgid "Favorite not Saved"
 msgstr "Favorito não foi salvo"
 
 #: js/widgets/persistentfilter/EditPersistentFilterPanel.js:132
-msgid ""
-"You have to supply a shorter name! Names of favorite can only be up to 40 "
-"characters long."
-msgstr ""
-"Você deve fornecer um nome curto! Nomes de favoritos devem ter mais de 40 "
-"caracteres"
+msgid "You have to supply a shorter name! Names of favorite can only be up to 40 characters long."
+msgstr "Você deve fornecer um nome curto! Nomes de favoritos devem ter mais de 40 caracteres"
 
 #: js/widgets/persistentfilter/EditPersistentFilterPanel.js:136
 msgid "You have to supply a name for the favorite!"
@@ -2391,9 +2349,7 @@ msgstr "Erro"
 
 #: js/widgets/container/GrantsDialog.js:126
 msgid "You are not allowed to remove all admins for this container!"
-msgstr ""
-"Você não tem permissão para remover todos os administradores deste "
-"repositório!"
+msgstr "Você não tem permissão para remover todos os administradores deste repositório!"
 
 #: js/widgets/container/FilterModel.js:142
 msgid "is personal of"
@@ -2488,9 +2444,7 @@ msgstr "Livre Ocupado"
 
 #: js/widgets/container/GrantsGrid.js:59
 msgid "The grant to access free busy information of events in this calendar"
-msgstr ""
-"O privilégio para acessar a informação de ventos livre ocupado neste "
-"calendário"
+msgstr "O privilégio para acessar a informação de ventos livre ocupado neste calendário"
 
 #: js/widgets/container/GrantsGrid.js:60
 msgid "Private"
@@ -2498,8 +2452,7 @@ msgstr "Privado0"
 
 #: js/widgets/container/GrantsGrid.js:61
 msgid "The grant to access records marked as private in this container"
-msgstr ""
-"O privilégio para acessar registros marcados como privados neste repositório"
+msgstr "O privilégio para acessar registros marcados como privados neste repositório"
 
 #: js/widgets/form/ConfigPanel.js:113
 msgid "Configuration Problem"
@@ -2543,12 +2496,8 @@ msgid "The last action you made was potentially not performed correctly."
 msgstr "A última ação que você fez pode não ter sido executada corretamente"
 
 #: js/ExceptionDialog.js:136
-msgid ""
-"Please help improving this software and notify the vendor. Include a brief "
-"description of what you where doing when the error occurred."
-msgstr ""
-"Por favor melhore este software e notifique o vendedor.  Inclua uma breve "
-"descrição do que você estava fazendo quando o erro ocorreu."
+msgid "Please help improving this software and notify the vendor. Include a brief description of what you where doing when the error occurred."
+msgstr "Por favor melhore este software e notifique o vendedor.  Inclua uma breve descrição do que você estava fazendo quando o erro ocorreu."
 
 #: js/ExceptionDialog.js:150
 msgid "Send Contact Information"
@@ -2582,15 +2531,18 @@ msgstr "Favor reiniciar seu navegador agora!"
 msgid "Your password expired. Please enter a new user password:"
 msgstr "Sua senha expirou. Entre com uma nova senha:"
 
-#: js/prototypeTranslations.js:20 js/prototypeTranslations.js:21
+#: js/prototypeTranslations.js:20
+#: js/prototypeTranslations.js:21
 msgid "Outdent Text"
 msgstr "Texto obsoleto"
 
-#: js/prototypeTranslations.js:22 js/prototypeTranslations.js:23
+#: js/prototypeTranslations.js:22
+#: js/prototypeTranslations.js:23
 msgid "Indent Text"
 msgstr "Indentar o Texto"
 
-#: js/prototypeTranslations.js:24 js/prototypeTranslations.js:25
+#: js/prototypeTranslations.js:24
+#: js/prototypeTranslations.js:25
 msgid "Remove Formatting"
 msgstr "Remover a Formatação"
 
@@ -2619,24 +2571,12 @@ msgid "Congratulations!"
 msgstr "Parabéns!"
 
 #: js/UserRegistration.js:171
-msgid ""
-"You have entered all needed information. If you press the Finish button we "
-"will send you the registration email."
-msgstr ""
-"Você informou todas as informações necessárias.  Se você pressionar o botão "
-"Terminar nós enviaremos o email de registro."
+msgid "You have entered all needed information. If you press the Finish button we will send you the registration email."
+msgstr "Você informou todas as informações necessárias.  Se você pressionar o botão Terminar nós enviaremos o email de registro."
 
 #: js/ux/PopupWindowManager.js:164
-msgid ""
-"The window you want to work with is backgrounded. Your browser doesn't "
-"support to foreground the window for you, so you need to use your operating "
-"systems window switching features. Please send complaints to your browser "
-"vendor!"
-msgstr ""
-"A janela que você quer trabalhar está no fundo.  Seu navegador não permite "
-"colocar a janela em primeiro plano, então você precisa usar a janela do seu "
-"sistema operacional alternando atributos.  Favor envie reclamações para o "
-"seu vendedor!"
+msgid "The window you want to work with is backgrounded. Your browser doesn't support to foreground the window for you, so you need to use your operating systems window switching features. Please send complaints to your browser vendor!"
+msgstr "A janela que você quer trabalhar está no fundo.  Seu navegador não permite colocar a janela em primeiro plano, então você precisa usar a janela do seu sistema operacional alternando atributos.  Favor envie reclamações para o seu vendedor!"
 
 #: js/ux/Percentage.js:190
 msgid "(paused)"
@@ -2688,9 +2628,7 @@ msgstr "Imagem falhou"
 
 #: js/ux/form/ImageField.js:146
 msgid "Could not load image. Please notify your Administrator"
-msgstr ""
-"Não foi possível carregar a image.  Favor informar ao Administrador do "
-"Sistema"
+msgstr "Não foi possível carregar a image.  Favor informar ao Administrador do Sistema"
 
 #: js/ux/form/ImageField.js:168
 msgid "Not An Image"
@@ -2702,14 +2640,14 @@ msgstr "Favor selecionar um arquivo de imagem (gif/png/jpeg)"
 
 #: js/ux/form/ImageField.js:211
 msgid "Could not upload image. Please notify your Administrator"
-msgstr ""
-"Não foi possível carregar a image.  Favor informar o Administrador do Sistema"
+msgstr "Não foi possível carregar a image.  Favor informar o Administrador do Sistema"
 
 #: js/ux/form/ImageField.js:224
 msgid "Change Image"
 msgstr "Alterar a Imagem"
 
-#: js/ux/form/ImageField.js:232 js/ux/form/ImageField.js:250
+#: js/ux/form/ImageField.js:232
+#: js/ux/form/ImageField.js:250
 msgid "Crop Image"
 msgstr "Obter Imagem"
 
@@ -2763,23 +2701,21 @@ msgid "%s's personal container"
 msgstr "%s's repositório pessoal"
 
 #: Container.php:1525
-msgid ""
-"You are not allowed to delete this Container. Please define another "
-"container as the default addressbook for internal contacts!"
-msgstr ""
-"Você não tem permissão para apagar este Repositório.  Favor definir outro "
-"repositório como catálogo de endereços para contatos internos!"
+msgid "You are not allowed to delete this Container. Please define another container as the default addressbook for internal contacts!"
+msgstr "Você não tem permissão para apagar este Repositório.  Favor definir outro repositório como catálogo de endereços para contatos internos!"
 
 # - =================== Added by SERPRO (begin) ==============================
 #: js/sieve/RulesGridPanel.js:214
 msgid "Action"
 msgstr "Ação"
 
-#: js/Expressomail.js:118 js/Expressomail.js:120
+#: js/Expressomail.js:118
+#: js/Expressomail.js:120
 msgid "Active Vacation Message"
 msgstr "Mensagem de férias ativa"
 
-#: js/MessageEditDialog.js:607 js/MessageEditDialog.js:869
+#: js/MessageEditDialog.js:607
+#: js/MessageEditDialog.js:869
 msgid "Compose email:"
 msgstr "Compor mensagem:"
 
@@ -2791,7 +2727,8 @@ msgstr "Criar novas contas de email"
 msgid "Export"
 msgstr "Exportar"
 
-#: js/GridDetailsPanel.js:251
+#: js/GridDetailsPanel.js:
+#: 251
 msgid "Verification Successful!"
 msgstr "Mensagem Verificada com Sucesso!"
 
@@ -2807,8 +2744,10 @@ msgstr "Novas mensagens"
 msgid "No connection to IMAP server."
 msgstr "Sem conexão com o servidor IMAP."
 
-#: js/AccountEditDialog.js:162 js/AccountEditDialog.js:203
-#: js/AccountEditDialog.js:218 js/AccountEditDialog.js:258
+#: js/AccountEditDialog.js:162
+#: js/AccountEditDialog.js:203
+#: js/AccountEditDialog.js:218
+#: js/AccountEditDialog.js:258
 #: js/ContactGrid.js:110
 msgid "None"
 msgstr "Nenhum"
@@ -2817,7 +2756,8 @@ msgstr "Nenhum"
 msgid "Send"
 msgstr "Enviar"
 
-#: js/GridPanel.js:519 js/Model.js:490
+#: js/GridPanel.js:519
+#: js/Model.js:490
 msgid "Sent"
 msgstr "Enviadas"
 
@@ -2838,12 +2778,8 @@ msgid "{0} account setting empty."
 msgstr "{0} configuração da conta vazia."
 
 #: js/MessageEditDialog.js:174
-msgid ""
-"Activate this toggle button to save the email text as a note attached to the "
-"recipient(s) contact(s)."
-msgstr ""
-"Ativar botão para salvar texto da mensagem como uma nota anexada ao(s) "
-"destinatário(s) no seu Catálogo de Endereços."
+msgid "Activate this toggle button to save the email text as a note attached to the recipient(s) contact(s)."
+msgstr "Ativar botão para salvar texto da mensagem como uma nota anexada ao(s) destinatário(s) no seu Catálogo de Endereços."
 
 #: js/TreeContextMenu.js:95
 msgid "Add Folder"
@@ -2885,7 +2821,8 @@ msgstr "Todos os destinatários"
 msgid "Delete trash messages after how many days"
 msgstr "Remover msgs da lixeira após quantos dias?"
 
-#: js/GridPanel.js:266 js/MessageDisplayDialog.js:59
+#: js/GridPanel.js:266
+#: js/MessageDisplayDialog.js:59
 msgid "Forward"
 msgstr "Encaminhar"
 
@@ -2901,7 +2838,8 @@ msgstr "HTML"
 msgid "ID"
 msgstr "ID"
 
-#: js/Expressomail.js:728 js/Expressomail.js:761
+#: js/Expressomail.js:728
+#: js/Expressomail.js:761
 msgid "IMAP Error"
 msgstr "Erro de IMAP"
 
@@ -2922,13 +2860,8 @@ msgid "No recipients set."
 msgstr "Nenhum destinatário informado."
 
 #: js/Expressomail.js:851
-msgid ""
-"One of your folders was deleted or renamed by another client. Please update "
-"the folder list of this account."
-msgstr ""
-"Uma de suas pastas foi excluída ou renomeada por outro cliente. Por favor "
-"atualize a lista de pastas desta conta. Se o problema persistir contate um "
-"administrador."
+msgid "One of your folders was deleted or renamed by another client. Please update the folder list of this account."
+msgstr "Uma de suas pastas foi excluída ou renomeada por outro cliente. Por favor atualize a lista de pastas desta conta. Se o problema persistir contate um administrador."
 
 #: js/MessageEditDialog.js:476
 msgid "Re:"
@@ -2954,7 +2887,8 @@ msgstr "Nome da pasta Enviadas"
 msgid "Set Filter Rules"
 msgstr "Configurar regras de filtro"
 
-#: js/GridDetailsPanel.js:141 js/GridDetailsPanel.js:385
+#: js/GridDetailsPanel.js:141
+#: js/GridDetailsPanel.js:385
 msgid "Show or hide header information"
 msgstr "Exibir ou esconder informações do cabeçalho"
 
@@ -2962,7 +2896,8 @@ msgstr "Exibir ou esconder informações do cabeçalho"
 msgid "Subject/From"
 msgstr "Assunto/De"
 
-#: js/GridPanel.js:512 js/Model.js:145
+#: js/GridPanel.js:512
+#: js/Model.js:145
 msgid "To"
 msgstr "Destinatário"
 
@@ -2994,7 +2929,8 @@ msgstr "Todas as mensagens marcadas como rascunho"
 msgid "All unread mail from Inbox"
 msgstr "Todas as mensagens não lidas"
 
-#: js/MessageEditDialog.js:1133
+#: js/MessageEditDialog.js:
+#: 1133
 msgid "Empty subject"
 msgstr "Assunto vazio"
 
@@ -3002,7 +2938,8 @@ msgstr "Assunto vazio"
 msgid "Number of contacts exceeds the maximum of 50 permitted."
 msgstr "Número de contatos excede o máximo de 50 permitidos."
 
-#: js/RecipientGrid.js:208 js/RecipientGrid.js:232
+#: js/RecipientGrid.js:208
+#: js/RecipientGrid.js:232
 msgid "To:"
 msgstr "Para:"
 
@@ -3034,11 +2971,13 @@ msgstr "Autenticação"
 msgid "Bcc"
 msgstr "Cco"
 
-#: Controller/Message/Send.php:236 js/MessageEditDialog.js:834
+#: Controller/Message/Send.php:236
+#: js/MessageEditDialog.js:834
 msgid "Body"
 msgstr "Corpo"
 
-#: js/RecipientGrid.js:211 js/RecipientGrid.js:233
+#: js/RecipientGrid.js:211
+#: js/RecipientGrid.js:233
 msgid "Cc:"
 msgstr "Cc:"
 
@@ -3048,8 +2987,7 @@ msgstr "Escolher sim, para mover as mensagens para a lixeira."
 
 #: Preference.php:115
 msgid "Compose Emails from the Addressbook with Expressomail."
-msgstr ""
-"Compor mensagens originadas no Catálogo de Endereços usando o Expressomail."
+msgstr "Compor mensagens originadas no Catálogo de Endereços usando o Expressomail."
 
 #: js/GridDetailsPanel.js:139
 msgid "Date"
@@ -3072,11 +3010,13 @@ msgstr "Trazendo mensagens... ({0}% done)"
 msgid "Forwarded"
 msgstr "Encaminhadas"
 
-#: js/GridDetailsPanel.js:136 js/MessageEditDialog.js:765
+#: js/GridDetailsPanel.js:136
+#: js/MessageEditDialog.js:765
 msgid "From"
 msgstr "De"
 
-#: js/sieve/RuleConditionsPanel.js:75 js/sieve/RuleConditionsPanel.js:77
+#: js/sieve/RuleConditionsPanel.js:75
+#: js/sieve/RuleConditionsPanel.js:77
 msgid "Header value"
 msgstr "Valor do cabeçalho"
 
@@ -3092,7 +3032,8 @@ msgstr "Sem conexão com o servidor IMAP: {0}"
 msgid "Plain"
 msgstr "Plain"
 
-#: js/GridPanel.js:320 js/MessageDisplayDialog.js:72
+#: js/GridPanel.js:320
+#: js/MessageDisplayDialog.js:72
 msgid "Print Message"
 msgstr "Imprimir mensagem"
 
@@ -3100,7 +3041,8 @@ msgstr "Imprimir mensagem"
 msgid "Remove from recipients"
 msgstr "Remover dos destinatários"
 
-#: js/GridPanel.js:248 js/MessageDisplayDialog.js:47
+#: js/GridPanel.js:248
+#: js/MessageDisplayDialog.js:47
 msgid "Reply"
 msgstr "Responder"
 
@@ -3120,12 +3062,16 @@ msgstr "Exibir mensagem de confirmação quando excluir mensagens."
 msgid "Sieve Error"
 msgstr "Erro de Sieve"
 
-#: js/GridPanel.js:569
+#: js/GridPanel.js:
+#: 569
 msgid "Signed"
 msgstr "Assinado"
 
-#: Controller/Message/Send.php:236 js/GridDetailsPanel.js:135
-#: js/GridPanel.js:487 js/MessageEditDialog.js:859 js/Model.js:142
+#: Controller/Message/Send.php:236
+#: js/GridDetailsPanel.js:135
+#: js/GridPanel.js:487
+#: js/MessageEditDialog.js:859
+#: js/Model.js:142
 #: js/sieve/RuleConditionsPanel.js:72
 msgid "Subject"
 msgstr "Assunto"
@@ -3138,11 +3084,13 @@ msgstr "Alternar destaque"
 msgid "Total Messages:"
 msgstr "Total de mensagens:"
 
-#: js/MessageEditDialog.js:198
+#: js/MessageEditDialog.js:
+#: 198
 msgid "Activate this toggle button to mark this message as important."
 msgstr "Ative este botão para marcar esta mensagem como importante."
 
-#: js/ImportEmlDialog.js:165
+#: js/ImportEmlDialog.js:
+#: 165
 msgid "File to Import"
 msgstr "Selecionar Arquivo para importar"
 
@@ -3150,7 +3098,8 @@ msgstr "Selecionar Arquivo para importar"
 msgid "All inboxes"
 msgstr "Todas as caixas de entrada"
 
-#: Controller/Message/Flags.php:24 js/GridPanel.js:582
+#: Controller/Message/Flags.php:24
+#: js/GridPanel.js:582
 msgid "Answered"
 msgstr "Respondida"
 
@@ -3174,7 +3123,8 @@ msgstr "Conta de Email"
 msgid "Empty Folder"
 msgstr "Esvaziar pasta"
 
-#: js/GridPanel.js:480 js/Model.js:146
+#: js/GridPanel.js:480
+#: js/Model.js:146
 msgid "Flags"
 msgstr "Etiquetas"
 
@@ -3192,10 +3142,10 @@ msgstr "De (Email e Nome)"
 
 #: Preference.php:111
 msgid "How often should Expressomail check for new Emails (in minutes)."
-msgstr ""
-"Frequência que o Expressomail deve verificar novas mensagens (em minutos)."
+msgstr "Frequência que o Expressomail deve verificar novas mensagens (em minutos)."
 
-#: js/sieve/VacationEditDialog.js:133 js/sieve/VacationEditDialog.js:167
+#: js/sieve/VacationEditDialog.js:133
+#: js/sieve/VacationEditDialog.js:167
 msgid "I am available (vacation message disabled)"
 msgstr "Estou disponível (mensagem de férias desabilitada)"
 
@@ -3207,7 +3157,8 @@ msgstr "IMAP"
 msgid "Incoming mails will be answered with this text:"
 msgstr "Mensagens recebida serão respondidas com este texto:"
 
-#: js/ContactGrid.js:341 js/MessageEditDialog.js:454
+#: js/ContactGrid.js:341
+#: js/MessageEditDialog.js:454
 msgid "Loading Mail Addresses"
 msgstr "Carregando endereços de correio"
 
@@ -3259,7 +3210,8 @@ msgstr "Porta (Padrão: 2000)"
 msgid "Save As Template"
 msgstr "Salvar como modelo"
 
-#: js/MessageEditDialog.js:342 js/FileUpload.js:76
+#: js/MessageEditDialog.js:342
+#: js/FileUpload.js:76
 msgid "Message Size Limit Exceeded"
 msgstr "Limite de Tamanho de Mensagem Excedido"
 
@@ -3298,7 +3250,8 @@ msgstr "Nome de usuário (opcional)"
 msgid "Your quota"
 msgstr "Sua cota"
 
-#: Model/Message.php:179
+#: Model/Message.php:
+#: 179
 msgid "in"
 msgstr "em"
 
@@ -3306,11 +3259,10 @@ msgstr "em"
 msgid "user"
 msgstr "Usuários"
 
-#: js/MessageEditDialog.js:186
+#: js/MessageEditDialog.js:
+#: 186
 msgid "Activate this toggle button to receive a reading confirmation."
-msgstr ""
-"Ative esta opção para receber uma confirmação de leitura dos destinatários "
-"deste email"
+msgstr "Ative esta opção para receber uma confirmação de leitura dos destinatários deste email"
 
 #: js/sieve/VacationEditDialog.js:191
 msgid "Only send all X days to the same sender"
@@ -3328,7 +3280,8 @@ msgstr "Salvar nota de email"
 msgid "Save Note default Value."
 msgstr "Salvar valor padrão de Nota"
 
-#: js/TreecontexMenu.js:266
+#: js/TreecontexMenu.js:
+#: 266
 msgid "Share mailbox"
 msgstr "Compartilhar pastas"
 
@@ -3336,7 +3289,8 @@ msgstr "Compartilhar pastas"
 msgid "Templates"
 msgstr "Modelos"
 
-#: Model/Message.php:178
+#: Model/Message.php:
+#: 178
 msgid "Was readed by:"
 msgstr "Foi lida por:"
 
@@ -3356,11 +3310,14 @@ msgstr "Adicionar como \"Para\""
 msgid "All inboxes of my email accounts"
 msgstr "Todas as caixas de entrada das minhas contas de email"
 
-#: js/GridDetailsPanel.js:232 js/GridPanel.js:473 js/MessageEditDialog.js:699
+#: js/GridDetailsPanel.js:232
+#: js/GridPanel.js:473
+#: js/MessageEditDialog.js:699
 msgid "Attachments"
 msgstr "Anexos"
 
-#: js/RecipientGrid.js:214 js/RecipientGrid.js:234
+#: js/RecipientGrid.js:214
+#: js/RecipientGrid.js:234
 msgid "Bcc:"
 msgstr "Cco:"
 
@@ -3370,8 +3327,7 @@ msgstr "Escolha o número de mensagens a serem exibidas em cada página."
 
 #: js/MessageEditDialog.js:240
 msgid "Click to search for and add recipients from the Addressbook."
-msgstr ""
-"Clique para buscar e adicionar destinatário(s) do Catálogo de Endereços."
+msgstr "Clique para buscar e adicionar destinatário(s) do Catálogo de Endereços."
 
 #: js/sieve/RulesGridPanel.js:206
 msgid "Conditions"
@@ -3389,7 +3345,8 @@ msgstr "Credenciais"
 msgid "Default Email Account"
 msgstr "Conta de email padrão"
 
-#: js/GridDetailsPanel.js:245
+#: js/GridDetailsPanel.js:
+#: 245
 msgid "Digital Signature"
 msgstr "Assinatura Digital"
 
@@ -3401,7 +3358,8 @@ msgstr "Intervalo de atualização de mensagens"
 msgid "Files are still uploading."
 msgstr "Arquivos ainda estão sendo carregados."
 
-#: js/GridPanel.js:499 js/Model.js:144
+#: js/GridPanel.js:499
+#: js/Model.js:144
 msgid "From (Name)"
 msgstr "De (Nome)"
 
@@ -3413,12 +3371,14 @@ msgstr "Cabeçalho contém"
 msgid "Header regex"
 msgstr "Expressão regular do cabeçalho"
 
-#: js/AccountEditDialog.js:141 js/AccountEditDialog.js:184
+#: js/AccountEditDialog.js:141
+#: js/AccountEditDialog.js:184
 #: js/AccountEditDialog.js:239
 msgid "Host"
 msgstr "Servidor"
 
-#: js/TreecontexMenu.js:329
+#: js/TreecontexMenu.js:
+#: 329
 msgid "Loading..."
 msgstr "Carregando..."
 
@@ -3426,11 +3386,13 @@ msgstr "Carregando..."
 msgid "Port (Default: 25)"
 msgstr "Porta (Padrão: 25)"
 
-#: js/GridPanel.js:1101 js/GridPanel.js:1133
+#: js/GridPanel.js:1101
+#: js/GridPanel.js:1133
 msgid "Quota unknown"
 msgstr "Cota desconhecida"
 
-#: js/GridPanel.js:257 js/MessageDisplayDialog.js:53
+#: js/GridPanel.js:257
+#: js/MessageDisplayDialog.js:53
 msgid "Reply To All"
 msgstr "Responder a todos"
 
@@ -3443,11 +3405,13 @@ msgstr "Regra"
 msgid "SMTP Error"
 msgstr "Erro de SMTP"
 
-#: js/AccountEditDialog.js:164 js/AccountEditDialog.js:205
+#: js/AccountEditDialog.js:164
+#: js/AccountEditDialog.js:205
 msgid "SSL"
 msgstr "SSL"
 
-#: js/GridPanel.js:472
+#: js/GridPanel.js:
+#: 472
 msgid "Security"
 msgstr "Segurança"
 
@@ -3471,7 +3435,8 @@ msgstr "Para (Email)"
 msgid "\"{0}\" recipients"
 msgstr "\"{0}\" destinatários"
 
-#: Model/Message.php:176
+#: Model/Message.php:
+#: 176
 msgid "Your message:"
 msgstr "Sua mensagem: "
 
@@ -3486,7 +3451,8 @@ msgstr "Adicionar contato ao catálogo de endereços"
 msgid "Checking Contacts"
 msgstr "Verificando Contatos"
 
-#: js/GridPanel.js:577
+#: js/GridPanel.js:
+#: 577
 msgid "Compressed"
 msgstr "Compactado"
 
@@ -3506,9 +3472,14 @@ msgstr "Formato de Exibição"
 msgid "Download all attachments"
 msgstr "baixar todos os anexos"
 
-#: js/FolderFilterModel.js:30 js/GridPanel.js:534 js/Model.js:54
-#: js/Model.js:496 js/TreeContextMenu.js:45 js/TreeContextMenu.js:100
-#: js/TreeContextMenu.js:103 js/TreeContextMenu.js:106
+#: js/FolderFilterModel.js:30
+#: js/GridPanel.js:534
+#: js/Model.js:54
+#: js/Model.js:496
+#: js/TreeContextMenu.js:45
+#: js/TreeContextMenu.js:100
+#: js/TreeContextMenu.js:103
+#: js/TreeContextMenu.js:106
 msgid "Folders"
 msgstr "Pastas"
 
@@ -3516,7 +3487,8 @@ msgstr "Pastas"
 msgid "Header \"{0}\" matches \"{1}\""
 msgstr "Cabeçalho \"{0}\" combina com \"{1}\""
 
-#: js/TreecontexMenu.js:284
+#: js/TreecontexMenu.js:
+#: 284
 msgid "Import msg(eml)"
 msgstr "Importar msg(eml)"
 
@@ -3524,7 +3496,8 @@ msgstr "Importar msg(eml)"
 msgid "Last update:"
 msgstr "Última atualização:"
 
-#: js/GridDetailsPanel.js:255
+#: js/GridDetailsPanel.js:
+#: 255
 msgid "Verification Failed!"
 msgstr "Falha na Verificação da Mensagem!"
 
@@ -3532,7 +3505,8 @@ msgstr "Falha na Verificação da Mensagem!"
 msgid "New Mail"
 msgstr "Nova mensagem"
 
-#: js/MessageEditDialog.js:178
+#: js/MessageEditDialog.js:
+#: 178
 msgid "Reading Confirmation"
 msgstr "Confirmação de Leitura"
 
@@ -3550,11 +3524,13 @@ msgstr "Selecionar destinatários para \"{0}\""
 msgid "Signature position"
 msgstr "Posição da assinatura"
 
-#: js/GridPanel.js:542 js/sieve/RuleConditionsPanel.js:73
+#: js/GridPanel.js:542
+#: js/sieve/RuleConditionsPanel.js:73
 msgid "Size"
 msgstr "Tamanho"
 
-#: js/AccountEditDialog.js:163 js/AccountEditDialog.js:204
+#: js/AccountEditDialog.js:163
+#: js/AccountEditDialog.js:204
 #: js/AccountEditDialog.js:259
 msgid "TLS"
 msgstr "TLS"
@@ -3601,11 +3577,13 @@ msgstr "{0} %"
 msgid "{0} Message"
 msgstr "{0} mensagem"
 
-#: js/MessageEditDialog.js:190
+#: js/MessageEditDialog.js:
+#: 190
 msgid "Mark as Important"
 msgstr "Marcar como Importante"
 
-#: Model/Message.php:175
+#: Model/Message.php:
+#: 175
 msgid "Reading Confirmation:"
 msgstr "Confirmação de Leitura:"
 
@@ -3653,7 +3631,8 @@ msgstr "Contas de Email"
 msgid "Email account \"{0}\" has an active vacation message."
 msgstr "Conta de email \"{0}\" tem uma mensagem de férias ativa"
 
-#: js/GridPanel.js:573
+#: js/GridPanel.js:
+#: 573
 msgid "Encrypted"
 msgstr "Criptografado"
 
@@ -3661,7 +3640,8 @@ msgstr "Criptografado"
 msgid "Error:"
 msgstr "Erro:"
 
-#: js/sieve/RuleConditionsPanel.js:75 js/sieve/RuleConditionsPanel.js:77
+#: js/sieve/RuleConditionsPanel.js:75
+#: js/sieve/RuleConditionsPanel.js:77
 msgid "Header name"
 msgstr "Nome do cabeçalho"
 
@@ -3711,10 +3691,10 @@ msgstr "Nome da pasta Modelos"
 
 #: js/Expressomail.js:746
 msgid "Your email credentials are wrong. Please contact your administrator"
-msgstr ""
-"Suas credenciais de email estão erradas. Por favor contate seu administrador."
+msgstr "Suas credenciais de email estão erradas. Por favor contate seu administrador."
 
-#: js/GridPanel.js:581
+#: js/GridPanel.js:
+#: 581
 msgid "Certs Only"
 msgstr "Apenas Certificados"
 
@@ -3750,7 +3730,9 @@ msgstr "Mensagens exibidas por página."
 msgid "Enable"
 msgstr "Habilitar"
 
-#: js/GridPanel.js:493 js/Model.js:143 js/sieve/RuleConditionsPanel.js:69
+#: js/GridPanel.js:493
+#: js/Model.js:143
+#: js/sieve/RuleConditionsPanel.js:69
 msgid "From (Email)"
 msgstr "De (Email)"
 
@@ -3758,7 +3740,8 @@ msgstr "De (Email)"
 msgid "Header \"{0}\" contains \"{1}\""
 msgstr "Cabeçalho \"{0}\" contém \"{1}\""
 
-#: js/sieve/VacationEditDialog.js:140 js/sieve/VacationEditDialog.js:168
+#: js/sieve/VacationEditDialog.js:140
+#: js/sieve/VacationEditDialog.js:168
 msgid "I am not available (vacation message enabled)"
 msgstr "Não estou disponível (mensagem de férias habilitada)"
 
@@ -3790,7 +3773,9 @@ msgstr "Em {0}, {1} escreveu"
 msgid "Plain Text"
 msgstr "Texto Plano"
 
-#: js/GridPanel.js:312 js/GridPanel.js:1258 js/GridPanel.js:1274
+#: js/GridPanel.js:312
+#: js/GridPanel.js:1258
+#: js/GridPanel.js:1274
 #: js/MessageDisplayDialog.js:78
 msgid "Print Preview"
 msgstr "Visualizar impressão"
@@ -3799,7 +3784,8 @@ msgstr "Visualizar impressão"
 msgid "Quota usage"
 msgstr "Uso da cota"
 
-#: js/GridPanel.js:527 js/Model.js:151
+#: js/GridPanel.js:527
+#: js/Model.js:151
 msgid "Received"
 msgstr "Recebidas"
 
@@ -3807,7 +3793,8 @@ msgstr "Recebidas"
 msgid "Recent"
 msgstr "Recente"
 
-#: js/AccountEditDialog.js:151 js/AccountEditDialog.js:193
+#: js/AccountEditDialog.js:151
+#: js/AccountEditDialog.js:193
 #: js/AccountEditDialog.js:248
 msgid "Secure Connection"
 msgstr "Conexão Segura"
@@ -3824,34 +3811,38 @@ msgstr "Regras de filtro Sieve"
 msgid "Use in Addressbook"
 msgstr "Usar no Catálogo de Endereços"
 
-#: Backend/Imap.php:194
+#: Backend/Imap.php:
+#: 194
 msgid "cannot create folder"
 msgstr "Não foi possível criar a pasta"
 
-#: Backend/Imap.php:194
+#: Backend/Imap.php:
+#: 194
 msgid "it already exists."
 msgstr "ela já existe."
 
-#: Backend/Imap.php:329
-msgid ""
-"cannot set flags, have you tried to set the recent flag or special chars?"
-msgstr ""
-"Não é possível mudar o status da mensagem, talvez já tenha sido mudado ou "
-"você não tem permissão."
+#: Backend/Imap.php:
+#: 329
+msgid "cannot set flags, have you tried to set the recent flag or special chars?"
+msgstr "Não é possível mudar o status da mensagem, talvez já tenha sido mudado ou você não tem permissão."
 
-#: Backend/Imap.php:76
+#: Backend/Imap.php:
+#: 76
 msgid "Could not select "
 msgstr "Não foi possível selecionar "
 
-#: Backend/Imap.php:398
+#: Backend/Imap.php:
+#: 398
 msgid "folder not found"
 msgstr "Pasta não encontrada"
 
-#: Backend/Imap.php:970
+#: Backend/Imap.php:
+#: 970
 msgid "cannot set deleted flags"
 msgstr "Não foi possível setar flag de excluída"
 
-#: Backend/Imap.php:180
+#: Backend/Imap.php:
+#: 180
 msgid "cannot change folder, maybe it does not exist"
 msgstr "Não pode trocar folder, pode ser que não exista"
 
@@ -3879,7 +3870,8 @@ msgstr "Marcada"
 msgid "No Messages found or the cache is empty."
 msgstr "Nenhuma mensagem encontrada ou o cache está vazio."
 
-#: Model/Message.php:177
+#: Model/Message.php:
+#: 177
 msgid "Received in"
 msgstr "Recebida em"
 
@@ -3895,8 +3887,7 @@ msgstr "Adicionar aos Contatos"
 
 #: js/MessageEditDialog.js:236,371
 msgid "Activate this toggle button to add unknown recipient to contacts."
-msgstr ""
-"Ative este botão para adicionar destinatários desconhecidos aos Contatos."
+msgstr "Ative este botão para adicionar destinatários desconhecidos aos Contatos."
 
 #: js/MessageEditDialog.js:371,425
 msgid "Error saving unknown contacts."
@@ -3910,79 +3901,93 @@ msgstr "Contatos Coletados"
 msgid "Saving unknown recipients to Unknown Contacts folder..."
 msgstr "Salvando destinatários na pasta Contatos Coletados..."
 
-#: js/GridDetailsPanel.js:547
+#: js/GridDetailsPanel.js:
+#: 547
 msgid "Verification Details"
 msgstr "Detalhes da Verificação"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js:
+#: 542
 msgid "Serial Number"
 msgstr "Serial"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js:
+#: 542
 msgid "Issuer"
 msgstr "Emissor"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js:
+#: 542
 msgid "Owner"
 msgstr "Dono"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js:
+#: 542
 msgid "Valid From"
 msgstr "Válido a Partir de"
 
-#: js/GridDetailsPanel.js:542
+#: js/GridDetailsPanel.js:
+#: 542
 msgid "Valid To"
 msgstr "Válido Até"
 
-#: Smime.php:129
+#: Smime.php:
+#: 129
 msgid "Message Integrity Verification Failure"
 msgstr "Falha na Verificação da Integridade da Mensagem"
 
-#: js/GridDetailsPanel.js:561
+#: js/GridDetailsPanel.js:
+#: 561
 msgid "Sender email is different from Digital Certificate email"
 msgstr "E-mail do Remetente Diferente do E-mail Informado no Certificado"
 
-#: js/GridDetailsPanel.js:392
+#: js/GridDetailsPanel.js:
+#: 392
 msgid "show details of digitial signature verification"
 msgstr "mostra detalhes da verificação da assinatura"
 
-#: Preference.php:166
+#: Preference.php:
+#: 166
 msgid "Digitally sign messages by default when sending mail"
 msgstr "Sempre assinar digitalmente as mensagens"
 
-#: Preference.php:166
-msgid ""
-"Choose yes, to open message editor with toggle button \"Sign Message\" "
-"pressed"
-msgstr ""
-"Escolher sim para sempre abrir o editor de mensagens com a opção \"Assinar "
-"Mensagem\" selecionada"
+#: Preference.php:
+#: 166
+msgid "Choose yes, to open message editor with toggle button \"Sign Message\" pressed"
+msgstr "Escolher sim para sempre abrir o editor de mensagens com a opção \"Assinar Mensagem\" selecionada"
 
-#: js/TreeContextMenu.js:194
+#: js/TreeContextMenu.js:
+#: 194
 msgid "Delete Folder"
 msgstr "Apagar Pasta"
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js:
+#: 199
 msgid "Warning"
 msgstr "Aviso"
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js:
+#: 199
 msgid "Delete your sub-folders first."
 msgstr "Delete as sub-pastas primeiro."
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js:
+#: 199
 msgid "Digitally Sign Mail"
 msgstr "Assinar Digitalmente"
 
-#: js/TreeContextMenu.js:199
+#: js/TreeContextMenu.js:
+#: 199
 msgid "Activate this toggle button to sign a message on send"
 msgstr "Ative este botão para assinar digitalmente a mensagem"
 
-#: js/GridDetailsPanel.js:656
+#: js/GridDetailsPanel.js:
+#: 656
 msgid "Block Sender"
 msgstr "Bloquear remetente"
 
-#: js/GridDetailsPanel.js:657
+#: js/GridDetailsPanel.js:
+#: 657
 msgid "Block incoming messages from this sender?"
 msgstr "Bloquear mensagens enviadas por este remetente"
 
@@ -4004,7 +4009,8 @@ msgstr "Todos os campos devem ser preenchidos"
 msgid "One or more contacts have not been added to the folder "
 msgstr "Um ou mais contatos não puderam ser adicionados a pasta "
 
-#: js/MessageEditDialog.js: 318, 321
+#: js/MessageEditDialog.js:
+#: 318, 321
 msgid "Checking existance of unknown recipients..."
 msgstr "Verificando existência de destinatários desconhecidos..."
 
@@ -4020,7 +4026,8 @@ msgstr "Número Máximo de Resultados em Buscas de Mensagens"
 msgid "New Mail (encrypted)"
 msgstr "Nova mensagem (cifrada)"
 
-#: Expressomail/js/GridPanel.js:260 Expressomail/js/MessageDisplayDialog.js:67
+#: Expressomail/js/GridPanel.js:260
+#: Expressomail/js/MessageDisplayDialog.js:67
 #: Expressomail/js/MessageEditDialog.js:158
 msgid "encrypted"
 msgstr "cifrada"
@@ -4030,12 +4037,8 @@ msgid "Enable sending encrypted messages"
 msgstr "Habilitar o envio de mensagens cifradas"
 
 #: Preference.php:177
-msgid ""
-"Choose yes, to enable sending encrypted messages (only if preference "
-"\"Windows Type\" is set to \"Browser windows\")."
-msgstr ""
-"Escolher sim, para habilitar o envio de mensagens cifradas (somente se a "
-"preferência \"Tipo da Janela\" for \"Browser windows\")."
+msgid "Choose yes, to enable sending encrypted messages (only if preference \"Windows Type\" is set to \"Browser windows\")."
+msgstr "Escolher sim, para habilitar o envio de mensagens cifradas (somente se a preferência \"Tipo da Janela\" for \"Browser windows\")."
 
 #: Expressomail/js/MessageEditDialog.js:158
 msgid "No valid certificate found for this email address."
@@ -4043,9 +4046,7 @@ msgstr "Um certificado válido não foi encontrado para esse endereço de email.
 
 #: Expressomail/js/MessageEditDialog.js:158
 msgid "No valid certificate found for one or more of these email address."
-msgstr ""
-"Os certificados dos seguintes usuários não foram encontrados ou são "
-"inválidos ou não puderam ser validados: "
+msgstr "Os certificados dos seguintes usuários não foram encontrados ou são inválidos ou não puderam ser validados: "
 
 #: Expressomail/js/Expressomail.js:1207
 msgid "Loading Criptography Components..."
@@ -4053,8 +4054,7 @@ msgstr "Carregando componentes de criptografia..."
 
 #: Expressomail/js/Expressomail.js:1239
 msgid "Failure loading criptography components, please try again."
-msgstr ""
-"Falha ao carregar os componentes de criptografia, por favor tente novamente."
+msgstr "Falha ao carregar os componentes de criptografia, por favor tente novamente."
 
 #: Expressomail/js/Expressomail.js:1368
 msgid "Failure decrypting the message, please try again."
@@ -4116,9 +4116,7 @@ msgstr "Sua lixeira não está vazia!"
 
 #: Expressomail/js/GridPanel.js:1091
 msgid "You can CANCEL this operation and clean trash before try again."
-msgstr ""
-"Você pode CANCELAR esta operação e limpar a lixeira antes de tentar "
-"novamente."
+msgstr "Você pode CANCELAR esta operação e limpar a lixeira antes de tentar novamente."
 
 #: Expressomail/js/GridPanel.js:1092
 msgid "or,"
@@ -4182,7 +4180,8 @@ msgstr "Mensagem Anexada"
 msgid "Saving as a draft..."
 msgstr "Salvando como rascunho..."
 
-#: Expressomail/js/MessageEditDialog.js:270 Expressomail/js/GridPanel.js:1709
+#: Expressomail/js/MessageEditDialog.js:270
+#: Expressomail/js/GridPanel.js:1709
 msgid "Failed to save draft!"
 msgstr "Erro ao salvar o rascunho!"
 
@@ -4191,14 +4190,12 @@ msgid "Keep as a draft?"
 msgstr "Manter como rascunho?"
 
 #: Expressomail/js/GridPanel.js:1710
-msgid ""
-"A draft could not be saved. Maybe the connection to the server was lost."
+msgid "A draft could not be saved. Maybe the connection to the server was lost."
 msgstr "O rascunho não pode ser salvo. Verifique a conexão com o servidor."
 
 #: js/AdminPanel.js:61
 msgid "Interval (in seconds) for Auto Saving Drafts (0 to disable)"
-msgstr ""
-"Intervalo (em segundos) de auto salvamento de rascunhos (0 para desabilitar)"
+msgstr "Intervalo (em segundos) de auto salvamento de rascunhos (0 para desabilitar)"
 
 #: js/MessageEditDialog.js:587
 msgid "Network problem."
@@