* SPDX-License-Identifier: AGPL-3.0-only ************************************/ /* crmv@48159 (diff rev 860-863) */ /* crmv@49395 (diff rev 889-893) */ /* crmv@51862 (diff rev 909-910) */ require_once('modules/Messages/MessagesRelationManager.php'); require_once('modules/Messages/src/Squirrelmail.php'); require_once('modules/Messages/Utils.php'); //crmv@49432 require_once('modules/Calendar/iCal/includeAll.php'); // crmv@68357 class Messages extends MessagesRelationManager { protected $folder; // Selected folder private $saved_messages; protected $account; var $folderSeparator = '/'; var $rootFolder = '/'; //crmv@125287 var $defaultSpecialFolders = array( 'INBOX'=>'', 'Drafts'=>'', 'Sent'=>'', 'Spam'=>'', //'Junk'=>'', 'Trash'=>'', ); var $fakeFolders = array('Shared','Flagged','Links','vteScheduled'); // crmv@187622 // crmv@192843 var $folderImgs = array( 'INBOX'=>'inbox', 'Drafts'=>'note', 'Sent'=>'send', 'Spam'=>'whatshot', 'Trash'=>'delete', 'Shared'=>'folder_shared', 'Flagged'=>'flag', 'Links'=>'arrow_downward', 'vteScheduled'=>'schedule', ); // crmv@192843e var $resetMailResource = false; var $other_contenttypes_attachment = array( 'application/pgp-signature', 'application/octet-stream', 'application/pdf', //crmv@53651 'message/delivery-status', 'text/rfc822-headers', //crmv@53651e 'text/calendar', 'message/rfc822', //crmv@62340 ); var $ical_methods = array('REQUEST', 'REPLY'); // crmv@68357 : attachments with this method and contenttype text/calendar are invitations or replies var $list_max_entries_first_page; //crmv@46154 var $list_max_entries_per_page; // navigation, fetch and append // IMAP Cron configuration var $messages_by_schedule; // max number of messages processed by cron Messages.service.php (0 = no limit) var $messages_by_schedule_inbox; // max number of messages processed by cron Inbox.service.php (0 = no limit) var $interval_schedulation; // '' = all (no temporary interval) var $max_message_cron_uid_attempts; //crmv@55450 var $update_duplicates = false; // crmv@57585 : if true in saveCache if I try to save a message already downloaded I update its informations. if false skip saving. var $fetch_array_chunk_limit = 500; //crmv@174681 //crmv@OPER8279 // store in db only messages in this interval (ex. 90 days, 4 months) // if it is empty it store all messagaes in db // if (interval_storage < interval_schedulation) interval_storage = interval_schedulation // this value must be in a range of search_intervals but not in the least // Lotus do not support SEARCH SINCE so we suggest to store all in order to do not use the imap search var $interval_storage; var $messages_cleaned_by_schedule; // number of messages to delete in a schedulation of cleanStorage var $preserve_search_results_date; // store for 1 day search results before delete them //crmv@OPER8279e var $fetchBodyInCron; // crmv@59094 : (string) yes | no | no_disposition_notification_to var $relatedEditButton = false; //crmv@61173 //crmv@62414 var $view_image_supported_extensions = array('png','bmp','gif','jpeg','jpg','tiff','tif'); //crmv@91321 var $viewerJS_supported_extensions = array('pdf','odt','ods','ots','ott','otp'); var $action_view_JSfunction_array = array( 'eml'=>'ViewEML', 'pdf'=>'ViewDocument', 'odt'=>'ViewDocument', 'ods'=>'ViewDocument', 'ots'=>'ViewDocument', 'ott'=>'ViewDocument', 'otp'=>'ViewDocument', 'png'=>'ViewImage', 'bmp'=>'ViewImage', 'gif'=>'ViewImage', 'jpeg'=>'ViewImage', 'jpg'=>'ViewImage', //crmv@91321 'tiff'=>'ViewImage', 'tif'=>'ViewImage', //crmv@91321e ); //crmv@62414e //crmv@76756 var $IMAPDebug; var $IMAPLogMaxSize = 5242880; // 5MB per logfile (more or less) var $IMAPLogDir = 'logs/imap/'; //crmv@76756e var $inline_image_supported_extensions = array('jpeg','jpg','gif','png','apng','svg','bmp','ico','tiff','tif'); //crmv@80250 crmv@91321 var $inline_image_convertible_extensions = array('tiff','tif'); //crmv@91321 var $view_related_messages_recipients; //crmv@86301 var $view_related_messages_drafts; //crmv@141429 to view messages with column draft = 0/1 //crmv@87055 var $search_intervals = array( array('','-2 months'), array('-2 months','-6 months'), array('-6 months','-1 year'), array('-1 year','-2 years'), array('-2 years',''), ); //crmv@87055e //crmv@125629 var $interval_inline_cache; // to keep in cache inline attachments for this time. If empty, the cache will never be emptied. var $force_check_imap_connection = false; /* * true: when you open module Messages if the conection to server is down or the credentials are wrong you are not permit to use the module * false: even if the conection to server is down or the credentials are wrong you can use the module */ //crmv@125629e var $force_index_querygenerator; //crmv@146435 protected $max_login_attempts = 5; //crmv@171904 function __construct() { parent::__construct(); //crmv@186709 $VTEP = VTEProperties::getInstance(); $this->list_max_entries_first_page = $VTEP->getProperty('modules.messages.list_max_entries_first_page'); $this->list_max_entries_per_page = $VTEP->getProperty('modules.messages.list_max_entries_per_page'); $this->messages_by_schedule = $VTEP->getProperty('modules.messages.messages_by_schedule'); $this->messages_by_schedule_inbox = $VTEP->getProperty('modules.messages.messages_by_schedule_inbox'); $this->interval_schedulation = $VTEP->getProperty('modules.messages.interval_schedulation'); $this->max_message_cron_uid_attempts = $VTEP->getProperty('modules.messages.max_message_cron_uid_attempts'); $this->interval_storage = $VTEP->getProperty('modules.messages.interval_storage'); $this->messages_cleaned_by_schedule = $VTEP->getProperty('modules.messages.messages_cleaned_by_schedule'); $this->preserve_search_results_date = $VTEP->getProperty('modules.messages.preserve_search_results_date'); $this->fetchBodyInCron = $VTEP->getProperty('modules.messages.fetchBodyInCron'); $this->IMAPDebug = $VTEP->getProperty('modules.messages.IMAPDebug'); $this->view_related_messages_recipients = $VTEP->getProperty('modules.messages.view_related_messages_recipients'); $this->view_related_messages_drafts = $VTEP->getProperty('modules.messages.view_related_messages_drafts'); $this->interval_inline_cache = $VTEP->getProperty('modules.messages.interval_inline_cache'); $this->force_index_querygenerator= $VTEP->getProperty('modules.messages.force_index_querygenerator'); //crmv@186709e } /** * @deprecated */ function loadZendFramework() { // crmv@196384 // do nothing, everything is already autoloaded } function getZendMailStorageImap($userid='') { global $current_user, $current_folder; if (empty(self::$mail)) { $this->loadZendFramework(); try { $this->getZendMailProtocolImap($userid); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 // if error in cron skip if (isset($_REQUEST['app_key']) && $_REQUEST['service'] == 'Messages') { throw new Exception('ERR_IMAP_CRON'); } //crmv@125629 if ($_REQUEST['file'] == 'Settings/index' && $_REQUEST['operation'] == 'SaveAccount') { throw new Exception('ERR_IMAP_AUTENTICATION'); } //crmv@125629e // show Shared folder even if no mail server configured if ($_REQUEST['action'] == 'DetailView' && !empty($_REQUEST['record']) && in_array($current_folder,$this->fakeFolders)) { return false; } $this->manageConnectionError($e,$userid); } $mail = new Zend\Mail\Storage\Imap(self::$protocol); self::$mail = $mail; return true; } } //crmv@133893 function getZendMailStorageImapGeneric($server,$port,$ssl_tls,$username,$password) { if (empty(self::$mail)) { $this->loadZendFramework(); try { $this->getZendMailProtocolImap(null,array( 'server'=>$server, 'port'=>$port, 'ssl_tls'=>$ssl_tls, 'username'=>$username, 'password'=>$password )); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); return false; } $mail = new Zend\Mail\Storage\Imap(self::$protocol); self::$mail = $mail; return true; } } //crmv@133893e //crmv@133893 function getZendMailProtocolImap($userid='',$params=array()) { if (empty(self::$protocol)) { if (empty($userid) && !empty($params)) { $server = $params['server']; $port = $params['port']; $ssl_tls = $params['ssl_tls']; $username = $params['username']; $password = $params['password']; $authentication = 'password'; // crmv@206145 } else { if (!empty($userid)) { $user = CRMEntity::getInstance('Users'); $user->retrieve_entity_info($userid,'Users'); } else { global $current_user; $user = $current_user; } $accountid = $this->getAccount(); $account = $this->getUserAccounts($user->id,$accountid); $account = $account[0]; $server = $account['server']; $port = (!empty($account['port']) ? $account['port'] : null); $ssl_tls = (!empty($account['ssl_tls']) ? $account['ssl_tls'] : false); if (empty($server)) { throw new Exception('ERR_IMAP_SERVER_EMPTY'); } $username = $account['username']; // crmv@206145 $authentication = $account['authentication']; if ($authentication == 'password') { $password = $account['password']; } // crmv@206145e } try { $protocol = new Zend\Mail\Protocol\Imap($server,$port,$ssl_tls); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 throw new Exception('ERR_IMAP_CONNECTION_FAILED'); } $protocol->crmMessage = $this; //crmv@76756 // crmv@206145 if ($authentication == 'password') { $login = $protocol->login($username,$password); } elseif ($authentication == 'oauth2') { $accessToken = $this->checkOauthToken($user->id,$accountid); $login = $protocol->loginOauth($username,$accessToken); } // crmv@206145e //crmv@125629 crmv@171904 global $adb, $table_prefix; if ($login === false) { if (empty($username) || ($authentication == 'password' && empty($password))) { // crmv@206145 $error = 'ERR_IMAP_CREDENTIALS_EMPTY'; } else { $error = 'ERR_IMAP_LOGIN_FAILED'; } $result = $adb->pquery("select attempts from {$table_prefix}_messages_account where id = ?", array($accountid)); $attempts = $adb->query_result($result,0,'attempts'); if ($attempts < $this->max_login_attempts) { $adb->pquery("update {$table_prefix}_messages_account set error = ?, attempts = ? where id = ?", array($error,($attempts+1),$accountid)); } throw new Exception($error); } else { $adb->pquery("update {$table_prefix}_messages_account set error = ?, attempts = ? where id = ?", array('',0,$accountid)); } //crmv@125629e crmv@171904e self::$protocol = $protocol; } return self::$protocol; // crmv@38592 } //crmv@133893e // crmv@206145 function checkOauthToken($userid, $accountid, $forceTokenRefresh=false) { global $adb, $table_prefix; $account = $this->getUserAccounts($userid,$accountid); $account = $account[0]; $accessToken = $account['token']; $refreshToken = $account['refresh_token']; $expires = $account['expires']; $accessTokenObj = new League\OAuth2\Client\Token\AccessToken([ 'access_token' => $accessToken, 'refresh_token' => $refreshToken, 'expires' => $expires ]); if ($accessTokenObj->hasExpired() || $forceTokenRefresh) { $providerName = $this->getOuathProviderName($account); $provider = $this->getOuathProvider($providerName); if ($provider !== false) { $newAccessToken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $accessTokenObj->getRefreshToken() ]); $accessToken = $newAccessToken->getToken(); // update token and expires $adb->pquery("update {$table_prefix}_messages_account set token = ?, expires = ? where id = ?", [$accessToken, $newAccessToken->getExpires(), $accountid]); } } return $accessToken; } function getOuathProviderName($accountinfo) { if ($accountinfo['account'] == 'Gmail' || strpos($accountinfo['server'],'gmail') !== false) { $providerName = 'Google'; } elseif ($accountinfo['account'] == 'Yahoo!' || strpos($accountinfo['server'],'yahoo') !== false) { $providerName = 'Yahoo'; } elseif ($accountinfo['account'] == 'Office365' || strpos($accountinfo['server'],'office365') !== false) { $providerName = 'Microsoft'; } return $providerName; } function getOuathProvider($providerName) { $VTEP = VTEProperties::getInstance(); $credentials = $VTEP->getProperty('modules.messages.oauth2.credentials'); $clientId = $credentials[$providerName]['clientId']; $clientSecret = $credentials[$providerName]['clientSecret']; $redirectUri = $credentials[$providerName]['redirectUri']; switch ($providerName) { case 'Microsoft': if (!empty($clientId) && !empty($clientSecret)) { // direct access return new Stevenmaguire\OAuth2\Client\Provider\Microsoft([ 'clientId' => $clientId, 'clientSecret' => $clientSecret, 'redirectUri' => $redirectUri, 'accessType' => 'offline' ]); } else { // proxy require_once('modules/Messages/OAuth2Proxy/Microsoft.php'); return new Messages\OAuth2\Proxy\MicrosoftProxy([ 'accessType' => 'offline' ]); } default: // TODO Google, Yahoo return false; } } function getOuathProviderOptions($providerName, $state='', $login_hint='', $force=false) { switch ($providerName) { case 'Microsoft': $options = [ 'scope' => [ 'wl.emails', 'wl.imap', 'wl.offline_access' ], ]; break; default: // TODO Google, Yahoo return false; } if (!empty($state)) $options['state'] = $state; if (!empty($login_hint)) $options['login_hint'] = $login_hint; if ($force) { if ($providerName == 'Microsoft') $options['prompt'] = 'consent'; elseif ($providerName == 'Google') $options['approval_prompt'] = 'force'; // TODO Yahoo } return $options; } // crmv@206145e //crmv@125629 function manageConnectionError($e,$userid='') { if (!empty($userid)) { $user = CRMEntity::getInstance('Users'); $user->retrieve_entity_info($userid,'Users'); } else { global $current_user; $user = $current_user; } echo $this->fetchConnectionError($e->getMessage(),$this->getAccount()); exit; } function fetchConnectionError($error,$account) { global $theme; $title = getTranslatedString($error,'Messages'); if ($title != $error) { $descr = getTranslatedString($error.'_DESCR','Messages'); } //if (in_array($error,array('ERR_IMAP_SERVER_EMPTY','ERR_IMAP_CONNECTION_FAILED'))) {} //if (in_array($error,array('ERR_IMAP_CREDENTIALS_EMPTY','ERR_IMAP_LOGIN_FAILED'))) {} $link = 'index.php?module=Messages&action=MessagesAjax&file=Settings/index&operation=Accounts'; $accounts = $this->getUserAccounts(); if ($error == 'ERR_IMAP_SERVER_EMPTY' && empty($accounts)) { $link = 'index.php?module=Messages&action=MessagesAjax&file=Settings/index&operation=EditAccount'; } elseif ($account !== '') { $link = 'index.php?module=Messages&action=MessagesAjax&file=Settings/index&operation=EditAccount&id='.$account; } $descr = sprintf($descr,''.getTranslatedString('LBL_HERE').''); //crmv@46468 crmv@114260 $smarty = new VteSmarty(); $smarty->assign('THEME', $theme); $smarty->assign('TITLE', $title); $smarty->assign('DESCR', $descr); return $smarty->fetch('Error.tpl'); } function checkAccountError($userid, $account='') { global $adb, $table_prefix; $query = "select error, attempts from {$table_prefix}_messages_account where userid = ?"; //crmv@171904 $params = array($userid); if ($account !== '') { $query .= " and id = ?"; $params[] = $account; } $result = $adb->pquery($query, $params); if ($result && $adb->num_rows($result) > 0) { $error = $adb->query_result($result,0,'error'); //crmv@171904 $attempts = $adb->query_result($result,0,'attempts'); if ($attempts < $this->max_login_attempts) { return ''; } //crmv@171904e if (!empty($error)) return $this->fetchConnectionError($error,$account); } return ''; } //crmv@125629e function getMailResource() { return self::$mail; } function resetMailResource() { if (!empty(self::$mail)) { self::$mail->__destruct(); self::$mail = ''; } if (!empty(self::$protocol)) { self::$protocol->__destruct(); self::$protocol = ''; } $this->__construct(); } function setAccount($id) { if ($this->account !== $id) { $this->account = $id; $this->resetMailResource(); } } function getAccount() { if (!is_numeric($this->account) && $this->account == '') { $this->account = $this->column_fields['account']; } if (!is_numeric($this->account) && $this->account == '') { $this->account = '-1'; } return $this->account; } //crmv@76756 function logIMAP($mode, $str) { if (!$this->IMAPDebug) return false; global $root_directory; $now = date('Y-m-d H:i:s'); $dir = $root_directory.$this->IMAPLogDir; if (!is_dir($dir)) { mkdir($dir, 0755); } // find a free name $logfile = false; for ($i=1; $i<1000; ++$i) { $logfile = $dir.str_pad(strval($i), 2, '0', STR_PAD_LEFT).'.log'; if (!file_exists($logfile) || filesize($logfile) < $this->IMAPLogMaxSize) break; } if (stripos($str,' LOGIN ') !== false) { $tmp = explode('"',$str); $tmp[3] = 'password'; $str = implode('"',$tmp); } if ($logfile) { @file_put_contents($logfile, "[$now] [ACCOUNT:{$this->getAccount()}] {$mode}: {$str}\n", FILE_APPEND); if (!file_exists($logfile)) @chmod($logfile, 0777); } } //crmv@76756e //crmv@178164 function setFolderSeparator($account,$separator) { global $adb, $table_prefix; $adb->pquery("update {$table_prefix}_messages_account set folder_separator = ? where id = ?", array($separator,$account)); } function getFolderSeparator($account) { static $folderSeparators = array(); if (!isset($folderSeparators[$account])) { global $adb, $table_prefix; $result = $adb->pquery("select folder_separator from {$table_prefix}_messages_account where id = ?", array($account)); if ($result && $adb->num_rows($result) > 0) { $folderSeparators[$account] = $adb->query_result($result,0,'folder_separator'); } } if (empty($folderSeparators[$account])) { $folderSeparators[$account] = $this->folderSeparator; } return $folderSeparators[$account]; } //crmv@178164e function setSpecialFolders($specialFolders,$accountid) { global $current_user, $adb, $table_prefix; $adb->pquery("delete from {$table_prefix}_messages_sfolders where userid = ? and accountid = ?",array($current_user->id,$accountid)); foreach($specialFolders as $special => $folder) { $adb->pquery("insert into {$table_prefix}_messages_sfolders (userid, accountid, special, folder) values (?,?,?,?)",array($current_user->id,$accountid,$special,$folder)); } } function getSpecialFolders($dieOnError=true) { global $adb, $table_prefix; $specialFolders = $this->defaultSpecialFolders; $accountid = $this->getAccount(); $result = $adb->pquery("select special, folder from {$table_prefix}_messages_sfolders where accountid = ?",array($accountid)); //crmv@44788 if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $specialFolders[$row['special']] = $row['folder']; } } if ($dieOnError) { if (!in_array($_REQUEST['file'],array('Settings/index','MessagePopup')) && (empty($specialFolders['INBOX']) || empty($specialFolders['Sent']) || empty($specialFolders['Drafts']) || empty($specialFolders['Trash'])) ) { $accounts = $this->getUserAccounts(); // check after set account if (!empty($accounts)) { // if error in cron skip if (isset($_REQUEST['app_key']) && $_REQUEST['service'] == 'Messages') { throw new Exception('ERR_IMAP_CRON'); } else { global $theme; $link = 'index.php?module=Messages&action=MessagesAjax&file=Settings/index&operation=Folders'; if ($accountid !== '') { $link = 'index.php?module=Messages&action=MessagesAjax&file=Settings/index&operation=Folders&account='.$accountid; } $smarty = new VteSmarty(); $smarty->assign('THEME', $theme); $smarty->assign('TITLE', getTranslatedString('LBL_ERROR_SPECIALFOLDERS_TITLE','Messages')); $descr = getTranslatedString('LBL_ERROR_SPECIALFOLDERS_DESCR','Messages'); $descr .= '
- '.getTranslatedString('LBL_Folder_INBOX','Messages'); $descr .= '
- '.getTranslatedString('LBL_Folder_Drafts','Messages'); $descr .= '
- '.getTranslatedString('LBL_Folder_Sent','Messages'); $descr .= '
- '.getTranslatedString('LBL_Folder_Trash','Messages'); $smarty->assign('DESCR', sprintf($descr,''.getTranslatedString('LBL_HERE').'')); //crmv@46468 crmv@114260 $smarty->display('Error.tpl'); exit; } } } } return $specialFolders; } function getAllSpecialFolders($special='',$userid='') { global $adb, $table_prefix; if (empty($userid)) { global $current_user; $userid = $current_user->id; } $specialFolders = array(); $query = "select accountid, special, folder from {$table_prefix}_messages_sfolders where userid = ?"; $params = array($userid); if (!empty($special)) { $query .= " and special = ?"; $params[] = $special; } $query .= " order by accountid"; $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { if (!empty($row['folder'])) $specialFolders[$row['accountid']][$row['special']] = $row['folder']; // crmv@192843 } } return $specialFolders; } /* * Find differences from imap and vte (new messages, changes in flags and messages to delete) * - change of flag is made immediately beacouse is only an update in table _messages * - actions of fetching and deleting of messages are recorded in a queue and it will be processed by another cron * * Parameter $skip_inbox: * - true : sync all folders except inbox ones * - false : sync all folders */ function syncUids($skip_inbox=true,$userid=null,$sync_account=null) { global $adb, $table_prefix, $current_user; $query = "SELECT {$table_prefix}_users.id FROM {$table_prefix}_users WHERE {$table_prefix}_users.status = ?"; $params = array('Active'); if (!empty($userid)) { $query .= " and {$table_prefix}_users.id = ?"; $params[] = $userid; } $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $tmp_current_user_id = $current_user->id; if (!$current_user) $current_user = CRMEntity::getInstance('Users'); // crmv@167234 $current_user->id = $user = $row['id']; if ($skip_inbox) $specialFolders = $this->getAllSpecialFolders('INBOX',$user); $accounts = $this->getUserAccounts($user); foreach($accounts as $account) { $accountid = $account['id']; if (!empty($sync_account) && $sync_account != $accountid) continue; try { $this->setAccount($accountid); $this->getZendMailStorageImap($user); // check special folders, do not download message for accounts not totally configured $specialFolders = $this->getSpecialFolders(false); if (empty($specialFolders['INBOX']) || empty($specialFolders['Sent']) || empty($specialFolders['Drafts']) || empty($specialFolders['Trash'])) continue; $special_folders_list = array_keys($specialFolders); //crmv@56609 //crmv@56609 get folder list $tmp2 = array(); $tmp1 = array(); $folders = self::$mail->getFolders(); foreach ($folders as $folder) { $foldername = $folder->getGlobalName(); $in_array = array_search(preg_replace('#'.$this->getFolderSeparator($accountid).'.*#','',$foldername),$special_folders_list); //crmv@178164 if ($in_array !== false) { $tmp1[$in_array.$foldername] = $folder; } else { $tmp2[$foldername] = $folder; } $tmp[$foldername] = $folder; } ksort($tmp1); $tmp = array_merge($tmp1, $tmp2); //crmv@56609e $folder_root = new Zend\Mail\Storage\Folder($this->rootFolder,$this->rootFolder,false,$tmp); //crmv@125287 $folders_it = new RecursiveIteratorIterator($folder_root,RecursiveIteratorIterator::SELF_FIRST); foreach ($folders_it as $folder) { if (!$folder->isSelectable()) continue; $foldername = $folder->getGlobalName(); if ($skip_inbox && $foldername == $specialFolders['INBOX']) continue; //crmv@51946 try { $this->selectFolder($foldername); } catch (Exception $e) { // reset connection $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $this->resetMailResource(); $this->getZendMailStorageImap($user); //crmv@59095 try { $this->selectFolder($foldername); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 continue; } //crmv@59095e } //crmv@51946e $server_ids = array(); // populated in checkFlagsChanges $server_ids_dates = array(); // populated in checkFlagsChanges $cache_ids = array(); // populated in checkFlagsChanges //Update flags of cached mail messages - start $flag_changed = $this->checkFlagsChanges($user,$server_ids,$server_ids_dates,$cache_ids); //end //merge cache_ids (ids saved in vte) with the ids in _messages_cron_uid $query = "select uid from {$table_prefix}_messages_cron_uid where action = ? and userid = ? and accountid = ? and folder = ?"; $params = array('fetch',$user,$accountid,$foldername); if (!empty($this->interval_schedulation)) { $dateCol = 'date'; $adb->format_columns($dateCol); $query .= " AND $dateCol >= ?"; $params[] = date('Y-m-d',strtotime("-{$this->interval_schedulation}")); } $result1 = $adb->pquery($query,$params); if ($result1 && $adb->num_rows($result1) > 0) { while($row1=$adb->fetchByAssoc($result1)) { $cache_ids[] = $row1['uid']; } } //Save new mail messages and delete - start $delete_ids = array_diff($cache_ids,$server_ids); if (!empty($delete_ids)) { $this->populateSyncUidsQueue('noinbox','delete',$user,$accountid,$foldername,$delete_ids,$server_ids_dates); } $new_ids = array_diff($server_ids,$cache_ids); $new_ids = array_reverse($new_ids,true); //scarico dai piu recenti ai piu vecchi if (!empty($new_ids)) { $this->populateSyncUidsQueue('noinbox','fetch',$user,$accountid,$foldername,$new_ids,$server_ids_dates); } //end } } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 //echo "ERROR {$e->getMessage()} user:$user account:$accountid\n"; continue; } } $current_user->id = $tmp_current_user_id; } } } function syncUidsInbox($userid=null,$account=null) { global $adb, $table_prefix, $current_user; // crmv@146653 if (!$current_user) { $current_user = CRMEntity::getInstance('Users'); $current_user->id = 1; } // crmv@146653e $query = "SELECT {$table_prefix}_users.id FROM {$table_prefix}_users WHERE {$table_prefix}_users.status = ?"; $params = array('Active'); if (!empty($userid)) { $query .= " and {$table_prefix}_users.id = ?"; $params[] = $userid; } $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $tmp_current_user_id = $current_user->id; $current_user->id = $user = $row['id']; $allSpecialFolders = $this->getAllSpecialFolders('INBOX',$user); foreach($allSpecialFolders as $accountid => $folders) { try { if (!empty($account) && $account != $accountid) continue; $foldername = $folders['INBOX']; $this->setAccount($accountid); $this->getZendMailStorageImap($user); $this->selectFolder($foldername); // check special folders, do not download message for accounts not totally configured $specialFolders = $this->getSpecialFolders(false); if (empty($specialFolders['INBOX']) || empty($specialFolders['Sent']) || empty($specialFolders['Drafts']) || empty($specialFolders['Trash'])) continue; $server_ids = array(); // populated in checkFlagsChanges $server_ids_dates = array(); // populated in checkFlagsChanges $cache_ids = array(); // populated in checkFlagsChanges //Update flags of cached mail messages - start $flag_changed = $this->checkFlagsChanges($user,$server_ids,$server_ids_dates,$cache_ids); //end //merge cache_ids (ids saved in vte) with the ids in _messages_cron_uidi $query = "select uid from {$table_prefix}_messages_cron_uidi where action = ? and userid = ? and accountid = ? and folder = ?"; $params = array('fetch',$user,$accountid,$foldername); if (!empty($this->interval_schedulation)) { $dateCol = 'date'; $adb->format_columns($dateCol); $query .= " AND $dateCol >= ?"; $params[] = date('Y-m-d',strtotime("-{$this->interval_schedulation}")); } $result1 = $adb->pquery($query,$params); if ($result1 && $adb->num_rows($result1) > 0) { while($row1=$adb->fetchByAssoc($result1)) { $cache_ids[] = $row1['uid']; } } //Save new mail messages and delete - start $delete_ids = array_diff($cache_ids,$server_ids); if (!empty($delete_ids)) { $this->populateSyncUidsQueue('inbox','delete',$user,$accountid,$foldername,$delete_ids,$server_ids_dates); } $new_ids = array_diff($server_ids,$cache_ids); $new_ids = array_reverse($new_ids,true); //scarico dai piu recenti ai piu vecchi if (!empty($new_ids)) { $this->populateSyncUidsQueue('inbox','fetch',$user,$accountid,$foldername,$new_ids,$server_ids_dates); } //end } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 //echo "ERROR {$e->getMessage()} user:$user account:$accountid\n"; continue; } } $current_user->id = $tmp_current_user_id; } } } function syncUidsAll() { global $adb, $table_prefix; $adb->query("delete from {$table_prefix}_messages_sync_all where inbox = 1 and other = 1"); $result = $adb->limitQuery("select * from {$table_prefix}_messages_sync_all where inbox = 0 or other = 0",0,1); if ($result && $adb->num_rows($result) > 0) { $this->interval_schedulation = ''; //crmv@OPER8279 if (!empty($this->interval_storage)) { // if isset interval_storage set the limit of sync $interval_storage = $this->getIntervalStorage(); $this->interval_schedulation = $interval_storage['interval']; } //crmv@OPER8279e $userid = $adb->query_result($result,0,'userid'); $accountid = $adb->query_result($result,0,'accountid'); if ($adb->query_result($result,0,'inbox') == 0) { $adb->pquery("update {$table_prefix}_messages_sync_all set inbox = 1 where accountid = ?",array($accountid)); $this->syncUidsInbox($userid, $accountid); } else { $adb->pquery("update {$table_prefix}_messages_sync_all set other = 1 where accountid = ?",array($accountid)); $this->syncUids(true, $userid, $accountid); } } } function populateSyncUidsQueue($mode,$action,$userid,$accountid,$folder,$uids,$server_ids_dates) { global $adb, $table_prefix; ($mode == 'inbox') ? $table = "{$table_prefix}_messages_cron_uidi" : $table = "{$table_prefix}_messages_cron_uid"; $uids = array_filter($uids); if (!empty($uids)) { foreach($uids as $uid) { ($action == 'delete' || empty($server_ids_dates[$uid])) ? $date = date('Y-m-d H:i:s') : $date = $server_ids_dates[$uid]; $values = array( 'sequence'=>$adb->getUniqueID($table), 'userid'=>$userid, 'accountid'=>$accountid, 'folder'=>$folder, 'uid'=>$uid, 'date'=>$date, 'action'=>$action, 'cdate'=>date('Y-m-d H:i:s'), ); if ($adb->isMysql()) { $adb->pquery("insert ignore into {$table} (".implode(',',array_keys($values)).") values (".generateQuestionMarks($values).")",array($values)); } else { $columns = array_keys($values); $adb->format_columns($columns); $result = $adb->pquery("select * from {$table} where userid = ? and accountid = ? and folder = ? and uid = ?",array($userid,$accountid,$folder,$uid)); if (!$result || $adb->num_rows($result) == 0) { $adb->pquery("insert into {$table} (".implode(',',$columns).") values (".generateQuestionMarks($values).")",array($values)); } } } } } function cleanSyncUidsQueue($userid,$accountid,$folder,$uids='',$crmids='') { global $adb, $table_prefix; $err_uids = $this->getErrUids(); //crmv@50124 $this->err_uids = array(); //crmv@53430 if (!empty($uids)) $uids = array_filter($uids); if (!empty($crmids)) $crmids = array_filter($crmids); if (!empty($err_uids)) $err_uids = array_filter($err_uids); if (!empty($uids)) { $uids = array_map('intval',$uids); if (!empty($uids)) { $adb->pquery("delete from {$table_prefix}_messages_cron_uid where userid = ? and accountid = ? and folder = ? and uid in (".generateQuestionMarks($uids).")",array($userid,$accountid,$folder,$uids)); $adb->pquery("delete from {$table_prefix}_messages_cron_uidi where userid = ? and accountid = ? and folder = ? and uid in (".generateQuestionMarks($uids).")",array($userid,$accountid,$folder,$uids)); } } if (!empty($crmids)) { $crmids = array_map('intval',$crmids); $adb->pquery("delete from {$table_prefix}_messages_cron_uid where userid = ? and accountid = ? and folder = ? and uid in ( select xuid from {$table_prefix}_messages where messagesid in (".generateQuestionMarks($crmids)."))", array($userid,$accountid,$folder,$crmids) ); $adb->pquery("delete from {$table_prefix}_messages_cron_uidi where userid = ? and accountid = ? and folder = ? and uid in ( select xuid from {$table_prefix}_messages where messagesid in (".generateQuestionMarks($crmids)."))", array($userid,$accountid,$folder,$crmids) ); } //crmv@50124 if (!empty($err_uids)) { $err_uids = array_map('intval',$err_uids); $adb->pquery("update {$table_prefix}_messages_cron_uid set status = 1 where userid = ? and accountid = ? and folder = ? and uid in (".generateQuestionMarks($err_uids).")",array($userid,$accountid,$folder,$err_uids)); $adb->pquery("update {$table_prefix}_messages_cron_uidi set status = 1 where userid = ? and accountid = ? and folder = ? and uid in (".generateQuestionMarks($err_uids).")",array($userid,$accountid,$folder,$err_uids)); } //crmv@50124e } function checkSyncUidsErrors() { global $adb, $table_prefix, $current_user; $error = false; $tables = array("{$table_prefix}_messages_cron_uid"=>'Messages',"{$table_prefix}_messages_cron_uidi"=>'MessagesInbox'); foreach($tables as $table => $cron) { $resultCron = $adb->pquery("select lastrun from {$table_prefix}_cronjobs where cronname = ?",array($cron)); if ($resultCron && $adb->num_rows($resultCron) > 0) { $lastrun = $adb->query_result($resultCron,0,'lastrun'); if (empty($lastrun)) continue; $result = $adb->pquery("select * from {$table} where userid = ? and action = ? and status = ? and cdate < ? and attempts = ?",array($current_user->id,'fetch',2,$lastrun,$this->max_message_cron_uid_attempts)); //crmv@55450 if ($result && $adb->num_rows($result) > 0) { $error = true; break; } } } return $error; } function checkSendQueueErrors() { global $adb, $table_prefix, $current_user; $error = false; $resultCron = $adb->pquery("select lastrun from {$table_prefix}_cronjobs where cronname = ?",array('MessagesSend')); if ($resultCron && $adb->num_rows($resultCron) > 0) { $lastrun = $adb->query_result($resultCron,0,'lastrun'); //crmv@98338 if (!empty($lastrun)){ $dateCol = 'date'; $adb->format_columns($dateCol); $result = $adb->pquery("select * from {$table_prefix}_emails_send_queue where userid = ? and method = ? and status = ? and s_send = ? and $dateCol < ?",array($current_user->id,'send',2,0,$lastrun)); if ($result && $adb->num_rows($result) > 0) { $error = true; } } //crmv@98338e } return $error; } function cronSync($user_start='',$user_end='') { // first of all propagate to server pending changes $this->propagateToImap(); // process uids in queue $i = 1; while($this->processSyncUidsQueue('noinbox',$user_start,$user_end)) { if ($this->messages_by_schedule > 0 && $i == $this->messages_by_schedule) break; $i++; } } function cronSyncInbox($user_start='',$user_end='') { // first of all propagate to server pending changes $this->propagateToImap('fast'); // process uids in queue only for inbox folders $i = 1; while($this->processSyncUidsQueue('inbox',$user_start,$user_end)) { if ($this->messages_by_schedule_inbox > 0 && $i == $this->messages_by_schedule_inbox) break; $i++; } } /* * Process sync queue in order to fetch or delete messages in vte * * Parameter $mode: * - 'inbox' : only process uids of inbox folders * - 'noinbox' : process all except uids of inbox folders * - any other value : process all */ function processSyncUidsQueue($mode='',$user_start='',$user_end='') { global $adb, $table_prefix, $current_user; ($mode == 'inbox') ? $table = "{$table_prefix}_messages_cron_uidi" : $table = "{$table_prefix}_messages_cron_uid"; // crmv@103120 $where = ''; if ($user_start != '') { $where = " WHERE mu.userid >= $user_start"; if ($user_end != '') { $where .= " AND mu.userid <= $user_end"; } } (empty($where)) ? $where .= ' WHERE ' : $where .= ' AND '; $where .= "(mu.status = 0 OR (mu.status = 2 AND mu.attempts < {$this->max_message_cron_uid_attempts}))"; //crmv@55450 : not already processed or attempts < max attempts $query = "SELECT mu.* FROM {$table} mu INNER JOIN {$table_prefix}_users u ON u.id = mu.userid AND u.status = 'Active' {$where} ORDER BY mu.date DESC"; // crmv@103120e $result = $adb->limitQuery($query,0,1); if ($result && $adb->num_rows($result) > 0) { $sequence = $adb->query_result($result,0,'sequence'); if (!$current_user) $current_user = CRMEntity::getInstance('Users'); // crmv@167234 $current_user->id = $userid = $adb->query_result($result,0,'userid'); $accountid = $adb->query_result($result,0,'accountid'); $folder = $adb->query_result_no_html($result,0,'folder'); $uid = $adb->query_result($result,0,'uid'); $action = $adb->query_result($result,0,'action'); //echo "$user_start-$user_end: $action u:$userid a:$accountid f:$folder uid:$uid\n"; $this->setAccount($accountid); try { $this->getZendMailStorageImap($userid); } catch (Exception $e) { // problems with connection (ex. account not configured) $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $this->cleanSyncUidsQueue($userid,$accountid,$folder,array($uid)); return true; } try { $this->selectFolder($folder); } catch (Exception $e) { // problems with reading of folder (es. folder deleted) $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $this->cleanSyncUidsQueue($userid,$accountid,$folder,array($uid)); return true; } // set as processing, so if there are problems or timeout with this message, next run skip this $adb->pquery("update {$table} set status = ?, cdate = ?, attempts = attempts+1 where sequence = ?",array(2,date('Y-m-d H:i:s'),$sequence)); //crmv@55450 if ($action == 'delete') { $result1 = $adb->pquery("select messagesid from {$table_prefix}_messages where deleted = 0 and smownerid = ? and account = ? and folder = ? and xuid = ?", array($userid,$accountid,$folder,$uid)); //crmv@171021 if ($result1 && $adb->num_rows($result1) > 0) { $crmid = $adb->query_result($result1,0,'messagesid'); if (!empty($crmid)) { $this->deleteCache(array($crmid=>$uid)); } } $this->cleanSyncUidsQueue($userid,$accountid,$folder,array($uid)); } elseif ($action == 'fetch') { try { $messageId = self::$mail->getNumberByUniqueId($uid); $this->saveCache(array($messageId=>$uid)); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 if ($e->getMessage() == 'unique id not found') { $this->cleanSyncUidsQueue($userid,$accountid,$folder,array($uid)); } //crmv@50124 if error status remain 2 -- $this->setSkippedUids($uid); } $this->cleanSyncUidsQueue($userid,$accountid,$folder,$this->getSkippedUids(),$this->getSavedMessages()); $this->skipped_uids = array(); //crmv@53430 $this->saved_messages = array(); //crmv@53430 } return true; } else { return false; } } /* * Sync immediately server mail folder with vte cache instead of syncUids/syncUidsInbox and then processSyncUidsQueue that made it in two steps. * * Parameters * - $num_news : if empty (null,false,0,'') download all $news_ids * - $only_news : download only new messages from the previous time */ function syncFolder($folder, $num_news=0, $only_news=false) { global $current_user, $adb, $table_prefix; $this->getZendMailStorageImap(); $this->selectFolder($folder); $server_ids = array(); // populated in checkFlagsChanges $server_ids_dates = array(); // populated in checkFlagsChanges $cache_ids = array(); // populated in checkFlagsChanges //Update flags of cached mail messages - start $flag_changed = $this->checkFlagsChanges($current_user->id,$server_ids,$server_ids_dates,$cache_ids); //end // if no messages cached disable $only_news if (empty($cache_ids)) { $only_news = false; } //Save new mail messages and delete - start $delete_ids = array_diff($cache_ids,$server_ids); $this->deleteCache($delete_ids); $this->cleanSyncUidsQueue($current_user->id,$this->account,$folder,$delete_ids); $new_ids = array_diff($server_ids,$cache_ids); $new_ids = array_reverse($new_ids,true); //scarico dai piu recenti ai piu vecchi if ($only_news) { $tmp = array(); //crmv@171021 $result = $adb->limitpQuery("SELECT xuid FROM {$this->table_name} WHERE deleted = 0 AND mtype = ? AND smownerid = ? AND account = ? AND folder = ? ORDER BY mdate DESC",0,1, array('Webmail',$current_user->id,$this->account,$folder)); //crmv@171021e if ($result && $adb->num_rows($result) > 0) { $last_uid = $adb->query_result($result,0,'xuid'); $last_messageid = array_search($last_uid,$server_ids); if (empty($last_messageid)) { //crmv@204525 try { $last_messageid = self::$mail->getNumberByUniqueId($last_uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } //crmv@204525e } foreach($new_ids as $messageid => $uid) { if ($messageid > $last_messageid) { $tmp[$messageid] = $uid; } } } $new_ids = $tmp; } if (!empty($num_news) && !empty($new_ids)) { $new_ids = array_slice($new_ids, 0, $num_news, true); } $this->saveCache($new_ids); $this->cleanSyncUidsQueue($current_user->id,$this->account,$folder,$this->getSkippedUids(),$this->getSavedMessages()); $this->skipped_uids = array(); //crmv@53430 $this->saved_messages = array(); //crmv@53430 //end return array( 'delete_ids'=>$delete_ids, 'new_ids'=>$new_ids, 'flag_changed'=>$flag_changed ); } function addToPropagationCron($operation, $params, $max_attempts=3) { global $adb, $table_prefix; if (is_array($params)) { $params = Zend_Json::encode($params); } $adb->pquery("insert into {$table_prefix}_messages_prop2imap (sequence,operation,params,status,attempts,max_attempts) values (?,?,?,?,?,?)",array( $adb->getUniqueID($table_prefix.'_messages_prop2imap'), $operation, $params, 0, 0, $max_attempts )); } function propagateToImap($mode='full') { global $adb, $table_prefix; // skip running propagations and attempts exceeded $query = "select * from {$table_prefix}_messages_prop2imap where status <> ? and attempts < max_attempts"; $params = array(2); if ($mode == 'fast') { // skip slow operations $query .= " and operation <> ?"; $params[] = 'empty'; } $query .= " order by sequence"; $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result,-1,false)) { $adb->pquery("update {$table_prefix}_messages_prop2imap set status = ?, attempts = ? where sequence = ?",array(2,$row['attempts']+1,$row['sequence'])); try { $params = Zend_Json::decode($row['params']); switch ($row['operation']) { case 'flag': $this->propagateSetFlag($params['id'],$params['flag'],$params['value']); break; case 'flag_folder': $this->propagateFlagFolder($params['userid'],$params['account'],$params['folder'],$params['flag'],$params['value']); break; case 'move': $this->propagateMoveMessage($params['userid'],$params['account'],$params['folder'],$params['uid'],$params['new_folder'],$params['skip_fetch']); break; case 'move_mass': $this->propagateMassMoveMessage($params['userid'],$params['account'],$params['folder'],$params['uid'],$params['new_folder']); break; case 'trash': $this->propagateTrash($params['userid'],$params['account'],$params['folder'],$params['uid'],$params['fetch']); break; case 'empty': $this->propagateEmpty($params['userid'],$params['account'],$params['folder']); break; } $adb->pquery("delete from {$table_prefix}_messages_prop2imap where sequence = ?",array($row['sequence'])); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $adb->pquery("update {$table_prefix}_messages_prop2imap set status = ?, error = ? where sequence = ?",array(1,$e->getMessage(),$row['sequence'])); } } // crmv@102274 // This is necessary because the propagateSetFlag (and probably others too) creates a new instance of Messages and use a different account. // The problem is that the self::$mail and self::$protocol are static, therefore are shared between all the instances. // When the fetch method set the account with setAccount, the self::$protocol is not cleared, since $this->account wasn't changed // (another instance was used) and the old $protocol is still used, even if connected with a different user, causing wrong messages // to be retrieved. $this->setAccount(''); // crmv@102274e } } function syncFolders($userid='', $account='',$skip_empty=false) { //crmv@49843 global $adb, $table_prefix; // crmv@138936 $query = "SELECT m.userid, m.id FROM {$table_prefix}_messages_account m INNER JOIN {$table_prefix}_users u ON u.id = m.userid AND u.status = 'Active'"; $params = array(); if (!empty($userid) && !empty($account)) { $query .= " WHERE m.userid = ? AND m.id = ?"; $params[] = $userid; $params[] = $account; } $query .= " ORDER BY m.userid, m.id"; // crmv@138936e $res = $adb->pquery($query,$params); if ($res && $adb->num_rows($res) > 0) { while($r=$adb->fetchByAssoc($res)) { $account = $r['id']; $userid = $r['userid']; $this->setAccount($account); try { $this->getZendMailStorageImap($userid); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 //crmv@125629 if ($e->getMessage() == 'ERR_IMAP_AUTENTICATION') { throw new Exception($e->getMessage()); } //crmv@125629e continue; } $specialFolders = $this->getSpecialFolders(false); if (empty($specialFolders['INBOX']) && $skip_empty) continue; //crmv@49843 $special_folders_list = array_keys($specialFolders); //Order folder list with $special_folders_list $tmp1 = array(); $tmp2 = array(); $depths = array(); $folders = self::$mail->getFolders(); $this->setFolderSeparator($account,self::$mail->folderSeparator); //crmv@178164 foreach ($folders as $folder) { $foldername = $folder->getGlobalName(); // crmv@178164 crmv@200733 $safeRegexpSeparator = str_replace('.', '\.', $this->getFolderSeparator($account)); $in_array = array_search(preg_replace('#'.$safeRegexpSeparator.'.*#','',$foldername),$special_folders_list); // crmv@178164e crmv@200733e if ($in_array !== false) { $tmp1[$in_array.$foldername] = $folder; } else { $tmp2[$foldername] = $folder; } if (strpos($foldername,$this->getFolderSeparator($account)) !== false) { //crmv@178164 $depths[$foldername] = substr_count($foldername,$this->getFolderSeparator($account)); //crmv@178164 } } ksort($tmp1); $folders = array_merge($tmp1, $tmp2); $folder_root = new Zend\Mail\Storage\Folder($this->rootFolder,$this->rootFolder,false,$folders); //crmv@125287 //end $folders_it = new RecursiveIteratorIterator($folder_root,RecursiveIteratorIterator::SELF_FIRST); $folders = array(); $folders[] = array( 'localname'=>$folder_root->getLocalName(), 'globalname'=>$folder_root->getGlobalName(), 'depth'=>0, 'selectable'=>0, 'count'=>0, ); // crmv@192843 removed count of Shared falder //crmv@171021 removed code // crmv@192843 removed count of Links falder // folder of Flagged mail $count = 0; //crmv@79192 crmv@171021 $result = $adb->pquery("SELECT count(distinct messagehash) AS count FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND account = ? AND flagged = ? and mtype = ?", array($userid,$account,1,'Webmail')); //crmv@79192e crmv@171021e if ($result && $adb->num_rows($result) > 0) { $count = $adb->query_result($result,0,'count'); } $folders[] = array( 'localname'=>'Flagged', 'globalname'=>'Flagged', 'depth'=>0, 'selectable'=>1, 'count'=>$count, ); // end // crmv@187622 $count = 0; $result = $adb->pquery("SELECT count(*) AS count FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND account = ? and mtype = ? and folder = ?", array($userid,$account,'Link','vteScheduled')); if ($result && $adb->num_rows($result) > 0) { $count = $adb->query_result($result,0,'count'); } $folders[] = array( 'localname'=>'vteScheduled', 'globalname'=>'vteScheduled', 'depth'=>0, 'selectable'=>1, 'count'=>$count, ); // crmv@187622e //crmv@85634 crmv@171021 $folder_counts = array(); $result_folder = $adb->pquery("SELECT folder FROM {$this->table_name} WHERE account = ? GROUP BY folder", array($account)); if ($result_folder && $adb->num_rows($result_folder) > 0) { while($row_folder=$adb->fetchByAssoc($result_folder, -1, false)) { $result = $adb->pquery("SELECT count(*) AS count FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND account = ? AND folder = ? AND mtype = ? AND seen = ?", array($userid,$account,$row_folder['folder'],'Webmail',0) ); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result, -1, false)) { $folder_counts[$row_folder['folder']] = $row['count']; } } } } //crmv@85634e crmv@171021e foreach ($folders_it as $folder) { $localName = $folder->getLocalName(); $globalName = $folder->getGlobalName(); $depth1 = $depths[$globalName]; $depth2 = $folders_it->getDepth(); $depth = max($depth1,$depth2); if (empty($depth)) $depth = 0; $folders[] = array( 'localname'=>$localName, 'globalname'=>$globalName, 'depth'=>$depth, 'selectable'=>$folder->isSelectable(), 'count'=>$folder_counts[$globalName], //crmv@51191 ); } $adb->pquery("delete from {$table_prefix}_messages_folders where userid = ? and accountid = ?",array($userid,$account)); $sequence = 0; foreach($folders as $folder) { (empty($folder['selectable'])) ? $selectable = 0 : $selectable = 1; (empty($folder['count'])) ? $folder['count'] = 0 : $folder['count']; //crmv@60402 if ($adb->isMysql()) { $adb->pquery("insert ignore into {$table_prefix}_messages_folders (userid,accountid,globalname,localname,depth,selectable,count,sequence) values (?,?,?,?,?,?,?,?)",array( $userid,$account,$folder['globalname'],$folder['localname'],$folder['depth'],$selectable,$folder['count'],$sequence )); } else { $result = $adb->pquery("select * from {$table_prefix}_messages_folders where userid = ? and accountid = ? and globalname = ?",array($userid,$account,$folder['globalname'])); if (!$result || $adb->num_rows($result) == 0) { $adb->pquery("insert into {$table_prefix}_messages_folders (userid,accountid,globalname,localname,depth,selectable,count,sequence) values (?,?,?,?,?,?,?,?)",array( $userid,$account,$folder['globalname'],$folder['localname'],$folder['depth'],$selectable,$folder['count'],$sequence )); } } $sequence++; } } } } //crmv@79192 crmv@171021 crmv@187622 crmv@192843 crmv@201605 function reloadCacheFolderCount($userid,$accountid,$folder) { global $adb, $table_prefix; ($folder == 'vteScheduled') ? $mtype = 'Link' : $mtype = 'Webmail'; ($folder == 'Flagged') ? $select_count = 'count(distinct messagehash)' : $select_count = 'count(*)'; $query = "SELECT account, folder, $select_count AS count FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? and mtype = ?"; $params = array($userid,$mtype); if ($accountid != 'all') { $query .= ' AND account = ?'; $params[] = $accountid; } if ($folder == 'Flagged') { $query .= " AND flagged = ?"; $params[] = 1; $query .= ' GROUP BY account'; } elseif ($folder == 'vteScheduled') { $query .= " and folder = ?"; $params[] = $folder; $query .= ' GROUP BY account'; } else { $query .= " AND seen = ?"; $params[] = 0; if ($accountid == 'all') { $folders = $this->getAllSpecialFolders($folder); $tmp = array(); foreach($folders as $a => $specialFolders) { $tmp[] = "(account = ? AND folder = ?)"; $params[] = array($a,$specialFolders[$folder]); } $query .= ' AND ('.implode(' OR ',$tmp).')'; } else { $query .= " AND folder = ?"; $params[] = $folder; } $query .= ' GROUP BY account, folder'; } $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result,-1,false)) { $adb->pquery("update {$table_prefix}_messages_folders set count = ? where userid = ? and accountid = ? and globalname = ?", array( $row['count'], $userid, $row['account'], ($folder == 'Flagged' || $folder == 'vteScheduled') ? $folder : $row['folder'] )); } } else { if ($accountid != 'all') { $adb->pquery("update {$table_prefix}_messages_folders set count = ? where userid = ? and accountid = ? and globalname = ?", array(0,$userid,$accountid,$folder)); } elseif ($accountid == 'all' && ($folder == 'Flagged' || $folder == 'vteScheduled')) { $adb->pquery("update {$table_prefix}_messages_folders set count = ? where userid = ? and globalname = ?", array(0,$userid,$folder)); } elseif ($accountid == 'all') { $params = array(0,$userid); $folders = $this->getAllSpecialFolders($folder,$userid); $tmp = array(); foreach($folders as $account => $specialFolders) { $tmp[] = "(account = ? AND folder = ?)"; $params[] = array($account,$specialFolders[$folder]); } if(!empty($tmp)) { $adb->pquery("update {$table_prefix}_messages_folders set count = ? where userid = ?".' AND ('.implode(' OR ',$tmp).')', $params); } } } } //crmv@79192e crmv@171021e crmv@187622e crmv@192843e crmv@201605e /* * Fetch new messages from folder, if $num empty -> fetch only the most recent */ /* crmv@53430 crmv@54904 */ function fetchNews($folder, $num=1) { global $current_user; $this->selectFolder($folder); $cache_ids = $this->getSavedUids($current_user->id); $server_ids = $this->getServerUids(); $new_ids = array_diff($server_ids,$cache_ids); $new_ids = array_slice(array_reverse($new_ids,true),0,$num,true); $this->saveCache($new_ids); $savedMessages = $this->getSavedMessages(); $this->cleanSyncUidsQueue($current_user->id,$this->account,$folder,$this->getSkippedUids(),$savedMessages); $this->skipped_uids = array(); $this->saved_messages = array(); return $savedMessages; } function fetch($account, $folder, $only_news = false) { global $current_user, $adb, $table_prefix; //crmv@48471 if (empty($folder) || $account == '' || in_array($folder,$this->fakeFolders)) { // || $account == 'all' //crmv@62140 return ''; } /* crmv@62140 $specialFolders = $this->getAllSpecialFolders('INBOX'); if (empty($specialFolders[$account]) || $folder == $specialFolders[$account]['INBOX']) { return ''; } crmv@62140e */ //crmv@125629 $err = $this->checkAccountError($current_user->id, $account); if ($err) return $err; //crmv@125629e // crmv@96019 if (PerformancePrefs::get('MESSAGES_UPDATE_ICON_PERFORM_IMAP_ACTIONS', '') == 'disable') { return 'RELOAD'; } // crmv@96019e // first of all propagate to server pending changes $this->propagateToImap(); //TODO parameterize by user //crmv@48471e // crmv@192843 if ($account == 'all') { $accounts = array(); $folders = $this->getAllSpecialFolders($folder); $tmp = $this->getUserAccounts(); foreach($tmp as $t) { $accountid = $t['id']; $accounts[$accountid] = $folders[$accountid][$folder]; } } else { $accounts = array($account => $folder); } $reload = false; foreach ($accounts as $account => $folder) { // crmv@192843e if (empty($folder)) continue; // crmv@192843 $this->setAccount($account); $sync_result = $this->syncFolder($folder, $this->list_max_entries_per_page, $only_news); $delete_ids = $sync_result['delete_ids']; $new_ids = $sync_result['new_ids']; $flag_changed = $sync_result['flag_changed']; if (!empty($delete_ids) || !empty($new_ids) || $flag_changed) { $reload = true; } } if ($reload) return 'RELOAD'; return ''; } // crmv@166575 /** * Fetch the body of the email from IMAP and save it into the message */ public function fetchBody() { global $default_charset; $this->setAccount($this->column_fields['account']); $this->getZendMailStorageImap($this->column_fields['assigned_user_id']); $this->selectFolder($this->column_fields['folder']); //crmv@204525 try { $messageId = $this->getMailResource()->getNumberByUniqueId($this->column_fields['xuid']); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } //crmv@204525e $message = $this->getMailResource()->getMessage($messageId); $data = $this->getMessageContentParts($message,$messageId,true); if (!empty($data['text/plain'])) $data['text/plain'] = implode("\n\n",$data['text/plain']); if (!empty($data['text/html'])) $data['text/html'] = implode('

',$data['text/html']); $body = ''; if (isset($data['text/html'])) { $body = $data['text/html']; $body = str_replace('<','&lt;',$body); $body = str_replace('>','&gt;',$body); } elseif (isset($data['text/plain'])) { $body = nl2br(htmlentities($data['text/plain'], ENT_COMPAT, $default_charset)); } $this->column_fields['cleaned_body'] = ''; // in order to recalculate it $this->column_fields['description'] = $body; $this->column_fields['other'] = $data['other']; $this->mode = 'edit'; $this->save('Messages'); return $data; } // crmv@166575e function selectFolder($folder) { $this->folder = $folder; self::$mail->selectFolder($folder); } function getServerUids() { return self::$mail->getUniqueId(); } function getSavedUids($userid) { if (empty($this->folder) || $this->account === '') { return false; } global $adb, $table_prefix; $external_codes = array(); $result = $adb->pquery("SELECT messagesid as crmid, xuid FROM {$this->table_name} WHERE deleted = 0 AND mtype = ? AND smownerid = ? AND account = ? AND folder = ?",array('Webmail',$userid,$this->account,$this->folder)); //crmv@171021 if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $external_codes[$row['crmid']] = $row['xuid']; } } return $external_codes; } function checkFlagsChanges($userid,&$server_ids,&$server_ids_dates,&$cache_ids) { if (empty($this->folder) || $this->account === '') { return; } // crmv@96019 if (PerformancePrefs::get('MESSAGES_UPDATE_ICON_PERFORM_IMAP_ACTIONS', '') == 'fast_sync') { if ($_REQUEST['file'] == 'Fetch') { $interval_imap_fast_sync = PerformancePrefs::get('INTERVAL_IMAP_FAST_SYNC', false); if (!empty($interval_imap_fast_sync)) { $this->interval_schedulation = $interval_imap_fast_sync; } } } // crmv@96019e if (!empty($this->interval_schedulation)) { $date = date('j-M-Y',strtotime("-{$this->interval_schedulation}")); $messageids = self::$protocol->search(array('SINCE "'.$date.'"','NOT DELETED')); //crmv@146115 /* Lotus do not support SEARCH SINCE... crmv@52514 crmv@57585 crmv@136224 */ if ($messageids !== false) { $chunk = array_chunk($messageids, 50); $tmp_server_ids = array(); foreach($chunk as $i=>$v){ $tmp = self::$protocol->fetch(array('UID','INTERNALDATE'),$v); if (!empty($tmp)) $tmp_server_ids += $tmp; } $searchSinceSupported = true; } else { $tmp_server_ids = self::$protocol->fetch(array('UID','INTERNALDATE','FLAGS'),1,INF); //crmv@146115 $searchSinceSupported = false; $limitTime = strtotime("-{$this->interval_schedulation}"); } /* crmv@52514e crmv@57585e crmv@136224e */ } else { /* all */ $tmp_server_ids = self::$protocol->fetch(array('UID','INTERNALDATE','FLAGS'),1,INF); //crmv@146115 } $server_ids = array(); foreach($tmp_server_ids as $messageid => $val) { //crmv@57585 $save = false; if (!empty($this->interval_schedulation) && !$searchSinceSupported) { (strtotime($val['INTERNALDATE']) >= $limitTime) ? $save = true : $save = false; } else { $save = true; } //crmv@146115 if (isset($val['FLAGS'])) { $flags = array_map('format_flags', $val['FLAGS']); if (in_array(Zend\Mail\Storage::FLAG_DELETED,$flags)) { $save = false; } } //crmv@146115e if ($save) { $server_ids[$messageid] = $val['UID']; $server_ids_dates[$val['UID']] = date('Y-m-d H:i:s',strtotime($val['INTERNALDATE'])); } //crmv@57585e } $found_changes = false; global $adb, $table_prefix; //crmv@58931 crmv@171021 $query = "SELECT xuid, seen, answered, flagged, forwarded, messagesid as crmid FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND mtype = ? AND account = ? AND folder = ?"; $params = array($userid,'Webmail',$this->account,$this->folder); //crmv@58931e crmv@171021e if (!empty($this->interval_schedulation)) { $query .= " AND mdate >= ?"; //crmv@171021 $params[] = date('Y-m-d',strtotime("-{$this->interval_schedulation}")); } $result = $adb->pquery($query,$params); if (!$result || $adb->num_rows($result)== 0) { return; } else { $cache_flags = array(); while($row=$adb->fetchByAssoc($result)) { $tmp = array(); if ($row['seen'] == '1') { $tmp[] = Zend\Mail\Storage::FLAG_SEEN; } if ($row['answered'] == '1') { $tmp[] = Zend\Mail\Storage::FLAG_ANSWERED; } if ($row['flagged'] == '1') { $tmp[] = Zend\Mail\Storage::FLAG_FLAGGED; } if ($row['forwarded'] == '1') { //$tmp[] = '$Forwarded'; $tmp[] = 'Forwarded'; } $cache_flags[$row['xuid']] = $tmp; $cache_ids[$row['crmid']] = $row['xuid']; } } $cache_uids = array_keys($cache_flags); $server_message_ids = array_flip($server_ids); $cache_list = array_intersect($server_ids,$cache_uids); //$cache_list = array_slice($cache_list,-1000,1000,true); //crmv@42701 //crmv@54310 $managed_flags = array(Zend\Mail\Storage::FLAG_SEEN,Zend\Mail\Storage::FLAG_ANSWERED,Zend\Mail\Storage::FLAG_FLAGGED,'$Forwarded','Forwarded'); $server_flags = array(); //crmv@54310 crmv@70424 crmv@174681 if (count($cache_list) <= $this->fetch_array_chunk_limit) { try { $server_flags_tmp = self::$protocol->fetch(array('UID','FLAGS'),array_keys($cache_list)); // read only messages already cached } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); } } else { // read all messages //$server_flags_tmp = self::$protocol->fetch(array('UID','FLAGS'),1,INF); $exception = false; $server_flags_tmp = array(); $tmp_cache_list = array_chunk($cache_list, $this->fetch_array_chunk_limit, true); foreach($tmp_cache_list as $tmp1) { try { $server_flags_tmp += self::$protocol->fetch(array('UID','FLAGS'),array_keys($tmp1)); } catch (Exception $e) { $exception = $e; break; } } if ($exception) { $this->logException($e,__FILE__,__LINE__,__METHOD__); $server_flags_tmp = array(); } } //crmv@54310e crmv@70424e crmv@174681e if (!empty($server_flags_tmp)) { //crmv@174681 foreach ($server_flags_tmp as $i => $info) { $uid = $info['UID']; //crmv@49432 $flags = array_map('format_flags', $info['FLAGS']); $server_flags[$uid] = array_intersect($flags,$managed_flags); //crmv@49432e if (in_array('Forwarded',$server_flags[$uid]) && in_array('$Forwarded',$server_flags[$uid])) { $server_flags[$uid] = array_diff($server_flags[$uid],array('$Forwarded')); } if (empty($server_flags[$uid])) $server_flags[$uid] = array(); if (empty($cache_flags[$uid])) $cache_flags[$uid] = array(); $inter = array_intersect($server_flags[$uid],$cache_flags[$uid]); if (count($inter) != count($server_flags[$uid]) || count($inter) != count($cache_flags[$uid])) { //$inters[$uid] = array('server'=>$server_flags[$uid],'cache'=>$cache_flags[$uid],'inter'=>$inter); $this->updateCacheFlags($userid,$uid,$server_flags[$uid]); //crmv@42701 $found_changes = true; } } } //crmv@174681 return $found_changes; } function updateCacheFlags($userid,$uid,$flags) { //crmv@42701 global $adb, $table_prefix; $sql_update = array( 'seen = ?' => 0, 'answered = ?' => 0, 'flagged = ?' => 0, 'forwarded = ?' => 0, ); foreach($flags as $flag) { switch ($flag) { case Zend\Mail\Storage::FLAG_SEEN : $sql_update['seen = ?'] = 1; break; case Zend\Mail\Storage::FLAG_ANSWERED : $sql_update['answered = ?'] = 1; break; case Zend\Mail\Storage::FLAG_FLAGGED : $sql_update['flagged = ?'] = 1; break; case 'Forwarded': case '$Forwarded': $sql_update['forwarded = ?'] = 1; break; } } //crmv@42701 crmv@63611 crmv@171021 $query = "UPDATE {$this->table_name} SET ".implode(',',array_keys($sql_update))." WHERE xuid = ? AND deleted = 0 AND smownerid = ? AND account = ? AND folder = ?"; $adb->pquery($query,array($sql_update,$uid,$userid,$this->account,$this->folder)); //crmv@42701e crmv@63611e crmv@171021e } function getCacheFlags() { global $adb, $table_prefix; $result = $adb->pquery("SELECT seen, answered, flagged, forwarded FROM {$this->table_name} WHERE {$this->table_name}.messagesid = ?",array($this->id)); $flags = array(); if ($result && $adb->num_rows($result) > 0) { if ($adb->query_result($result,0,'seen') == '1') { $flags[Zend\Mail\Storage::FLAG_SEEN] = Zend\Mail\Storage::FLAG_SEEN; } if ($adb->query_result($result,0,'answered') == '1') { $flags[Zend\Mail\Storage::FLAG_ANSWERED] = Zend\Mail\Storage::FLAG_ANSWERED; } if ($adb->query_result($result,0,'flagged') == '1') { $flags[Zend\Mail\Storage::FLAG_FLAGGED] = Zend\Mail\Storage::FLAG_FLAGGED; } if ($adb->query_result($result,0,'forwarded') == '1') { $flags['$Forwarded'] = '$Forwarded'; $flags['Forwarded'] = 'Forwarded'; } } return $flags; } function getAddressListString($header_obj,$param) { if (get_class($header_obj) != 'ArrayIterator') { $header_obj = array($header_obj); } if ($param == 'full') { $return = array(); foreach ($header_obj as $i) { $return[] = $i->toString(); } return implode(', ',$return); } else { $return = array(); foreach ($header_obj as $i) { $addresslist = $i->getAddressList(); foreach($addresslist as $address_obj) { if ($param == 'email') { $return[] = $address_obj->getEmail(); } elseif ($param == 'name') { $return[] = $address_obj->getName(); } } } return implode(', ',array_filter($return)); // crmv@111982 } } function getMessageHeader($message) { $headerkeys_addr_type = array('From','To','ReplyTo','Cc','Bcc'); $headerkeys = array('From','To','ReplyTo','Cc','Bcc','Date','Subject','Sender','Messageid','Xmailer','In-Reply-To','References','Thread-Index','X-Rcpt-To','X-MDRcpt-To','X-MDArrival-Date','Content-Class','Delivery-Date'); // crmv@64178 crmv@84628 crmv@86123 $return = array(); $squirrelmail = new Squirrelmail($this,true); foreach($headerkeys as $headerkey) { try { $isset = isset($message->{strtolower($headerkey)}); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $isset = false; } if ($isset) { if (in_array($headerkey,$headerkeys_addr_type)) { try { $headerobj = $message->getHeader($headerkey); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 continue; } $full = str_replace("$headerkey: ",'',$this->getAddressListString($headerobj,'full')); if ($headerkey == 'ReplyTo') { $full = str_replace('Reply-To: ','',$full); } $full = $squirrelmail->decodeHeader($full,true,false); $name = $this->getAddressListString($headerobj,'name'); $name = $squirrelmail->decodeHeader($name,true,false); $email = $this->getAddressListString($headerobj,'email'); $return[$headerkey] = array( 'email'=>strval($email), 'name'=>strval($name), 'full'=>strval($full), ); } else { //crmv@49548 try { $value = $message->{strtolower($headerkey)}; } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $headers_arr = $message->getHeaders()->toArray(); $value = $headers_arr[$headerkey]; } //crmv@49548e $return[$headerkey] = strval($squirrelmail->decodeHeader($value,true,false)); } } } return $return; } /* crmv@59492 crmv@59094 */ function getMessageData($message,$id,$include_attach_content=false) { global $default_charset; $data = array(); $data['header'] = $this->getMessageHeader($message); $data['flags'] = $this->getMessageFlags($message); try { $dispositionNotificationTo = $message->getHeaderField('Disposition-Notification-To'); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $dispositionNotificationTo = ''; } if ($this->fetchBodyInCron == 'yes' || ($this->fetchBodyInCron == 'no_disposition_notification_to' && empty($dispositionNotificationTo))) { $content = $this->getMessageContentParts($message,$id,$include_attach_content); if ($content === false) return false; elseif (!empty($content)) $data = array_merge($data, $content); } if (empty($data['flags']['seen'])) { $this->restoreSeenFlag($message,$id); } if (!empty($data['text/plain'])) { $data['text/plain'] = implode("\n\n",$data['text/plain']); } if (!empty($data['text/html'])) { $data['text/html'] = implode('

',$data['text/html']); } // crmv@68357 if (!empty($data['text/calendar'])) { $data['text/calendar'] = $this->parseAndSplitIcal($data['text/calendar']); } // crmv@68357e // crmv@64178 // fix missing headers for some servers (For example: MailDaemon) if (empty($data['header']['Messageid'])) { // generate a fake messageid $uniq_id = md5(strval($uid) . '_' . $data['header']['Subject']); $mid = sprintf('<%s@%s>', $uniq_id, 'localhost'); $data['header']['Messageid'] = $mid; } // crmv@86123 if (!empty($data['header']['Date']) && strpos($data['header']['Date'],"\n") !== false) { $data['header']['Date'] = substr($data['header']['Date'],0,strpos($data['header']['Date'],"\n")); } if (empty($data['header']['Date']) && !empty($data['header']['X-MDArrival-Date'])) { $data['header']['Date'] = $data['header']['X-MDArrival-Date']; } if (empty($data['header']['Date']) && !empty($data['header']['Delivery-Date'])) { $data['header']['Date'] = $data['header']['Delivery-Date']; } // crmv@86123e if (empty($data['header']['To']['full']) && !empty($data['header']['X-Rcpt-To'])) { $data['header']['To']['full'] = $data['header']['X-Rcpt-To']; } if (empty($data['header']['To']['full']) && !empty($data['header']['X-MDRcpt-To'])) { $data['header']['To']['full'] = $data['header']['X-MDRcpt-To']; } // crmv@64178e return $data; } // crmv@68357 // parse several ics/ical inline parts and split them in order to have one event/todo per item public function parseAndSplitIcal($icals) { $list = array(); if (!is_array($icals)) $icals = array($icals); foreach ($icals as $icalTxt) { $pieces = array(); //$config = array( "unique_id" => "VTECRM"); $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($icalTxt); if ($r === false) continue; // add the prodid, since it's not read properly if (preg_match('/^PRODID:(.*)$/m', $icalTxt, $matches)) { $vcalendar->prodid = $matches[1]; } // now parse events and todos, other components are not supported while ($piece = $vcalendar->getComponent("vevent")) { $pieces[] = $piece; } while ($piece = $vcalendar->getComponent("vtodo")) { $pieces[] = $piece; } if (count($pieces) == 0) { continue; // unknown components } elseif (count($pieces) == 1) { // only 1, output as it was $list[] = trim($icalTxt); } else { // more than 1, must split $tzone = $vcalendar->getComponent("vtimezone"); foreach ($pieces as $piece) { $newcal = new VTEvcalendar(); if ($tzone) $newcal->addComponent($tzone); if ($vcalendar->version) $newcal->setVersion($vcalendar->version); if ($vcalendar->prodid) $newcal->prodid = $vcalendar->prodid; if ($vcalendar->method) $newcal->setMethod($vcalendar->method); if ($vcalendar->calscale) $newcal->setCalscale($vcalendar->calscale); $newcal->addComponent($piece); $out = $newcal->createCalendar(); if ($out !== false) $list[] = trim($out); } } } return $list; } // crmv@68357e /* crmv@59094 */ function getMessageContentParts($message,$id,$include_attach_content=false) { $data = array(); $isMultipart = false; try { if ($message->isMultipart()) { $isMultipart = true; } } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } //crmv@150957 $boundary = ''; try { $boundary = $message->getHeaderField('content-type', 'boundary'); } catch (Exception $e) {} if (!$isMultipart && empty($boundary)) { // try to search the boundary in the content $content = $message->__toString($message->getContent()); $matches = array(); preg_match('#Content-Type: multipart\/[^;]+;\s*boundary="([^"]+)"#i', $content, $matches); list(, $boundary) = $matches; if (!empty($boundary)) { $isMultipart = true; $message->contentType = 'multipart/alternative'; $message->boundary = $boundary; } } //crmv@150957e if (!$isMultipart) { try { $contentobj = $message->getHeader('Content-Type'); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } if (get_class($contentobj) == 'Zend\Mail\Header\ContentType') { $contenttype = strtolower($contentobj->getType()); $parameters = $contentobj->getParameters(); //crmv@90966 } elseif (get_class($contentobj) == 'ArrayIterator') { foreach ($contentobj as $contenttmp) { $contenttype = strtolower($contenttmp->getType()); $parameters = $contenttmp->getParameters(); //crmv@90966 break; } } else { $contenttype = 'text/plain'; $parameters = ''; //crmv@90966 } if (!in_array($contenttype,array('text/plain','text/html', 'text/calendar')) && strpos($contenttype,'text/') !== false) $contenttype = 'text/plain'; //crmv@59605 crmv@68357 try { $charset = $message->getHeaderField('Content-Type', 'charset'); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $charset = ''; } $encoding = ''; try { $isset = (isset($message->contentTransferEncoding) && !empty($message->contentTransferEncoding)); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $isset = false; } if ($isset) { $encoding = $message->contentTransferEncoding; } $content = $message->__toString($message->getContent()); // <- this slow down!!!!! //crmv@90966 if (!in_array($contenttype,array('text/plain','text/html', 'text/calendar'))) { $otherContent = array('content'=>$content); $otherContent['parameters'] = $parameters; $otherContent['parameters']['contenttype'] = $contenttype; if (isset($message->contentdisposition)) { $otherContent['parameters']['contentdisposition'] = $message->getHeaderField('contentdisposition'); } else { $otherContent['parameters']['contentdisposition'] = 'attachment'; } if (!empty($charset)) { $otherContent['parameters']['charset'] = $charset; } if (!empty($encoding)) { $otherContent['parameters']['encoding'] = $encoding; } $otherContent['parameters']['size'] = $message->getSize(); //crmv@65328 try { $contentid = $message->getHeader('Content-ID'); //crmv@58436 $contentidClass = get_class($contentid); if ($contentidClass !== false && $contentidClass == 'ArrayIterator') { foreach($contentid as $c) { try { $contentid = $c->getFieldValue(); break; } catch (Exception $e) {} } } else { $contentid = $contentid->getFieldValue(); } //crmv@58436e $contentid = ltrim($contentid,'<'); $contentid = rtrim($contentid,'>'); $otherContent['parameters']['content_id'] = $contentid; } catch (Exception $e) {} //crmv@45179 crmv@43245 crmv@53651 //crmv@136313 if (!empty($otherContent['parameters']['name'])) { $filename_parts = pathinfo($otherContent['parameters']['name']); if (empty($filename_parts['filename'])) unset($otherContent['parameters']['name']); } //crmv@136313e if (empty($otherContent['parameters']['name'])) { $filename = 'Unknown'; try { $filename_tmp = $message->getHeader('Content-Disposition')->getFieldValue(); $pos = stripos($filename_tmp,'filename='); //crmv@129689 if (!empty($filename_tmp) && $pos !== false) { $r = preg_match('/filename="([^"]+)"/i', $filename_tmp, $matches); //crmv@129689 if (!empty($matches[1])) $filename = $matches[1]; } } catch (Exception $e) {} if ($filename == 'Unknown' && $contenttype == 'message/delivery-status') { $filename = 'details.txt'; } if ($filename == 'Unknown' && $contenttype == 'text/rfc822-headers') { $filename = 'message.txt'; } $otherContent['parameters']['name'] = $filename; } //crmv@45179e crmv@43245e crmv@53651e if (!$include_attach_content) unset($otherContent['content']); //crmv@59492 $data['other'][] = $otherContent; } else { $content = $this->decodePart($content,$encoding,$charset); $data[$contenttype][] = $content; } //crmv@90966e } else { try { foreach (new RecursiveIteratorIterator($message) as $part) { // <- this slow down!!!!! /* echo $id.'
';
					print_r($part);
					echo '


'; */ try { $contentobj = $part->getHeader('Content-Type'); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } if (get_class($contentobj) == 'Zend\Mail\Header\ContentType') { $contenttype = strtolower($contentobj->getType()); $parameters = $contentobj->getParameters(); } elseif (get_class($contentobj) == 'ArrayIterator') { foreach ($contentobj as $contenttmp) { $contenttype = strtolower($contenttmp->getType()); $parameters = $contenttmp->getParameters(); break; } } else { $contenttype = 'text/plain'; $parameters = ''; } try { $charset = $part->getHeaderField('Content-Type', 'charset'); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $charset = ''; } $encoding = ''; try { $isset = (isset($part->contentTransferEncoding) && !empty($part->contentTransferEncoding)); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $isset = false; } if ($isset) { $encoding = $part->contentTransferEncoding; } $content = $part->__toString($part->getContent()); // text/html content $txtContent = $this->decodePart($content,$encoding,$charset); // attachment content $otherContent = array('content'=>$content); $otherContent['parameters'] = $parameters; $otherContent['parameters']['contenttype'] = $contenttype; if (isset($part->contentdisposition)) { $otherContent['parameters']['contentdisposition'] = $part->getHeaderField('contentdisposition'); } if (!empty($charset)) { $otherContent['parameters']['charset'] = $charset; } if (!empty($encoding)) { $otherContent['parameters']['encoding'] = $encoding; } $otherContent['parameters']['size'] = $part->getSize(); //crmv@65328 try { $contentid = $part->getHeader('Content-ID'); //crmv@58436 $contentidClass = get_class($contentid); if ($contentidClass !== false && $contentidClass == 'ArrayIterator') { foreach($contentid as $c) { try { $contentid = $c->getFieldValue(); break; } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } } } else { $contentid = $contentid->getFieldValue(); } //crmv@58436e $contentid = ltrim($contentid,'<'); $contentid = rtrim($contentid,'>'); $otherContent['parameters']['content_id'] = $contentid; } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } // check if is text/html part or attachment $isText = false; if (in_array($contenttype,array('text/plain','text/html', 'text/calendar'))) { // crmv@68357 $isText = true; } //crmv@46629 if (in_array($contenttype,array('text/plain','text/html', 'text/calendar')) && $otherContent['parameters']['contentdisposition'] == 'inline') { // crmv@68357 $isText = true; //crmv@46629e } elseif (!in_array($contenttype,array('text/plain','text/html', 'text/calendar')) || !empty($otherContent['parameters']['name']) || !empty($otherContent['parameters']['contentdisposition'])) { // crmv@68357 if ($isText && $contenttype == 'text/calendar') $data[$contenttype][] = $txtContent; // crmv@68357, split it as an attachment + ical $isText = false; //crmv@45179 crmv@43245 crmv@53651 //crmv@136313 if (!empty($otherContent['parameters']['name'])) { $filename_parts = pathinfo($otherContent['parameters']['name']); if (empty($filename_parts['filename'])) unset($otherContent['parameters']['name']); } //crmv@136313e if (empty($otherContent['parameters']['name'])) { $filename = 'Unknown'; try { $filename_tmp = $part->getHeader('Content-Disposition')->getFieldValue(); $pos = stripos($filename_tmp,'filename='); //crmv@129689 if (!empty($filename_tmp) && $pos !== false) { $r = preg_match('/filename="([^"]+)"/i', $filename_tmp, $matches); //crmv@129689 if (!empty($matches[1])) $filename = $matches[1]; } } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } if ($filename == 'Unknown' && $contenttype == 'message/delivery-status') { $filename = 'details.txt'; } if ($filename == 'Unknown' && $contenttype == 'text/rfc822-headers') { $filename = 'message.txt'; } //crmv@129689 if ($filename == 'Unknown' && $contenttype == 'message/rfc822') { $messagesid = 0; $error = ''; $str = $otherContent['content']; $str = $this->decodeAttachment($str,$otherContent['parameters']['encoding'],$otherContent['parameters']['charset']); $eml_message = $this->parseEML(0, $messagesid, $error, $str, true); if (empty($error) && !empty($eml_message['subject'])) $filename = $eml_message['subject']; } //crmv@129689e //crmv@90697 if ($filename == 'Unknown' && stripos($contenttype,'image/') === 0) { $extension = substr($contenttype,6); if(in_array(strtolower($extension),$this->inline_image_supported_extensions)){ $filename .= '.'.$extension; } } if ($filename == 'Unknown' && empty($otherContent['parameters']['contentdisposition'])) { $otherContent['parameters']['contentdisposition'] = 'attachment'; } //crmv@90697e $otherContent['parameters']['name'] = $filename; } //crmv@45179e crmv@43245e crmv@53651e } if ($isText) { $data[$contenttype][] = $txtContent; } else { if (!$include_attach_content) unset($otherContent['content']); //crmv@59492 $data['other'][] = $otherContent; } } } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 if ($e->getMessage() == 'Not a valid Mime Message: End Missing') { return false; } } } return $data; } function getMessageFlags($message) { $flags = array( 'seen' => '', 'answered' => '', 'flagged' => '', 'forwarded' => '', 'draft' => '', //crmv@84628 'deleted' => '', //crmv@146115 ); if ($message->hasFlag(Zend\Mail\Storage::FLAG_SEEN)) { $flags['seen'] = 'on'; } if ($message->hasFlag(Zend\Mail\Storage::FLAG_ANSWERED)) { $flags['answered'] = 'on'; } if ($message->hasFlag(Zend\Mail\Storage::FLAG_FLAGGED)) { $flags['flagged'] = 'on'; } if ($message->hasFlag('Forwarded') || $message->hasFlag('$Forwarded')) { $flags['forwarded'] = 'on'; } //crmv@84628 if ($message->hasFlag(Zend\Mail\Storage::FLAG_DRAFT)) { $flags['draft'] = 'on'; } //crmv@84628e //crmv@146115 if ($message->hasFlag(Zend\Mail\Storage::FLAG_DELETED)) { $flags['deleted'] = 'on'; } //crmv@146115e return $flags; } function restoreSeenFlag($message,$id) { $flags = $message->getFlags(); //crmv@49432 unset($flags[array_search(Zend\Mail\Storage::FLAG_SEEN, $flags)]); unset($flags[array_search(Zend\Mail\Storage::FLAG_RECENT, $flags)]); // error to set recent flag //crmv@49432e if (!empty(self::$mail)) //crmv@90941 try { self::$mail->setFlags($id, $flags); } catch (Zend\Mail\Storage\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } catch (Zend\Mail\Protocol\Exception\RuntimeException $e) { // crmv@191000 $this->logException($e,__FILE__,__LINE__,__METHOD__); } } function decodePart($content,$encoding='',$charset='') { global $default_charset; if (isset($encoding)) { switch (strtolower($encoding)) { //crmv@46629 case 'base64': $content = base64_decode($content); break; case 'quoted-printable': $content = quoted_printable_decode($content); break; } } //crmv@54247 crmv@80351 if (function_exists('mb_detect_encoding') && (empty($charset) || strtolower(substr($charset, 0, 4)) == 'iso-' || in_array(strtolower($charset),array('ascii','utf-8')))) { //crmv@127068 crmv@134869 crmv@142043 // add here new encodings to check, pay attention to the order! if (strtolower(substr($charset, 0, 4)) == 'iso-') { // use the provided charset as the fallback during detection, // since there is no way to tell from the different ISO charsets $encorder = 'ASCII,UTF-8,'.strtoupper($charset); } else { // otherwise do it as usual $encorder = 'ASCII,UTF-8,ISO-8859-1'; } $detect_charset = mb_detect_encoding($content, $encorder); if (!empty($detect_charset)) $charset = $detect_charset; } //crmv@54247e crmv@80351e //crmv@90390 $content_encoded = correctEncoding($content, $default_charset, $charset); if ($content_encoded !== false) $content = $content_encoded; //crmv@90390e return $content; } function decodeAttachment($content,$encoding='',$charset='') { global $default_charset; if (isset($encoding)) { switch (strtolower($encoding)) { //crmv@46629 case 'base64': $content = base64_decode($content); break; case 'quoted-printable': $content = quoted_printable_decode($content); break; } } return $content; } function propagateEmpty($userid,$account,$folder) { global $adb, $table_prefix, $current_user; $tmp_current_user_id = $current_user->id; $current_user->id = $userid; $focus = CRMEntity::getInstance('Messages'); $focus->setAccount($account); $focus->getZendMailStorageImap($userid); $focus->emptyFolder($folder); $focus->syncFolder($folder); $focus->reloadCacheFolderCount($userid,$account,$folder); $current_user->id = $tmp_current_user_id; } /* crmv@56636 */ function emptyFolder($folder) { // delete messages in folder self::$mail->selectFolder($folder); $uids = $this->getServerUids(); if (!empty($uids)) { foreach($uids as $messageId => $uid) { //$messageId = self::$mail->getNumberByUniqueId($uid); try { self::$mail->removeMessage($messageId); } catch (Zend\Mail\Storage\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } } } // delete messages in subfolders $subfolders = array(); try { $folders = self::$mail->getFolders($folder); if ($folders->getGlobalName() == $this->getFolderSeparator($this->account)) { // check to have the correct tree //crmv@178164 $folders_it = new RecursiveIteratorIterator($folders,RecursiveIteratorIterator::CHILD_FIRST); foreach ($folders_it as $tmp_folders) { if ($tmp_folders->getGlobalName() == $folder) { $folders = $tmp_folders; break; } } } $specialFolders = $this->getSpecialFolders(); $folders_it = new RecursiveIteratorIterator($folders,RecursiveIteratorIterator::CHILD_FIRST); foreach ($folders_it as $localName => $leave_folder) { if ($leave_folder == $folder || in_array($leave_folder,$specialFolders)) { // check to not delete Trash folder or other special folders continue; } $leave_folder = htmlspecialchars($leave_folder); self::$mail->selectFolder($leave_folder); $uids = $this->getServerUids(); if (!empty($uids)) { foreach($uids as $messageId => $uid) { //$messageId = self::$mail->getNumberByUniqueId($uid); self::$mail->removeMessage($messageId); } } $subfolders[] = $leave_folder; } } catch (Zend\Mail\Exception\InvalidArgumentException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } // delete subfolders if (!empty($subfolders)) { try { self::$mail->selectFolder($folder); foreach ($subfolders as $leave_folder) { self::$mail->removeFolder($leave_folder); } } catch (Zend\Mail\Exception\InvalidArgumentException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } } } function flagFolder($account,$folder,$flag) { global $adb, $table_prefix, $current_user; if ($flag == 'seen') { $field = 'seen'; $value = 1; } elseif ($flag == 'unseen') { $field = 'seen'; $value = 0; } $this->addToPropagationCron('flag_folder', array('userid'=>$current_user->id,'account'=>$account,'folder'=>$folder,'flag'=>$field,'value'=>$value)); //crmv@63611 crmv@171021 $adb->pquery("UPDATE {$this->table_name} SET $field = ? WHERE deleted = 0 AND mtype = ? AND smownerid = ? AND account = ? AND folder = ? AND $field <> ? ",array($value,'Webmail',$current_user->id,$account,$folder,$value)); //crmv@57797 //crmv@63611e crmv@171021e if ($field == 'seen') { $this->reloadCacheFolderCount($current_user->id,$account,$folder); } } function propagateFlagFolder($userid,$account,$folder,$flag,$value) { $focus = CRMEntity::getInstance('Messages'); $focus->setAccount($account); $focus->getZendMailStorageImap($userid); self::$mail->selectFolder($folder); $managed_flags = array(Zend\Mail\Storage::FLAG_SEEN,Zend\Mail\Storage::FLAG_ANSWERED,Zend\Mail\Storage::FLAG_FLAGGED,'$Forwarded','Forwarded'); $server_flags = array(); $server_flags_tmp = self::$protocol->fetch(array('UID','FLAGS'),1,INF); foreach ($server_flags_tmp as $i => $info) { $uid = array_shift($info); //crmv@49432 $flags = array_map('format_flags', $info['FLAGS']); $oldflags = $flags = array_intersect($flags,$managed_flags); //crmv@49432e if ($flag == 'seen') { if ($value == 0) { unset($flags[array_search(Zend\Mail\Storage::FLAG_SEEN,$flags)]); } elseif ($value == 1 && !in_array(Zend\Mail\Storage::FLAG_SEEN,$flags)) { $flags[] = Zend\Mail\Storage::FLAG_SEEN; } } $server_flags[$uid] = $flags; try { self::$mail->setFlags($i, $flags); } catch (Zend\Mail\Storage\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } } } function folderMove($account,$folder,$move_in) { global $current_user; // crmv@205127 $this->setAccount($account); $specialFolders = $this->getSpecialFolders(); if (in_array($folder,$specialFolders)) { return false; } $this->getZendMailStorageImap(); $folder_tree = explode($this->getFolderSeparator($account),$folder); //crmv@178164 //crmv@125287 if ($move_in == $this->rootFolder) $move_in = $folder_tree[count($folder_tree)-1]; else $move_in .= $this->getFolderSeparator($account).$folder_tree[count($folder_tree)-1]; //crmv@47411 crmv@178164 //crmv@125287e try { self::$mail->renameFolder($folder,$move_in); $this->syncFolders($current_user->id,$account); // crmv@205127 force sync return true; } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 /* try { // new folder already exixsts $folder = self::$mail->getFolders(); foreach($folder_tree as $f) { $folder = $folder->__get($f); } } catch (Exception $e) { // old folder do not exists } */ return false; } } function folderCreate($account,$folder,$current_folder) { global $current_user; // crmv@205127 if ($current_folder == $this->rootFolder) $current_folder = null; //crmv@125287 $this->setAccount($account); $this->getZendMailStorageImap(); try { //crmv@91187 global $default_charset; if (function_exists('mb_convert_encoding')) { $folder = mb_convert_encoding($folder, "UTF7-IMAP",$default_charset); } //crmv@91187e self::$mail->createFolder($folder,$current_folder,$this->getFolderSeparator($account)); //crmv@47411 crmv@178164 $this->syncFolders($current_user->id,$account); // crmv@205127 force sync } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 return false; } } function getFoldersList($mode='list',$current_folder='',$move_mode='') { global $adb, $table_prefix, $current_user; $folders = array(); $query = "select * from {$table_prefix}_messages_folders where userid = ? and accountid = ?"; $params = array($current_user->id,$this->getAccount()); // crmv@187622 if ($mode != 'list') { $query .= " and localname not in (".generateQuestionMarks($this->fakeFolders).")"; $params[] = $this->fakeFolders; } // crmv@187622e if ($move_mode != 'folders') { $query .= " and localname <> ?"; $params[] = $this->rootFolder; //crmv@125287 } $query .= " order by sequence"; $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { //crmv@61520 while($row=$adb->fetchByAssoc($result, -1, false)) { $localName = htmlentities(str_replace("\x00", '', imap_utf7_decode($row['localname'])), ENT_NOQUOTES, 'ISO-8859-1'); $globalName = htmlentities(str_replace("\x00", '', imap_utf7_decode($row['globalname'])), ENT_NOQUOTES, 'ISO-8859-1'); switch ($localName) { case $this->rootFolder: //crmv@125287 $folders[($globalName)] = array( 'label'=>''.($localName).''.getTranslatedString('LBL_ROOT','Messages'), //crmv@61520 e 'selectable'=>true, 'depth'=>0 ); break; case (in_array($localName,$this->fakeFolders)): // crmv@187622 if ($row['count'] > 0 && in_array($localName,array('Flagged','vteScheduled'))) { // crmv@192843 $arr = array( 'label'=>getTranslatedString('LBL_Folder_'.$localName,'Messages'), 'selectable'=>$row['selectable'], 'depth'=>$row['depth'], 'count'=>$row['count'] ); (isset($this->folderImgs[$localName])) ? $arr['vteicon'] = $this->folderImgs[$localName] : $arr['vteicon'] = 'folder'; // crmv@192843 $folders[$globalName] = $arr; } break; default: $specialFolders = $this->getSpecialFolders(); $aliasSpecialFolder = array_search($globalName,$specialFolders); if (!empty($aliasSpecialFolder)) { $label = $aliasSpecialFolder; } else { $label = ($localName); //crmv@61520 } $label_trans = getTranslatedString('LBL_Folder_'.$label,'Messages'); if ($label_trans != 'LBL_Folder_'.$label) { $label = $label_trans; } (!empty($aliasSpecialFolder)) ? $img_str = $aliasSpecialFolder : $img_str = $localName; // crmv@192843 $arr = array( 'label'=>$label, // crmv@192843 removed 'selectable'=>$row['selectable'], 'depth'=>$row['depth'], 'count'=>$row['count'], 'bg_notification_color'=>'#2c80c8' ); if ($mode == 'move' && !empty($current_folder) && $globalName == $current_folder) { $arr['selectable'] = false; } (isset($this->folderImgs[$img_str])) ? $arr['vteicon'] = $this->folderImgs[$img_str] : $arr['vteicon'] = 'folder'; // crmv@192843 $folders[$globalName] = $arr; break; } } /* } else { // force sync $this->syncFolders($current_user->id,$this->getAccount()); $folders = $this->getFoldersList($mode,$current_folder,$move_mode); */ } return $folders; } function getStrUnreadMessageCount($folder='') { $string = ''; $count = $this->getUnreadMessageCount($folder); if (intval($count) > 0) { $string = ' ('.$count.')'; } return $string; } function getUnreadMessageCount($folder='') { if (empty($folder)) { global $current_folder; $folder = $current_folder; } $account = $this->getAccount(); if (!empty($folder) && !in_array($folder,$this->fakeFolders)) { // crmv@192843 global $adb, $table_prefix, $current_user; //crmv@171021 $query = "SELECT count(*) AS count FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND seen = ? and mtype = ?"; //crmv@171021e $params = array($current_user->id,0,'Webmail'); if ($account == 'all') { // crmv@192843 $folders = $this->getAllSpecialFolders($folder); $tmp = array(); foreach($folders as $account => $specialFolders) { $tmp[] = "(account = ? AND folder = ?)"; //crmv@171021 $params[] = array($account,$specialFolders[$folder]); } // crmv@192843e if(!empty($tmp)) $query .= ' AND ('.implode(' OR ',$tmp).')'; // crmv@170276 // crmv@42537 } elseif ($folder == 'any') { $query .= ' AND account = ?'; $params[] = array($account); // crmv@42537e } else { $query .= " and account = ? and folder = ?"; $params[] = array($account,$folder); } $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { return $adb->query_result($result,0,'count'); } } else { return false; } } // crmv@63349 public function getRelatedModComments($return_query=false, $userid='') { if (PerformancePrefs::getBoolean('USE_TEMP_TABLES', true)) { return $this->getRelatedModComments_tmp($return_query, $userid); } else { return $this->getRelatedModComments_notmp($return_query, $userid); } } public function getRelatedModComments_notmp($return_query=false, $userid='') { global $adb, $table_prefix, $current_user; if (empty($userid)) { global $current_user; $user = $current_user; } else { $user = CRMEntity::getInstance('Users'); $user->retrieveCurrentUserInfoFromFile($userid); } $query = "SELECT messagesid AS \"id\" FROM {$table_prefix}_modcomments_msgrel WHERE userid = ?"; $params = array($user->id); if ($return_query) { return $adb->convert2Sql($query,$adb->flatten_array($params)); } $result = $adb->pquery($query,$params); $tmp = array(); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result, -1, false)) { $tmp[] = $row['id']; } } return $tmp; } public function isMessageRelatedModComments($messageId) { global $adb, $table_prefix, $current_user; $cnt = 0; $result = $adb->pquery("SELECT COUNT(*) AS cnt FROM {$table_prefix}_modcomments_msgrel WHERE userid = ? AND messagesid = ?", array($current_user->id, $messageId)); if ($result && $adb->num_rows($result) > 0) { $cnt = intval($adb->query_result_no_html($result, 0, 'cnt')); } return ($cnt > 0); } public function countRelatedModComments() { global $adb, $table_prefix, $current_user; $cnt = 0; $result = $adb->pquery("SELECT COUNT(*) AS cnt FROM {$table_prefix}_modcomments_msgrel WHERE userid = ?", array($current_user->id)); if ($result && $adb->num_rows($result) > 0) { $cnt = intval($adb->query_result_no_html($result, 0, 'cnt')); } return $cnt; } public function regenCommentsMsgRelTable($userid, $messagesid = 0) { global $adb, $table_prefix; if (empty($userid)) { global $current_user; $user = $current_user; } else { $user = CRMEntity::getInstance('Users'); $user->retrieveCurrentUserInfoFromFile($userid); } // clean $this->cleanCommentsMsgRelTable($userid, $messagesid); //crmv@58931 crmv@60402 crmv@171021 $params = Array(); if($adb->isMssql() || $adb->isOracle()){ $col_arr = array('user'); $adb->format_columns($col_arr); $userCol = $col_arr[0]; } else { $userCol = 'user'; } $idCol = 'ID'; // leave uppercase, or oracle will have problems $adb->format_columns($idCol); $msgidSql = ''; if ($messagesid > 0) { $msgidSql = "AND {$table_prefix}_messages.messagesid = $messagesid"; } if ($user->column_fields['receive_public_talks'] == '1') { $query1 = "SELECT {$table_prefix}_modcomments.related_to AS \"ID\", {$table_prefix}_modcomments.modcommentsid FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to WHERE {$table_prefix}_crmentity.deleted = 0 $msgidSql AND {$table_prefix}_messages.deleted = 0 and visibility_comm = ? AND {$table_prefix}_crmentity.smownerid <> ? AND {$table_prefix}_modcomments.parent_comments = 0 AND {$table_prefix}_modcomments.related_to <> 0 AND {$table_prefix}_modcomments.related_to <> '' "; // crmv@175523 $params[] = 'All'; $params[] = $user->id; $query2 = "SELECT {$table_prefix}_modcomments.related_to AS \"ID\", {$table_prefix}_modcomments.modcommentsid FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to INNER JOIN {$table_prefix}_modcomments_users ON {$table_prefix}_modcomments_users.$idCol = {$table_prefix}_modcomments.modcommentsid WHERE {$table_prefix}_crmentity.deleted = 0 $msgidSql AND {$table_prefix}_messages.deleted = 0 AND visibility_comm = ? AND {$table_prefix}_modcomments_users.{$userCol} = ? AND {$table_prefix}_modcomments.parent_comments = 0 AND {$table_prefix}_modcomments.related_to <> 0 AND {$table_prefix}_modcomments.related_to <> '' "; // crmv@175523 $params[] = 'Users'; $params[] = $user->id; $query = "select t.$idCol, MIN(t.modcommentsid) AS \"modcommentsid\" from ($query1 union $query2) t GROUP BY $idCol"; } else { $query = "SELECT {$table_prefix}_modcomments.related_to AS \"ID\", MIN({$table_prefix}_modcomments.modcommentsid) AS \"modcommentsid\" FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to INNER JOIN {$table_prefix}_modcomments_users ON {$table_prefix}_modcomments_users.$idCol = {$table_prefix}_modcomments.modcommentsid WHERE {$table_prefix}_crmentity.deleted = 0 AND $msgidSql {$table_prefix}_messages.deleted = 0 AND visibility_comm = ? AND {$table_prefix}_modcomments_users.{$userCol} = ? AND {$table_prefix}_modcomments.parent_comments = 0 AND {$table_prefix}_modcomments.related_to <> 0 AND {$table_prefix}_modcomments.related_to <> '' GROUP BY {$table_prefix}_modcomments.related_to"; // crmv@175523 $params[] = 'Users'; $params[] = $user->id; } $q = $adb->convert2Sql($query,$adb->flatten_array($params)); //crmv@58931e crmv@60402e crmv@171021e // now insert into the table $q = "INSERT INTO {$table_prefix}_modcomments_msgrel (userid, messagesid) SELECT $userid as userid, tcomments.$idCol FROM ($q) tcomments"; $adb->query($q); } /** * Clean the Talks-Messages table for the specified user or messageid */ public function cleanCommentsMsgRelTable($userid = 0, $messagesid = 0) { global $adb, $table_prefix; $params = array(); $wheres = array(); $q = "DELETE FROM {$table_prefix}_modcomments_msgrel"; if ($userid > 0) { $wheres[] = "userid = ?"; $params[] = $userid; } if ($messagesid > 0) { $wheres[] = "messagesid = ?"; $params[] = $messagesid; } if (count($wheres) > 0) { $q .= " WHERE ".implode(' AND ', $wheres); } $adb->pquery($q, $params); } // crmv@63349e function getRelatedModComments_tmp($return_query=false,$userid='') { // crmv@63349 if (empty($userid)) { global $current_user; $user = $current_user; } else { $user = CRMEntity::getInstance('Users'); $user->retrieveCurrentUserInfoFromFile($userid); } static $ids_msg_with_comments = array(); static $ids_msg_with_comments_presence = array(); if (empty($ids_msg_with_comments_presence[$user->id])) $ids_msg_with_comments_presence[$user->id] = false; if (!$return_query && $ids_msg_with_comments_presence[$user->id]) { return $ids_msg_with_comments[$user->id]; } //crmv@171021 removed code global $adb, $table_prefix; //crmv@58931 crmv@60402 crmv@171021 $params = Array(); if($adb->isMssql()){ $col_arr = array('user'); $adb->format_columns($col_arr); $userCol = $col_arr[0]; } else { $userCol = 'user'; } if ($user->column_fields['receive_public_talks'] == '1') { $query1 = "SELECT {$table_prefix}_modcomments.related_to AS \"id\" FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to WHERE {$table_prefix}_crmentity.deleted = 0 AND {$table_prefix}_messages.deleted = 0 and visibility_comm = ? AND {$table_prefix}_crmentity.smownerid <> ? group by {$table_prefix}_modcomments.related_to"; $params[] = 'All'; $params[] = $user->id; $query2="SELECT {$table_prefix}_modcomments.related_to AS \"id\" FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to INNER JOIN {$table_prefix}_modcomments_users ON {$table_prefix}_modcomments_users.id = {$table_prefix}_modcomments.modcommentsid WHERE {$table_prefix}_crmentity.deleted = 0 AND {$table_prefix}_messages.deleted = 0 AND visibility_comm = ? AND {$table_prefix}_modcomments_users.{$userCol} = ? group by {$table_prefix}_modcomments.related_to"; $params[] = 'Users'; $params[] = $user->id; $query = "select id from ($query1 union $query2) t group by id"; } else { $query="SELECT {$table_prefix}_modcomments.related_to AS \"id\" FROM {$table_prefix}_modcomments INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_modcomments.modcommentsid INNER JOIN {$table_prefix}_messages ON {$table_prefix}_messages.messagesid = {$table_prefix}_modcomments.related_to INNER JOIN {$table_prefix}_modcomments_users ON {$table_prefix}_modcomments_users.id = {$table_prefix}_modcomments.modcommentsid WHERE {$table_prefix}_crmentity.deleted = 0 AND {$table_prefix}_messages.deleted = 0 AND visibility_comm = ? AND {$table_prefix}_modcomments_users.{$userCol} = ? group by {$table_prefix}_modcomments.related_to"; $params[] = 'Users'; $params[] = $user->id; } //crmv@58931e crmv@60402e crmv@171021e if ($return_query) { return $adb->convert2Sql($query,$adb->flatten_array($params)); } $result = $adb->pquery($query,$params); $tmp = array(); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $tmp[] = $row['id']; } } $ids_msg_with_comments[$user->id] = $tmp; $ids_msg_with_comments_presence[$user->id] = true; return $tmp; } function magicHTML($body, $uid, $data='') { $squirrelmail = new Squirrelmail($this,true); // quick and dirty trick to remove scripts, because the method magicHTML is buggy // it removes everything between 2 tags, but without checking if they are closed in the // middle $body = preg_replace('//i', '', $body); $html = $squirrelmail->magicHTML($body, $uid, $data, $this->folder, false); //TODO ultimo parametro per convertire i mailto:... in link interni $content_ids = $squirrelmail->getContentIds(); return array('html'=>$html,'content_ids'=>$content_ids); } // crmv@49398 function saveCleanedBody($messageid, $body, $content_ids = array()) { global $adb, $table_prefix; $messageid = intval($messageid); if (is_array($content_ids)) $content_ids = Zend_Json::encode($content_ids); $adb->pquery("update {$this->table_name} set content_ids = ? where {$this->table_index} = ?", array($content_ids, $messageid)); $adb->updateClob($this->table_name,'cleaned_body',"{$this->table_index} = $messageid",$body); } // crmv@49398e //crmv@59097 crmv@120786 function stripHTML($str) { $str = preg_replace('/(<|>)\1{2}/is', '', $str); $str = preg_replace( array(// Remove invisible content '@]*?>.*?@siu', '@]*?>.*?@siu', '@]*?.*?@siu', '@]*?.*?@siu', ), "", //replace above with nothing $str ); // remove inline styles so next replacements work better // doesn't work... why?? //$str = preg_replace('/(<[^>]+)style=[\'"].*?[\'"]/siu', '\1', $str); // add some newlines where needed $str = preg_replace('#\s*#i', "
\n", $str); $str = preg_replace('#\s*#i', str_repeat('-', 40)."\n", $str); $str = preg_replace('#

\s*#i', "

\n", $str); $str = preg_replace('#(]*>)#i', '\1 * ', $str); $str = preg_replace('#\s*#i', "\n", $str); $str = preg_replace('#\s*#i', "\n", $str); $str = preg_replace('#()#i', '\1'."\n", $str); $str = strip_tags($str); // convert basic entitites $str = str_replace(array(' ', ''', '"'), array(' ', "'", '"'), $str); // convert Win newlines to unix style $str = str_replace("\r\n", "\n", $str); // collapse empty lines $str = preg_replace('/^[ \t]+$/m', '', $str); // no more than 2 consecutive new lines $str = preg_replace("/[\n\r]{3,}/", "\n\n", $str); // and collapse multiple spaces $str = preg_replace("/[\t ]{2,}/", " ", $str); // remove initial and final spaces $str = trim($str); return $str; } //crmv@59097e crmv@120786e function getRecipientEmails($field='') { if (empty($field)) { $fields = array('mto','mcc','mbcc'); } else { $fields = array($field); } $recipients = array(); foreach ($fields as $field) { //crmv@128409 crmv@191584 $parsed_array = $this->parseAddressList($this->column_fields[$field.'_f']); $emails = array(); foreach($parsed_array as $mail_arr){ $email = $this->cleanEmail($mail_arr['email']); (!empty($mail_arr['name'])) ? $name = $mail_arr['name'] : $name = $email; $recipients[$field][$name] = $email; } //crmv@128409e crmv@191584e } return $recipients; } //crmv@128409 crmv@141432 /** * Parse an email address list according to RFC822 */ function parseAddressList($addressList){ if (!class_exists('\Zend\Loader\StandardAutoloader', false)) { $this->loadZendFramework(); } $result = array(); try { $h = \Zend\Mail\Header\Cc::fromString('Cc: '.$addressList); } catch (Exception $e) { return $result; } $list = $h->getAddressList(); foreach ($list as $addr) { $result[] = array( 'name' => $addr->getName(), 'email' => $addr->getEmail() ); } return $result; } //crmv@128409e crmv@141432e function getAddressName($email,$name,$full,$textlength_check=false) { global $default_charset; $name = html_entity_decode($name, ENT_QUOTES, $default_charset); $name = trim(trim($name),'"'); if (empty($name)) { $name = trim($email); } if (substr_count($full,',') > substr_count($name, ',')) { // crmv@111982 crmv@152633 $name = trim($full); } $name = strip_tags($name); // crmv@196013 if ($textlength_check) { global $listview_max_textlength; $listview_max_textlength_tmp = $listview_max_textlength; $listview_max_textlength = 30; $name = textlength_check($name); $listview_max_textlength = $listview_max_textlength_tmp; } return $name; } // crmv@192843 function getAddressImage($mode,$email,$business_card) { if (strpos($email,', ') !== false) { $img = "people"; return $img; } $module = $business_card['module']; $id = $business_card['id']; $name = $business_card['name']; $type = getSingleModuleName($module); switch ($module) { case 'Users': $avatar = getUserAvatar($id); $img = "$name"; break; case 'Contacts': case 'Accounts': case 'Leads': case 'Vendors': $img = ""; break; default: if ($mode == 'addsender') { $title = getTranslatedString('Add sender','Messages'); } elseif ($mode == 'addrecipient') { $title = getTranslatedString('Add recipient','Messages'); } $img = "id}','{$mode}');\">person_add"; // crmv@43864 break; } return $img; } // crmv@192843e function saveCache($ids) { if (empty($ids)) return; global $adb, $table_prefix; global $current_user, $default_charset; $filtered = array(); // apply filters $crmid = array(); $skipped_uids = array(); $err_uids = array(); //crmv@50124 foreach ($ids as $messageId => $uid) { /* $uid = self::$mail->getUniqueId($messageId); $uid = 17130; $messageId = self::$mail->getNumberByUniqueId($uid); */ //crmv@62140 if (empty(self::$mail)) { $this->resetMailResource(); $this->getZendMailStorageImap(); $this->selectFolder($this->folder); } //crmv@62140e try { $message = self::$mail->getMessage($messageId); } catch (Zend\Mail\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 // ignore parse errors and continue //crmv@50124 if error status remain 2 -- $skipped_uids[] = $uid; //echo "$messageId($uid),"; $error_message = $e->getMessage(); if ($error_message == 'unique id not found') { $skipped_uids[] = $uid; } elseif ($error_message == 'the single id was not found in response') { $err_uids[] = $uid; } continue; } /* if ($uid == 5545) { echo '
';
				print_r($message);
				echo '
'; die; } */ //crmv@57876 crmv@59492 /* $memory_usage = memory_get_usage(); try { $message_size = $message->getSize(); } catch (Zend\Mail\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $message_size = 0; } if ($message_size > $memory_usage) { // error status remain 2 but there isn't fatal error continue; } */ //crmv@57876e crmv@59492e //echo "$current_user->id,$this->account,$this->folder,$uid\n"; (empty($this->interval_inline_cache)) ? $include_attach_content = false : $include_attach_content = true; //crmv@125629 $data = $this->getMessageData($message,$messageId,$include_attach_content); //crmv@59094 crmv@125629 if (empty($data)) { //crmv@50124 if error status remain 2 -- $skipped_uids[] = $uid; continue; } // crmv@64178e // skip the message if no messageid is present if (empty($data['header']['Messageid'])) { $err_uids[] = $uid; continue; } // crmv@64178e $date = $this->getImap2DbDate($data); //crmv@OPER8279 check date if is out of range if (!empty($this->interval_storage) && ($_REQUEST['service'] == 'Messages' || $_REQUEST['file'] == 'Fetch')) { $interval_storage = $this->getIntervalStorage(); $limit_storage_time = $interval_storage['time']; if (strtotime($date) < $limit_storage_time) continue; } //crmv@OPER8279e // check if exists $existingCrmid = 0; //crmv@81338 $query = "select messagesid, xuid from {$this->table_name} where deleted = 0 and mtype = ? and messageid = ? and smownerid = ? and account = ? and folder = ? and subject = ?"; //crmv@171021 $params = array('Webmail',$data['header']['Messageid'],$current_user->id,$this->account,$this->folder,$data['header']['Subject']); if (!empty($date) && substr($date,0,10) != '1970-01-01') { $query .= " and mdate = ?"; $params[] = $date; } $res = $adb->pquery($query, $params); //crmv@81338e if ($res && $adb->num_rows($res) > 0) { $existingCrmid = $adb->query_result_no_html($res, 0, 'messagesid'); $existingUid = $adb->query_result_no_html($res, 0, 'xuid'); //crmv@59094 if ($this->update_duplicates && $existingCrmid > 0) { // do nothing } elseif ($existingCrmid > 0) { //crmv@57585 // crmv@90388 - set as error, not skipped, otherwise they are downloaded again nex time //$skipped_uids[] = $uid; $err_uids[] = $uid; // crmv@90388e continue; } elseif ($existingUid >= $uid) { // if lower/equal uid, skip - crmv@58645 //crmv@50124 // set status = 1 : don't check again $err_uids[] = $uid; //crmv@50124e continue; } //crmv@59094e } $body = $this->getImap2DbBody($data); // crmv@68357 if (!empty($data['text/calendar'])) { $data['icals'] = $data['text/calendar']; } // crmv@68357e if ($data['header']['Content-Class'] == 'VTECRM-DRAFT') $data['flags']['draft'] = 'on'; //crmv@84628 $focus = CRMentity::getInstance('Messages'); $focus->column_fields = array( 'subject'=>$data['header']['Subject'], 'description'=>$body, 'mdate'=>$date, 'mfrom'=>$data['header']['From']['email'], 'mfrom_n'=>$data['header']['From']['name'], 'mfrom_f'=>$data['header']['From']['full'], 'mto'=>$data['header']['To']['email'], 'mto_n'=>$data['header']['To']['name'], 'mto_f'=>$data['header']['To']['full'], 'mcc'=>$data['header']['Cc']['email'], 'mcc_n'=>$data['header']['Cc']['name'], 'mcc_f'=>$data['header']['Cc']['full'], 'mbcc'=>$data['header']['Bcc']['email'], 'mbcc_n'=>$data['header']['Bcc']['name'], 'mbcc_f'=>$data['header']['Bcc']['full'], 'mreplyto'=>$data['header']['ReplyTo']['email'], 'mreplyto_n'=>$data['header']['ReplyTo']['name'], 'mreplyto_f'=>$data['header']['ReplyTo']['full'], 'messageid'=>$data['header']['Messageid'], 'in_reply_to'=>$data['header']['In-Reply-To'], 'mreferences'=>$data['header']['References'], 'thread_index'=>$data['header']['Thread-Index'], 'xmailer'=>$data['header']['Xmailer'], 'xuid'=>$uid, 'account'=>$this->account, 'folder'=>self::$mail->getCurrentFolder(), 'seen'=>$data['flags']['seen'], 'answered'=>$data['flags']['answered'], 'flagged'=>$data['flags']['flagged'], 'forwarded'=>$data['flags']['forwarded'], 'draft'=>$data['flags']['draft'], //crmv@84628 'assigned_user_id'=>$current_user->id, 'mtype'=>'Webmail', 'other'=>$data['other'], 'icals'=>$data['icals'], // crmv@68357 ); $outOfOffice = $focus->outOfOfficeReply(); // crmv@191351 // apply filters $filtered_status = $focus->applyFilters($messageId,$filtered); if ($filtered_status) { $skipped_uids[] = $uid; continue; } //crmv@63453 $retrySave = false; try { //crmv@44482 if ($existingCrmid > 0) { $focus->id = $existingCrmid; $focus->mode = 'edit'; } $dieOnErrorTmp = $adb->dieOnError; $adb->dieOnError = false; $focus->save('Messages', true); $adb->dieOnError = $dieOnErrorTmp; $crmid[] = $focus->id; } catch (Exception $e) { //ERR_SAVING_IN_DB $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 $retrySave = true; } if ($retrySave) { try { $adb = new PearDatabase(); $adb->connect(); $columns = $focus->column_fields; $focus = CRMentity::getInstance('Messages'); $focus->column_fields = $columns; $focus->column_fields['description'] = substr($focus->column_fields['description'],0,50000); if ($existingCrmid > 0) { $focus->id = $existingCrmid; $focus->mode = 'edit'; } $focus->save('Messages'); $crmid[] = $focus->id; } catch (Exception $e) { //ERR_SAVING_IN_DB $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 } } //crmv@63453e // crmv@191351 if ($outOfOffice !== false && !empty($focus->id)) { $adb->pquery("update {$table_prefix}_messages_outofo_q set in_reply_to = ? where id = ?", array($focus->id, $outOfOffice)); } // crmv@191351e } $this->setSavedMessages($crmid); $this->setSkippedUids($skipped_uids); $this->setErrUids($err_uids); //crmv@50124 $this->fetchFiltered($filtered); // apply filters } function getImap2DbDate($data) { $date = $this->imap2DbDate($data['header']['Date']); if ((empty($date) || substr($date,0,10) == '1970-01-01') && !empty($data['header']['X-MDArrival-Date'])) { $date = $this->imap2DbDate($data['header']['X-MDArrival-Date']); } if ((empty($date) || substr($date,0,10) == '1970-01-01') && !empty($data['header']['Delivery-Date'])) { $date = $this->imap2DbDate($data['header']['Delivery-Date']); } return $date; } function getImap2DbBody($data) { global $default_charset; $body = ''; if (isset($data['text/html'])) { $body = $data['text/html']; $body = str_replace('<','&lt;',$body); $body = str_replace('>','&gt;',$body); } elseif (isset($data['text/plain'])) { $body = nl2br(htmlentities($data['text/plain'], ENT_COMPAT, $default_charset)); } $body = preg_replace('/[\xF0-\xF7].../s', '', $body); //crmv@65555 return $body; } function setSavedMessages($crmid) { if (!empty($this->saved_messages)) { $this->saved_messages = array_merge($this->saved_messages, $crmid); } else { $this->saved_messages = $crmid; } } function getSavedMessages() { return $this->saved_messages; } function setSkippedUids($uids) { if (!empty($this->skipped_uids)) { $this->skipped_uids = array_merge($this->skipped_uids, $uids); } else { $this->skipped_uids = $uids; } } function getSkippedUids() { return $this->skipped_uids; } //crmv@50124 function setErrUids($uids) { if (!empty($this->err_uids)) { $this->err_uids = array_merge($this->err_uids, $uids); } else { $this->err_uids = $uids; } } function getErrUids() { return $this->err_uids; } //crmv@50124e function saveModComment($crmid,$messageid) { global $current_user; $focus = CRMEntity::getInstance('Messages'); $focus->retrieve_entity_info_no_html($crmid,'Messages'); if ($messageid == $focus->column_fields['messageid']) { if (isPermitted('ModComments', 'EditView', '') == 'yes') { $modObj = CRMEntity::getInstance('ModComments'); $modObj->column_fields['commentcontent'] = vtlib_purify(strip_tags($_REQUEST['comment'])); $modObj->column_fields['related_to'] = $crmid; $modObj->column_fields['visibility_comm'] = vtlib_purify($_REQUEST['ModCommentsMethod']); $modObj->column_fields['users_comm'] = vtlib_purify($_REQUEST['users_comm']); $modObj->column_fields['assigned_user_id'] = $current_user->id; $modObj->save('ModComments'); } } } function saveCacheLink($column_fields) { global $current_user; $mailer = new VTEMailer(); // crmv@180739 $uniq_id = md5(uniqid(time())); $messageid = sprintf('<%s@%s>', $uniq_id, $mailer->getHostname()); // in this way, we won't duplicate messages, crmv@180739 $xuid = ''; $mfrom = (!empty($column_fields['mfrom']) ? $column_fields['mfrom'] : ''); $mto = (!empty($column_fields['mto']) ? $column_fields['mto'] : ''); $mcc = (!empty($column_fields['mcc']) ? $column_fields['mcc'] : ''); $mbcc = (!empty($column_fields['mbcc']) ? $column_fields['mbcc'] : ''); $mreplyto = (!empty($column_fields['mreplyto']) ? $column_fields['mreplyto'] : ''); if ($column_fields['mtype'] != 'Link'){ $account = ''; if ($column_fields['account'] !== '') { $account = $column_fields['account']; } elseif (!empty($mfrom)) { $focusEmails = CRMentity::getInstance('Emails'); $account = $focusEmails->getFromEmailAccount($mfrom); } if ($account === '') { $main_account = $this->getMainUserAccount(); $account = $main_account['id']; } $this->setAccount($account); $specialFolders = $this->getSpecialFolders($column_fields); } else{ $specialFolders = Array('INBOX'=>'','Sent'=>'','Drafts'=>'','Trash'=>''); $account = $column_fields['account']; //crmv@86304 crmv@80216 } $focus = CRMentity::getInstance('Messages'); // crmv@66378 $focus->column_fields = array_merge($column_fields, array( 'subject'=>(!empty($column_fields['subject']) ? $column_fields['subject'] : ''), 'description'=>(!empty($column_fields['description']) ? $column_fields['description'] : ''), 'mdate'=>(!empty($column_fields['mdate']) ? $column_fields['mdate'] : date('Y-m-d H:i:s')), 'mfrom'=>$mfrom, 'mfrom_n'=>(!empty($column_fields['mfrom_n']) ? $column_fields['mfrom_n'] : ''), 'mfrom_f'=>(!empty($column_fields['mfrom_f']) ? $column_fields['mfrom_f'] : $mfrom), 'mto'=>$mto, 'mto_n'=>(!empty($column_fields['mto_n']) ? $column_fields['mto_n'] : ''), 'mto_f'=>(!empty($column_fields['mto_f']) ? $column_fields['mto_f'] : $mto), 'mcc'=>$mcc, 'mcc_n'=>(!empty($column_fields['mcc_n']) ? $column_fields['mcc_n'] : ''), 'mcc_f'=>(!empty($column_fields['mcc_f']) ? $column_fields['mcc_f'] : $mcc), 'mbcc'=>$mbcc, 'mbcc_n'=>(!empty($column_fields['mbcc_n']) ? $column_fields['mbcc_n'] : ''), 'mbcc_f'=>(!empty($column_fields['mbcc_f']) ? $column_fields['mbcc_f'] : $mbcc), 'mreplyto'=>$mreplyto, 'mreplyto_n'=>(!empty($column_fields['mreplyto_n']) ? $column_fields['mreplyto_n'] : ''), 'mreplyto_f'=>$mreplyto, 'in_reply_to'=>(!empty($column_fields['in_reply_to']) ? $column_fields['in_reply_to'] : ''), 'mreferences'=>(!empty($column_fields['mreferences']) ? $column_fields['mreferences'] : ''), 'thread_index'=>(!empty($column_fields['thread_index']) ? $column_fields['thread_index'] : ''), 'xmailer'=>(!empty($column_fields['xmailer']) ? $column_fields['xmailer'] : 'VTECRM-WEBMAIL'), 'xuid'=>(!empty($column_fields['xuid']) ? $column_fields['xuid'] : $xuid), 'messageid'=>(!empty($column_fields['messageid']) ? $column_fields['messageid'] : $messageid), 'seen'=>(!empty($column_fields['seen']) ? $column_fields['seen'] : '1'), 'answered'=>(!empty($column_fields['answered']) ? $column_fields['answered'] : '0'), 'flagged'=>(!empty($column_fields['flagged']) ? $column_fields['flagged'] : '0'), 'forwarded'=>(!empty($column_fields['forwarded']) ? $column_fields['forwarded'] : '0'), 'folder'=>(!empty($column_fields['folder']) ? $column_fields['folder'] : $specialFolders['Sent']), 'assigned_user_id'=>(!empty($column_fields['assigned_user_id']) ? $column_fields['assigned_user_id'] : $current_user->id), 'mtype'=>(!empty($column_fields['mtype']) ? $column_fields['mtype'] : 'Link'), 'mvisibility'=>(!empty($column_fields['mvisibility']) ? $column_fields['mvisibility'] : ''), 'send_mode'=>(!empty($column_fields['send_mode']) ? $column_fields['send_mode'] : ''), 'other'=>(!empty($column_fields['other']) ? $column_fields['other'] : ''), 'parent_id'=>(!empty($column_fields['parent_id']) ? $column_fields['parent_id'] : ''), 'recipients'=>(!empty($column_fields['recipients']) ? $column_fields['recipients'] : ''), 'messagehash'=>(!empty($column_fields['messagehash']) ? $column_fields['messagehash'] : ''), // crmv@119358 'account'=>$account, )); // crmv@66378e $focus->save('Messages'); return $focus->id; } function deleteCache($ids) { if (empty($ids)) return; foreach ($ids as $crmid => $uid) { if (!$this->isDuplicated($crmid) && $this->haveRelations($crmid,'','-')) { // crmv@139797 $this->convertToLink($crmid); // crmv@139797 } else { parent::trash('Messages', $crmid); } } $this->cleanDraftCache(array_keys($ids)); } function trash($module, $id) { // move to Trash if (empty($this->column_fields['folder']) || empty($this->column_fields['xuid']) || empty($this->column_fields['account'])) { $this->retrieve_entity_info($id,$module); } if ($this->column_fields['mtype'] == 'Webmail') { $this->cleanDraftCache($id); $specialFolders = $this->getSpecialFolders(); if (!$this->isDuplicated($id) && $this->column_fields['folder'] == $specialFolders['Trash'] && $this->haveRelations($id,'','-')) { // crmv@139797 $this->convertToLink($id); // crmv@139797 $this->addToPropagationCron('trash', array( 'userid'=>$this->column_fields['assigned_user_id'], 'account'=>$this->column_fields['account'], 'folder'=>$this->column_fields['folder'], 'uid'=>$this->column_fields['xuid'], 'fetch'=>false )); } else { parent::trash($module, $id); $this->addToPropagationCron('trash', array( 'userid'=>$this->column_fields['assigned_user_id'], 'account'=>$this->column_fields['account'], 'folder'=>$this->column_fields['folder'], 'uid'=>$this->column_fields['xuid'], 'fetch'=>true )); } } else { parent::trash($module, $id); } } function propagateTrash($userid,$account,$folder,$uid,$fetch=false) { $focus = CRMEntity::getInstance('Messages'); $focus->setAccount($account); $focus->getZendMailStorageImap($userid); $focus->selectFolder($folder); //crmv@204525 try { $messageId = self::$mail->getNumberByUniqueId($uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } //crmv@204525e $specialFolders = $focus->getSpecialFolders(); if ($folder == $specialFolders['Trash'] || $folder == $specialFolders['Drafts']) { //crmv@49923 self::$mail->removeMessage($messageId); } else { self::$mail->moveMessage($messageId,$specialFolders['Trash']); } //fetch new messages from Trash folder if ($fetch) { global $current_user; $tmp = $current_user->id; $current_user->id = $userid; $focus->fetchNews($specialFolders['Trash']); $current_user->id = $tmp; } } // crmv@139797 function convertToLink($messagesid) { global $adb, $table_prefix; $adb->pquery("update {$this->table_name} set mtype = ? where {$this->table_index} = ?",array('Link',$messagesid)); $this->saveAllDocuments($messagesid); //crmv@63475 $this->beforeTrashFunctions($messagesid); } function isDuplicated($messagesid) { // check duplicates in the same account. ex. messages can be already moved in an other folder by an other client global $adb, $table_prefix; //crmv@171021 $result = $adb->pquery("select messagehash, smownerid, account from {$this->table_name} where $this->table_index = ?", array($messagesid)); $hash = $adb->query_result($result,0,'messagehash'); $owner = $adb->query_result($result,0,'smownerid'); $account = $adb->query_result($result,0,'account'); //crmv@171021e $query = "select messagesid from {$this->table_name} where deleted = 0 and mtype = ? and messagehash = ? and smownerid = ? and account = ? and messagesid <> ?"; $params = array('Webmail',$hash,$owner,$account,$messagesid); $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { // there is a duplicate! return true; } return false; } // crmv@139797e function cleanDraftCache($ids) { global $adb, $table_prefix, $current_user; if (!is_array($ids)) { $ids = array($ids); } $draftids = array(); $result = $adb->pquery("SELECT messagehash FROM {$this->table_name} WHERE messagesid IN (".generateQuestionMarks($ids).")",$ids); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $draftids[] = $row['messagehash']; } $adb->pquery("DELETE FROM {$table_prefix}_messages_drafts WHERE userid = ? AND messagehash IN (".generateQuestionMarks($draftids).")",array($current_user->id,$draftids)); } } function markAsViewed($userid,$skip_update_flag='no') { parent::markAsViewed($userid); if ($skip_update_flag != 'yes') { $this->setFlag('seen',1); } } //crmv@44179 function massSetFlag($flag,$value,$ids) { global $adb, $current_user, $current_account, $current_folder; if (!empty($ids) && is_array($ids)) { foreach ($ids as $id) { $this->addToPropagationCron('flag', array('id'=>$id,'flag'=>$flag,'value'=>$value)); } if (!empty($ids)) { $adb->pquery("update {$this->table_name} set {$flag} = ? where messagesid in (".implode(',',$ids).") and {$flag} <> ?",array($value,$value)); } if ($flag == 'seen') { $this->reloadCacheFolderCount($current_user->id,$current_account,$current_folder); } elseif ($flag == 'flagged') { $this->reloadCacheFolderCount($current_user->id,$current_account,'Flagged'); } } } function setFlag($flag,$value) { global $adb, $table_prefix, $current_user; // crmv@49398 $status = false; if ($this->column_fields[$flag] != $value // if flag change && !empty($this->column_fields['assigned_user_id']) && $current_user->id == $this->column_fields['assigned_user_id']) { // if message is assigned to me (not in folder Shared) $this->addToPropagationCron('flag', array('id'=>$this->id,'flag'=>$flag,'value'=>$value)); $adb->pquery("update {$this->table_name} set {$flag} = ?, modifiedtime = ? where messagesid = ?",array($value, $adb->formatDate(date('Y-m-d H:i:s'), true), $this->id)); // crmv@49398 crmv@69690 crmv@171021 $this->column_fields[$flag] = $value; if ($flag == 'seen') { $this->reloadCacheFolderCount($this->column_fields['assigned_user_id'],$this->column_fields['account'],$this->column_fields['folder']); } elseif ($flag == 'flagged') { $this->reloadCacheFolderCount($this->column_fields['assigned_user_id'],$this->column_fields['account'],'Flagged'); } $status = true; } return $status; } //crmv@44179e function propagateSetFlag($messagesid,$flag,$value) { global $adb, $table_prefix; $focus = CRMEntity::getInstance('Messages'); $error = $focus->retrieve_entity_info($messagesid,'Messages',false); if (!empty($error)) { throw new Exception($error); } $focus->id = $messagesid; $focus->resetMailResource(); $focus->getZendMailStorageImap($focus->column_fields['assigned_user_id']); $focus->selectFolder($focus->column_fields['folder']); //crmv@204525 try { $messageId = self::$mail->getNumberByUniqueId($focus->column_fields['xuid']); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } //crmv@204525e //Get current flags with server call $message = self::$mail->getMessage($messageId); $current_flags = $flags = $message->getFlags(); //Get current flags using cached flags //$current_flags = $flags = $focus->getCacheFlags(); //need $focus->id switch ($flag) { case 'seen': if ($value == '1') { $flags = array_merge($flags,array(Zend\Mail\Storage::FLAG_SEEN)); } elseif ($value == '0') { unset($flags[array_search(Zend\Mail\Storage::FLAG_SEEN, $flags)]); //crmv@49432 } break; case 'flagged': if ($value == '1') { $flags = array_merge($flags,array(Zend\Mail\Storage::FLAG_FLAGGED)); } elseif ($value == '0') { unset($flags[array_search(Zend\Mail\Storage::FLAG_FLAGGED, $flags)]); //crmv@49432 } break; case 'answered': if ($value == '1') { $flags = array_merge($flags,array(Zend\Mail\Storage::FLAG_ANSWERED)); } break; case 'forwarded': if ($value == '1') { $flags = array_merge($flags,array('$Forwarded','Forwarded')); } break; } if ($current_flags != $flags) { try { self::$mail->setFlags($messageId, $flags); return true; } catch (Zend\Mail\Storage\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 //crmv@49432 if (empty($flags)) return self::$protocol->store($current_flags, $messageId, null, '-'); else //crmv@49432e throw new Exception($e->getMessage()); } } } function getPreviewBody($rawValue) { global $default_charset, $listview_max_textlength, $current_user; $listview_max_textlength_tmp = $listview_max_textlength; $listview_max_textlength = 120; $temp_val = preg_replace("/(<\/?)(\w+)([^>]*>)/i","",$rawValue); $temp_val = str_replace(' ',' ',$temp_val); $temp_val = html_entity_decode($temp_val, ENT_QUOTES, $default_charset); $search = array( '@]*?>.*?@si', // Strip out title tag '@]*?>.*?@si', // Strip out javascript '@]*?>.*?@siU', // Strip style tags properly ); $temp_val = preg_replace($search, "\n", $temp_val); $temp_val = preg_replace('/\s+/',' ',strip_tags($temp_val)); $value = textlength_check($temp_val); $listview_max_textlength = $listview_max_textlength_tmp; return $value; } function cleanEmail($email) { if (strpos($email,'<') !== false) { $email = substr($email,strpos($email,'<')+1); } if (strpos($email,'>') !== false) { $email = substr($email,0,strpos($email,'>')); } return trim($email); } // crmv@107655 function getBusinessCard($type) { // crmv@111982 if ($type == 'TO') { $email = $this->column_fields['mto']; $name = $this->column_fields['mto_n']; $full = $this->column_fields['mto_f']; } elseif ($type == 'FROM') { $email = $this->column_fields['mfrom']; $name = $this->column_fields['mfrom_n']; $full = $this->column_fields['mfrom_f']; } elseif ($type == 'CC') { $email = $this->column_fields['mcc']; $name = $this->column_fields['mcc_n']; $full = $this->column_fields['mcc_f']; } if (substr_count($full,',') > substr_count($email,',') + substr_count($name,',')) { $email = trim($full); } // crmv@111982e if (strpos($email,',') !== false) { $emails = explode(',',$email); } else { $emails = array($email); } $entitiesInfo = array(); if (!empty($emails)) { foreach($emails as $email) { $email = $this->cleanEmail($email); $entityid = ''; $entity = $this->getEntitiesFromEmail($email,false,false,array('Contacts','Accounts','Leads','Vendors','Users'),true); if (!empty($entity)) { $entityid = $entity['crmid']; $entitytype = $entity['module']; } $entityInfo = array(); if (!empty($entityid)) { $retrieveFields = array(); if ($entitytype == 'Contacts') { $retrieveFields = array('account_id', 'salutationtype', 'mobile', 'phone', 'homephone', 'otherphone'); } elseif ($entitytype == 'Accounts') { $retrieveFields = array('bill_city', 'phone', 'otherphone'); } elseif ($entitytype == 'Leads') { $retrieveFields = array('company', 'leadsource', 'mobile', 'phone'); } elseif ($entitytype == 'Vendors') { $retrieveFields = array('website', 'phone'); } elseif ($entitytype == 'Users') { $retrieveFields = array('title', 'department', 'phone_mobile', 'phone_work', 'phone_home', 'phone_other'); } if (count($retrieveFields) > 0) { $skypeFields = $this->getUitypeFields($entitytype, 85); // skype uitype if (!empty($skypeFields)) { foreach ($skypeFields as $sfield) $retrieveFields[] = $sfield['name']; $retrieveFields = array_unique($retrieveFields); } } $entityFocus = CRMEntity::getInstance($entitytype); $entityFocus->id = $entityid; $error = $entityFocus->retrieve_entity_info($entityid,$entitytype,false, $retrieveFields); if ($entitytype == 'Users') $error = ''; if (!empty($error)) continue; $entityName = $entityFocus->getRecordName(); //crmv@104310 if ($entitytype == 'Users') { $entityInfo = array( 'module'=>$entitytype, 'id'=>$entityid, 'name'=>getUserFullName($entityid), 'title'=>implode(' - ',array_filter(array($entityFocus->column_fields['title'],$entityFocus->column_fields['department']))), ); $phone = array( 'phone_mobile'=>array('label'=>getTranslatedString('Mobile',$entitytype),'value'=>$entityFocus->column_fields['phone_mobile']), 'phone_work'=>array('label'=>getTranslatedString('Office Phone',$entitytype),'value'=>$entityFocus->column_fields['phone_work']), 'phone_home'=>array('label'=>getTranslatedString('Home Phone',$entitytype),'value'=>$entityFocus->column_fields['phone_home']), 'phone_other'=>array('label'=>getTranslatedString('Other Phone',$entitytype),'value'=>$entityFocus->column_fields['phone_other']), ); } elseif ($entitytype == 'Contacts') { $accName = ''; if (!empty($entityFocus->column_fields['account_id'])) { $accEntityName = getEntityName('Accounts',$entityFocus->column_fields['account_id']); if (!empty($accEntityName)) { $accName = array_values($accEntityName); $accName = $accName[0]; } } $salutationtype = ''; // crmv@184459 if ($entityFocus->column_fields['salutationtype'] != '--None--') { $salutationtype = getTranslatedString($entityFocus->column_fields['salutationtype'],$entitytype); } $entityInfo = array( 'module'=>$entitytype, 'id'=>$entityid, 'name'=>implode(' ',array_filter(array($salutationtype,$entityName))), 'accountid'=>$entityFocus->column_fields['account_id'], 'accountname'=>$accName, ); $phone = array( 'mobile'=>array('label'=>getTranslatedString('Mobile',$entitytype),'value'=>$entityFocus->column_fields['mobile']), 'phone'=>array('label'=>getTranslatedString('Office Phone',$entitytype),'value'=>$entityFocus->column_fields['phone']), 'homephone'=>array('label'=>getTranslatedString('Home Phone',$entitytype),'value'=>$entityFocus->column_fields['homephone']), 'otherphone'=>array('label'=>getTranslatedString('Other Phone',$entitytype),'value'=>$entityFocus->column_fields['otherphone']), ); } elseif ($entitytype == 'Accounts') { $entityInfo = array( 'module'=>$entitytype, 'id'=>$entityid, 'name'=>$entityName, 'bill_city'=>$entityFocus->column_fields['bill_city'], ); $phone = array( 'phone'=>array('label'=>getTranslatedString('Phone',$entitytype),'value'=>$entityFocus->column_fields['phone']), 'otherphone'=>array('label'=>getTranslatedString('Other Phone',$entitytype),'value'=>$entityFocus->column_fields['otherphone']), ); } elseif ($entitytype == 'Leads') { $entityInfo = array( 'module'=>$entitytype, 'id'=>$entityid, 'name'=>$entityName, 'company'=>$entityFocus->column_fields['company'], 'leadsource'=>$entityFocus->column_fields['leadsource'], ); $phone = array( 'mobile'=>array('label'=>getTranslatedString('Mobile',$entitytype),'value'=>$entityFocus->column_fields['mobile']), 'phone'=>array('label'=>getTranslatedString('Phone',$entitytype),'value'=>$entityFocus->column_fields['phone']), ); } elseif ($entitytype == 'Vendors') { $entityInfo = array( 'module'=>$entitytype, 'id'=>$entityid, 'name'=>$entityName, 'website'=>$entityFocus->column_fields['website'], ); $phone = array( 'phone'=>array('label'=>getTranslatedString('Phone',$entitytype),'value'=>$entityFocus->column_fields['phone']), ); } // check for skype fields if ($entityInfo && !empty($skypeFields)) { if (!is_array($phone)) $phone = array(); foreach ($skypeFields as $sfield) { $value = trim($entityFocus->column_fields[$sfield['name']]); if (!empty($value)) { $phone['skype'] = array('label'=>$sfield['label'],'value'=>$value); // take the first valid one break; } } } if (!empty($phone)) { foreach ($phone as $k => $v) { if (empty($v['value'])) { unset($phone[$k]); } } } $entityInfo['phone'] = $phone; $entityInfo['module_permitted'] = (isPermitted($entitytype, 'DetailView', $entityid) == 'yes'); } $entityInfo['email'] = $email; $entitiesInfo[] = $entityInfo; } } return $entitiesInfo; } /** * Return the field names of all the field of the specified uitypes */ protected function getUitypeFields($module, $uitypes) { global $current_user; $fields = array(); if (!is_array($uitypes)) $uitypes = array($uitypes); $RC = RCache::getInstance(); $allFields = $RC->get('ws_fields_mod_'.$module); if ($allFields == null) { require_once('include/Webservices/DescribeObject.php'); try { $modinfo = vtws_describe($module, $current_user); $allFields = $modinfo['fields']; } catch (Exception $e) { // ignore errors and skip the fields $allFields = array(); } $RC->set('ws_fields_mod_'.$module, $allFields); } if ($allFields && is_array($allFields)) { foreach ($allFields as $field) { if (in_array($field['uitype'], $uitypes)) { $fields[] = $field; } } } return $fields; } // crmv@107655e function getLuckyMessage($account,$folder,$record='') { global $adb, $table_prefix, $current_user; $id = ''; $query = "SELECT messagesid FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND seen = ?"; //crmv@171021 $params = array($current_user->id,1); if ($account == 'all') { // crmv@192843 if (in_array($folder,array_keys($this->defaultSpecialFolders))) { $folders = $this->getAllSpecialFolders($folder); $tmp = array(); foreach($folders as $account => $account_folders) { $tmp[] = "(account = ? AND folder = ?)"; //crmv@171021 $params[] = array($account,$account_folders[$folder]); } $query .= ' AND ('.implode(' OR ',$tmp).')'; } elseif (in_array($folder,$this->fakeFolders)) { if ($folder == 'Shared') { return ''; // TODO } elseif ($folder == 'Links') { $query .= ' AND mtype = ? AND folder <> ?'; $params[] = array('Link','vteScheduled'); } elseif ($folder == 'Flagged') { $query .= ' AND mtype = ? AND flagged = ?'; $params[] = array('Webmail',1); } elseif ($folder == 'vteScheduled') { $query .= ' AND mtype = ? AND folder = ?'; $params[] = array('Link','vteScheduled'); } } // crmv@192843e } else { $query .= " AND account = ? AND folder = ?"; $params[] = $account; $params[] = $folder; } if (!empty($record)) { if (!is_array($record)) { $record = array($record); } $result = $adb->pquery("SELECT messagesid, mdate FROM {$table_prefix}_messages WHERE messagesid IN (".generateQuestionMarks($record).")",$record); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { if (!empty($row['mdate'])) { $query .= " AND (messagesid <> ? AND mdate <= ?)"; $params[] = $row['messagesid']; $params[] = $row['mdate']; } } } } $query .= " ORDER BY mdate DESC"; $result = $adb->limitPquery($query,0,1,$params); if ($result && $adb->num_rows($result) > 0) { $id = $adb->query_result($result,0,'messagesid'); } return $id; } // crmv@48677 function haveAttachments($id, $excludeDisposition = array()) { //crmv@65648 global $adb,$table_prefix; $params = array($id,$this->other_contenttypes_attachment); if (!is_array($excludeDisposition)) $excludeDisposition = array_filter(array($excludeDisposition)); if (count($excludeDisposition) > 0) { $dispQuery = " AND contentdisposition not in (".generateQuestionMarks($excludeDisposition).")"; $params[] = $excludeDisposition; } else { $dispQuery = ''; } $query = "select messagesid from {$this->table_name}_attach where {$this->table_index} = ? and ( contenttype IN (".generateQuestionMarks($this->other_contenttypes_attachment).") OR (contentdisposition IS NOT NULL $dispQuery) )"; $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { return true; } return false; } function getAttachments($excludeDisposition = array()) { //crmv@65648 global $adb,$table_prefix; $attachments = array(); $params = array($this->id,$this->other_contenttypes_attachment); if (!is_array($excludeDisposition)) $excludeDisposition = array_filter(array($excludeDisposition)); if (count($excludeDisposition) > 0) { $dispQuery = " AND contentdisposition not in (".generateQuestionMarks($excludeDisposition).")"; $params[] = $excludeDisposition; } else { $dispQuery = ''; } // crmv@68357 - if there is an embedded invitation/reply in ical format, don't show it as attachment unless it has a filename $icalExcludeSql = " AND NOT (contentmethod IN (".generateQuestionMarks($this->ical_methods).") AND contenttype = 'text/calendar' AND (contentname IS NULL OR contentname = 'Unknown'))"; $params[] = $this->ical_methods; $query = "select * from {$this->table_name}_attach where {$this->table_index} = ? and ( contenttype IN (".generateQuestionMarks($this->other_contenttypes_attachment).") OR (contentdisposition IS NOT NULL $dispQuery) ) $icalExcludeSql"; // crmv@68357e $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { // crmv@88997 if (empty($row['document'])) { // search if the same attach is already saved $query1 = "SELECT {$this->table_name}_attach.* FROM {$this->table_name}_attach INNER JOIN {$this->table_name} ON {$this->table_name}_attach.{$this->table_index} = {$this->table_name}.{$this->table_index} INNER JOIN {$table_prefix}_crmentity ON setype = ? AND document = {$table_prefix}_crmentity.crmid WHERE {$table_prefix}_crmentity.deleted = 0 AND messagehash = ? AND {$this->table_name}.{$this->table_index} <> ? AND document IS NOT NULL AND document > 0 AND contentid = ?"; $params1 = array('Documents', $this->column_fields['messagehash'], $this->id, $row['contentid']); if ($row['content_id'] == null) { $query1 .= ' AND content_id IS NULL'; } else { $query1 .= ' AND content_id = ?'; $params1[] = $row['content_id']; } if ($row['contentname'] == null) { $query1 .= ' AND contentname IS NULL'; } else { $query1 .= ' AND contentname = ?'; $params1[] = $row['contentname']; } $result1 = $adb->pquery($query1, $params1); if ($result1 && $adb->num_rows($result1) > 0) { $row['document'] = $adb->query_result($result1,0,'document'); $adb->pquery("update {$this->table_name}_attach set document = ? where {$this->table_index} = ? and contentid = ?", array($row['document'], $this->id, $row['contentid'])); } } // crmv@88997e $target = ''; if (stripos($row['contenttype'],'image') !== false || $row['contenttype'] == 'text/rfc822-headers') { //crmv@53651 $target = '_blank'; } $document = ''; if (!empty($row['document'])) { $result1 = $adb->pquery("SELECT crmid FROM {$table_prefix}_crmentity WHERE crmid = ? AND deleted = 0",array($row['document'])); if ($result1 && $adb->num_rows($result1) > 0) { $document = $row['document']; } } if ($row['contentid'] < 0) { $attachmentid = $adb->query_result($adb->pquery("select * from ".$table_prefix."_seattachmentsrel where crmid = ?", array($document)),0,'attachmentsid'); $link = "index.php?module=uploads&action=downloadfile&fileid=$attachmentid&entityid=$document"; } else { $link = "index.php?module=Messages&action=MessagesAjax&file=Download&record={$this->id}&contentid={$row['contentid']}"; } $action_download = true; $action_download_tnef = false; //crmv@112756 $action_save = true; $action_link = true; //crmv@62340 crmv@62414 $action_view = false; $action_view_JSfunction = false; $action_label = false; $extension = substr(strrchr($row['contentname'], "."), 1); if(in_array(strtolower($extension),$this->viewerJS_supported_extensions)){ $action_view = true; $action_view_JSfunction=$this->action_view_JSfunction_array[strtolower($extension)]; $action_label = 'LBL_VIEW_DOCUMENT'; } if(in_array(strtolower($extension),$this->view_image_supported_extensions)){ $action_view = true; $action_view_JSfunction=$this->action_view_JSfunction_array[strtolower($extension)]; $action_label = 'LBL_VIEW_DOCUMENT'; } // crmv@107356 crmv@129689 if(strtolower($extension) == 'eml' || $row['contenttype'] == 'message/rfc822'){ $extension = strtolower($extension) ?: 'eml'; if (!in_array($extension,$this->action_view_JSfunction_array)) $extension = 'eml'; $action_view = true; $action_view_JSfunction=$this->action_view_JSfunction_array[$extension]; $action_label = 'LBL_VIEW_AS_EMAIL'; } // crmv@107356e crmv@129689e if($this->isEML()){ $action_save = false; $action_link = false; } //crmv@112756 if ($row['contenttype'] == 'application/ms-tnef') { $action_download = false; $action_download_tnef = true; } //crmv@112756e // crmv@187622 if ($this->column_fields['folder'] == 'vteScheduled') { $action_download = false; $action_save = false; $action_link = false; $action_view = false; $action_view_JSfunction = false; } // crmv@187622e $attachments[] = array( 'action_download'=>$action_download, 'action_download_tnef'=>$action_download_tnef, //crmv@112756 'action_save'=>$action_save, 'action_link'=>$action_link, 'action_view'=>$action_view, 'action_view_JSfunction'=>$action_view_JSfunction, 'action_view_label'=>$action_label, 'contentid'=>$row['contentid'], 'name'=>$row['contentname'], 'link'=>$link, // crmv@192843 removed img 'target'=>$target, 'document'=>$document, ); //crmv@62340e crmv@62414e } } return $attachments; } // crmv@48677e function getAttachmentsInfo() { global $adb,$table_prefix; $attachments = array(); $result = $adb->pquery("select * from {$this->table_name}_attach where {$this->table_index} = ?",array($this->id)); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $attachments[$row['contentid']]['parameters'] = array( 'content_id'=>$row['content_id'], 'name'=>$row['contentname'], 'contenttype'=>$row['contenttype'], 'contentdisposition'=>$row['contentdisposition'], 'charset'=>$row['contentcharset'], 'encoding'=>$row['contentencoding'], 'method'=>$row['contentmethod'], // crmv@68357 'size'=>$row['size'], //crmv@65328 ); } } return $attachments; } // crmv@68357 crmv@81126 function processIcalReply($uuid, $recurrIdx, $content) { global $adb, $table_prefix; $recurrIdx = intval($recurrIdx) ?: 0; $calendar = CRMEntity::getInstance('Calendar'); // check for an existing event $activityid = $calendar->getCrmidFromUuid($uuid, $recurrIdx); if ($activityid > 0 && isPermitted('Calendar', 'DetailView', $activityid) == 'yes') { // first link with that event $this->save_related_module('Messages', $this->id, 'Calendar', $activityid); // then parse the event to get my address $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($content); if ($r === false) return false; // get the event $event = $vcalendar->getComponent('vevent'); if (empty($event)) $event = $vcalendar->getComponent('vtodo'); $att = $event->getProperty('ATTENDEE', false, true); $attMail = preg_replace('/^MAILTO:/i', '', $att['value']); $part = $att['params']['PARTSTAT']; $partNo = 0; if ($part == 'DECLINED') { $partNo = 1; } elseif ($part == 'ACCEPTED') { $partNo = 2; } if (!empty($attMail) && $partNo > 0) { // now get invitees $updateList = array(); $invitees = $calendar->getInvitees($activityid); foreach ($invitees as $inv) { if ($inv['type'] == 'Contacts' && (strcasecmp($inv['email1'], $attMail) == 0 || strcasecmp($inv['email2'], $attMail) == 0)) { // ok, this is the invitee $updateList[$inv['id']] = $partNo; } } // and update the partecipations if (count($updateList) > 0) { foreach ($updateList as $inviteeid => $partecipation) { // now, this is ugly!! $from = 'invite_con'; $_REQUEST['partecipation'] = $partecipation; $_REQUEST['activityid'] = $activityid; $_REQUEST['userid'] = $inviteeid; include('modules/Calendar/SavePartecipation.php'); } } } } return true; } function processIcalRequest($uuid, $recurrIdx, $content) { global $current_user; $recurrIdx = intval($recurrIdx) ?: 0; $calendar = CRMEntity::getInstance('Calendar'); // check for an existing event and link it to the email if I'm one of the invitees $activityid = $calendar->getCrmidFromUuid($uuid, $recurrIdx); if ($activityid > 0 && isPermitted('Calendar', 'DetailView', $activityid) == 'yes') { if ($this->id && $calendar->isUserInvited($activityid, $current_user->id)) { // ok, I'm invited, link the event to the message $this->save_related_module('Messages', $this->id, 'Calendar', $activityid); } } } // crmv@81126e function sendIcalReply($icalid, $answer = 'yes') { global $current_user; $ical = $this->getIcals($icalid); $ical = $ical[0]; if (empty($ical)) return false; $myself = $ical['myemail']; // parse the event $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($ical['content']); if ($r === false) return false; // crmv@199992 $method = $vcalendar->getProperty('METHOD'); if ($method == 'PUBLISH') { // if you receive a publish ics instead of request, you aren't allowed to // reply, since it's not an invitation, so we can ignore the reply and // create the event anyway $this->setIcalPartecipation($icalid, $answer == 'yes' ? 2 : 1); return true; } // crmv@199992e // get the timezone $tzone = $vcalendar->getComponent("vtimezone"); // prepare the new calendar $newcal = new VTEvcalendar(); if ($tzone) $newcal->addComponent($tzone); if ($vcalendar->version) $newcal->setVersion($vcalendar->version); if ($vcalendar->prodid) $newcal->prodid = $vcalendar->prodid; if ($vcalendar->calscale) $newcal->setCalscale($vcalendar->calscale); $newcal->setMethod('REPLY'); // get the original event $event = $vcalendar->getComponent('vevent'); if (empty($event)) $event = $vcalendar->getComponent('vtodo'); // search for myself $myselfInvitee = null; while ($att = $event->getProperty('ATTENDEE', false, true)) { $amail = preg_replace('/^mailto:/i', '', $att['value']); if (strcasecmp($amail, $myself) == 0) { // myself $myselfInvitee = $att; break; } } if (!$myselfInvitee) return false; // remove all attendees while ($event->deleteProperty('ATTENDEE')) ; // add myself with participation $myselfInvitee['params']['PARTSTAT'] = ($answer == 'yes' ? 'ACCEPTED' : 'DECLINED'); unset($myselfInvitee['params']['RSVP']); $event->setAttendee($myselfInvitee['value'], $myselfInvitee['params']); // get some params $organizer = $event->getProperty('ORGANIZER', false, true); $subject = $event->getProperty('SUMMARY'); // add it to the new calendar $newcal->addComponent($event); $out = $newcal->createCalendar(); if (empty($out)) return false; $out = trim($out); // now prepare the email and send it! $attachment = array( array( 'sourcetype' => 'string', 'content' => $out, 'contenttype' => 'text/calendar', 'altbody' => true, 'charset' => 'UTF-8', 'encoding' => '7bit', 'method' => 'REPLY', ), array( 'sourcetype' => 'string', 'filename' => 'invite.ics', 'content' => $out, 'contenttype' => 'application/ics', ), ); // find the sender (organizator, otherwise the sender of the email) $to_email = preg_replace('/^mailto:/i', '', $organizer['value']) ?: $ical['sender']; $myname = $myselfInvitee['params']['CN'] ?: getUserFullName($current_user->id); if ($answer == 'yes') { $description = "$myname ({$myself}) ".getTranslatedString('LBL_INVITATION_ACCEPTED', 'Calendar'); $email_subject = getTranslatedString('LBL_INVITATION_ACCEPTED_SUBJECT', 'Calendar').": $subject"; } else { $description = "$myname ({$myself}) ".getTranslatedString('LBL_INVITATION_DECLINED', 'Calendar'); $email_subject = getTranslatedString('LBL_INVITATION_DECLINED_SUBJECT', 'Calendar').": $subject"; } // send // crmv@78362 $myemail = $myself ?: getUserEmailId('id', $current_user->id); $mail_status = send_mail('Emails',$to_email,$myname,$myemail,$email_subject,$description, '', '', $attachment); // crmv@78362e if ($mail_status == 1) { $this->setIcalPartecipation($icalid, $answer == 'yes' ? 2 : 1); } return ($mail_status == 1); } //crmv@81126 function createEventFromIcal($icalid, &$activityid) { global $current_user, $table_prefix, $adb; $ical = $this->getIcals($icalid); $ical = $ical[0]; if (empty($ical)) return false; // parse the ical $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($ical['content']); if ($r === false) return false; // get the event or todo $isTodo = false; $event = $vcalendar->getComponent('vevent'); if (empty($event)) { $event = $vcalendar->getComponent('vtodo'); if (empty($event)) return false; $isTodo = true; } $calendar = CRMEntity::getInstance('Calendar'); $messagesid = $ical['messagesid']; // check for an existing event $activityid = $calendar->getCrmidFromUuid($ical['uuid'], $ical['recurring_idx']); if ($activityid > 0) { // get the owner and the invitees, if I'm the owner, do nothing, if I'm an invitee, update the participation $owner = getSingleFieldValue($table_prefix.'_crmentity', 'smownerid', 'crmid', $activityid); if ($owner == $current_user->id) { // crmv@189405 // it's mine, do nothing, but check if it's an update if ($ical['is_update']) { $res = $vcalendar->generateArray($event,$isTodo ? 'vtodo' : "vevent"); if (!$res['description']) unset($res['description']); unset($res['recurring_idx']); $calendar->retrieve_entity_info_no_html($activityid, 'Calendar'); $calendar->column_fields = array_replace($calendar->column_fields,$res); $calendar->recurringObject = $res['recurrence']; // crmv@185576 $calendar->mode = 'edit'; $calendar->save('Calendar'); } // crmv@189405e } else { // check if I'm one of the invitees if ($messagesid && $calendar->isUserInvited($activityid, $current_user->id)) { // ok, it's me, set the answer to yes! $calendar->setUserInvitationAnswer($activityid , $current_user->id, 2); // 2 = yes! // crmv@202383 // if invited and can modify, change the event if ($ical['is_update'] && isPermitted('Calendar', 'EditView', $activityid) == 'yes') { $res = $vcalendar->generateArray($event,$isTodo ? 'vtodo' : "vevent"); if (!$res['description']) unset($res['description']); unset($res['recurring_idx']); $calendar->retrieve_entity_info_no_html($activityid, 'Calendar'); $calendar->column_fields = array_replace($calendar->column_fields,$res); $calendar->recurringObject = $res['recurrence']; // crmv@185576 $calendar->mode = 'edit'; $calendar->save('Calendar'); } // crmv@202383e } } } else { // create a new one $res = $vcalendar->generateArray($event,$isTodo ? 'vtodo' : "vevent"); if (!$res['description']) $res['description'] = ''; $calendar->column_fields = array_merge($calendar->column_fields,$res); $calendar->column_fields['assigned_user_id'] = $current_user->id; $calendar->recurringObject = $res['recurrence']; // crmv@185576 $calendar->save('Calendar'); if (empty($calendar->id)) return false; $activityid = $calendar->id; // crmv@185576 // create repeated events if ($calendar->recurringObject) { require_once 'modules/Calendar/RepeatEvents.php'; Calendar_RepeatEvents::repeat($calendar, $calendar->recurringObject); } // crmv@185576e // add the invitees (users only, no notifications) if (is_array($ical['values']['invitees'])) { $calInvitees = array(); $calInviteesPart = array(); foreach ($ical['values']['invitees'] as $invitee) { if ($invitee['record'] && $invitee['record']['module'] == 'Users') { $userid = $invitee['record']['crmid']; if ($userid != $current_user->id) { $calInvitees[] = $userid; $calInviteesPart[$userid] = $invitee['partecipation']; } } } if (count($calInvitees) > 0) { $calendar->insertIntoInviteeTable('Calendar', $calInvitees, $calInviteesPart); } } } // and save again the relation, to be sure if ($messagesid > 0) { $this->save_related_module('Messages', $messagesid, 'Calendar', $activityid); // crmv@189222 // link the event to all email with the same invitation $res = $adb->pquery("SELECT DISTINCT messagesid FROM {$table_prefix}_messages_ical WHERE uuid = ? AND messagesid != ?", array($ical['uuid'], $messagesid)); if ($res && $adb->num_rows($res) > 0) { while ($row = $adb->FetchByAssoc($res, -1, false)) { $this->save_related_module('Messages', $row['messagesid'], 'Calendar', $activityid); } } // crmv@189222e } return true; } function deleteEventFromIcal($icalid) { global $current_user, $table_prefix, $adb; $ical = $this->getIcals($icalid); $ical = $ical[0]; if (empty($ical)) return false; $calendar = CRMEntity::getInstance('Calendar'); $activityid = $calendar->getCrmidFromUuid($ical['uuid'], $ical['recurring_idx']); if ($activityid > 0) { $owner = getSingleFieldValue($table_prefix.'_crmentity', 'smownerid', 'crmid', $activityid); if ($owner == $current_user->id) { // I'm the owner, recreate the event for all the users that accepted $usersInv = array(); $invitees = $calendar->getInvitees($activityid); if (is_array($invitees)) { foreach ($invitees as $inv) { if ($inv['type'] == 'Users' && $inv['id'] != $current_user->id && $inv['partecipation'] == 2) { $usersInv[] = $inv['id']; } } } // delete the event $calendar->trash('Calendar', $activityid); // now create a new one with the first user found (the other invitees will be added automatically) if (count($usersInv) > 0) { // change the user $saveCurrentUser = $current_user; $current_user = CRMEntity::getInstance('Users'); $current_user->retrieveCurrentUserInfoFromFile($usersInv[0]); $this->createEventFromIcal($icalid); // switch back $current_user = $saveCurrentUser; } } else { // otherwise reply no, and unlink from message $this->cancelEventFromUuid($ical['uuid'], $ical['recurring_idx']); } } return true; } function cancelEventFromIcal($icalid) { global $current_user, $table_prefix, $adb; $ical = $this->getIcals($icalid); $ical = $ical[0]; if (empty($ical)) return false; return $this->cancelEventFromUuid($ical['uuid'], $ical['recurring_idx']); } // send the invitation answer If I'm invited to an event function cancelEventFromUuid($uuid, $recurrIdx = 0) { global $current_user, $table_prefix, $adb; $calendar = CRMEntity::getInstance('Calendar'); $activityid = $calendar->getCrmidFromUuid($uuid, $recurrIdx); if ($activityid > 0) { $owner = getSingleFieldValue($table_prefix.'_crmentity', 'smownerid', 'crmid', $activityid); if ($owner != $current_user->id) { // check If I'm invited, and change my partecipation if ($calendar->isUserInvited($activityid, $current_user->id)) { $calendar->setUserInvitationAnswer($activityid , $current_user->id, 1); // 1 = no! } // and remove the link with the email if ($this->id > 0) { $this->unlinkRelationship($this->id, 'Calendar', $activityid); } } } return true; } //crmv@81126e function setIcalPartecipation($icalid, $part = 0) { global $adb, $table_prefix; $adb->pquery("UPDATE {$this->table_name}_ical SET partecipation = ? WHERE messagesid = ? AND sequence = ?", array($part, $this->id, $icalid)); } function getIcals($icalid = null) { global $adb,$table_prefix; $icals = array(); $calFocus = CRMEntity::getInstance('Calendar'); // crmv@174249 $query = "SELECT {$this->table_name}_ical.*, {$this->table_name}.mfrom as sender, {$this->table_name}_account.email as myemail, {$this->table_name}_account.userid as recipient_userid FROM {$this->table_name}_ical INNER JOIN {$this->table_name} ON {$this->table_name}_ical.messagesid = {$this->table_name}.messagesid LEFT JOIN {$this->table_name}_account ON {$this->table_name}_account.id = {$this->table_name}.account WHERE {$this->table_name}_ical.{$this->table_index} = ?"; // crmv@174249e $params = array($this->id); if ($icalid > 0) { // crmv@182005 if (is_numeric($icalid)) { $query .= " AND sequence = ?"; } else { $query .= " AND uuid = ?"; } // crmv@182005e $params[] = $icalid; } $result = $adb->pquery($query, $params); if ($result && $adb->num_rows($result) > 0) { while ($row = $adb->fetchByAssoc($result, -1, false)) { $row['method'] = trim($row['method']); $row['recipient_userid'] = intval($row['recipient_userid']); // crmv@174249 $row['activityid'] = $calFocus->getCrmidFromUuid($row['uuid'], $row['recurring_idx']); // crmv@81126 $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($row['content']); if ($r === false) continue; $event = $vcalendar->getComponent('vevent'); if (!$event) continue; $values = $vcalendar->generateArray($event, 'vevent'); $values['subject'] = nl2br(htmlentities($values['subject'], ENT_COMPAT, 'UTF-8')); $values['location'] = nl2br(htmlentities($values['location'], ENT_COMPAT, 'UTF-8')); $values['description_html'] = nl2br(htmlentities($values['description'], ENT_COMPAT, 'UTF-8')); $values['description_html'] = $this->linkToTags($values['description_html']); // crmv@189405 // check if it's an update to existing event if ($row['activityid'] > 0) { $row['is_update'] = $this->isIcalUpdate($values, $row['activityid']); } // crmv@189405e // format the when $values['when_formatted'] = $this->formatIcalDateRange($values['date_start'].' '.$values['time_start'], $values['due_date'].' '.$values['time_end']); $row['values'] = $values; $icals[] = $row; } } return $icals; } // crmv@189405 /** * Check if the passed ical values represent an update to the event $activityid; */ public function isIcalUpdate($values, $activityid) { global $adb, $table_prefix; $res = $adb->pquery("SELECT date_start, due_date, time_start, time_end FROM {$table_prefix}_activity WHERE activityid = ?", array($activityid)); $arow = $adb->fetchByAssoc($res, -1, false); if ($arow) { if ( $arow['date_start'] != $values['date_start'] || $arow['due_date'] != $values['due_date'] || $arow['time_start'] != $values['time_start'] || $arow['time_end'] != $values['time_end'] ) { return true; } } return false; } // crmv@189405e // quick function to get only the start datetime, in local timezone function getIcalStartDate($icalid, &$icalRow) { global $default_timezone; $icalRow = $this->getIcals($icalid); $icalRow = $icalRow[0]; if (empty($icalRow)) return false; $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($icalRow['content']); if ($r === false) return false; $event = $vcalendar->getComponent('vevent'); if (!$event) $event = $vcalendar->getComponent('vtodo'); if (!$event) return false; $dt = $event->getProperty('DTSTART'); $dt = $vcalendar->strtodatetime($dt); $dt = $dt[0].' '.$dt[1]; return $dt; } function formatIcalDateRange($start, $end, $allday = false) { $monthList = array( 'LBL_MONTH_JANUARY', 'LBL_MONTH_FEBRUARY', 'LBL_MONTH_MARCH', 'LBL_MONTH_APRIL', 'LBL_MONTH_MAY', 'LBL_MONTH_JUNE', 'LBL_MONTH_JULY', 'LBL_MONTH_AUGUST', 'LBL_MONTH_SEPTEMBER', 'LBL_MONTH_OCTOBER', 'LBL_MONTH_NOVEMBER', 'LBL_MONTH_DECEMBER', ); $ts1 = strtotime($start); $ts2 = strtotime($end); if (!$ts1 || !$ts2) return null; $day1 = substr($start, 0, 10); $day2 = substr($end, 0, 10); $date = ''; $dow = date('w', $ts1); $mn = date('m', $ts1); $date .= getTranslatedString('LBL_DAY'.$dow, 'Calendar'); $date .= date(' j ', $ts1); $date .= getTranslatedString($monthList[$mn-1]); $date .= date(' Y', $ts1); if ($day1 == $day2) { // same day if (!$allday) $date .= ', '.date('H:i', $ts1).' - '.date('H:i', $ts2) ; } else { // spans on multiple days $dow2 = date('w', $ts2); $mn2 = date('m', $ts2); if (!$allday) $date .= ', '.date('H:i', $ts1); $date .= ' - '; $date .= getTranslatedString('LBL_DAY'.$dow2, 'Calendar'); $date .= date(' j ', $ts2); $date .= getTranslatedString($monthList[$mn2-1]); $date .= date(' Y', $ts2); if (!$allday) $date .= ', '.date('H:i', $ts2); } return $date; } function linkToTags($text) { global $adb; preg_match_all("/([\w]+?:\/\/.*?[^ \"\n\r\t<]*)/",$text,$links1); preg_match_all("/((www|ftp)\.[\w\-]+\.[\w\-.\~]+(?:\/[^ \"\t\n\r<]*)?)/",$text,$links2); $links = array_merge($links1,$links2); if (is_array($links)) { $links = $adb->flatten_array(array_filter($links)); if (is_array($links)) { $links = array_filter($links,function($var) { if ($var == "" || $var == "www") return false; else return true; }); if (is_array($links)) { $links = array_unique($links); } } } $text = preg_replace("/(^|[\n ])([\w]+?:\/\/.*?[^ \"\n\r\t<]*)/","\\1\\2",$text); $text = preg_replace("/(^|[\n ])((www|ftp)\.[\w\-]+\.[\w\-.\~]+(?:\/[^ \"\t\n\r<]*)?)/","\\1\\2",$text); $text = preg_replace("/,\"|\.\"|\)\"|\)\.\"|\.\)\"/","\"",$text); $searchkey = ''; if (!empty($links)) { // clean links foreach ($links as $url) { $dirty_url = str_ireplace($searchkey, ''.$searchkey.'', $url); $text = str_ireplace($dirty_url, $url, $text); } // replace marks foreach ($links as $url) { if (strlen($url) > 60) { $first_part = str_ireplace($searchkey, ''.$searchkey.'', substr($url,0,45)); $last_part = str_ireplace($searchkey, ''.$searchkey.'', substr($url,-12)); $link = $first_part.'...'.$last_part; } else { $link = str_ireplace($searchkey, ''.$searchkey.'', $url); } $text = str_replace(">$url<",'>'.$link.'<',$text); } } return $text; } // crmv@68357e // crmv@91980 crmv@113417 // put the cleaned body in the description function retrieve_entity_info($record, $module, $dieOnError=true, $onlyFields = array()) { $return = parent::retrieve_entity_info($record, $module, $dieOnError, $onlyFields); if (empty($this->column_fields['description']) && !empty($this->column_fields['cleaned_body'])) { $this->column_fields['description'] = $this->column_fields['cleaned_body']; } return $return; } function retrieve_entity_info_no_html($record, $module, $dieOnError=true, $onlyFields = array()) { $return = parent::retrieve_entity_info_no_html($record, $module, $dieOnError, $onlyFields); if (empty($this->column_fields['description']) && !empty($this->column_fields['cleaned_body'])) { $this->column_fields['description'] = $this->column_fields['cleaned_body']; } return $return; } // crmv@113417e // avoid to save the description, use directly the cleaned body function save($module_name,$longdesc=false,$offline_update=false,$triggerEvent=true) { // save the description for later $this->description_backup = $this->column_fields['description']; $this->column_fields['description'] = null; // call the parent return parent::save($module_name,$longdesc,$offline_update,$triggerEvent); } // crmv@91980e function save_module($module) { global $adb, $table_prefix; //crmv@171021 //crmv@44482 : check if saving has been successfully completed $result = $adb->pquery("SELECT {$this->table_index} FROM {$this->table_name} WHERE {$this->table_index} = ?",array($this->id)); //crmv@171021e if ($adb->num_rows($result) == 0) { throw new Exception('ERR_SAVING_IN_DB'); } if (empty($this->column_fields['messageid'])) { $mailer = new VTEMailer(); // crmv@180739 $uniq_id = md5(uniqid(time())); $messageid = sprintf('<%s@%s>', $uniq_id, $mailer->ServerHostname()); $adb->pquery("update {$this->table_name} set messageid = ? where {$this->table_name}.{$this->table_index} = ?", array($messageid, $this->id)); $this->column_fields['messageid'] = $messageid; } //crmv@37004 crmv@81338 crmv@86194 // save the hash when saving the record $specialFolders = $this->getSpecialFolders(false); if (!empty($this->column_fields['folder']) && $this->column_fields['folder'] == $specialFolders['Drafts']) { $hash = $this->getMessageHash($this->column_fields['messageid'], ''); } else { $cleanSubject = html_entity_decode($this->column_fields['subject'], ENT_COMPAT, 'UTF-8'); $hash = $this->getMessageHash($this->column_fields['messageid'], $cleanSubject); } if ($hash && $this->id && empty($this->column_fields['messagehash'])) { // crmv@119358 $adb->pquery("update {$this->table_name} set messagehash = ? where {$this->table_name}.{$this->table_index} = ?", array($hash, $this->id)); $this->column_fields['messagehash'] = $hash; } //crmv@37004e crmv@81338e crmv@86194e // crmv@109127 crmv@171021 // recover ModComments relations of deleted Messages $query = "SELECT {$this->relation_table}.{$this->relation_table_otherid}, {$this->table_name}.{$this->table_index} as \"oldmessagesid\" FROM {$this->relation_table} INNER JOIN {$this->table_name} ON {$this->table_name}.messagehash = {$this->relation_table}.{$this->relation_table_id} WHERE {$this->table_name}.deleted = ? AND {$this->relation_table}.{$this->relation_table_id} = ? AND {$this->relation_table}.{$this->relation_table_othermodule} = ?"; $result = $adb->pquery($query,array(1,$hash,'ModComments')); if ($result && $adb->num_rows($result) > 0) { while ($row = $adb->fetchByAssoc($result, -1, false)) { $modcommentsid = $row[$this->relation_table_otherid]; $oldMessagesid = $row['oldmessagesid']; $adb->pquery("update {$table_prefix}_modcomments set related_to = ? where modcommentsid = ?",array($this->id,$modcommentsid)); $adb->pquery("UPDATE {$table_prefix}_modcomments_msgrel SET messagesid = ? WHERE messagesid = ?", array($this->id, $oldMessagesid)); } } // crmv@109127e crmv@171021e // thread if (empty($this->column_fields['mreferences']) && !empty($this->column_fields['in_reply_to'])) { $adb->pquery("update {$this->table_name} set mreferences = ? where {$this->table_name}.{$this->table_index} = ?", array($this->column_fields['in_reply_to'], $this->id)); $this->column_fields['mreferences'] = $this->column_fields['in_reply_to']; } // crmv@85493 $this->deleteMrefs($this->id); $this->insertMrefs($this->id, $this->column_fields['mreferences']); // crmv@85493e if ($this->column_fields['mtype'] == 'Webmail') { //$this->updateThreadCount($hash); $this->updateThreadCount(); } // save attachments information if (!empty($this->column_fields['other'])) { if ($this->mode == 'edit') { $adb->pquery("delete from {$this->table_name}_attach where {$this->table_index} = ?",array($this->id)); } foreach ($this->column_fields['other'] as $id => $content) { //crmv@65328 crmv@68357 $adb->pquery("insert into {$this->table_name}_attach ({$this->table_index},contentid,content_id,contentname,contenttype,contentdisposition,contentcharset,contentencoding,contentmethod,size) values (?,?,?,?,?,?,?,?,?,?)", array($this->id,$id,$content['parameters']['content_id'],$content['parameters']['name'],$content['parameters']['contenttype'],$content['parameters']['contentdisposition'],$content['parameters']['charset'],$content['parameters']['encoding'],$content['parameters']['method'],$content['parameters']['size'])); //crmv@65328e crmv@68357e } } //crmv@63475 crmv@171021 recover attach relations of deleted Messages $query = "SELECT {$table_prefix}_messages_attach.* FROM {$this->table_name} INNER JOIN {$table_prefix}_messages_attach ON {$this->table_name}.messagesid = {$table_prefix}_messages_attach.messagesid WHERE deleted = ? AND messagehash = ? AND document IS NOT NULL"; $result = $adb->pquery($query,array(1,$hash)); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByASsoc($result)) { $adb->pquery("update {$table_prefix}_messages_attach set document = ? where messagesid = ? and contentid = ?",array($row['document'],$this->id,$row['contentid'])); } } //crmv@63475e crmv@171021e // crmv@68357 crmv@81126 - save text/calendar parts to be able to show the invitation/reply if (!empty($this->column_fields['icals'])) { foreach ($this->column_fields['icals'] as $seq => $ical) { //crmv@177526 crmv@185956 // extract uid $vcalendar = new VTEvcalendar(); $r = $vcalendar->parse($ical); if ($r === false) continue; $uuid = $vcalendar->getProperty('UID'); $method = $vcalendar->getProperty('METHOD'); $recurrIdx = $vcalendar->getProperty('SEQUENCE'); if (is_array($uuid)) $uuid = array_keys($uuid)[0]; ($recurrIdx === false) ? $recurrIdx = 0 : $recurrIdx = intval($recurrIdx); if (!empty($uuid)) { //crmv@177526e crmv@185956e $res = $adb->pquery("SELECT messagesid FROM {$this->table_name}_ical WHERE messagesid = ? AND sequence = ?", array($this->id,$seq)); if ($res && $adb->num_rows($res) > 0) { // update $adb->pquery("UPDATE {$this->table_name}_ical SET uuid = ?, recurring_idx = ?, method = ?, content = ? WHERE messagesid = ? AND sequence = ?", array($uuid, $recurrIdx, $method, $ical, $this->id,$seq)); } else { // insert $adb->pquery("INSERT INTO {$this->table_name}_ical ({$this->table_index},sequence,uuid,recurring_idx,method,content) values (?,?,?,?,?,?)", array($this->id,$seq, $uuid, $recurrIdx, $method, $ical)); } if ($method == 'REPLY') { $this->processIcalReply($uuid, $recurrIdx, $ical); } elseif ($method == 'REQUEST') { $this->processIcalRequest($uuid, $recurrIdx, $ical); } } } } // crmv@68357e crmv@81126e //crmv@46760 if (isset($_FILES) && !empty($_FILES) && isset($_REQUEST['element'])){ $elements = @Zend_Json::decode($_REQUEST['element']); if (isset($elements) && $elements['hasattachments'] == 'True' && $elements['external_plugin'] == 'true'){ $files_arr = $_FILES; $contentid = 0; foreach($files_arr as $fileindex => $files){ if($files['name'] != '' && $files['size'] > 0){ $_FILES = Array(); $_FILES['filename'] = $files; //TODO:check if other plugins than outlook put unique id before real name... if (strpos($files['name'],"_")!== false){ $files['name'] = explode("_",$files['name'],2); $files['name'] = $files['name'][1]; } // Create document record //crmv@86304 $resFolder = $adb->pquery("select folderid from {$table_prefix}_crmentityfolder where foldername = ?", array('Message attachments')); ($resFolder && $adb->num_rows($resFolder) > 0) ? $folderid = $adb->query_result($resFolder,0,'folderid') : $folderid = 1; //crmv@86304e $document = CRMEntity::getInstance('Documents'); $document->column_fields['notes_title'] = $files['name']; $document->column_fields['filelocationtype'] = 'I'; $document->column_fields['folderid'] = $folderid; //crmv@86304 $document->column_fields['filestatus'] = 1; // Active $document->column_fields['assigned_user_id'] = $this->column_fields['assigned_user_id']; $document->parentid = $this->id; if (method_exists($document,'autoSetBUMC')) $document->autoSetBUMC('Documents',$current_user->id); //crmv@93302 $document->save('Documents'); $documentid = $document->id; if ($documentid != ''){ $params = Array( $this->table_index=>$id, 'messagesid'=>$this->id, 'contentid'=>$contentid, 'contentname'=>$files['name'], 'contenttype'=>$files['type'], 'contentdisposition'=>'external attachment', 'document'=>$documentid, 'size'=>$files['size'], //crmv@65328 ); $sql = "insert into {$this->table_name}_attach (".implode(",",array_keys($params)).") values (".generateQuestionMarks($params).")"; $adb->pquery($sql,$params); } $contentid++; } } } } //crmv@46760e // crmv@49398 crmv@56409 crmv@91980 if ($this->id > 0 && !empty($this->description_backup)) { // clean the body and save it if (empty($this->column_fields['cleaned_body'])) { $attachments_info = $this->getAttachmentsInfo(); $message_data = array('other'=>$attachments_info); $description = str_replace('&', '&', $this->description_backup); $magicHTML = $this->magicHTML($description, $this->column_fields['xuid'], $message_data); $this->saveCleanedBody($this->id, $magicHTML['html'], $magicHTML['content_ids']); $this->column_fields['cleaned_body'] = $magicHTML['html']; $this->column_fields['content_ids'] = $magicHTML['content_ids']; } // save the phone numbers $numbers = $this->extractPhoneNumbers($this->description_backup); if (count($numbers) > 0) { $this->deletePhoneNumbers($this->id); $this->savePhoneNumbers($this->id, $numbers); } } // and unset, to release memory unset($this->description_backup); // crmv@49398e crmv@56409e crmv@91980e // set recipients if (!empty($this->column_fields['recipients'])) { $adb->pquery("delete from {$table_prefix}_messages_recipients where messagesid = ?",array($this->id)); $this->setRecipients($this->id,$this->column_fields['recipients']); } // set/update relations if (!empty($this->column_fields['parent_id'])) { $ids = array_filter(explode('|', $this->column_fields['parent_id'])); foreach ($ids as $relid) { list($elid, $fieldid) = explode('@', $relid, 2); if (strpos($elid,'x') !== false) { $elid = explode('x',$elid); $elid = $elid[1]; } $mod = getSalesEntityType($elid); if ($mod) { $this->save_related_module_small($messageid, $mod, $elid); } } } //crmv@125629 : save in cache inline attachments if (!empty($this->column_fields['content_ids'])) { $content_ids = $this->column_fields['content_ids']; foreach($content_ids as $contentid) { if (isset($this->column_fields['other'][$contentid])) { $content = $this->column_fields['other'][$contentid]; $content['content'] = $this->decodeAttachment($content['content'],$content['parameters']['encoding'],$content['parameters']['charset']); $this->saveInlineCache($this->id,$contentid,$content['content'],array( 'name'=>$content['parameters']['name'], 'contenttype'=>$content['parameters']['contenttype'], 'contentdisposition'=>$content['parameters']['contentdisposition'], )); } } } //crmv@125629e } // crmv@81338 crmv@81889 function getParentMessage($id,$folder,$prev_mid=array()) { global $adb, $table_prefix; $focus = CRMEntity::getInstance('Messages'); $focus->retrieve_entity_info_no_html($id,'Messages'); if (!empty($focus->column_fields['mreferences'])) { if (preg_match_all('/<[^<>]+>/',$focus->column_fields['mreferences'],$matches) && !empty($matches[0])) { $references = $matches[0]; foreach($references as $reference) { $mid = trim($reference); if (is_array($prev_mid) && count($prev_mid) > 0 && in_array($mid, $prev_mid)) { return $id; } $result = $adb->pquery("SELECT {$this->table_index} FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND folder = ? AND messageid = ?", array($focus->column_fields['assigned_user_id'],$folder,$mid)); //crmv@171021 if ($result && $adb->num_rows($result)>0) { $prev_mid[] = $mid; return $this->getParentMessage($adb->query_result_no_html($result,0,$this->table_index),$folder,array_unique($prev_mid)); } else { // search father in other folders (ex. Sent) and so search the next father in the current folder $result = $adb->pquery("SELECT {$this->table_index} FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND folder <> ? AND messageid = ?", array($focus->column_fields['assigned_user_id'],$folder,$mid)); //crmv@171021 if ($result && $adb->num_rows($result)>0) { $result1 = $adb->pquery("SELECT in_reply_to FROM {$this->table_name} WHERE {$this->table_index} = ?", array($adb->query_result_no_html($result,0,$this->table_index))); if ($result1 && $adb->num_rows($result1) > 0) { $in_reply_to = $adb->query_result_no_html($result1,0,'in_reply_to'); if (!empty($in_reply_to)) { $mid = trim($in_reply_to); $result = $adb->pquery("SELECT {$this->table_index} FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND folder = ? AND messageid = ?", array($focus->column_fields['assigned_user_id'],$folder,$mid)); //crmv@171021 if ($result && $adb->num_rows($result)>0) { $prev_mid[] = $mid; return $this->getParentMessage($adb->query_result_no_html($result,0,$this->table_index),$folder,array_unique($prev_mid)); } } } } } } } } return $id; } // crmv@81338e crmv@81889e function updateThreadCount() { $folder = $this->column_fields['folder']; $father = $this->getParentMessage($this->id,$folder); $this->insertIntoTh($folder,$father,$this->id); $adopt_result = $this->adoptChildren($folder,$father); if (!$adopt_result && !empty($this->column_fields['mreferences'])) { $this->referenceChildren($folder,$this->column_fields['mreferences']); //TODO: $this->adoptReferenceChildren($folder,$this->column_fields['mreferences']); } $this->updateLastSon($folder); } function insertIntoTh($folder,$father,$son) { global $adb, $table_prefix; $adb->pquery("delete from {$table_prefix}_messages_th where folder = ? and father = ? and son = ?",array($folder,$son,$son)); //prevent duplicate rows (only 1 row for son) if ($adb->isMysql()) { $adb->pquery("insert ignore into {$table_prefix}_messages_th (folder,father,son) values (?,?,?)",array($folder,$father,$son)); } else { $result = $adb->pquery("SELECT * FROM {$table_prefix}_messages_th WHERE {$table_prefix}_messages_th.folder = ? AND {$table_prefix}_messages_th.father = ? AND {$table_prefix}_messages_th.son = ?", array($folder,$father,$son)); if (!$result || $adb->num_rows($result) == 0) { $adb->pquery("insert into {$table_prefix}_messages_th (folder,father,son) values (?,?,?)",array($folder,$father,$son)); } } } function adoptChildren($folder,$id) { global $adb, $table_prefix; $messageid = ''; $result = $adb->pquery("SELECT messageid FROM {$this->table_name} WHERE deleted = 0 AND {$this->table_index} = ?",array($id)); //crmv@171021 if ($result && $adb->num_rows($result)>0) { $messageid = $adb->query_result_no_html($result,0,'messageid'); //crmv@81889 } if (!empty($messageid)) { // crmv@85493 crmv@171021 $result = $adb->pquery( "SELECT {$this->table_name}.messagesid FROM {$this->table_name} INNER JOIN {$table_prefix}_messages_mref ON {$table_prefix}_messages_mref.messagesid = {$this->table_name}.{$this->table_index} WHERE deleted = 0 AND smownerid = ? AND folder = ? AND {$table_prefix}_messages_mref.mreference = ?", array($this->column_fields['assigned_user_id'],$folder,$messageid) ); // crmv@85493e crmv@171021e if ($result && $adb->num_rows($result)>0) { while($row=$adb->fetchByAssoc($result)) { if ($adb->isMysql()) { $adb->pquery("update ignore {$table_prefix}_messages_th set father = ? where father = ?",array($id,$row['messagesid'])); } else { //TODO $adb->pquery("update {$table_prefix}_messages_th set father = ? where father = ?",array($id,$row['messagesid'])); } } return true; } } return false; } function updateLastSon($folder,$father='') { global $adb, $table_prefix; if (empty($father)) { $father = $this->getFather($this->id, $folder); } if (!empty($father)) { $children = $this->getChildren($father,$folder); if (!empty($children)) { global $adb, $table_prefix; $lastson = $children[0]; if (!empty($lastson)) { $adb->pquery("update {$table_prefix}_messages set lastson = ? where messagesid = ?",array($lastson,$father)); } $children = array_diff($children,array($father)); if (!empty($children)) { $adb->pquery("update {$table_prefix}_messages set lastson = null where messagesid IN (".generateQuestionMarks($children).")",array($children)); } } } } function referenceChildren($folder,$mreferences) { // se trovo un Messaggio piu vecchio con reference simile al mio diventa mio padre global $adb, $table_prefix; // crmv@85493 crmv@171021 $reflist = $this->splitMrefs($mreferences); if (count($reflist) == 0) return false; $result = $adb->limitpQuery( "SELECT {$this->table_name}.messagesid FROM {$this->table_name} INNER JOIN {$table_prefix}_messages_mref ON {$table_prefix}_messages_mref.messagesid = {$this->table_name}.{$this->table_index} WHERE deleted = 0 AND smownerid = ? AND folder = ? AND {$table_prefix}_messages_mref.mreference IN (".generateQuestionMarks($reflist).") AND {$this->table_name}.{$this->table_index} <> ? AND mdate < ? ORDER BY mdate DESC", 0,1, array($this->column_fields['assigned_user_id'],$folder,$reflist,$this->id,$this->column_fields['mdate']) ); // crmv@85493e crmv@171021e if ($result && $adb->num_rows($result)>0) { $messagesid = $adb->query_result($result,0,$this->table_index); $father = $this->getFather($messagesid, $folder); if (!empty($messagesid) && !empty($father)) { $this->insertIntoTh($folder,$father,$this->id); } return true; } return false; } // crmv@85493 function rebuildMrefTable() { global $adb, $table_prefix; // empty the table if ($adb->isMysql()) { $adb->query("TRUNCATE TABLE {$table_prefix}_messages_mref"); } else { $adb->query("DELETE FROM {$table_prefix}_messages_mref"); } $query = "SELECT messagesid, mreferences FROM {$this->table_name} WHERE deleted = 0 AND mreferences IS NOT NULL"; //crmv@171021 ($adb->isMssql()) ? $query .= " AND mreferences NOT LIKE ''" : $query .= " AND mreferences != ''"; $result = $adb->query($query); if ($result && $adb->num_rows($result)>0) { while ($row = $adb->fetchByAssoc($result, -1, false)) { $messagesid = $row[$this->table_index]; $refs = trim($row['mreferences']); if ($refs) { $this->insertMrefs($messagesid, $refs); } } } } function splitMrefs($mrefs) { $list = array(); // convert strange spaces to regular space $mrefs = str_replace(array("\t", "\n", "\r"), "", $mrefs); // split $refs = array_filter(array_map('trim', explode(' ', $mrefs))); if (count($refs) > 0) { foreach ($refs as $mref) { // now explode again, because some stupid mrefs are not space separated $refs2 = preg_split('/><|>,\s* 1) { foreach ($refs2 as $mref) { if ($mref[0] != '<') $mref = "<".$mref; if (substr($mref, -1) != '>') $mref .= ">"; $list[] = $mref; } } else { // single mref $mref = trim($mref, ",;"); if ($mref[0] != '<') $mref = "<".$mref; if (substr($mref, -1) != '>') $mref .= ">"; $list[] = $mref; } } } return $list; } function insertMrefs($messagesid, $mrefs) { $refs = $this->splitMrefs($mrefs); if (is_array($refs) && count($refs) > 0) { foreach ($refs as $mref) { $this->insertMref($messagesid,$mref); } } } function insertMref($messagesid, $mref) { global $adb, $table_prefix; // sanitize mref $mref = trim(str_replace(array('<', '>'), array('<', '>'), $mref)); // insert if ($adb->isMysql()) { $adb->pquery("INSERT IGNORE INTO {$table_prefix}_messages_mref (messagesid, mreference) VALUES (?,?)", array($messagesid, $mref)); } else { $result = $adb->pquery("SELECT messagesid FROM {$table_prefix}_messages_mref WHERE messagesid = ? AND mreference = ?",array($messagesid, $mref)); if ($result && $adb->num_rows($result) == 0) { $adb->pquery("INSERT INTO {$table_prefix}_messages_mref (messagesid, mreference) VALUES (?,?)", array($messagesid, $mref)); } } } function deleteMref($messagesid, $mref) { global $adb, $table_prefix; $adb->pquery("DELETE FROM {$table_prefix}_messages_mref WHERE messagesid = ? AND mreference = ?",array($messagesid, $mref)); } function deleteMrefs($messagesid) { global $adb, $table_prefix; $adb->pquery("DELETE FROM {$table_prefix}_messages_mref WHERE messagesid = ?",array($messagesid)); } function getMrefs($messagesid) { // TODO } function searchMref($search) { $msgids = array(); // TODO return $msgids; } // crmv@85493e /* TODO function adoptReferenceChildren($folder,$mreferences) { // se trovo Messaggi piu recenti con reference simile al mio diventano miei figli global $adb, $table_prefix; $result = $adb->pquery("SELECT {$this->table_index} FROM {$this->table_name} WHERE deleted = 0 AND smownerid = ? AND folder = ? AND mreferences LIKE ? AND {$this->table_index} <> ? AND mdate >= ?", //crmv@171021 array($this->column_fields['assigned_user_id'],$folder,"%{$mreferences}%",$this->id,$this->column_fields['mdate'])); if ($result && $adb->num_rows($result)>0) { while ($row=$adb->fetchByAssoc($result)) { $messagesid = $row[$this->table_index]; $father = $this->getFather($messagesid, $folder); if (!empty($messagesid) && !empty($father) && ($messagesid == $father)) { //delete vecchie righe... $this->insertIntoTh($folder,$this->id,$messagesid); } } return true; } return false; } */ function getFather($record,$folder='') { global $adb, $table_prefix, $current_folder; if (empty($folder)) { $folder = $current_folder; } //crmv@171021 $query = "SELECT messageFather.messagesid FROM {$table_prefix}_messages_th INNER JOIN {$table_prefix}_messages messageSon ON messageSon.messagesid = {$table_prefix}_messages_th.son INNER JOIN {$table_prefix}_messages messageFather ON messageFather.messagesid = {$table_prefix}_messages_th.father WHERE messageFather.deleted = 0 AND messageSon.deleted = 0 AND {$table_prefix}_messages_th.folder = ? AND messageSon.messagesid = ?"; //crmv@171021e $result = $adb->pquery($query,array($folder,$record)); if ($result && $adb->num_rows($result) > 0) { $father = $adb->query_result($result,0,'messagesid'); return $father; } return false; } function getChildren($father,$folder='',$return_count=false,$select='') { global $adb, $table_prefix, $current_folder; // crmv@138980 if (empty($father)){ return $return_count ? 0 : Array(); } // crmv@138980e if (empty($folder)) { $folder = $current_folder; } if (empty($select)) { $select = 'DISTINCT messageSon.messagesid'; } $query = "SELECT $select as \"messagesid\""; if ($adb->isMssql() || $adb->isOracle()) $query .= ", messageSon.mdate"; //crmv@63611 //crmv@171021 $query .= " FROM {$table_prefix}_messages_th INNER JOIN {$table_prefix}_messages messageFather ON messageFather.messagesid = {$table_prefix}_messages_th.father INNER JOIN {$table_prefix}_messages messageSon ON messageSon.messagesid = {$table_prefix}_messages_th.son WHERE messageFather.deleted = 0 AND messageSon.deleted = 0 AND {$table_prefix}_messages_th.folder = ? AND messageFather.messagesid = ? ORDER BY messageSon.mdate DESC"; //crmv@171021e $result = $adb->pquery($query,array($folder,$father)); $count = $adb->num_rows($result); if ($result && $count > 0) { if ($return_count) { return $count; } else { $children = array(); while($row=$adb->fetchByAssoc($result)) { $children[] = $row['messagesid']; } return $children; } } } function getParents($record,$folder='') { $father = $this->getFather($record,$folder); if ($father) { $children = $this->getChildren($father,$folder); if (!empty($children)) { $children = array_diff($children,array($record)); return $children; } } return false; } function appendMessage($sendmail, $account, $specialFolder, $parentids='') { //crmv@84628 $this->setAccount($account); $specialFolders = $this->getSpecialFolders(false); //crmv@53929 $folder = $specialFolders[$specialFolder]; //crmv@84628 if (empty($folder)) { return false; } //crmv@53929 try { $this->getZendMailStorageImap(); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 return false; } //crmv@53929e //crmv@34888 $sendmail->resetErrors(); // crmv@180739 reset errors //crmv@34888e $sendmail->Mailer = 'sendmail'; if ($specialFolder == 'Drafts') $sendmail->addCustomHeader("Content-Class: VTECRM-DRAFT"); //crmv@84628 // crmv@198780 $header = $sendmail->CreateHeader($sendmail->message_id); $body = $sendmail->CreateBody(); if (empty($body)) $body = $sendmail->AltBody; $message = "$header\r\n$body"; // crmv@198780e $flags = array(Zend\Mail\Storage::FLAG_SEEN); if ($specialFolder == 'Drafts') $flags[] = Zend\Mail\Storage::FLAG_DRAFT; //crmv@84628 try { self::$mail->appendMessage($message, $folder, $flags); // set/update relations if (!empty($parentids)) { $ids = array_filter(explode('|', $parentids)); foreach ($ids as $relid) { list($elid, $fieldid) = explode('@', $relid, 2); if (strpos($elid,'x') !== false) { $elid = explode('x',$elid); $elid = $elid[1]; } $mod = getSalesEntityType($elid); if ($mod) { ($specialFolder == 'Drafts') ? $this->save_related_module_small($sendmail->message_id, $mod, $elid, '') : $this->save_related_module_small($sendmail->message_id, $mod, $elid, $sendmail->Subject); // crmv@81338 crmv@86194 } } } return true; } catch (Zend\Mail\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 return false; } } function moveMessage($folder,$skip_fetch=false) { parent::trash('Messages', $this->id); $this->addToPropagationCron('move', array( 'userid'=>$this->column_fields['assigned_user_id'], 'account'=>$this->column_fields['account'], 'folder'=>$this->column_fields['folder'], 'uid'=>$this->column_fields['xuid'], 'new_folder'=>$folder, 'skip_fetch'=>$skip_fetch )); } function propagateMoveMessage($userid,$account,$folder,$uid,$new_folder,$skip_fetch=false) { $focus = CRMEntity::getInstance('Messages'); $focus->setAccount($account); $focus->getZendMailStorageImap($userid); $focus->selectFolder($folder); //crmv@204525 try { $messageId = self::$mail->getNumberByUniqueId($uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } self::$mail->moveMessage($messageId,$new_folder); //crmv@204525e //fetch new message from destination folder if (!$skip_fetch) { global $current_user; $tmp = $current_user->id; $current_user->id = $userid; $focus->fetchNews($new_folder); $current_user->id = $tmp; } } function massMoveMessage($account,$old_folder,$folder) { global $adb, $table_prefix, $currentModule, $current_user; $ids = getListViewCheck($currentModule); if (!empty($ids) && is_array($ids)) { $idstring = implode(',',$ids); $result = $adb->query("SELECT messagesid, xuid FROM {$this->table_name} WHERE messagesid in ({$idstring})"); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { parent::trash('Messages', $row['messagesid']); $uids[] = $row['xuid']; } $this->addToPropagationCron('move_mass', array( 'userid'=>$current_user->id, 'account'=>$account, 'folder'=>$old_folder, 'uid'=>$uids, 'new_folder'=>$folder, )); } } } function propagateMassMoveMessage($userid,$account,$folder,$uids,$new_folder) { $focus = CRMEntity::getInstance('Messages'); $focus->setAccount($account); $focus->getZendMailStorageImap($userid); $focus->selectFolder($folder); foreach($uids as $uid) { //crmv@204525 try { $messageId = self::$mail->getNumberByUniqueId($uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { continue; } } self::$mail->moveMessage($messageId,$new_folder); //crmv@204525e } global $current_user; $tmp = $current_user->id; $current_user->id = $userid; $focus->fetchNews($new_folder,count($uids)); $current_user->id = $tmp; } function beforeTrashFunctions($record) { $focus = CRMEntity::getInstance('Messages'); $focus->id = $record; //crmv@80636 $result = $focus->retrieve_entity_info($record,'Messages',false); if (in_array($result,array('LBL_RECORD_DELETE','LBL_RECORD_NOT_FOUND'))) { return false; } //crmv@80636e // functions $focus->removeFromThread(); } function removeFromThread() { global $adb, $table_prefix; $record = $this->id; $folder = $this->column_fields['folder']; $father = $this->getFather($record,$folder); if (empty($father)) { $father = $record; } if ($record == $father) { $children = $this->getChildren($record,$folder); if (!empty($children)) { // delete _messages_th $adb->pquery("delete from {$table_prefix}_messages_th where father = ? and folder = ? and son = ?",array($record,$folder,$record)); // if it has children, set new father and reload lastson if (count($children) > 1) { $newfather = $children[count($children)-2]; $adb->pquery("update {$table_prefix}_messages_th set father = ? where folder = ? and father = ?",array($newfather,$folder,$record)); $this->updateLastSon($folder,$newfather); } } } else { // if it is son, delete from _messages_th and reload lastson $adb->pquery("delete from {$table_prefix}_messages_th where father = ? and folder = ? and son = ?",array($father,$folder,$record)); $this->updateLastSon($folder,$father); } } function getNonAdminAccessControlQuery($module,$user,$scope='',$join_cond=''){ //crmv@131239 if (PerformancePrefs::getBoolean('USE_TEMP_TABLES', true)) { global $table_prefix; $userid = $user->id; require('user_privileges/requireUserPrivileges.php'); // crmv@39110 require('user_privileges/sharing_privileges_'.$user->id.'.php'); $query = ' '; $tabId = getTabid($module); if($is_admin==false && $profileGlobalPermission[1] == 1 && $profileGlobalPermission[2] == 1 && $defaultOrgSharingPermission[$tabId] == 3) { $tableName = 'vt_tmp_u'.$user->id; $sharingRuleInfoVariable = $module.'_share_read_permission'; $sharingRuleInfo = $$sharingRuleInfoVariable; $sharedTabId = null; if(!empty($sharingRuleInfo) && (count($sharingRuleInfo['ROLE']) > 0 || count($sharingRuleInfo['GROUP']) > 0 || count($sharingRuleInfo['USR']) > 0)) { $tableName = $tableName.'_t'.$tabId; $sharedTabId = $tabId; }elseif($module == 'Calendar' || !empty($scope)) { $tableName .= '_t'.$tabId; } $this->setupTemporaryTable_tmp($tableName, $sharedTabId, $user, $current_user_parent_role_seq, $current_user_groups); // crmv@63349 } } //crmv@131239e return ''; } //crmv@47243 crmv@61173 function getNonAdminUserAccessQuery($user,$parentRole,$userGroups){ $defOrgSharingPermission = getAllDefaultSharingAction(); if ($defOrgSharingPermission[getTabid('Messages')] == 8) { global $table_prefix; $query = "select id from (SELECT id from ".$table_prefix."_users where id = '$user->id'"; return $query; } else { return parent::getNonAdminUserAccessQuery($user,$parentRole,$userGroups); } } //crmv@47243e crmv@61173e // crmv@63349 function getQueryExtraJoin() { //crmv@79192 $sql = ''; global $table_prefix, $currentModule, $current_user, $current_folder, $current_account; if ($current_folder == 'Flagged') { $sql .= " INNER JOIN ( SELECT MIN({$this->table_name}.{$this->table_index}) AS {$this->table_index} FROM {$this->table_name} WHERE {$this->table_name}.deleted = 0 AND {$this->table_name}.smownerid = {$current_user->id} AND {$this->table_name}.mtype = 'Webmail'"; if ($current_account != 'all') $sql .= " AND {$this->table_name}.account = {$current_account}"; // crmv@192843 $sql .= " AND {$this->table_name}.flagged = 1 GROUP BY {$this->table_name}.messagehash ) flagged_messages ON flagged_messages.{$this->table_index} = {$this->table_name}.{$this->table_index}"; } if (PerformancePrefs::getBoolean('USE_TEMP_TABLES', true)) { $sql .= $this->getQueryExtraJoin_tmp(); } else { $sql .= $this->getQueryExtraJoin_notmp(); } return $sql; //crmv@79192e } function getQueryExtraJoin_notmp() { global $adb, $table_prefix, $current_folder, $current_user; $sql = $query = ''; if ($current_folder == 'Shared') { $tableName = $table_prefix."_modcomments_msgrel"; $sql = " INNER JOIN $tableName ON $tableName.userid = {$current_user->id} AND $tableName.messagesid = {$this->table_name}.{$this->table_index}"; } return $sql; } // crmv@63349e function getQueryExtraJoin_tmp() { // crmv@63349 global $adb, $current_folder, $current_user; $sql = $query = ''; if ($current_folder == 'Shared') { $query = $this->getRelatedModComments(true); } if (!empty($query)) { $tableName = 'vt_tmp_s_'.$current_user->id; if ($adb->isMysql()) { $query = "create temporary table IF NOT EXISTS $tableName(id int(11) primary key) ignore ".$query; $result = $adb->query($query); } else { if (!$adb->table_exist($tableName,true)){ Vtecrm_Utils::CreateTable($tableName,"id I(11) NOTNULL PRIMARY",true,true); } $tableName = $adb->datadict->changeTableName($tableName); $query = "insert into $tableName $query where not exists (select * from $tableName where $tableName.id = un_table.id)"; $result = $adb->query($query); } $sql = " INNER JOIN $tableName ON $tableName.id = {$this->table_name}.{$this->table_index}"; } return $sql; } function getQueryExtraWhere() { global $current_account, $current_folder, $current_user, $thread; $sql = ''; if ($current_folder == 'Links') { $sql .= " and {$this->table_name}.mtype = 'Link'"; $sql .= " and {$this->table_name}.smownerid = {$current_user->id}"; //crmv@171021 $sql .= " and {$this->table_name}.folder <> 'vteScheduled'"; // crmv@187622 // crmv@187622 } elseif ($current_folder == 'vteScheduled') { if ($current_account != 'all') $sql .= " and {$this->table_name}.account = '$current_account'"; // crmv@192843 $sql .= " and {$this->table_name}.folder = '$current_folder'"; $sql .= " and {$this->table_name}.smownerid = {$current_user->id}"; $sql .= " and {$this->table_name}.mtype = 'Link'"; // crmv@187622e } elseif (in_array($current_folder, array('Shared','Flagged'))) { //crmv@79192 // do nothing, checks done in getQueryExtraJoin } elseif (!empty($current_folder)) { if ($current_account != 'all') $account_condition = " and {$this->table_name}.account = '{$current_account}'"; // crmv@192843 if ($current_account == 'all') { $folders = $this->getAllSpecialFolders($current_folder); // crmv@192843 $tmp = array(); foreach($folders as $account => $folder) { $tmp[] = "({$this->table_name}.account = '{$account}' AND {$this->table_name}.folder = '{$folder[$current_folder]}')"; // crmv@192843 } $account_condition = ' AND ('.implode(' OR ',$tmp).')'; } else { $sql .= " and {$this->table_name}.folder = '$current_folder'"; } $sql .= " and {$this->table_name}.smownerid = {$current_user->id}"; //crmv@171021 $sql .= " and {$this->table_name}.mtype = 'Webmail'"; } $sql .= $account_condition; if (!empty($thread)) { $children = $this->getChildren($thread); if (!empty($children)) { $sql .= " and {$this->table_name}.messagesid in (".implode(',',$children).")"; } else { $sql .= " and {$this->table_name}.messagesid in (0)"; //force empty list } } return trim($sql); } //crmv@47243 crmv@61173 function getAdvancedPermissionFunction($is_admin,$module,$actionname,$record_id='') { require('user_privileges/requireUserPrivileges.php'); // crmv@39110 $defOrgSharingPermission = getAllDefaultSharingAction(); //crmv@160797 if (in_array($actionname,array('Import','Export','Merge','DuplicatesHandling'))) { return 'no'; } elseif (in_array($actionname,array('PopupDetailForm'))) { // real check done in the file return 'yes'; } //if (!$is_admin && !empty($record_id)) { //crmv@44747: give to admin all permissions for workflow if (!empty($record_id)) { //crmv@55336 global $current_user, $adb, $table_prefix; $smownerid = getSingleFieldValue($table_prefix.'_messages', 'smownerid', 'messagesid', $record_id); // the owner can do everything (performance fix, avoid following code when not needed) if ($smownerid == $current_user->id) return 'yes'; // only owner can delete //crmv@153789 if ($actionname == 'Delete' && $_REQUEST['module'] != $_REQUEST['return_module']) { // deleting relation if ($current_user->id == $smownerid) { return 'yes'; } else { // check if the current user has a message with the same messagehash $messagehash = getSingleFieldValue($table_prefix.'_messages', 'messagehash', 'messagesid', $record_id); $result = $adb->pquery("select messagesid from {$table_prefix}_messages where deleted = 0 and smownerid = ? and messagehash = ?", array($current_user->id,$messagehash)); //crmv@171021 if ($result && $adb->num_rows($result) > 0) { return 'yes'; } else { return 'no'; } } } elseif ($actionname == 'Delete' && $current_user->id != $smownerid) { //echo 'delete'; return 'no'; } //crmv@153789e $mvisibility = getSingleFieldValue($table_prefix.'_messages', 'mvisibility', 'messagesid', $record_id); if ($mvisibility == 'Public') { //echo 'public'; return 'yes'; } //crmv@61173 $mtype = getSingleFieldValue($table_prefix.'_messages', 'mtype', 'messagesid', $record_id); if ($mtype == 'Link' && in_array($actionname,array('EditView','Delete'))) { //echo 'link'; return 'no'; } //crmv@61173e $account = getSingleFieldValue($table_prefix.'_messages', 'account', 'messagesid', $record_id); $this->setAccount($account); // crmv@63349 if (PerformancePrefs::getBoolean('USE_TEMP_TABLES', true)) { if (in_array($record_id,$this->getRelatedModComments())) return 'yes'; } else { if ($this->isMessageRelatedModComments($record_id)) return 'yes'; } // crmv@63349e $tabid = getTabid($module); // check owner // crmv@63349 if (PerformancePrefs::getBoolean('USE_TEMP_TABLES', true)) { $tableName = 'vt_tmp_u'.$current_user->id; $sharingRuleInfoVariable = $module.'_share_read_permission'; $sharingRuleInfo = $$sharingRuleInfoVariable; if(!empty($sharingRuleInfo) && (count($sharingRuleInfo['ROLE']) > 0 || count($sharingRuleInfo['GROUP']) > 0 || count($sharingRuleInfo['USR']) > 0)) { $tableName = $tableName.'_t'.$tabid; }elseif(!empty($scope)) { $tableName .= '_t'.$tabid; } if (empty($current_user_parent_role_seq)) { $user_role = $current_user->column_fields['roleid']; $user_role_info = getRoleInformation($user_role); $current_user_parent_role_seq = $user_role_info[$user_role][1]; } if (empty($current_user_groups)) { $userGroupFocus = new GetUserGroups(); $userGroupFocus->getAllUserGroups($current_user->id); $current_user_groups = $userGroupFocus->user_groups; } $this->setupTemporaryTable($tableName, $tabid, $current_user, $current_user_parent_role_seq, $current_user_groups); if($adb->isMssql()) $tableName = $adb->datadict->changeTableName($tableName); //crmv@60402 $result = $adb->pquery("select id from $tableName where id = ?",array($smownerid)); if ($result && $adb->num_rows($result) > 0) { return 'yes'; } } else { if ($smownerid != $current_user->id) { $tutables = TmpUserTables::getInstance(); $tumtables = TmpUserModTables::getInstance(); // crmv@146653 crmv@160797 if ($defOrgSharingPermission[$tabid] == 3) { if ($tutables->hasSubUser($current_user->id, $smownerid) || $tumtables->hasSubUser($current_user->id, $smownerid, 'Messages')) { return 'yes'; } } elseif ($defOrgSharingPermission[$tabid] == 8) { if ($tumtables->hasSubUser($current_user->id, $smownerid, 'Messages')) { return 'yes'; } } // crmv@146653e crmv@160797e } else { return 'yes'; } } // crmv@63349e if ($defOrgSharingPermission[$tabid] == 0) { $rm = RelationManager::getInstance(); $relIds = $rm->getRelatedIds($module,$record_id); foreach($relIds as $id) { $m = getSalesEntityType($id); if (isPermitted($m, 'DetailView', $id) == 'yes' && in_array($actionname,array('DetailView','Download','DownloadAttachments','Print','PrintHeader','ViewDocument','ViewImage'))) { //crmv@61173 crmv@66929 crmv@89037 crmv@128077 //echo 'ereditato '.$defOrgSharingPermission[$tabid]; return 'yes'; } } //crmv@56829 $result = $adb->pquery("select id from {$table_prefix}_messages_recipients where messagesid = ?",array($record_id)); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $id = $row['id']; $m = getSalesEntityType($id); if (isPermitted($m, 'DetailView', $id) == 'yes') return 'yes'; } } //crmv@56829e } return 'no'; } } //crmv@47243e crmv@61173e /* * $params : array width column_fields of message * ex. $params = array('subject'=>'Test','description'=>'test message','mto'=>'to@domain.com','mfrom'=>'from@domain.org',...); * NB. you can also relate message to records by $params['parent_id'] (permitted formats: 12, 3x12, 3x12|3x14, 12@200|14@202) * * TODO : gestire l'invio di allegati passando in send_mail_attachment una stringa o un array di percorsi di file da inviare */ function send($params,$append=true,$queue=false) { // crmv@129149 $queue = (!$append && $queue); // crmv@129149 enable queue only if append is false $mail_tmp = (!empty($params['mail_tmp']) ? $params['mail_tmp'] : ''); $mail_status = send_mail( 'Emails', $params['mto'], (!empty($params['mfrom_n']) ? $params['mfrom_n'] : $params['mfrom']), $params['mfrom'], $params['subject'], $params['description'], $params['mcc'], $params['mbcc'], (!empty($params['send_mail_attachment']) ? $params['send_mail_attachment'] : 'all'), (!empty($params['send_mail_emailid']) ? $params['send_mail_emailid'] : 0), (!empty($params['send_mail_logo']) ? $params['send_mail_logo'] : ''), (!empty($params['send_mail_newsletter_params']) ? $params['send_mail_newsletter_params'] : ''), $mail_tmp, (!empty($params['send_mail_messageid']) ? $params['send_mail_messageid'] : ''), (!empty($params['send_mail_message_mode']) ? $params['send_mail_message_mode'] : ''), $queue // crmv@129149 ); if ($append) { $append_status = false; $mainAccount = $this->getMainUserAccount(); $account = (!empty($params['account']) ? $params['account'] : $mainAccount['id']); if ($mail_status == 1 && !empty($account)) { try { $append_status = append_mail( $mail_tmp, $account, $params['parent_id'], $params['mto'], (!empty($params['mfrom_n']) ? $params['mfrom_n'] : $params['mfrom']), $params['mfrom'], $params['subject'], $params['description'], $params['mcc'], $params['mbcc'] ); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 //echo $e->getMessage()."\n"; } } if ($append_status === false) { $focus = CRMentity::getInstance('Messages'); $focus->saveCacheLink($params); } } return $mail_status; } function setRecipients($messagesid,$recipientids) { global $adb, $table_prefix; if (!is_array($recipientids)) { $recipientids = explode('|',$recipientids); } $recipientids = array_filter($recipientids); if (!empty($recipientids)) { foreach ($recipientids as $relid) { list($elid, $fieldid) = explode('@', $relid, 2); // check existence $r = $adb->pquery("select messagesid from {$table_prefix}_messages_recipients where messagesid = ? and id = ? and fieldid = ?",array($messagesid,$elid,$fieldid)); if ($r && $adb->num_rows($r) == 0) { $adb->pquery("insert into {$table_prefix}_messages_recipients (messagesid,id,fieldid) values (?,?,?)",array($messagesid,$elid,$fieldid)); } } } } function getRecipients($format='array') { global $adb, $table_prefix; $recipientids = array(); $result = $adb->pquery("select id, fieldid from {$table_prefix}_messages_recipients where messagesid = ?",array($this->id)); if($result && $adb->num_rows($result)) { while($row=$adb->fetchByAssoc($result)) { $recipientids[] = $row['id'].'@'.$row['fieldid']; } } if ($format == 'string') { return implode('|',$recipientids); } else { return $recipientids; } } function setSendMode($messagesid,$send_mode) { global $adb, $table_prefix; $adb->pquery("update {$table_prefix}_messages set send_mode = ? where messagesid = ?",array($send_mode,$messagesid)); } function setVisibility($messagesid,$visibility) { global $adb, $table_prefix; $adb->pquery("update {$table_prefix}_messages set mvisibility = ? where messagesid = ?",array($visibility,$messagesid)); } function checkThreadFlag($flag,$id,$thread) { //TODO do a unique query and cache values global $current_account, $current_folder, $current_user, $adb, $table_prefix; if ($flag == 'unseen') { $condition = 'AND seen = 0'; } elseif ($flag == 'flagged') { $condition = 'AND flagged = 1'; } $query = "select messagesid from {$table_prefix}_messages where deleted = 0 ".$condition; //crmv@171021 $children = $this->getChildren($thread,'',false,'distinct messageSon.messagehash'); $query .= " and {$this->relation_table_id} in (".generateQuestionMarks($children).")"; $params = array($children); if ($current_account != 'all') { $query .= " and account = ?"; $params[] = $current_account; } $query .= " and folder = ? and smownerid = ?"; $params[] = array($current_folder,$current_user->id); $result = $adb->pquery($query,$params); if ($result && $adb->num_rows($result) > 0) { return true; } return false; } //crmv@44037 function getAccountSignature($id) { $account = $this->getUserAccounts('',$id); $return = $account[0]['signature']; $return = str_replace("\r",'',$return); $return = str_replace("\n",'',$return); return $return; } //crmv@44037e //crmv@3086m function relatedlist_preview_link($module, $entity_id, $current_module, $header, $relation_id) { return null; } //crmv@3086me //crmv@48693 function getAdvancedSearchOptionString($old_mode=false,&$controller,&$queryGenerator) { $module = $queryGenerator->getModule(); $meta = $queryGenerator->getMeta($module); $moduleFields = $meta->getModuleFields(); $i =0; foreach ($moduleFields as $fieldName=>$field) { if(!in_array($field->getPresence(), array('0','2'))){ continue; } if(!in_array($fieldName, array('subject','cleaned_body','mdate','seen'))){ continue; } if($field->getFieldDataType() == 'reference' || $field->getFieldDataType() == 'owner') { $typeOfData = 'V'; } else if($field->getFieldDataType() == 'boolean') { $typeOfData = 'C'; } else { $typeOfData = $field->getTypeOfData(); $typeOfData = explode("~",$typeOfData); $typeOfData = $typeOfData[0]; } $label = getTranslatedString($field->getFieldLabelKey(), $module); if(empty($label)) { $label = $field->getFieldLabelKey(); } $selected = ''; if($i++ == 0) { $selected = "selected"; } // place option in array for sorting later if ($old_mode){ $tableName = $field->getTableName(); $columnName = $field->getColumnName(); $OPTION_SET[$fieldName] = ""; } else $OPTION_SET[$fieldName] = ""; } if (!is_array($OPTION_SET)) return ''; $options = array( "", "", $OPTION_SET['subject'], $OPTION_SET['cleaned_body'], $OPTION_SET['mdate'], $OPTION_SET['seen'], // TODO "", ); return implode('',$options); } function addUserSearchConditions($input,&$queryGenerator) { global $log,$default_charset; if($input['searchtype']=='advance') { if(empty($input['search_cnt'])) { return ; } $noOfConditions = vtlib_purify($input['search_cnt']); if($input['matchtype'] == 'all') { $matchType = $queryGenerator::$AND; } else { $matchType = $queryGenerator::$OR; } if($queryGenerator->getconditionInstanceCount() > 0) { $queryGenerator->startGroup($queryGenerator::$AND); } else { $queryGenerator->startGroup(''); } for($i=0; $i<$noOfConditions; $i++) { $fieldInfo = 'Fields'.$i; $condition = 'Condition'.$i; $value = 'Srch_value'.$i; list($fieldName,$typeOfData) = explode("::::",str_replace('\'','', stripslashes($input[$fieldInfo]))); $moduleFields = $queryGenerator->getModuleFields(); $field = $moduleFields[$fieldName]; if (in_array($fieldName,array('senders','recipients'))) { $whereFields = $queryGenerator->getWhereFields(); if(($i-1) >= 0 && !empty($whereFields)) { $queryGenerator->addConditionGlue($matchType); } $operator = str_replace('\'','',stripslashes($input[$condition])); $searchValue = $input[$value]; $searchValue = urldecode($searchValue); //crmv@60585 $searchValue = function_exists('iconv') ? @iconv("UTF-8",$default_charset, // crmv@167702 $searchValue) : $searchValue; if (in_array($operator,array('n','k'))) { $intertnalGlue = $queryGenerator::$AND; } elseif (in_array($operator,array('e','s','ew','c'))) { $intertnalGlue = $queryGenerator::$OR; } $queryGenerator->startGroup(''); if ($fieldName == 'senders') { $queryGenerator->addCondition('mfrom', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mfrom_n', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mfrom_f', $searchValue, $operator); } elseif ($fieldName == 'recipients') { $queryGenerator->addCondition('mto', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mto_n', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mto_f', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mcc', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mcc_n', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mcc_f', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mbcc', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mbcc_n', $searchValue, $operator); $queryGenerator->addConditionGlue($intertnalGlue); $queryGenerator->addCondition('mbcc_f', $searchValue, $operator); } $queryGenerator->endGroup(); /* TODO } elseif ($fieldName == 'links') { $operator = str_replace('\'','',stripslashes($input[$condition])); $searchValue = $input[$value]; $searchValue = urldecode($searchValue); //crmv@60585 $searchValue = function_exists(iconv) ? @iconv("UTF-8",$default_charset, $searchValue) : $searchValue; $subselectCondition = ''; if (($operator == 'e' && $searchValue == 'Yes') || ($operator == 'n' && $searchValue == 'No')) { $subselectCondition = 'in'; } elseif (($operator == 'n' && $searchValue == 'Yes') || ($operator == 'e' && $searchValue == 'No')) { $subselectCondition = 'not in'; } if (!empty($subselectCondition)) { $whereFields = $queryGenerator->getWhereFields(); if(($i-1) >= 0 && !empty($whereFields)) { $queryGenerator->addConditionGlue($matchType); } global $table_prefix; $sql = "{$table_prefix}_messages.messagehash $subselectCondition (select messagehash from {$table_prefix}_messagesrel)"; $queryGenerator->appendToWhereClause($sql); } */ } elseif ($fieldName == 'mdate') { if (!$field) continue; $type = $field->getFieldDataType(); $whereFields = $queryGenerator->getWhereFields(); if(($i-1) >= 0 && !empty($whereFields)) { $queryGenerator->addConditionGlue($matchType); } $operator = str_replace('\'','',stripslashes($input[$condition])); if (in_array($operator,array('custom','yesterday','today','lastweek','thisweek','lastmonth','thismonth','last60days','last90days'))) { $searchValue = urldecode($input[$value]); $searchValue = function_exists('iconv') ? @iconv("UTF-8",$default_charset, // crmv@167702 $searchValue) : $searchValue; list($start,$end) = explode('|##|',$searchValue); if (strlen($start) == 10) $start .= ' 00:00:00'; if (strlen($end) == 10) $end .= ' 23:59:59'; $queryGenerator->startGroup(''); $queryGenerator->addCondition('mdate', $start, 'h'); $queryGenerator->addConditionGlue($queryGenerator::$AND); $queryGenerator->addCondition('mdate', $end, 'm'); $queryGenerator->endGroup(); } else { $searchValue = $input[$value]; $searchValue = urldecode($searchValue); //crmv@60585 $searchValue = function_exists('iconv') ? @iconv("UTF-8",$default_charset, // crmv@167702 $searchValue) : $searchValue; $queryGenerator->addCondition($fieldName, $searchValue, $operator); } } else { if (!$field) continue; $type = $field->getFieldDataType(); $whereFields = $queryGenerator->getWhereFields(); if(($i-1) >= 0 && !empty($whereFields)) { $queryGenerator->addConditionGlue($matchType); } $operator = str_replace('\'','',stripslashes($input[$condition])); $searchValue = $input[$value]; $searchValue = urldecode($searchValue); //crmv@60585 $searchValue = function_exists('iconv') ? @iconv("UTF-8",$default_charset, // crmv@167702 $searchValue) : $searchValue; $queryGenerator->addCondition($fieldName, $searchValue, $operator); } } $queryGenerator->endGroup(); } else { return 'continue'; } } function getAdvCriteriaJS() { $today = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d"), date("Y"))); $tomorrow = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+1, date("Y"))); $yesterday = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-1, date("Y"))); $currentmonth0 = date("Y-m-d",mktime(0, 0, 0, date("m"), "01", date("Y"))); $currentmonth1 = date("Y-m-t"); $lastmonth0 = date("Y-m-d",mktime(0, 0, 0, date("m")-1, "01", date("Y"))); $lastmonth1 = date("Y-m-t", strtotime("-1 Month")); $nextmonth0 = date("Y-m-d",mktime(0, 0, 0, date("m")+1, "01", date("Y"))); $nextmonth1 = date("Y-m-t", strtotime("+1 Month")); $lastweek0 = date("Y-m-d",strtotime("-2 week Sunday")); $lastweek1 = date("Y-m-d",strtotime("-1 week Saturday")); $thisweek0 = date("Y-m-d",strtotime("-1 week Sunday")); $thisweek1 = date("Y-m-d",strtotime("this Saturday")); $nextweek0 = date("Y-m-d",strtotime("this Sunday")); $nextweek1 = date("Y-m-d",strtotime("+1 week Saturday")); $next7days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+6, date("Y"))); $next30days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+29, date("Y"))); $next60days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+59, date("Y"))); $next90days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+89, date("Y"))); $next120days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")+119, date("Y"))); $last7days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-6, date("Y"))); $last30days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-29, date("Y"))); $last60days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-59, date("Y"))); $last90days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-89, date("Y"))); $last120days = date("Y-m-d",mktime(0, 0, 0, date("m") , date("d")-119, date("Y"))); $currentFY0 = date("Y-m-d",mktime(0, 0, 0, "01", "01", date("Y"))); $currentFY1 = date("Y-m-t",mktime(0, 0, 0, "12", date("d"), date("Y"))); $lastFY0 = date("Y-m-d",mktime(0, 0, 0, "01", "01", date("Y")-1)); $lastFY1 = date("Y-m-t", mktime(0, 0, 0, "12", date("d"), date("Y")-1)); $nextFY0 = date("Y-m-d",mktime(0, 0, 0, "01", "01", date("Y")+1)); $nextFY1 = date("Y-m-t", mktime(0, 0, 0, "12", date("d"), date("Y")+1)); if(date("m") <= 3) { $cFq = date("Y-m-d",mktime(0, 0, 0, "01","01",date("Y"))); $cFq1 = date("Y-m-d",mktime(0, 0, 0, "03","31",date("Y"))); $nFq = date("Y-m-d",mktime(0, 0, 0, "04","01",date("Y"))); $nFq1 = date("Y-m-d",mktime(0, 0, 0, "06","30",date("Y"))); $pFq = date("Y-m-d",mktime(0, 0, 0, "10","01",date("Y")-1)); $pFq1 = date("Y-m-d",mktime(0, 0, 0, "12","31",date("Y")-1)); } else if(date("m") > 3 and date("m") <= 6) { $pFq = date("Y-m-d",mktime(0, 0, 0, "01","01",date("Y"))); $pFq1 = date("Y-m-d",mktime(0, 0, 0, "03","31",date("Y"))); $cFq = date("Y-m-d",mktime(0, 0, 0, "04","01",date("Y"))); $cFq1 = date("Y-m-d",mktime(0, 0, 0, "06","30",date("Y"))); $nFq = date("Y-m-d",mktime(0, 0, 0, "07","01",date("Y"))); $nFq1 = date("Y-m-d",mktime(0, 0, 0, "09","30",date("Y"))); } else if(date("m") > 6 and date("m") <= 9) { $nFq = date("Y-m-d",mktime(0, 0, 0, "10","01",date("Y"))); $nFq1 = date("Y-m-d",mktime(0, 0, 0, "12","31",date("Y"))); $pFq = date("Y-m-d",mktime(0, 0, 0, "04","01",date("Y"))); $pFq1 = date("Y-m-d",mktime(0, 0, 0, "06","30",date("Y"))); $cFq = date("Y-m-d",mktime(0, 0, 0, "07","01",date("Y"))); $cFq1 = date("Y-m-d",mktime(0, 0, 0, "09","30",date("Y"))); } else if(date("m") > 9 and date("m") <= 12) { $nFq = date("Y-m-d",mktime(0, 0, 0, "01","01",date("Y")+1)); $nFq1 = date("Y-m-d",mktime(0, 0, 0, "03","31",date("Y")+1)); $pFq = date("Y-m-d",mktime(0, 0, 0, "07","01",date("Y"))); $pFq1 = date("Y-m-d",mktime(0, 0, 0, "09","30",date("Y"))); $cFq = date("Y-m-d",mktime(0, 0, 0, "10","01",date("Y"))); $cFq1 = date("Y-m-d",mktime(0, 0, 0, "12","31",date("Y"))); } $date_format = parse_calendardate($app_strings['NTC_DATE_FORMAT']); $sjsStr = ''; return $sjsStr; } //crmv@48693e //crmv@63475 function saveAllDocuments($record) { global $adb, $table_prefix; $result = $adb->pquery("SELECT * FROM {$table_prefix}_messages_attach WHERE messagesid = ? AND document IS NULL AND contentmethod IS NULL",array($record)); // crmv@68357 if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result)) { $this->saveDocument($record,$row['contentid']); } } } function saveDocument($record,$contentid,$linkto=null,$linkto_module=null,$content_part=null,$decode_attachment=true) { //crmv@84807 crmv@86304 global $adb, $table_prefix, $root_directory, $currentModule; $document = CRMEntity::getInstance('Documents'); // crmv@201830 // If contentid has been already converted in Document we use the existing Document $documentid = ''; $result = $adb->pquery("SELECT {$table_prefix}_messages_attach.document FROM {$table_prefix}_messages_attach INNER JOIN {$table_prefix}_crmentity ON {$table_prefix}_crmentity.crmid = {$table_prefix}_messages_attach.document WHERE deleted = 0 AND {$table_prefix}_messages_attach.messagesid = ? AND {$table_prefix}_messages_attach.contentid = ?", array($record,$contentid)); if ($result && $adb->num_rows($result) > 0) { $documentid = $adb->query_result($result,0,'document'); } if (empty($documentid)) { $this->retrieve_entity_info($record,$currentModule); $userid = $this->column_fields['assigned_user_id']; //crmv@84807 if (empty($content_part)) { $uid = $this->column_fields['xuid']; $this->setAccount($this->column_fields['account']); try { $this->getZendMailStorageImap($userid); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); return; } $this->selectFolder($this->column_fields['folder']); //crmv@204525 try { $messageId = self::$mail->getNumberByUniqueId($uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return; } } //crmv@204525e $message = self::$mail->getMessage($messageId); $parts = $this->getMessageContentParts($message,$messageId,true); //crmv@59492 $content_part = $parts['other'][$contentid]; } if (!empty($content_part)) { $parameters = $content_part['parameters']; //crmv@86304 // crmv@111124 $FS = FileStorage::getInstance(); $FSDB = FileStorageDB::getInstance(); // crmv@205309 $filename = $FS->sanitizeFilename($parameters['name']); // crmv@111124e $current_id = $adb->getUniqueID($table_prefix."_crmentity"); $date_var = date('Y-m-d H:i:s'); $upload_file_path = decideFilePath(); // crmv@105191 crmv@205309 $destPath = $root_directory.$upload_file_path.$current_id."_".$filename; if (!empty($content_part['file'])) { // path of existing file $filesize = filesize($content_part['file']); $fileType = mime_content_type($content_part['file']); $r = copy($content_part['file'], $destPath); if ($r === false) { $r = $FSDB->saveFile($content_part['file'], $destPath, $current_id); } } else { // content of file $str = $content_part['content']; if ($decode_attachment) $str = $this->decodeAttachment($str,$parameters['encoding'],$parameters['charset']); $filesize = strlen($str); // crmv@198701 $finfo = finfo_open(FILEINFO_MIME_TYPE); $fileType = finfo_buffer($finfo, $str); finfo_close($finfo); // crmv@198701e $fp = fopen($destPath, 'wb'); if ($fp !== false) { $r = fwrite($fp,$str,$filesize); fclose ($fp); } else { $r = false; } if ($r === false) { @unlink($destPath); $r = $FSDB->saveFileData($str, $destPath, $current_id); } } //crmv@86304e //crmv@84807e //crmv@205309e $sql1 = "insert into ".$table_prefix."_crmentity (crmid,smcreatorid,smownerid,setype,createdtime,modifiedtime) values(?,?,?,?,?,?)"; $params1 = array($current_id, $userid, $userid, "Documents Attachment", $adb->formatDate($date_var, true), $adb->formatDate($date_var, true)); $adb->pquery($sql1, $params1); // crmv@205309 - finfo moved up $sql2 = "insert into ".$table_prefix."_attachments(attachmentsid, name, type, path) values(?,?,?,?)"; $params2 = array($current_id, $filename, $fileType, $upload_file_path); // crmv@198701 $adb->pquery($sql2, $params2); // Create document record //crmv@86304 $resFolder = $adb->pquery("select folderid from {$table_prefix}_crmentityfolder where foldername = ?", array('Message attachments')); ($resFolder && $adb->num_rows($resFolder) > 0) ? $folderid = $adb->query_result($resFolder,0,'folderid') : $folderid = 1; //crmv@86304e $document->column_fields['notes_title'] = $filename; $document->column_fields['filename'] = $filename; $document->column_fields['filestatus'] = 1; $document->column_fields['filelocationtype'] = 'I'; $document->column_fields['folderid'] = $folderid; //crmv@86304 $document->column_fields['assigned_user_id'] = $userid; $document->column_fields['filesize'] = $filesize; // crmv@205309 $document->column_fields['filetype'] = $fileType; // crmv@198701 // crmv@105191e if (method_exists($document,'autoSetBUMC')) $document->autoSetBUMC('Documents',$current_user->id); //crmv@93302 $document->save('Documents'); $documentid = $document->id; // Link file attached to document $adb->pquery("insert into ".$table_prefix."_seattachmentsrel(crmid, attachmentsid) values(?,?)",Array($documentid, $current_id)); // Link documentid to the real attachment for faster next relations $adb->pquery("update {$table_prefix}_messages_attach set document = ? where messagesid = ? and contentid = ?",array($documentid, $record, $contentid)); } } // crmv@42752 crmv@110370 if (!empty($linkto) && !empty($document)) { $ids = array(); // Split the string of ids $ids = array_filter(explode(",", trim($linkto,","))); // Link document to linkto $document->save_related_module('Documents', $documentid, $linkto_module, $ids); } // Link document to message in any case $this->save_related_module($currentModule, $record, 'Documents', $documentid); // crmv@42752e crmv@110370e } //crmv@63475e //crmv@62340 public function parseEmlFile($filepath){ $zend_mail_storage_message = new \Zend\Mail\Storage\Message(array( 'file' => $filepath )); return $zend_mail_storage_message; } //crmv@84807 public function saveEmlAttachments($record,$other){ global $adb; if (!empty($other)){ foreach($other as $contentid => $tmp_files){ $this->saveDocument($record,$contentid,null,null,$other[$contentid]); } } return true; } //crmv@84807e public function isEML(){ $messageid = $this->column_fields['messageid']; $compare_str = '_eml'; $cnt = -1 * abs(strlen($compare_str)); if(substr($messageid,$cnt) == $compare_str){ return true; } else{ return false; } } //crmv@62340e // crmv@62340 crmv@84807 crmv@88981 crmv@90941 crmv@129689 public function parseEML($contentid, &$messagesid, &$error=null, $str=null, $return_column_fields=false) { global $adb, $table_prefix, $default_charset; $userid = $this->column_fields['assigned_user_id']; $uid = $this->column_fields['xuid']; $accountid = $this->column_fields['account']; $folder = $this->column_fields['folder']; if (empty($str)) { // if the message is already scanned by mailconverter if ($this->column_fields['mtype'] == 'Link') { $new_messageid = $this->column_fields['messageid']."_{$contentid}_eml"; $result1 = $adb->pquery("SELECT messagesid FROM {$table_prefix}_messages WHERE deleted = 0 AND messageid = ?", array($new_messageid)); //crmv@171021 if ($result1 && $adb->num_rows($result1) > 0) { $messagesid = $adb->query_result_no_html($result1,0,'messagesid'); if ($return_column_fields) { $focus = CRMEntity::getInstance('Messages'); $focus->retrieve_entity_info_no_html($messagesid,'Messages'); return $focus->column_fields; } return true; } else { return false; } } $this->setAccount($accountid); $this->getZendMailStorageImap($userid); $this->selectFolder($folder); //crmv@204525 try { $messageId = $this->getMailResource()->getNumberByUniqueId($uid); } catch(Exception $e) { if ($e->getMessage() == 'unique id not found') { return false; } } //crmv@204525e $message = $this->getMailResource()->getMessage($messageId); $parts = $this->getMessageContentParts($message,$messageId,true); if (!empty($parts['other'][$contentid])) { $content = $parts['other'][$contentid]; $str = $content['content']; $str = $this->decodeAttachment($str,$content['parameters']['encoding'],$content['parameters']['charset']); } } else { $this->loadZendFramework(); } if (!empty($str)) { $savepath = "./cache/emlattach_{$this->id}_{$contentid}.eml"; $r = @file_put_contents($savepath,$str); if (!$r) { $error = 'Unable to save the temporary file'; return false; } try { $eml_message = $this->parseEmlFile($savepath); } catch (Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 @unlink($savepath); $error = 'Malformed eml attachment'; return false; } unlink($savepath); $headers = $this->getMessageHeader($eml_message); $data = $this->getMessageData($eml_message,$headers['Messageid'], true); /* crmv@158850 */ if (!empty($data['header']['Messageid'])) { $new_messageid = $data['header']['Messageid']."_{$contentid}_eml"; } elseif ($this->column_fields['mtype'] == 'Link' && !empty($this->column_fields['messageid'])) { $new_messageid = $this->column_fields['messageid']."_{$contentid}_eml"; } else { $error = 'Messageid not found'; return false; } //check for mail already "scanned" $result1 = $adb->pquery("SELECT messagesid FROM {$table_prefix}_messages WHERE deleted = 0 AND messageid = ?", array($new_messageid)); //crmv@171021 if ($result1 && $adb->num_rows($result1) > 0) { $messagesid = $adb->query_result_no_html($result1,0,'messagesid'); if ($return_column_fields) { $focus = CRMEntity::getInstance('Messages'); $focus->retrieve_entity_info_no_html($messagesid,'Messages'); return $focus->column_fields; } return true; } else{ $date = $this->imap2DbDate($data['header']['Date']); //crmv@49480 $body = ''; if (isset($data['text/html'])) { $body = $data['text/html']; $body = str_replace('<','&lt;',$body); $body = str_replace('>','&gt;',$body); } elseif (isset($data['text/plain'])) { $body = nl2br(htmlentities($data['text/plain'], ENT_COMPAT, $default_charset)); } $body = preg_replace('/[\xF0-\xF7].../s', '', $body); //crmv@65555 $column_fields = array( 'subject'=>$data['header']['Subject'], 'description'=>$body, 'mdate'=>$date, 'mfrom'=>$data['header']['From']['email'], 'mfrom_n'=>$data['header']['From']['name'], 'mfrom_f'=>$data['header']['From']['full'], 'mto'=>$data['header']['To']['email'], 'mto_n'=>$data['header']['To']['name'], 'mto_f'=>$data['header']['To']['full'], 'mcc'=>$data['header']['Cc']['email'], 'mcc_n'=>$data['header']['Cc']['name'], 'mcc_f'=>$data['header']['Cc']['full'], 'mbcc'=>$data['header']['Bcc']['email'], 'mbcc_n'=>$data['header']['Bcc']['name'], 'mbcc_f'=>$data['header']['Bcc']['full'], 'mreplyto'=>$data['header']['ReplyTo']['email'], 'mreplyto_n'=>$data['header']['ReplyTo']['name'], 'mreplyto_f'=>$data['header']['ReplyTo']['full'], 'messageid'=>$new_messageid, 'in_reply_to'=>$data['header']['In-Reply-To'], 'xuid'=>0, 'account'=>$accountid, 'folder'=>'', 'assigned_user_id'=>$userid, 'mtype'=>'Link', 'other'=>$data['other'], 'parent_id'=>"", 'mvisibility'=>'Public', ); if ($return_column_fields) return $column_fields; $newfocus = CRMentity::getInstance('Messages'); $messagesid = $newfocus->saveCacheLink($column_fields); if(!empty($messagesid)){ $newfocus->saveEmlAttachments($messagesid,$data['other']); return true; } else { $error = 'Unable to save the attachment'; return false; } } } $error = 'Unknown error'; return false; } // crmv@62340e crmv@84807e crmv@88981e crmv@90941e crmv@129689e //crmv@65328 function getAttachmentsSize($messageId) { global $adb, $table_prefix; $size = 0; $atts = $this->getAttachmentsInfo(); if (!empty($atts)) { if (empty($atts[0]['parameters']['size'])) { if ($this->column_fields['mtype'] == 'Link') { $sql = "select t.* from {$table_prefix}_messages_attach a inner join {$table_prefix}_seattachmentsrel s on s.crmid = a.document inner join {$table_prefix}_notes n on n.notesid = a.document inner join {$table_prefix}_attachments t on t.attachmentsid = s.attachmentsid inner join {$table_prefix}_crmentity e on e.crmid = t.attachmentsid where messagesid = ? and coalesce(a.document,'') <> '' and e.deleted=0"; $params = Array($this->id); $res = $adb->pquery($sql,$params); if ($res && $adb->num_rows($res)>0) { while($row=$adb->fetchByAssoc($res)) { $filewithpath = $root_directory.$row['path'].$row['attachmentsid']."_".$row['name']; if (is_file($filewithpath)) { $size += filesize($filewithpath); } } } } else { $this->setAccount($this->column_fields['account']); $this->getZendMailStorageImap($this->column_fields['assigned_user_id']); $this->selectFolder($this->column_fields['folder']); try { $messageId = self::$mail->getNumberByUniqueId($this->column_fields['xuid']); } catch(Exception $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 if ($e->getMessage() == 'unique id not found') { return; } } $size = self::$mail->getSize($messageId); } } else { foreach($atts as $contentid => $att) { $size += (int)$att['parameters']['size']; } } } return $size; } //crmv@65328e //crmv@80250 function isSupportedInlineFormat($filename) { $extension = substr(strrchr($filename, "."), 1); if(in_array(strtolower($extension),$this->inline_image_supported_extensions)){ return true; } return false; } //crmv@80250e //crmv@91321 function isConvertableFormat($filename) { $extension = substr(strrchr($filename, "."), 1); if(in_array(strtolower($extension),$this->inline_image_convertible_extensions)){ return true; } return false; } //crmv@91321e //crmv@81766 function convertInternalMailerLinks($description) { // trasforma in link al compositore interno gli indirizzi email $description = preg_replace("/(^|[\n ])([a-z0-9&\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)/i","\\1\\2@\\3",$description); // sostituisce mailto con il compositore interno $r = '`\]+)href\=\"mailto\:([^">]+)\"([^>]*)\>(.*?)\<\/a\>`ism'; if (preg_match_all($r, $description, $regs, PREG_SET_ORDER)) { foreach ($regs as $reg) { list($email,$params) = explode('?',$reg[2]); //TODO manage $params (subject, body, ecc.) $internal_mailto = "javascript:InternalMailer('{$email}','','','','email_addy');"; $mailto_after = ''.$reg[4].''; $description = str_replace($reg[0], $mailto_after, $description); } } return $description; } //crmv@81766e //crmv@86304 function internalAppendMessage($mail,$account,$parentid,$to,$from_name,$from_address,$subject,$description,$cc,$bcc,$send_mode,$save_documents=true,$date='',$folder='') { // crmv@187622 $mreplyto = array(); $mreplyto_n = array(); if (!empty($mail->ReplyTo)) { foreach($mail->ReplyTo as $r) { $mreplyto[] = $r[0]; $mreplyto_n[] = $r[1]; } } if (!empty($mail->CustomHeader)) { foreach($mail->CustomHeader as $c) { if ($c[0] == 'In-Reply-To') $in_reply_to = trim($c[1]); elseif ($c[0] == 'References') $mreferences = trim($c[1]); } } $other = array(); // crmv@206153 $attachments = $mail->getAttachments(); if (!empty($attachments)) { foreach($attachments as $a) { // crmv@206153e $content = $file = ''; ($a[5]) ? $content = $a[0] : $file = $a[0]; $other[] = array( 'parameters'=>array( 'name'=>$a[2], 'contenttype'=>$a[4], 'contentdisposition'=>$a[6], 'encoding'=>$a[3], ), 'content'=>$content, 'file'=>$file, ); } } $record = $this->saveCacheLink(array( 'subject'=>$subject, 'description'=>$description, 'mfrom'=>$from_address, 'mfrom_n'=>$from_name, 'mfrom_f'=>"$from_name <$from_address>", 'mto'=>(is_array($to)) ? implode(', ',$to) : $to, 'mcc'=>(is_array($cc)) ? implode(', ',$cc) : $cc, 'mbcc'=>(is_array($bcc)) ? implode(', ',$bcc) : $bcc, 'mreplyto'=>$replyTo['emails'], 'mreplyto_n'=>$replyTo['names'], 'in_reply_to'=>$in_reply_to, 'mreferences'=>$mreferences, 'xmailer'=>null, 'messageid'=>$mail->message_id, 'send_mode'=>$send_mode, 'other'=>$other, 'parent_id'=>$_REQUEST['relation'], 'recipients'=>$parentid, //crmv@80216 'mtype'=>'Link', 'account'=>$account, //crmv@80216e // crmv@187622 'mdate'=>$date, 'folder'=>$folder, // crmv@187622e )); if ($save_documents && !empty($record) && !empty($other)) { // crmv@187622 foreach($other as $contentid => $content){ $this->saveDocument($record,$contentid,null,null,$content,false); } } return $record; // crmv@187622 } //crmv@86304e // crmv@91980 function extractPhoneNumbers($description) { $allPhoneNumbers = array(); if (empty($description)) return $allPhoneNumbers; if (preg_match_all('/href\s*=\s*[\'"](tel|sms):([%0-9 +.)(-]+)[\'"]/i', $description, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $type = strtolower(trim($match[1])); $num = trim(rawurldecode($match[2])); if (($type == 'tel' || $type == 'sms') && !empty($num)) { $allPhoneNumbers[] = array( 'number' => $num, 'type' => ($type == 'sms' ? 'mobile' : 'phone') ); } } } return $allPhoneNumbers; } // retrieve them from the table function getPhoneNumbers($messagesid) { global $adb, $table_prefix; $list = array(); $res = $adb->pquery("SELECT phone, type FROM {$table_prefix}_messages_ntel WHERE messagesid = ?", array($messagesid)); if ($res && $adb->num_rows($res) > 0) { while ($row = $adb->fetchByASsoc($res,-1, false)) { $list[] = array('number' => $row['phone'], 'type' => $row['type']); } } return $list; } // save the numbers in the table function savePhoneNumbers($messagesid, $numbers) { global $adb, $table_prefix; $inserts = array(); foreach ($numbers as $entry) { $inserts[] = array($messagesid, $entry['number'], $entry['type']); } if (count($inserts) > 0) { $adb->bulkInsert($table_prefix."_messages_ntel", array('messagesid', 'phone', 'type'), $inserts); } } function deletePhoneNumbers($messagesid) { global $adb, $table_prefix; $adb->pquery("DELETE FROM {$table_prefix}_messages_ntel WHERE messagesid = ?", array($messagesid)); } // crmv@91980e //crmv@94282 function get_navigation_values($list_query_count,$url_string,$currentModule,$type='',$forusers=false,$viewid = '') { return Zend_Json::encode(Array('nav_array'=>Array(),'rec_string'=>'')); } //crmv@94282e //crmv@112756 crmv@130734 function extractTnefAndZip(&$zipname, &$content, &$filesize) { define('SM_PATH', $root_directory."modules/Messages/src/attachment_tnef/"); require_once('modules/Messages/src/attachment_tnef/plugins/attachment_tnef/constants.php'); require_once('modules/Messages/src/attachment_tnef/plugins/attachment_tnef/functions.php'); include_once('modules/Messages/src/attachment_tnef/plugins/attachment_tnef/class/tnef.php'); require_once('vtlib/thirdparty/dZip.inc.php'); global $root_directory; $tmp_folder = "cache/upload/"; $tmp_fullpath = $root_directory.$tmp_folder; //sanitize subject for filename $zipname = preg_replace('/[\/:*?"<>|]/','',$zipname); $zipname = preg_replace('/\s+/', '_', $zipname); $zipname = str_replace('.dat', '', $zipname); $zipname .= ".zip"; $tmp_zipname = ''; $files2clean = array(); $tnef_debug = false; $attachment = new TnefAttachment($tnef_debug); // crmv@146653 $result = $attachment->decodeTnef($content); $tnef_files = &$attachment->getFilesNested(); $attachments = array(); if (!empty($tnef_files)) { $tmp_zipname = tempnam($tmp_fullpath,'tnef'); $zip=new dZip($tmp_zipname); foreach($tnef_files as $tnef_file) { $name = $tnef_file->getName(); $tmp_name = tempnam($tmp_fullpath,'attach'); file_put_contents($tmp_name,$tnef_file->getContent()); $files2clean[$name]=$tmp_name; $zip->addFile($tmp_name, $name); } $zip->save(); } //cleaning temp files if (!empty($files2clean)) { foreach($files2clean as $filepath){ unlink($filepath); } } if (empty($tmp_zipname)) { $filesize = 0; return false; } $filesize = filesize($tmp_zipname); //$filesize = $filesize + ($filesize % 1024); //for zip files //crmv@79484 $content = fread(fopen($tmp_zipname, "r"), $filesize); return $tmp_zipname; } //crmv@112756e crmv@130734e //crmv@OPER8279 function getIntervalStorage() { // use max from interval_storage and interval_schedulation (if not empty) $interval_schedulation = strtotime("-{$this->interval_schedulation}"); $interval_storage = strtotime("-{$this->interval_storage}"); ((!empty($this->interval_schedulation)) && $interval_storage > $interval_schedulation) ? $interval = $this->interval_schedulation : $interval = $this->interval_storage; return array( 'interval'=>$interval, 'time'=>strtotime("-{$interval}"), 'date'=>date('Y-m-d',strtotime("-{$interval}")), ); } function cleanStorage() { global $adb, $table_prefix; // exit if interval_storage is set to store all if (empty($this->interval_storage)) return false; // first of all propagate to server pending changes $this->propagateToImap(); $interval_storage = $this->getIntervalStorage(); $this->interval_storage = $interval_storage['interval']; $limit_date = $interval_storage['date']; if (empty($this->interval_storage)) return false; // crmv@186732 // delete from db all messages with mdate < interval_storage and no relations $adb->pquery("delete from {$table_prefix}_messages_cron_uid where date < ?", array($limit_date)); $adb->pquery("delete from {$table_prefix}_messages_cron_uidi where date < ?", array($limit_date)); // crmv@186732e //crmv@171021 crmv@197432 $result = $adb->limitpQuery("select {$table_prefix}_messages.messagesid, {$table_prefix}_messages.messagehash, mdate, folder from {$table_prefix}_messages left join {$table_prefix}_messagesrel on {$table_prefix}_messagesrel.messagehash = {$table_prefix}_messages.messagehash where mtype = ? and mdate < ? and {$table_prefix}_messagesrel.crmid is null and ({$table_prefix}_messages.createdtime is null or {$table_prefix}_messages.createdtime <= ?)", 0, $this->messages_cleaned_by_schedule, array('Webmail', $limit_date, date('Y-m-d H:i:s',strtotime($this->preserve_search_results_date)))); //crmv@171021e crmv@197432e if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result,-1,false)) { // echo "INTERVAL: ".$this->interval_storage.' - LIMIT DATE: '.$limit_date.' - MESSAGE: '.$row['messagesid'].' '.$row['messagehash'].' '.$row['folder'].' '.$row['mdate']."\n"; $this->cleanMessage($row['messagesid'],$row['messagehash']); } } return true; } function cleanMessage($messagesid, $messagehash) { global $adb, $table_prefix; $tables = array( //crmv@171021 removed table _crmentity '_messages'=>'messagesid', '_messages_attach'=>'messagesid', '_messages_deflist'=>'id', '_messages_ical'=>'messagesid', '_messages_mref'=>'messagesid', '_messages_ntel'=>'messagesid', '_messages_recipients'=>'messagesid', '_messages_th'=>'son', '_messages_tmp_prel'=>'id', '_messages_tmp_rlist'=>'id', //crmv@171021 removed table _messagescf ); foreach($tables as $table => $key) { $adb->pquery("delete from {$table_prefix}{$table} where $key = ?", array($messagesid)); } // if do not exists other records with the same messagehash clean tables based on messagehash $result_hash = $adb->pquery("select messagesid from {$table_prefix}_messages where messagehash = ?", array($messagehash)); //crmv@171021 if ($adb->num_rows($result_hash) == 0) { $tables = array( '_messages_drafts'=>'messagehash', '_messagesrel'=>'messagehash', ); foreach($tables as $table => $key) { $adb->pquery("delete from {$table_prefix}{$table} where $key = ?", array($messagehash)); } } } function getSearchIntervals() { static $search_intervals = array(); if (empty($search_intervals)) { $search_in_imap = false; $check_interval_storage_1 = false; $check_interval_storage_2 = false; foreach($this->search_intervals as $start => $si) { $search_intervals_0 = $this->search_intervals[$start][0]; $search_intervals_1 = $this->search_intervals[$start][1]; if (!empty($this->interval_storage)) { $interval_storage = $this->getIntervalStorage(); $limit_storage_time = $interval_storage['time']; } if (!empty($search_intervals_1)) { $time = strtotime($search_intervals_1); if (!$check_interval_storage_1 && $limit_storage_time > $time) { $time = $limit_storage_time; $search_intervals_1 = '-'.$interval_storage['interval']; $check_interval_storage_1 = true; } // mdate >= '".date('Y-m-d',$time)." 00:00:00' } if (!empty($search_intervals_0)) { $time = strtotime($search_intervals_0); if (!$check_interval_storage_2 && $limit_storage_time > strtotime($this->search_intervals[$start-1][1])) { $time = $limit_storage_time; $search_intervals_0 = '-'.$interval_storage['interval']; $check_interval_storage_2 = true; $search_in_imap = true; } // mdate < '".date('Y-m-d',$time)." 00:00:00' } $search_intervals[] = array($search_intervals_0, $search_intervals_1, $search_in_imap); } } return $search_intervals; } // first step contains messages stored (from now to limit_storage) and then the steps are te same of getSearchIntervals function getImapNavigationIntervals() { $intervals = array(); $search_intervals = $this->getSearchIntervals(); foreach($search_intervals as $i => $search_interval) { if ($search_interval[2] == 0 && $i == 0) { $intervals[0] = $search_interval; } elseif ($search_interval[2] == 0) { $intervals[0][1] = $search_interval[1]; } elseif ($search_interval[2] == 1) { $intervals[] = $search_interval; } } return $intervals; } function getSearchParams($input) { global $current_user, $currentModule; $queryGenerator = QueryGenerator::getInstance($currentModule, $current_user); $search_params = array( 'searchtype'=>$input['searchtype'], ); if ($input['searchtype'] == 'BasicSearch') { $search_params['search_text'] = $input['search_text']; } elseif ($input['searchtype'] == 'advance') { $search_params['matchtype'] = ($input['matchtype'] == 'all') ? $queryGenerator::$AND : $queryGenerator::$OR; $noOfConditions = vtlib_purify($input['search_cnt']); for($i=0; $i<$noOfConditions; $i++) { $fieldInfo = 'Fields'.$i; $condition = 'Condition'.$i; $value = 'Srch_value'.$i; list($fieldName,$typeOfData) = explode("::::",str_replace('\'','',stripslashes($input[$fieldInfo]))); $operator = str_replace('\'','',stripslashes($input[$condition])); $searchValue = $input[$value]; $searchValue = urldecode($searchValue); //crmv@60585 $searchValue = function_exists('iconv') ? @iconv("UTF-8",$default_charset,$searchValue) : $searchValue; // crmv@167702 $search_params['conditions'][] = array('field'=>$fieldName,'operator'=>$operator,'value'=>$searchValue); } } return $search_params; } /* * imap search sources * https://tools.ietf.org/html/rfc3501#section-6.4.4 * https://www.limilabs.com/blog/imap-search-requires-parentheses */ function getListViewEntriesImap($before, $since, $search_params=array(), $list_result, &$lv_error='') { global $adb, $current_user, $currentModule, $default_charset, $current_folder; $userid = $current_user->id; $account = $this->getAccount(); $folder = $current_folder; $current_user->id = $userid; $this->setAccount($account); $this->getZendMailStorageImap($userid); $this->selectFolder($folder); // search messages where date >= $since and date < $before if (empty($before) && empty($since)) { $lv_error = getTranslatedString('LBL_IMAP_SEARCH_ERROR_1','Messages'); return false; } $queryGenerator = QueryGenerator::getInstance($currentModule, $current_user); $controller = ListViewController::getInstance($adb, $current_user, $queryGenerator); $listview_rows = array(); $listview_xuid = array(); if ($list_result && $adb->num_rows($list_result) > 0) { while($row=$adb->fetchByAssoc($list_result,-1,false)) { $listview_rows[$row['messagesid']] = $row; $listview_xuid[$row['xuid']] = $row['messagesid']; } } $imap_params = array(); if (!empty($before)) $imap_params[] = 'BEFORE "'.date('j-M-Y',strtotime($before)).'"'; if (!empty($since)) $imap_params[] = 'SINCE "'.date('j-M-Y',strtotime($since)).'"'; if ($search_params['searchtype'] == 'BasicSearch') { $search_string = urldecode($search_params['search_text']); $stringConvert = function_exists('iconv') ? @iconv("UTF-8",$default_charset,$search_string) : $search_string; // crmv@167702 $search_string = trim($stringConvert); if (empty($search_string)) { $lv_error = getTranslatedString('LBL_IMAP_SEARCH_ERROR_2','Messages'); return false; } $imap_params[] = 'TEXT "'.$search_string.'"'; } elseif ($search_params['searchtype'] == 'advance') { $conditions = $search_params['conditions']; if (empty($conditions)) { $lv_error = getTranslatedString('LBL_IMAP_SEARCH_ERROR_3','Messages'); return false; } $imap_conditions = array(); foreach($conditions as $condition) { // check supported operators if (in_array($condition['field'],array('seen','mdate'))) {} // for seen and date all operators are supported elseif (!in_array($condition['operator'],array('c','k'))) { $lv_error = getTranslatedString('LBL_IMAP_SEARCH_ERROR_4','Messages'); return false; } if ($condition['field'] == 'subject') { $str = ($condition['operator'] == 'k') ? 'NOT ' : ''; $str .= 'SUBJECT "'.$condition['value'].'"'; $imap_conditions[] = $str; } elseif ($condition['field'] == 'description') { $str = ($condition['operator'] == 'k') ? 'NOT ' : ''; $str .= 'BODY "'.$condition['value'].'"'; $imap_conditions[] = $str; } elseif ($condition['field'] == 'mdate') { if (in_array($condition['operator'],array('custom','yesterday','today','lastweek','thisweek','lastmonth','thismonth','last60days','last90days'))) { list($start,$end) = explode('|##|',$condition['value']); if (strlen($start) == 10) $imap_conditions[] = 'SINCE "'.date('j-M-Y',strtotime(getValidDBInsertDateValue($start))).'"'; if (strlen($end) == 10) $imap_conditions[] = 'BEFORE "'.date('j-M-Y',strtotime(getValidDBInsertDateValue($end))).'"'; } else { $value = getValidDBInsertDateValue($condition['value']); if ($condition['operator'] == 'e') { // equal $imap_conditions[] = 'SINCE "'.date('j-M-Y',strtotime($value)).'"'; $imap_conditions[] = 'BEFORE "'.date('j-M-Y',strtotime('+1 day',strtotime($value))).'"'; // since + 1 day } elseif ($condition['operator'] == 'n') { // not equal $imap_conditions[] = 'NOT (SINCE "'.date('j-M-Y',strtotime($value)).'" BEFORE "'.date('j-M-Y',strtotime('+1 day',strtotime($value))).'")'; } elseif ($condition['operator'] == 'l') { // less than $imap_conditions[] = 'BEFORE "'.date('j-M-Y',strtotime($value)).'"'; } elseif ($condition['operator'] == 'g') { // greater than $imap_conditions[] = 'SINCE "'.date('j-M-Y',strtotime('+1 day',strtotime($value))).'"'; } elseif ($condition['operator'] == 'm') { // less or equal $imap_conditions[] = 'BEFORE "'.date('j-M-Y',strtotime('+1 day',strtotime($value))).'"'; } elseif ($condition['operator'] == 'h') { // greater or equal $imap_conditions[] = 'SINCE "'.date('j-M-Y',strtotime($value)).'"'; } } } elseif ($condition['field'] == 'senders') { $str = ($condition['operator'] == 'k') ? 'NOT ' : ''; $str .= 'FROM "'.$condition['value'].'"'; $imap_conditions[] = $str; } elseif ($condition['field'] == 'recipients') { $str = ($condition['operator'] == 'k') ? 'NOT ' : ''; $str .= '(OR TO "'.$condition['value'].'" OR CC "'.$condition['value'].'" BCC "'.$condition['value'].'")'; $imap_conditions[] = $str; } elseif ($condition['field'] == 'seen') { if ($condition['operator'] == 'e' && strtolower($condition['value']) == 'yes') $imap_conditions[] = 'SEEN'; elseif ($condition['operator'] == 'e' && strtolower($condition['value']) == 'no') $imap_conditions[] = 'UNSEEN'; elseif ($condition['operator'] == 'n' && strtolower($condition['value']) == 'yes') $imap_conditions[] = 'NOT SEEN'; elseif ($condition['operator'] == 'n' && strtolower($condition['value']) == 'no') $imap_conditions[] = 'NOT UNSEEN'; } } if (!empty($imap_conditions)) { if ($search_params['matchtype'] == $queryGenerator::$AND) { foreach($imap_conditions as $imap_condition) { $imap_params[] = $imap_condition; } } elseif ($search_params['matchtype'] == $queryGenerator::$OR) { if (count($imap_conditions) == 1) { $imap_params[] = $imap_conditions[0]; } else { $imap_param = '('; for($i=0;$i 0) $imap_param .= ' '; ($isearch($imap_params); if ($messageids === false) { /* Lotus do not support SEARCH SINCE */ return false; } else { $tmp_server_ids = self::$protocol->fetch(array('UID','INTERNALDATE'),$messageids); } $ids = array(); foreach($tmp_server_ids as $messageid => $val) { $ids[$messageid] = $val['UID']; //$ids_dates[$val['UID']] = date('Y-m-d H:i:s',strtotime($val['INTERNALDATE'])); } krsort($ids); $ret_arr = array(); foreach ($ids as $messageId => $uid) { if (isset($listview_xuid[$uid])) { // if message is saved use the saved one $row = $listview_rows[$listview_xuid[$uid]]; ($this->haveAttachments($row['messagesid'])) ? $row['has_attachments'] = 1 : $row['has_attachments'] = 0; $ret_arr[$listview_xuid[$uid]] = $controller->getListViewEntryLight($this,$currentModule,$row); } else { try { $message = self::$mail->getMessage($messageId); } catch (Zend\Mail\Exception\RuntimeException $e) { $this->logException($e,__FILE__,__LINE__,__METHOD__); //crmv@90390 // ignore parse errors and continue continue; } $data = $this->getMessageData($message,$messageId); //crmv@59094 if (empty($data)) continue; // skip the message if no messageid is present if (empty($data['header']['Messageid'])) continue; $date = $this->getImap2DbDate($data); $body = $this->getImap2DbBody($data); $description = str_replace('&', '&', $body); $magicHTML = $this->magicHTML($description, $uid); $cleaned_body = $magicHTML['html']; $row = array( 'subject'=>$data['header']['Subject'], 'mdate'=>$date, 'mfrom'=>$data['header']['From']['email'], 'mfrom_n'=>$data['header']['From']['name'], 'mfrom_f'=>$data['header']['From']['full'], 'mto'=>$data['header']['To']['email'], 'mto_n'=>$data['header']['To']['name'], 'mto_f'=>$data['header']['To']['full'], 'cleaned_body'=>$cleaned_body, 'seen'=>($data['flags']['seen']=='on')?'1':'0', 'answered'=>($data['flags']['answered']=='on')?'1':'0', 'forwarded'=>($data['flags']['forwarded']=='on')?'1':'0', 'flagged'=>($data['flags']['flagged']=='on')?'1':'0', 'has_attachments'=>!empty($data['other'])?'1':'0', //'thread'=>'', // TODO ? 'xuid'=>$uid, 'folder'=>$folder, 'account'=>$account, ); $ret_arr['xuid_'.$uid] = $controller->getListViewEntryLight($this,$currentModule,$row); $ret_arr['xuid_'.$uid]['ghost'] = true; } } return $ret_arr; } //crmv@OPER8279e //crmv@125629 function saveInlineCache($messagesid,$contentid,$content,$parameters=array()) { global $adb, $table_prefix; if ($adb->isMysql()) { $adb->pquery("insert ignore into {$table_prefix}_messages_inline_cache (messagesid,contentid,cachedate,content,parameters) values (?,?,?,?,?)", array($messagesid,$contentid,date('Y-m-d H:i:s'),$content,Zend_Json::encode($parameters))); } else { $result = $adb->pquery("select messagesid from {$table_prefix}_messages_inline_cache where messagesid = ? and contentid = ?",array($messagesid,$contentid)); if (!$result || $adb->num_rows($result) == 0) { $adb->pquery("insert into {$table_prefix}_messages_inline_cache (messagesid,contentid,cachedate,content,parameters) values (?,?,?,?,?)", array($messagesid,$contentid,date('Y-m-d H:i:s'),$content,Zend_Json::encode($parameters))); } } } function cleanInlineCache() { global $adb, $table_prefix; // exit if interval_storage is set to store all if (empty($this->interval_inline_cache)) return false; $result = $adb->pquery("delete from {$table_prefix}_messages_inline_cache where cachedate < ?", array(date('Y-m-d H:i:s',strtotime("-{$this->interval_inline_cache}")))); return true; } function forceInlineCache() { global $adb, $table_prefix; // force 1 month in order to prevent timeout $this->interval_inline_cache = '1 month'; //crmv@171021 $result = $adb->pquery("select messagesid, smownerid, account, folder, xuid from {$table_prefix}_messages where deleted = 0 and mtype = 'Webmail' and mdate >= ? order by mdate desc", array(date('Y-m-d H:i:s',strtotime("-{$this->interval_inline_cache}")))); //crmv@171021e if ($result && $adb->num_rows($result) > 0) { while ($row = $adb->fetchByASsoc($result,-1, false)) { // TODO download inline or simulate save } } } //crmv@125629e // crmv@187622 function saveScheduledMessage($date, $request) { $emailsFocus = CRMEntity::getInstance('Emails'); $account = $emailsFocus->getFromEmailAccount($request['from_email']); $parentid = $request['parent_id']; $myids = explode("|",$parentid); if (!empty($myids)) $myids = array_filter($myids); $to = $emailsFocus->getToList($request['send_mode'],$request['to_mail'],$myids); $cc = explode(',',$request['ccmail']); $cc = array_map('trim', $cc); $cc = array_filter($cc); $bcc = explode(',',$request['bccmail']); $bcc = array_map('trim', $bcc); $bcc = array_filter($bcc); $message_mode = vtlib_purify($request['message_mode']); $messageid = vtlib_purify($request['message']); ($message_mode == 'forward') ? $attach_messageid = $messageid : $attach_messageid = ''; (!empty($request['attachments_mode'])) ? $attach_mode = $request['attachments_mode'] : $attach_mode = 'all'; $mail = new VTEMailer(); // crmv@180739 setMailerProperties($mail,$request['subject'],$request['description'],$request['from_email'],$request['from_email'],$to,$attach_mode,$attach_messageid,'Emails'); $messagesid = $this->internalAppendMessage($mail,$account,$parentid,$to,$request['from_email'],$request['from_email'],$request['subject'],$request['description'],$cc,$bcc,$request['send_mode'],false,$date,'vteScheduled'); $this->retrieve_entity_info($messagesid,'Messages'); $this->reloadCacheFolderCount($this->column_fields['assigned_user_id'],$account,'vteScheduled'); return $messagesid; } // crmv@187622e // crmv@191351 function outOfOfficeReply() { global $adb, $table_prefix; $settings = $this->getOutOfOfficeSettings(); // echo $this->column_fields['mdate'].' '.$this->column_fields['subject']."\n"; // check if outOfOffice is active if (!$settings['active']) { // echo "not active\n"; return false; } // check if outOfOffice is active for the current account if (!in_array($this->column_fields['account'],$settings['accounts'])) { // echo "not active account\n"; return false; } // check if this message is in the inbox $specialFolders = $this->getAllSpecialFolders('INBOX'); if (empty($specialFolders[$this->column_fields['account']]['INBOX']) || $this->column_fields['folder'] != $specialFolders[$this->column_fields['account']]['INBOX']) { // echo "not inbox\n"; return false; } // check time interval if (!$settings['start_date_allday']) $start_time = $settings['start_time']; else $start_time = '00:00:00'; if (!$settings['start_date_allday']) $end_time = $settings['end_time']; else $end_time= '23:59:59'; if (strtotime($this->column_fields['mdate']) < strtotime($settings['start_date'].' '.$start_time)) { // echo "not start date\n"; return false; } if ($settings['end_date_active'] && strtotime('now') > strtotime($settings['end_date'].' '.$end_time)) { // echo "end of interval is in the past\n"; return false; } if ($settings['end_date_active'] && strtotime($this->column_fields['mdate']) > strtotime($settings['end_date'].' '.$end_time)) { // echo "not end date\n"; return false; } // if the option only_known_addresses_active is true, check if the sender is a known address if ($settings['only_known_addresses_active']) { require_once('include/utils/EmailDirectory.php'); $emailDirectory = new EmailDirectory(); $modules = $emailDirectory->getModules(); $entity = $this->getEntitiesFromEmail($this->column_fields['mfrom'], false, false, $modules, true); if (empty($entity) || empty($entity['crmid'])) { // echo "not known address\n"; return false; } } // check the notification interval $check_date = date('Y-m-d H:i:s', strtotime('-5 days')); $result = $adb->pquery("select id from {$table_prefix}_messages_outofo_q where to_email = ? and date > ?", array($this->column_fields['mfrom'],$check_date)); if ($result && $adb->num_rows($result) > 0) { // echo "notification already sent less than 5 days ago\n"; return false; } $subject = 'Re: '.$this->column_fields['subject']; if (!empty($settings['message_subject'])) $subject .= ' '.$settings['message_subject']; // enqueue the reply $account = $this->getUserAccounts($this->column_fields['assigned_user_id'],$this->column_fields['account']); $params = array( 'id'=>$adb->getUniqueID($table_prefix.'_messages_outofo_q'), 'from_email'=>$account[0]['email'], 'to_email'=>$this->column_fields['mfrom'], 'subject'=>$subject, 'body'=>$settings['message_body'], 'date'=>date('Y-m-d H:i:s'), 'in_reply_to'=>$this->column_fields['messageid'], ); $adb->pquery("insert into {$table_prefix}_messages_outofo_q (".implode(',',array_keys($params)).") values (".generateQuestionMarks($params).")",array($params)); return $params['id']; } function processOutOfOfficeQueue() { global $adb, $table_prefix, $current_user; require_once("modules/Emails/mail.php"); $focusEmails = CRMEntity::getInstance('Emails'); $mail = new VTEMailer(); // crmv@55094 crmv@180739 // clean queue $clean_date = date('Y-m-d H:i:s', strtotime('-7 days')); $adb->pquery("delete from {$table_prefix}_messages_outofo_q where date < ?", array($clean_date)); // process queue $sql = "select * from {$table_prefix}_messages_outofo_q where status = ? or (status = ? and attempts < ?) order by id"; $result = $adb->limitpQuery($sql,0,50,array(0,2,$focusEmails->max_emails_send_queue_attempts)); if ($result && $adb->num_rows($result) > 0) { while($row=$adb->fetchByAssoc($result,-1,false)) { if ($mail->SMTPDebug) echo "sending message {$row['id']} from {$table_prefix}_messages_outofo_q...\n"; //crmv@55094 $adb->pquery("update {$table_prefix}_messages_outofo_q set status = ?, attempts = attempts + 1 where id = ?",array(2,$row['id'])); $mail_tmp = ''; $mail_status = send_mail('Emails',$row['to_email'],$row['from_email'],$row['from_email'],$row['subject'],$row['body'],'','','','','','',$mail_tmp,$row['in_reply_to'],'reply',false); if ($mail_status == 1) { $adb->pquery("update {$table_prefix}_messages_outofo_q set status = ? where id = ?",array(1,$row['id'])); } else { $adb->pquery("update {$table_prefix}_messages_outofo_q set error = ? where id = ?",array($mail_status,date('Y-m-d H:i:s'),$row['id'])); } if ($mail->SMTPDebug) echo "\nmessage {$row['id']} from {$table_prefix}_messages_outofo_q sent!\n\n"; //crmv@55094 } } } // crmv@191351e }