2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
41 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42 * Reserved. Contributor(s): ______________________________________..
43 *********************************************************************************/
45 require_once("include/ytree/Tree.php");
46 require_once("include/ytree/ExtNode.php");
47 require_once("include/SugarFolders/SugarFolders.php");
53 var $folder; // place holder for SugarFolder object
54 var $folderStates = array(); // array of folderPath names and their states (1/0)
56 var $addressSeparators = array(";", ",");
57 var $rolloverStyle = "<style>div#rollover {position: relative;float: left;margin: none;text-decoration: none;}div#rollover a:hover {padding: 0;}div#rollover a span {display: none;}div#rollover a:hover span {text-decoration: none;display: block;width: 250px;margin-top: 5px;margin-left: 5px;position: absolute;padding: 10px;color: #333; border: 1px solid #ccc; background-color: #fff; font-size: 12px;z-index: 1000;}</style>\n";
58 var $groupCss = "<span class='groupInbox'>";
59 var $cacheTimeouts = array(
60 'messages' => 86400, // 24 hours
61 'folders' => 300, // 5 mins
62 'attachments' => 86400, // 24 hours
64 var $userCacheDir = '';
65 var $coreDynamicFolderQuery = "SELECT emails.id polymorphic_id, 'Emails' polymorphic_module FROM emails
66 JOIN emails_text on emails.id = emails_text.email_id
67 WHERE (type = '::TYPE::' OR status = '::STATUS::') AND assigned_user_id = '::USER_ID::' AND emails.deleted = '0'";
76 $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
78 if(!empty($folderStateSerial)) {
79 $this->folderStates = unserialize($folderStateSerial);
82 $this->smarty = new Sugar_Smarty();
83 $this->folder = new SugarFolder();
84 $this->userCacheDir = sugar_cached("modules/Emails/{$current_user->id}");
85 $this->db = DBManagerFactory::getInstance();
89 ///////////////////////////////////////////////////////////////////////////
92 * Renders the frame for emails
94 function displayEmailFrame() {
96 require_once("include/OutboundEmail/OutboundEmail.php");
98 global $app_strings, $app_list_strings;
100 global $sugar_config;
101 global $current_user;
105 global $sugar_version;
106 global $sugar_flavor;
107 global $current_language;
108 global $server_unique_key;
110 $this->preflightUserCache();
111 $ie = new InboundEmail();
118 'unreadChecked' => 0,
122 $this->_generateComposeConfigData('email_compose');
125 //Check quick create module access
126 $QCAvailableModules = $this->_loadQuickCreateModules();
128 //Get the quickSearch js needed for assigned user id on Search Tab
129 require_once('include/QuickSearchDefaults.php');
130 $qsd = QuickSearchDefaults::getQuickSearchDefaults();
131 $qsd->setFormName('advancedSearchForm');
132 $quicksearchAssignedUser = "if(typeof sqs_objects == 'undefined'){var sqs_objects = new Array;}";
133 $quicksearchAssignedUser .= "sqs_objects['advancedSearchForm_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
134 $qsd->setFormName('Distribute');
135 $quicksearchAssignedUser .= "sqs_objects['Distribute_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
136 $this->smarty->assign('quickSearchForAssignedUser', $quicksearchAssignedUser);
139 ///////////////////////////////////////////////////////////////////////
141 $this->smarty->assign("currentUserId",$current_user->id);
142 $this->smarty->assign("CURRENT_USER_EMAIL",$current_user->email1);
143 $this->smarty->assign("currentUserName",$current_user->name);
144 $this->smarty->assign('yuiPath', 'modules/Emails/javascript/yui-ext/');
145 $this->smarty->assign('app_strings', $app_strings);
146 $this->smarty->assign('mod_strings', $mod_strings);
147 $this->smarty->assign('theme', $theme);
148 $this->smarty->assign('sugar_config', $sugar_config);
149 $this->smarty->assign('is_admin', $current_user->is_admin);
150 $this->smarty->assign('sugar_version', $sugar_version);
151 $this->smarty->assign('sugar_flavor', $sugar_flavor);
152 $this->smarty->assign('current_language', $current_language);
153 $this->smarty->assign('server_unique_key', $server_unique_key);
154 $this->smarty->assign('qcModules', json_encode($QCAvailableModules));
155 $extAllDebugValue = "ext-all.js";
156 $this->smarty->assign('extFileName', $extAllDebugValue);
159 $e2UserPreferences = $this->getUserPrefsJS();
160 $emailSettings = $e2UserPreferences['emailSettings'];
162 ///////////////////////////////////////////////////////////////////////
164 // settings: accounts
166 $cuDatePref = $current_user->getUserDateTimePreferences();
167 $this->smarty->assign('dateFormat', $cuDatePref['date']);
168 $this->smarty->assign('dateFormatExample', str_replace(array("Y", "m", "d"), array("yyyy", "mm", "dd"), $cuDatePref['date']));
169 $this->smarty->assign('calFormat', $timedate->get_cal_date_format());
170 $this->smarty->assign('TIME_FORMAT', $timedate->get_user_time_format());
172 $ieAccounts = $ie->retrieveByGroupId($current_user->id);
173 $ieAccountsOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
175 foreach($ieAccounts as $k => $v) {
176 $disabled = (!$v->is_personal) ? "DISABLED" : "";
177 $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
178 $ieAccountsOptions .= "<option value='{$v->id}' $disabled>{$group}{$v->name}</option>\n";
181 $this->smarty->assign('ieAccounts', $ieAccountsOptions);
182 $this->smarty->assign('rollover', $this->rolloverStyle);
184 $protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']);
185 $this->smarty->assign('PROTOCOL', get_select_options_with_id($protocol, ''));
186 $this->smarty->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], ''));
187 $this->smarty->assign('ie_mod_strings', return_module_language($current_language, 'InboundEmail'));
189 $charsetSelectedValue = isset($emailSettings['defaultOutboundCharset']) ? $emailSettings['defaultOutboundCharset'] : false;
190 if (!$charsetSelectedValue) {
191 $charsetSelectedValue = $current_user->getPreference('default_export_charset', 'global');
192 if (!$charsetSelectedValue) {
193 $charsetSelectedValue = $locale->getPrecedentPreference('default_email_charset');
197 'options' => $locale->getCharsetSelect(),
198 'selected' => $charsetSelectedValue,
200 $this->smarty->assign('charset', $charset);
202 $emailCheckInterval = array('options' => $app_strings['LBL_EMAIL_CHECK_INTERVAL_DOM'], 'selected' => $emailSettings['emailCheckInterval']);
203 $this->smarty->assign('emailCheckInterval', $emailCheckInterval);
204 $this->smarty->assign('attachmentsSearchOptions', $app_list_strings['checkbox_dom']);
205 $this->smarty->assign('sendPlainTextChecked', ($emailSettings['sendPlainText'] == 1) ? 'CHECKED' : '');
206 $this->smarty->assign('showNumInList', get_select_options_with_id($app_list_strings['email_settings_num_dom'], $emailSettings['showNumInList']));
208 //// END USER SETTINGS
209 ///////////////////////////////////////////////////////////////////////
211 ///////////////////////////////////////////////////////////////////////
213 $prependSignature = ($current_user->getPreference('signature_prepend')) ? 'true' : 'false';
214 $defsigID = $current_user->getPreference('signature_default');
215 $this->smarty->assign('signatures', $current_user->getSignatures(false, $defsigID));
216 $this->smarty->assign('signaturesSettings', $current_user->getSignatures(false, $defsigID, false));
217 $signatureButtons = $current_user->getSignatureButtons('SUGAR.email2.settings.createSignature', !empty($defsigID));
218 if (!empty($defsigID)) {
219 $signatureButtons = $signatureButtons . '<span name="delete_sig" id="delete_sig" style="visibility:inherit;"><input class="button" onclick="javascript:SUGAR.email2.settings.deleteSignature();" value="'.$app_strings['LBL_EMAIL_DELETE'].'" type="button" tabindex="392">
222 $signatureButtons = $signatureButtons . '<span name="delete_sig" id="delete_sig" style="visibility:hidden;"><input class="button" onclick="javascript:SUGAR.email2.settings.deleteSignature();" value="'.$app_strings['LBL_EMAIL_DELETE'].'" type="button" tabindex="392">
225 $this->smarty->assign('signatureButtons', $signatureButtons);
226 $this->smarty->assign('signaturePrepend', $prependSignature == 'true' ? 'CHECKED' : '');
228 ///////////////////////////////////////////////////////////////////////
230 ///////////////////////////////////////////////////////////////////////
232 $email_templates_arr = $this->getEmailTemplatesArray();
233 natcasesort($email_templates_arr);
234 $this->smarty->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, ''));
235 //// END EMAIL TEMPLATES
236 ///////////////////////////////////////////////////////////////////////
238 ///////////////////////////////////////////////////////////////////////
239 //// FOLDERS & TreeView
240 $this->smarty->assign('groupUserOptions', $ie->getGroupsWithSelectOptions(array('' => $app_strings['LBL_EMAIL_CREATE_NEW'])));
242 $tree = $this->getMailboxNodes();
245 $preloadFolder = 'lazyLoadFolder = ';
246 $focusFolderSerial = $current_user->getPreference('focusFolder', 'Emails');
247 if(!empty($focusFolderSerial)) {
248 $focusFolder = unserialize($focusFolderSerial);
249 //$focusFolder['ieId'], $focusFolder['folder']
250 $preloadFolder .= json_encode($focusFolder).";";
252 $preloadFolder .= "new Object();";
255 ///////////////////////////////////////////////////////////////////////
258 $out .= $this->smarty->fetch("modules/Emails/templates/_baseEmail.tpl");
259 $out .= $tree->generate_header();
260 $out .= $tree->generateNodesNoInit(true, 'email2treeinit');
262 <script type="text/javascript" language="javascript">
264 var loader = new YAHOO.util.YUILoader({
266 "layout", "element", "tabview", "menu",
267 "cookie", "sugarwidgets"
270 skin: { base: 'blank', defaultSkin: '' },
271 onSuccess: email2init,
273 base: "include/javascript/yui/build/"
276 name :"sugarwidgets",
278 fullpath: "include/javascript/sugarwidgets/SugarYUIWidgets.js",
279 varName: "YAHOO.SUGAR",
280 requires: ["datatable", "dragdrop", "treeview", "tabview", "calendar"]
294 * Generate the frame needed for the quick compose email UI. This frame is loaded dynamically
297 * @return JSON An object containing html markup and js script variables.
299 function displayQuickComposeEmailFrame()
301 $this->preflightUserCache();
303 $this->_generateComposeConfigData('email_compose_light');
304 $javascriptOut = $this->smarty->fetch("modules/Emails/templates/_baseConfigData.tpl");
306 $divOut = $this->smarty->fetch("modules/Emails/templates/overlay.tpl");
307 $divOut .= $this->smarty->fetch("modules/Emails/templates/addressSearchContent.tpl");
309 $outData = array('jsData' => $javascriptOut,'divData'=> $divOut);
310 $out = json_encode($outData);
315 * Load the modules from the metadata file and include in a custom one if it exists
319 protected function _loadQuickCreateModules()
321 $QCAvailableModules = array();
322 $QCModules = array();
324 include('modules/Emails/metadata/qcmodulesdefs.php');
325 if (file_exists('custom/modules/Emails/metadata/qcmodulesdefs.php')) {
326 include('custom/modules/Emails/metadata/qcmodulesdefs.php');
329 foreach($QCModules as $module) {
330 $seed = SugarModule::get($module)->loadBean();
331 if ( ( $seed instanceOf SugarBean ) && $seed->ACLAccess('edit') ) {
332 $QCAvailableModules[] = $module;
336 return $QCAvailableModules;
340 * Given an email link url (eg. index.php?action=Compose&parent_type=Contacts...) break up the
341 * request components and create a compose package that can be used by the quick compose UI. The
342 * result is typically passed into the js call SUGAR.quickCompose.init which initalizes the quick compose
345 * @param String $emailLinkUrl
346 * @return JSON Object containing the composePackage and full link url
348 function generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, $lazyLoad=false)
350 $composeData = explode("&",$emailLinkUrl);
351 $a_composeData = array();
352 foreach ($composeData as $singleRequest)
354 $tmp = explode("=",$singleRequest);
355 $a_composeData[$tmp[0]] = urldecode($tmp[1]);
358 return $this->generateComposePackageForQuickCreate($a_composeData,$emailLinkUrl, $lazyLoad);
361 * Generate the composePackage for the quick compose email UI. The package contains
362 * key/value pairs generated by the Compose.php file which are then set into the
363 * quick compose email UI (eg. to addr, parent id, parent type, etc)
365 * @param Array $composeData Associative array read and processed by generateComposeDataPackage.
366 * @param String $fullLinkUrl A link that contains all pertinant information so the user can be
367 * directed to the full compose screen if needed
368 * @param SugarBean $bean Optional - the parent object bean with data
369 * @return JSON Object containg composePackage and fullLinkUrl
371 function generateComposePackageForQuickCreate($composeData,$fullLinkUrl, $lazyLoad=false, $bean = null)
373 $_REQUEST['forQuickCreate'] = true;
376 require_once('modules/Emails/Compose.php');
377 $composePackage = generateComposeDataPackage($composeData,FALSE, $bean);
379 $composePackage = $composeData;
382 // JSON object is passed into the function defined within the a href onclick event
383 // which is delimeted by '. Need to escape all single quotes and &, <, >
384 // but not double quotes since json would escape them
385 foreach ($composePackage as $key => $singleCompose)
387 if (is_string($singleCompose))
388 $composePackage[$key] = str_replace(" ", " ", from_html($singleCompose));
391 $quickComposeOptions = array('fullComposeUrl' => $fullLinkUrl,'composePackage' => $composePackage);
393 $j_quickComposeOptions = JSON::encode($quickComposeOptions, false ,true);
396 return $j_quickComposeOptions;
400 * Generate the config data needed for the Full Compose UI and the Quick Compose UI. The set of config data
401 * returned is the minimum set needed by the quick compose UI.
403 * @param String $type Drives which tinyMCE options will be included.
405 function _generateComposeConfigData($type = "email_compose_light" )
407 global $app_list_strings,$current_user, $app_strings, $mod_strings,$current_language,$locale;
410 $parent_types = $app_list_strings['record_type_display'];
411 $disabled_parent_types = ACLController::disabledModuleList($parent_types, false, 'list');
413 foreach($disabled_parent_types as $disabled_parent_type) {
414 unset($parent_types[$disabled_parent_type]);
416 asort($parent_types);
417 $linkBeans = json_encode(get_select_options_with_id($parent_types, ''));
420 require_once("include/SugarTinyMCE.php");
421 $tiny = new SugarTinyMCE();
422 $tinyConf = $tiny->getConfig($type);
424 //Generate Language Packs
425 $lang = "var app_strings = new Object();\n";
426 foreach($app_strings as $k => $v) {
427 if(strpos($k, 'LBL_EMAIL_') !== false) {
428 $lang .= "app_strings.{$k} = '{$v}';\n";
431 //Get the email mod strings but don't use the global variable as this may be overridden by
432 //other modules when the quick create is rendered.
433 $email_mod_strings = return_module_language($current_language,'Emails');
434 $modStrings = "var mod_strings = new Object();\n";
435 foreach($email_mod_strings as $k => $v) {
436 $v = str_replace("'", "\'", $v);
437 $modStrings .= "mod_strings.{$k} = '{$v}';\n";
439 $lang .= "\n\n{$modStrings}\n";
441 //Grab the Inboundemail language pack
442 $ieModStrings = "var ie_mod_strings = new Object();\n";
443 $ie_mod_strings = return_module_language($current_language,'InboundEmail');
444 foreach($ie_mod_strings as $k => $v) {
445 $v = str_replace("'", "\'", $v);
446 $ieModStrings .= "ie_mod_strings.{$k} = '{$v}';\n";
448 $lang .= "\n\n{$ieModStrings}\n";
450 $this->smarty->assign('linkBeans', $linkBeans);
451 $this->smarty->assign('linkBeansOptions', $parent_types);
452 $this->smarty->assign('tinyMCE', $tinyConf);
453 $this->smarty->assign('lang', $lang);
454 $this->smarty->assign('app_strings', $app_strings);
455 $this->smarty->assign('mod_strings', $email_mod_strings);
456 $ie1 = new InboundEmail();
459 $defsigID = $current_user->getPreference('signature_default');
460 $defaultSignature = $current_user->getDefaultSignature();
461 $sigJson = !empty($defaultSignature) ? json_encode(array($defaultSignature['id'] => from_html($defaultSignature['signature_html']))) : "new Object()";
462 $this->smarty->assign('defaultSignature', $sigJson);
463 $this->smarty->assign('signatureDefaultId', (isset($defaultSignature['id'])) ? $defaultSignature['id'] : "");
465 $this->smarty->assign('userPrefs', json_encode($this->getUserPrefsJS()));
467 //Get the users default outbound id
468 $defaultOutID = $ie1->getUsersDefaultOutboundServerId($current_user);
469 $this->smarty->assign('defaultOutID', $defaultOutID);
472 $charsets = json_encode($locale->getCharsetSelect());
473 $this->smarty->assign('emailCharsets', $charsets);
475 //Relateable List of People for address book search
477 $peopleTables = array("users",
482 $filterPeopleTables = array();
483 global $app_list_strings, $app_strings;
484 $filterPeopleTables['LBL_DROPDOWN_LIST_ALL'] = $app_strings['LBL_DROPDOWN_LIST_ALL'];
485 foreach($peopleTables as $table) {
486 $module = ucfirst($table);
487 $class = substr($module, 0, strlen($module) - 1);
488 require_once("modules/{$module}/{$class}.php");
489 $person = new $class();
491 if (!$person->ACLAccess('list')) continue;
492 $filterPeopleTables[$person->table_name] = $app_list_strings['moduleList'][$person->module_dir];
494 $this->smarty->assign('listOfPersons' , get_select_options_with_id($filterPeopleTables,''));
501 ///////////////////////////////////////////////////////////////////////////
503 ///////////////////////////////////////////////////////////////////////////
506 * Retrieves all relationship metadata for a user's address book
509 function getContacts() {
510 global $current_user;
512 $q = "SELECT * FROM address_book WHERE assigned_user_id = '{$current_user->id}' ORDER BY bean DESC";
513 $r = $this->db->query($q);
517 while($a = $this->db->fetchByAssoc($r)) {
518 $ret[$a['bean_id']] = array(
519 'id' => $a['bean_id'],
520 'module' => $a['bean'],
528 * Saves changes to a user's address book
529 * @param array contacts
531 function setContacts($contacts) {
532 global $current_user;
534 $oldContacts = $this->getContacts();
536 foreach($contacts as $cid => $contact) {
537 if(!in_array($contact['id'], $oldContacts)) {
538 $q = "INSERT INTO address_book (assigned_user_id, bean, bean_id) VALUES ('{$current_user->id}', '{$contact['module']}', '{$contact['id']}')";
539 $r = $this->db->query($q, true);
545 * Removes contacts from the user's address book
548 function removeContacts($ids) {
549 global $current_user;
553 foreach($ids as $id) {
557 $concat .= "'{$id}'";
560 $q = "DELETE FROM address_book WHERE assigned_user_id = '{$current_user->id}' AND bean_id IN ({$concat})";
561 $r = $this->db->query($q);
565 * saves editted Contact info
566 * @param string $str JSON serialized object
568 function saveContactEdit($str) {
570 $json = getJSONobj();
572 $str = from_html($str);
573 $obj = $json->decode($str);
575 $contact = new Contact();
576 $contact->retrieve($obj['contact_id']);
577 $contact->first_name = $obj['contact_first_name'];
578 $contact->last_name = $obj['contact_last_name'];
581 // handle email address changes
582 $addresses = array();
584 foreach($obj as $k => $req) {
585 if(strpos($k, 'emailAddress') !== false) {
586 $addresses[$k] = $req;
590 // prefill some REQUEST vars for emailAddress save
591 $_REQUEST['emailAddressOptOutFlag'] = $obj['optOut'];
592 $_REQUEST['emailAddressInvalidFlag'] = $obj['invalid'];
593 $contact->emailAddress->save($obj['contact_id'], 'Contacts', $addresses, $obj['primary'], '');
597 * Prepares the Edit Contact mini-form via template assignment
598 * @param string id ID of contact in question
599 * @param string module Module in focus
602 function getEditContact($id, $module) {
606 if(!class_exists("Contact")) {
610 $contact = new Contact();
611 $contact->retrieve($_REQUEST['id']);
614 if($contact->ACLAccess('edit')) {
615 $contactMeta = array();
616 $contactMeta['id'] = $contact->id;
617 $contactMeta['module'] = $contact->module_dir;
618 $contactMeta['first_name'] = $contact->first_name;
619 $contactMeta['last_name'] = $contact->last_name;
621 $this->smarty->assign("app_strings", $app_strings);
622 $this->smarty->assign("contact_strings", return_module_language($_SESSION['authenticated_user_language'], 'Contacts'));
623 $this->smarty->assign("contact", $contactMeta);
625 $ea = new SugarEmailAddress();
626 $newEmail = $ea->getEmailAddressWidgetEditView($id, $module, true);
627 $this->smarty->assign("emailWidget", $newEmail['html']);
629 $ret['form'] = $this->smarty->fetch("modules/Emails/templates/editContact.tpl");
630 $ret['prefillData'] = $newEmail['prefillData'];
633 $ret['form'] = $app_strings['LBL_EMAIL_ERROR_NO_ACCESS'];
634 $ret['prefillData'] = '{}';
638 $ret['contactName'] = $contact->full_name;
645 * Retrieves a concatenated list of contacts, those with assigned_user_id = user's id and those in the address_book
647 * @param array $contacts Array of contact types -> IDs
648 * @param object $user User in focus
651 function getUserContacts($contacts, $user=null) {
653 global $current_user;
657 $user = $current_user;
660 $emailAddress = new SugarEmailAddress();
666 foreach($contacts as $contact) {
667 if(!isset($modules[$contact['module']])) {
668 $modules[$contact['module']] = array();
670 $modules[$contact['module']][] = $contact;
673 foreach($modules as $module => $contacts) {
675 $union .= " UNION ALL ";
678 $table = strtolower($module);
681 foreach($contacts as $contact) {
682 if(!empty($idsSerial)) {
685 $idsSerial .= "'{$contact['id']}'";
688 $union .= "(SELECT id, first_name, last_name, title, '{$module}' module FROM {$table} WHERE id IN({$idsSerial}) AND deleted = 0 )";
691 $union .= " ORDER BY last_name";
694 $r = $user->db->query($union);
698 while($a = $user->db->fetchByAssoc($r)) {
701 $c['name'] = $locale->getLocaleFormattedName($a['first_name'], "<b>{$a['last_name']}</b>", '', $a['title'], '', $user);
703 $c['module'] = $a['module'];
704 $c['email'] = $emailAddress->getAddressesByGUID($a['id'], $a['module']);
710 //// END ADDRESS BOOK
711 ///////////////////////////////////////////////////////////////////////////
714 ///////////////////////////////////////////////////////////////////////////
715 //// EMAIL 2.0 Preferences
716 function getUserPrefsJS() {
717 global $current_user;
720 // sort order per mailbox view
721 $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
722 $sortArray = array();
723 if(!empty($sortSerial)) {
724 $sortArray = unserialize($sortSerial);
727 // treeview collapsed/open states
728 $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
729 $folderStates = array();
730 if(!empty($folderStateSerial)) {
731 $folderStates = unserialize($folderStateSerial);
734 // subscribed accounts
735 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
738 $emailSettings = $current_user->getPreference('emailSettings', 'Emails');
740 if(empty($emailSettings)) {
741 $emailSettings = array();
742 $emailSettings['emailCheckInterval'] = -1;
743 $emailSettings['autoImport'] = '';
744 $emailSettings['alwaysSaveOutbound'] = '1';
745 $emailSettings['sendPlainText'] = '';
746 $emailSettings['defaultOutboundCharset'] = $GLOBALS['sugar_config']['default_email_charset'];
747 $emailSettings['showNumInList'] = 20;
751 $focusFolder = $current_user->getPreference('focusFolder', 'Emails');
752 $focusFolder = !empty($focusFolder) ? unserialize($focusFolder) : array();
755 $showUnreadOnly = $current_user->getPreference('showUnreadOnly', 'Emails');
757 $listViewSort = array(
759 "sortDirection" => 'DESC',
763 $signaturePrepend = $current_user->getPreference('signature_prepend') ? 'true' : 'false';
764 $signatureDefault = $current_user->getPreference('signature_default');
766 'signature_prepend' => $signaturePrepend,
767 'signature_default' => $signatureDefault
773 'emailAddresses' => $current_user->emailAddress->getAddressesByGUID($current_user->id, 'Users'),
774 'full_name' => from_html($current_user->full_name),
777 $userPreferences = array();
778 $userPreferences['sort'] = $sortArray;
779 $userPreferences['folderStates'] = $folderStates;
780 $userPreferences['showFolders'] = $showFolders;
781 $userPreferences['emailSettings'] = $emailSettings;
782 $userPreferences['focusFolder'] = $focusFolder;
783 $userPreferences['showUnreadOnly'] = $showUnreadOnly;
784 $userPreferences['listViewSort'] = $listViewSort;
785 $userPreferences['signatures'] = $signatures;
786 $userPreferences['current_user'] = $user;
787 return $userPreferences;
792 ///////////////////////////////////////////////////////////////////////////
793 //// FOLDER FUNCTIONS
796 * Creates a new Sugar folder
797 * @param string $nodeLabel New sugar folder name
798 * @param string $parentLabel Parent folder name
800 function saveNewFolder($nodeLabel, $parentId, $isGroup=0) {
801 global $current_user;
803 $this->folder->name = $nodeLabel;
804 $this->folder->is_group = $isGroup;
805 $this->folder->parent_folder = ($parentId == 'Home') ? "" : $parentId;
806 $this->folder->has_child = 0;
807 $this->folder->created_by = $current_user->id;
808 $this->folder->modified_by = $current_user->id;
809 $this->folder->date_modified = $this->folder->date_created = TimeDate::getInstance()->nowDb();
811 $this->folder->save();
813 'action' => 'newFolderSave',
814 'id' => $this->folder->id,
815 'name' => $this->folder->name,
816 'is_group' => $this->folder->is_group,
817 'is_dynamic' => $this->folder->is_dynamic
822 * Saves user sort prefernces
824 function saveListViewSortOrder($ieId, $focusFolder, $sortBy, $sortDir) {
825 global $current_user;
827 $sortArray = array();
829 $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
830 if(!empty($sortSerial)) {
831 $sortArray = unserialize($sortSerial);
834 $sortArray[$ieId][$focusFolder]['current']['sort'] = $sortBy;
835 $sortArray[$ieId][$focusFolder]['current']['direction'] = $sortDir;
836 $sortSerial = serialize($sortArray);
837 $current_user->setPreference('folderSortOrder', $sortSerial, '', 'Emails');
841 * Stickies folder collapse/open state
843 function saveFolderOpenState($focusFolder, $focusFolderOpen) {
844 global $current_user;
846 $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
847 $folderStates = array();
849 if(!empty($folderStateSerial)) {
850 $folderStates = unserialize($folderStateSerial);
853 $folderStates[$focusFolder] = $focusFolderOpen;
854 $newFolderStateSerial = serialize($folderStates);
855 $current_user->setPreference('folderOpenState', $newFolderStateSerial, '', 'Emails');
859 * saves a folder's view state
861 function saveListView($ieId, $folder) {
862 global $current_user;
864 $saveState = array();
865 $saveState['ieId'] = $ieId;
866 $saveState['folder'] = $folder;
867 $saveStateSerial = serialize($saveState);
868 $current_user->setPreference('focusFolder', $saveStateSerial, '', 'Emails');
872 * Generates cache folder structure
874 function preflightEmailCache($cacheRoot) {
876 if(!file_exists($cacheRoot))
877 mkdir_recursive(clean_path($cacheRoot));
880 if(!file_exists($cacheRoot."/folders"))
881 mkdir_recursive(clean_path("{$cacheRoot}/folders"));
884 if(!file_exists($cacheRoot."/messages"))
885 mkdir_recursive(clean_path("{$cacheRoot}/messages"));
888 if(!file_exists($cacheRoot."/attachments"))
889 mkdir_recursive(clean_path("{$cacheRoot}/attachments"));
892 function deleteEmailCacheForFolders($cacheRoot) {
893 $filePath = $cacheRoot."/folders/folders.php";
894 if (file_exists($filePath)) {
898 ///////////////////////////////////////////////////////////////////////////
901 * Identifies subscribed mailboxes and empties the trash
902 * @param object $ie InboundEmail
904 function emptyTrash(&$ie) {
905 global $current_user;
907 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
909 if(is_array($showFolders)) {
910 foreach($showFolders as $ieId) {
912 $ie->retrieve($ieId);
920 * returns an array of nodes that correspond to IMAP mailboxes.
921 * @param bool $forceRefresh
922 * @return object TreeView object
924 function getMailboxNodes() {
925 global $sugar_config;
926 global $current_user;
929 $tree = new Tree("frameFolders");
930 $tree->tree_style= 'include/ytree/TreeView/css/check/tree.css';
933 $ie = new InboundEmail();
934 $refreshOffset = $this->cacheTimeouts['folders']; // 5 mins. this will be set via user prefs
936 $rootNode = new ExtNode($app_strings['LBL_EMAIL_HOME_FOLDER'], $app_strings['LBL_EMAIL_HOME_FOLDER']);
937 $rootNode->dynamicloadfunction = '';
938 $rootNode->expanded = true;
939 $rootNode->dynamic_load = true;
940 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
942 if(empty($showFolders)) {
943 $showFolders = array();
947 if($current_user->hasPersonalEmail()) {
948 $personals = $ie->retrieveByGroupId($current_user->id);
950 foreach($personals as $k => $personalAccount) {
951 if(in_array($personalAccount->id, $showFolders)) {
952 // check for cache value
953 $cacheRoot = sugar_cached("modules/Emails/{$personalAccount->id}");
954 $this->preflightEmailCache($cacheRoot);
956 if($this->validCacheFileExists($personalAccount->id, 'folders', "folders.php")) {
957 $mailboxes = $this->getMailBoxesFromCacheValue($personalAccount);
959 $mailboxes = $personalAccount->getMailboxes();
962 $acctNode = new ExtNode('Home::' . $personalAccount->name, $personalAccount->name);
963 $acctNode->dynamicloadfunction = '';
964 $acctNode->expanded = false;
965 $acctNode->set_property('cls', 'ieFolder');
966 $acctNode->set_property('ieId', $personalAccount->id);
967 $acctNode->set_property('protocol', $personalAccount->protocol);
969 if(array_key_exists('Home::'.$personalAccount->name, $this->folderStates)) {
970 if($this->folderStates['Home::'.$personalAccount->name] == 'open') {
971 $acctNode->expanded = true;
974 $acctNode->dynamic_load = true;
976 $nodePath = $acctNode->_properties['id'];
978 foreach($mailboxes as $k => $mbox) {
979 $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $personalAccount->id,
980 $nodePath, false, $personalAccount));
983 $rootNode->add_node($acctNode);
989 $beans = $ie->retrieveAllByGroupId($current_user->id, false);
990 foreach($beans as $k => $groupAccount) {
991 if(in_array($groupAccount->id, $showFolders)) {
992 // check for cache value
993 $cacheRoot = sugar_cached("modules/Emails/{$groupAccount->id}");
994 $this->preflightEmailCache($cacheRoot);
995 //$groupAccount->connectMailserver();
997 if($this->validCacheFileExists($groupAccount->id, 'folders', "folders.php")) {
998 $mailboxes = $this->getMailBoxesFromCacheValue($groupAccount);
1000 $mailboxes = $groupAccount->getMailBoxesForGroupAccount();
1003 $acctNode = new ExtNode($groupAccount->name, "group.{$groupAccount->name}");
1004 $acctNode->dynamicloadfunction = '';
1005 $acctNode->expanded = false;
1006 $acctNode->set_property('isGroup', 'true');
1007 $acctNode->set_property('ieId', $groupAccount->id);
1008 $acctNode->set_property('protocol', $groupAccount->protocol);
1010 if(array_key_exists('Home::'.$groupAccount->name, $this->folderStates)) {
1011 if($this->folderStates['Home::'.$groupAccount->name] == 'open') {
1012 $acctNode->expanded = true;
1015 $acctNode->dynamic_load = true;
1016 $nodePath = $rootNode->_properties['id']."::".$acctNode->_properties['id'];
1018 foreach($mailboxes as $k => $mbox) {
1019 $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $groupAccount->id,
1020 $nodePath, true, $groupAccount));
1023 $rootNode->add_node($acctNode);
1027 // SugarFolder nodes
1028 /* SugarFolders are built at onload when the UI renders */
1030 $tree->add_node($rootNode);
1034 function getMailBoxesFromCacheValue($mailAccount) {
1035 $foldersCache = $this->getCacheValue($mailAccount->id, 'folders', "folders.php", 'foldersCache');
1036 $mailboxes = $foldersCache['mailboxes'];
1037 $mailboxesArray = $mailAccount->generateFlatArrayFromMultiDimArray($mailboxes, $mailAccount->retrieveDelimiter());
1038 $mailAccount->saveMailBoxFolders($mailboxesArray);
1039 $this->deleteEmailCacheForFolders($cacheRoot);
1044 * Builds up a TreeView Node object
1048 * @param string ID of InboundEmail instance
1049 * @param string nodePath Serialized path from root node to current node
1050 * @param bool isGroup
1051 * @param bool forceRefresh
1054 function buildTreeNode($key, $label, $mbox, $ieId, $nodePath, $isGroup, $ie) {
1055 global $sugar_config;
1057 // get unread counts
1058 $exMbox = explode("::", $nodePath);
1060 $GLOBALS['log']->debug("$key --- $nodePath::$label");
1062 if(count($exMbox) >= 2) {
1064 for($i=2; $i<count($exMbox); $i++) {
1065 if($mailbox != "") {
1068 $mailbox .= "{$exMbox[$i]}";
1071 $mailbox = substr($key, strpos($key, '.'));
1073 $unseen = $this->getUnreadCount($ie, $mailbox);
1076 //$label = " <span id='span{$ie->id}{$ie->mailbox}' style='font-weight:bold'>{$label} (<span id='span{$ie->id}{$ie->mailbox}nums'>{$unseen}</span>)</span>";
1080 $nodePath = $nodePath."::".$label;
1081 $node = new ExtNode($nodePath, $label);
1082 $node->dynamicloadfunction = '';
1083 $node->expanded = false;
1084 $node->set_property('labelStyle', "remoteFolder");
1087 if(array_key_exists($nodePath, $this->folderStates)) {
1088 if($this->folderStates[$nodePath] == 'open') {
1089 $node->expanded = true;
1093 $group = ($isGroup) ? 'true' : 'false';
1094 $node->dynamic_load = true;
1095 //$node->set_property('href', " SUGAR.email2.listView.populateListFrame(YAHOO.namespace('frameFolders').selectednode, '{$ieId}', 'false');");
1096 $node->set_property('isGroup', $group);
1097 $node->set_property('isDynamic', 'false');
1098 $node->set_property('ieId', $ieId);
1099 $node->set_property('mbox', $key);
1100 $node->set_property('unseen', $unseen);
1101 $node->set_property('cls', 'ieFolder');
1103 if(is_array($mbox)) {
1104 foreach($mbox as $k => $v) {
1105 $node->add_node($this->buildTreeNode("$key.$k", $k, $v, $ieId, $nodePath, $isGroup, $ie));
1113 * Totals the unread emails
1115 function getUnreadCount(&$ie, $mailbox) {
1116 global $sugar_config;
1120 return $ie->getCacheUnreadCount($mailbox);
1123 ///////////////////////////////////////////////////////////////////////////
1126 * Used exclusively by draft code. Returns Notes and Documents as attachments.
1130 function getDraftAttachments($ret) {
1133 // $ret['uid'] is the draft Email object's GUID
1134 $ret['attachments'] = array();
1136 $q = "SELECT id, filename FROM notes WHERE parent_id = '{$ret['uid']}' AND deleted = 0";
1137 $r = $db->query($q);
1139 while($a = $db->fetchByAssoc($r)) {
1140 $ret['attachments'][$a['id']] = array(
1142 'filename' => $a['filename'],
1149 function createCopyOfInboundAttachment($ie, $ret, $uid) {
1150 global $sugar_config;
1151 if ($ie->isPop3Protocol()) {
1152 // get the UIDL from database;
1153 $cachedUIDL = md5($uid);
1154 $cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$cachedUIDL}.php");
1156 $cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$uid}.php");
1158 if(file_exists($cache)) {
1159 include($cache); // profides $cacheFile
1160 $metaOut = unserialize($cacheFile['out']);
1161 $meta = $metaOut['meta']['email'];
1162 if (isset($meta['attachments'])) {
1163 $attachmentHtmlData = $meta['attachments'];
1164 $actualAttachmentInfo = array();
1165 $this->parseAttachmentInfo($actualAttachmentInfo, $attachmentHtmlData);
1166 if (sizeof($actualAttachmentInfo) > 0) {
1167 foreach($actualAttachmentInfo as $key => $value) {
1168 $info_vars = array();
1169 parse_str($value, $info_vars);
1170 $fileName = $info_vars['tempName'];
1171 $attachmentid = $info_vars['id'];
1172 $guid = create_guid();
1173 $destination = clean_path("{$this->userCacheDir}/{$guid}");
1175 $attachmentFilePath = sugar_cached("modules/Emails/{$ie->id}/attachments/{$attachmentid}");
1176 copy($attachmentFilePath, $destination);
1177 $ret['attachments'][$guid] = array();
1178 $ret['attachments'][$guid]['id'] = $guid . $fileName;
1179 $ret['attachments'][$guid]['filename'] = $fileName;
1189 function parseAttachmentInfo(&$actualAttachmentInfo, $attachmentHtmlData) {
1190 $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
1191 while ($downLoadPHP) {
1192 $attachmentHtmlData = substr($attachmentHtmlData, $downLoadPHP+30);
1193 $final = strpos($attachmentHtmlData, "\">");
1194 $actualAttachmentInfo[] = substr($attachmentHtmlData, 0, $final);
1195 $attachmentHtmlData = substr($attachmentHtmlData, $final);
1196 $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
1200 * Renders the QuickCreate form from Smarty and returns HTML
1201 * @param array $vars request variable global
1202 * @param object $email Fetched email object
1203 * @param bool $addToAddressBook
1206 function getQuickCreateForm($vars, $email, $addToAddressBookButton=false) {
1207 require_once("include/EditView/EditView2.php");
1208 global $app_strings;
1209 global $mod_strings;
1210 global $current_user;
1213 global $current_language;
1215 //Setup the current module languge
1216 $mod_strings = return_module_language($current_language, $_REQUEST['qc_module']);
1218 $bean = $beanList[$_REQUEST['qc_module']];
1219 $class = $beanFiles[$bean];
1220 require_once($class);
1222 $focus = new $bean();
1228 $emailAddress = array();
1231 if(in_array($bean, $people)) {
1233 $focus->lead_source = 'Email';
1234 $focus->lead_source_description = trim($email->name);
1236 $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr;
1238 if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail']))
1240 if($email->status == "sent")
1242 $from = (isset($email->to_addrs_names) && !empty($email->to_addrs_names)) ? $email->to_addrs_names : $email->to_addrs;
1244 $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr_name;
1248 $name = explode(" ", trim($from));
1250 $address = trim(array_pop($name));
1251 $address = str_replace(array("<",">","<",">"), "", $address);
1253 $emailAddress[] = array(
1254 'email_address' => $address,
1255 'primary_address' => 1,
1256 'invalid_email' => 0,
1258 'reply_to_address' => 1
1261 $focus->email1 = $address;
1264 $focus->last_name = trim(array_pop($name));
1266 foreach($name as $first) {
1267 if(!empty($focus->first_name)) {
1268 $focus->first_name .= " ";
1270 $focus->first_name .= trim($first);
1274 // bugs, cases, tasks
1275 $focus->name = trim($email->name);
1278 $focus->description = trim(strip_tags($email->description));
1279 $focus->assigned_user_id = $current_user->id;
1282 $EditView = new EditView();
1283 $EditView->ss = new Sugar_Smarty();
1284 //MFH BUG#20283 - checks for custom quickcreate fields
1285 $EditView->setup($_REQUEST['qc_module'], $focus, 'custom/modules/'.$focus->module_dir.'/metadata/editviewdefs.php', 'include/EditView/EditView.tpl');
1286 $EditView->process();
1287 $EditView->render();
1289 $EditView->defs['templateMeta']['form']['buttons'] = array(
1290 'email2save' => array(
1291 'id' => 'e2AjaxSave',
1292 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_SAVE_BUTTON_LABEL']
1293 . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(false);" />'
1295 'email2saveandreply' => array(
1296 'id' => 'e2SaveAndReply',
1297 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_SAVE_AND_REPLY']
1298 . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(\'reply\');" />'
1300 'email2cancel' => array(
1302 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_CANCEL']
1303 . ' " onclick="SUGAR.email2.detailView.quickCreateDialog.hide();" />'
1308 if($addToAddressBookButton) {
1309 $EditView->defs['templateMeta']['form']['buttons']['email2saveAddToAddressBook'] = array(
1310 'id' => 'e2addToAddressBook',
1311 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_ADDRESS_BOOK_SAVE_AND_ADD']
1312 . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(true);" />'
1316 //Get the module language for javascript
1317 if(!is_file(sugar_cached('jsLanguage/') . $_REQUEST['qc_module'] . '/' . $GLOBALS['current_language'] . '.js')) {
1318 require_once('include/language/jsLanguage.php');
1319 jsLanguage::createModuleStringsCache($_REQUEST['qc_module'], $GLOBALS['current_language']);
1321 $jsLanguage = getVersionedScript("cache/jsLanguage/{$_REQUEST['qc_module']}/{$GLOBALS['current_language']}.js", $GLOBALS['sugar_config']['js_lang_version']);
1324 $EditView->view = 'EmailQCView';
1325 $EditView->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl';
1326 $EditView->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl';
1328 $meta['html'] = $jsLanguage . $EditView->display(false, true);
1329 $meta['html'] = str_replace("src='".getVersionedPath('include/SugarEmailAddress/SugarEmailAddress.js')."'", '', $meta['html']);
1330 $meta['emailAddress'] = $emailAddress;
1332 $mod_strings = return_module_language($current_language, 'Emails');
1338 * Renders the Import form from Smarty and returns HTML
1339 * @param array $vars request variable global
1340 * @param object $email Fetched email object
1341 * @param bool $addToAddressBook
1344 function getImportForm($vars, $email, $formName = 'ImportEditView') {
1345 require_once("include/EditView/EditView2.php");
1346 require_once("include/TemplateHandler/TemplateHandler.php");
1347 require_once('include/QuickSearchDefaults.php');
1348 $qsd = QuickSearchDefaults::getQuickSearchDefaults();
1349 $qsd->setFormName($formName);
1351 global $app_strings;
1352 global $current_user;
1353 global $app_list_strings;
1354 $sqs_objects = array(
1355 "{$formName}_parent_name" => $qsd->getQSParent(),
1357 $smarty = new Sugar_Smarty();
1358 $smarty->assign("APP",$app_strings);
1359 $smarty->assign('formName',$formName);
1360 $showAssignTo = false;
1361 if (!isset($vars['showAssignTo']) || $vars['showAssignTo'] == true) {
1362 $showAssignTo = true;
1364 if ($showAssignTo) {
1365 if(empty($email->assigned_user_id) && empty($email->id))
1366 $email->assigned_user_id = $current_user->id;
1367 if(empty($email->assigned_name) && empty($email->id))
1368 $email->assigned_user_name = $current_user->user_name;
1369 $sqs_objects["{$formName}_assigned_user_name"] = $qsd->getQSUser();
1371 $smarty->assign("showAssignedTo",$showAssignTo);
1373 $showDelete = false;
1374 if (!isset($vars['showDelete']) || $vars['showDelete'] == true) {
1377 $smarty->assign("showDelete",$showDelete);
1379 $smarty->assign("userId",$email->assigned_user_id);
1380 $smarty->assign("userName",$email->assigned_user_name);
1381 $parent_types = $app_list_strings['record_type_display'];
1382 $smarty->assign('parentOptions', get_select_options_with_id($parent_types, $email->parent_type));
1384 $quicksearch_js = '<script type="text/javascript" language="javascript">sqs_objects = ' . json_encode($sqs_objects) . '</script>';
1385 $smarty->assign('SQS', $quicksearch_js);
1388 $meta['html'] = $smarty->fetch("modules/Emails/templates/importRelate.tpl");
1393 * This function returns the detail view for email in new 2.0 interface
1396 function getDetailViewForEmail2($emailId) {
1398 require_once('include/DetailView/DetailView.php');
1399 global $app_strings, $app_list_strings;
1400 global $mod_strings;
1402 $smarty = new Sugar_Smarty();
1405 $focus = new Email();
1406 $focus->retrieve($emailId);
1407 $detailView->ss = new Sugar_Smarty();
1408 $detailView = new DetailView();
1411 if($focus->type == 'out') {
1412 $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true);
1413 } elseif ($focus->type == 'draft') {
1414 $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true);
1415 } elseif($focus->type == 'inbound') {
1416 $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true);
1418 $smarty->assign("emailTitle", $title);
1420 // DEFAULT TO TEXT IF NO HTML CONTENT:
1421 $html = trim(from_html($focus->description_html));
1423 $smarty->assign('SHOW_PLAINTEXT', 'true');
1425 $smarty->assign('SHOW_PLAINTEXT', 'false');
1428 //if not empty or set to test (from test campaigns)
1429 if (!empty($focus->parent_type) && $focus->parent_type !='test') {
1430 $smarty->assign('PARENT_MODULE', $focus->parent_type);
1431 $smarty->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ":");
1435 $smarty->assign('MOD', $mod_strings);
1436 $smarty->assign('APP', $app_strings);
1437 $smarty->assign('GRIDLINE', $gridline);
1438 $smarty->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']);
1439 $smarty->assign('ID', $focus->id);
1440 $smarty->assign('TYPE', $focus->type);
1441 $smarty->assign('PARENT_NAME', $focus->parent_name);
1442 $smarty->assign('PARENT_ID', $focus->parent_id);
1443 $smarty->assign('NAME', $focus->name);
1444 $smarty->assign('ASSIGNED_TO', $focus->assigned_user_name);
1445 $smarty->assign('DATE_MODIFIED', $focus->date_modified);
1446 $smarty->assign('DATE_ENTERED', $focus->date_entered);
1447 $smarty->assign('DATE_START', $focus->date_start);
1448 $smarty->assign('TIME_START', $focus->time_start);
1449 $smarty->assign('FROM', $focus->from_addr);
1450 $smarty->assign('TO', nl2br($focus->to_addrs));
1451 $smarty->assign('CC', nl2br($focus->cc_addrs));
1452 $smarty->assign('BCC', nl2br($focus->bcc_addrs));
1453 $smarty->assign('CREATED_BY', $focus->created_by_name);
1454 $smarty->assign('MODIFIED_BY', $focus->modified_by_name);
1455 $smarty->assign('DATE_SENT', $focus->date_entered);
1456 $smarty->assign('EMAIL_NAME', 'RE: '.$focus->name);
1457 $smarty->assign("TAG", $focus->listviewACLHelper());
1458 $smarty->assign("SUGAR_VERSION", $GLOBALS['sugar_version']);
1459 $smarty->assign("JS_CUSTOM_VERSION", $GLOBALS['sugar_config']['js_custom_version']);
1460 if(!empty($focus->reply_to_email)) {
1463 <td class=\"tabDetailViewDL\"><slot>".$mod_strings['LBL_REPLY_TO_NAME']."</slot></td>
1464 <td colspan=3 class=\"tabDetailViewDF\"><slot>".$focus->reply_to_addr."</slot></td>
1466 $smarty->assign("REPLY_TO", $replyTo);
1468 ///////////////////////////////////////////////////////////////////////////////
1469 //// JAVASCRIPT VARS
1471 $jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';";
1472 $jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';";
1473 $smarty->assign("JS_VARS", $jsVars);
1474 ///////////////////////////////////////////////////////////////////////////////
1475 //// NOTES (attachements, etc.)
1476 ///////////////////////////////////////////////////////////////////////////////
1479 $where = "notes.parent_id='{$focus->id}'";
1480 //take in account if this is from campaign and the template id is stored in the macros.
1482 if(isset($macro_values) && isset($macro_values['email_template_id'])){
1483 $where = "notes.parent_id='{$macro_values['email_template_id']}'";
1485 $notes_list = $note->get_full_list("notes.name", $where, true);
1487 if(! isset($notes_list)) {
1488 $notes_list = array();
1492 for($i=0; $i<count($notes_list); $i++) {
1493 $the_note = $notes_list[$i];
1494 $attachments .= "<a href=\"index.php?entryPoint=download&id={$the_note->id}&type=Notes\">".$the_note->name."</a><br />";
1495 $focus->cid2Link($the_note->id, $the_note->file_mime_type);
1497 $smarty->assign('DESCRIPTION', nl2br($focus->description));
1498 $smarty->assign('DESCRIPTION_HTML', from_html($focus->description_html));
1499 $smarty->assign("ATTACHMENTS", $attachments);
1500 ///////////////////////////////////////////////////////////////////////////////
1502 ///////////////////////////////////////////////////////////////////////////////
1503 $show_subpanels = true;
1504 if ($show_subpanels) {
1505 require_once('include/SubPanel/SubPanelTiles.php');
1506 $subpanel = new SubPanelTiles($focus, 'Emails');
1507 $smarty->assign("SUBPANEL", $subpanel->display());
1509 $meta['html'] = $smarty->fetch("modules/Emails/templates/emailDetailView.tpl");
1515 * Sets the "read" flag in the overview cache
1517 function setReadFlag($ieId, $mbox, $uid) {
1518 $this->markEmails('read', $ieId, $mbox, $uid);
1522 * Marks emails with the passed flag type. This will be applied to local
1523 * cache files as well as remote emails.
1524 * @param string $type Flag type
1525 * @param string $ieId
1526 * @param string $folder IMAP folder structure or SugarFolder GUID
1527 * @param string $uids Comma sep list of UIDs or GUIDs
1529 function markEmails($type, $ieId, $folder, $uids) {
1531 global $app_strings;
1532 $uids = $this->_cleanUIDList($uids);
1533 $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1535 if(strpos($folder, 'sugar::') !== false) {
1536 // dealing with a sugar email object, uids are GUIDs
1537 foreach($exUids as $id) {
1538 $email = new Email();
1539 $email->retrieve($id);
1542 // Bug 50973 - marking unread in group inbox removes message
1543 if (empty($email->assigned_user_id))
1545 $email->setFieldNullable('assigned_user_id');
1551 $email->status = 'unread';
1556 $email->status = 'read';
1565 $email->flagged = 1;
1570 $email->flagged = 0;
1577 // Bug 50973 - reset assigned_user_id field defs
1578 if (empty($email->assigned_user_id))
1580 $email->revertFieldNullable('assigned_user_id');
1585 /* dealing with IMAP email, uids are IMAP uids */
1586 global $ie; // provided by EmailUIAjax.php
1589 $ie = new InboundEmail();
1591 $ie->retrieve($ieId);
1592 $ie->mailbox = $folder;
1593 $ie->connectMailserver();
1595 if($type == 'deleted') {
1596 $ie->deleteMessageOnMailServer($uids);
1597 $ie->deleteMessageFromCache($uids);
1599 $overviews = $ie->getCacheValueForUIDs($ie->mailbox, $exUids);
1600 $manipulated = array();
1602 foreach($overviews['retArr'] as $k => $overview) {
1603 if(in_array($overview->uid, $exUids)) {
1606 $overview->seen = 0;
1610 $overview->seen = 1;
1614 $overview->flagged = 1;
1618 $overview->flagged = 0;
1621 $manipulated[] = $overview;
1625 if(!empty($manipulated)) {
1626 $ie->setCacheValue($ie->mailbox, array(), $manipulated);
1627 /* now mark emails on email server */
1628 $ie->markEmails(implode(",", explode($app_strings['LBL_EMAIL_DELIMITER'], $uids)), $type);
1630 } // end not type == deleted
1634 function doAssignment($distributeMethod, $ieid, $folder, $uids, $users) {
1635 global $app_strings;
1636 $users = explode(",", $users);
1637 $emailIds = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1639 if($folder != 'sugar::Emails') {
1640 $emailIds = array();
1641 $uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1642 $ie = new InboundEmail();
1643 $ie->retrieve($ieid);
1645 // dealing with an inbound email data so we need to import an email and then
1646 foreach($uids as $uid) {
1647 $ie->mailbox = $folder;
1648 $ie->connectMailserver();
1650 if (!$ie->isPop3Protocol()) {
1651 $msgNo = imap_msgno($ie->conn, $uid);
1653 $msgNo = $ie->getCorrectMessageNoForPop3($uid);
1656 if(!empty($msgNo)) {
1657 if ($ie->importOneEmail($msgNo, $uid)) {
1658 $emailIds[] = $ie->email->id;
1659 $ie->deleteMessageOnMailServer($uid);
1660 //$ie->retrieve($ieid);
1661 //$ie->connectMailserver();
1662 $ie->mailbox = $folder;
1663 $ie->deleteMessageFromCache(($uids[] = $uid));
1665 $out = $out . "Message No : " . $messageIndex . " failed. Reason : Message already imported \r\n";
1672 if (count($emailIds) > 0) {
1673 $this->doDistributionWithMethod($users, $emailIds, $distributeMethod);
1679 * get team id and team set id from request
1682 function getTeams() {
1685 function doDistributionWithMethod($users, $emailIds, $distributionMethod) {
1686 // we have users and the items to distribute
1687 if($distributionMethod == 'roundRobin') {
1688 $this->distRoundRobin($users, $emailIds);
1689 } elseif($distributionMethod == 'leastBusy') {
1690 $this->distLeastBusy($users, $emailIds);
1691 } elseif($distributionMethod == 'direct') {
1692 if(count($users) > 1) {
1693 // only 1 user allowed in direct assignment
1697 $this->distDirect($user, $emailIds);
1704 * distributes emails to users on Round Robin basis
1705 * @param $userIds array of users to dist to
1706 * @param $mailIds array of email ids to push on those users
1707 * @return boolean true on success
1709 function distRoundRobin($userIds, $mailIds) {
1710 // check if we have a 'lastRobin'
1711 $lastRobin = $userIds[0];
1712 foreach($mailIds as $k => $mailId) {
1713 $userIdsKeys = array_flip($userIds); // now keys are values
1714 $thisRobinKey = $userIdsKeys[$lastRobin] + 1;
1715 if(!empty($userIds[$thisRobinKey])) {
1716 $thisRobin = $userIds[$thisRobinKey];
1717 $lastRobin = $userIds[$thisRobinKey];
1719 $thisRobin = $userIds[0];
1720 $lastRobin = $userIds[0];
1723 $email = new Email();
1724 $email->retrieve($mailId);
1725 $email->assigned_user_id = $thisRobin;
1726 $email->status = 'unread';
1734 * distributes emails to users on Least Busy basis
1735 * @param $userIds array of users to dist to
1736 * @param $mailIds array of email ids to push on those users
1737 * @return boolean true on success
1739 function distLeastBusy($userIds, $mailIds) {
1740 foreach($mailIds as $k => $mailId) {
1741 $email = new Email();
1742 $email->retrieve($mailId);
1743 foreach($userIds as $k => $id) {
1744 $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '.$id.' AND status = 'unread'");
1745 $a = $this->db->fetchByAssoc($r);
1746 $counts[$id] = $a['c'];
1748 asort($counts); // lowest to highest
1749 $countsKeys = array_flip($counts); // keys now the 'count of items'
1750 $leastBusy = array_shift($countsKeys); // user id of lowest item count
1751 $email->assigned_user_id = $leastBusy;
1752 $email->status = 'unread';
1759 * distributes emails to 1 user
1760 * @param $user users to dist to
1761 * @param $mailIds array of email ids to push
1762 * @return boolean true on success
1764 function distDirect($user, $mailIds) {
1765 foreach($mailIds as $k => $mailId) {
1766 $email = new Email();
1767 $email->retrieve($mailId);
1768 $email->assigned_user_id = $user;
1769 $email->status = 'unread';
1776 function getAssignedEmailsCountForUsers($userIds) {
1778 foreach($userIds as $id) {
1779 $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '$id' AND status = 'unread'");
1780 $a = $this->db->fetchByAssoc($r);
1781 $counts[$id] = $a['c'];
1786 function getLastRobin($ie) {
1788 if($this->validCacheFileExists($ie->id, 'folders', "robin.cache.php")) {
1789 $lastRobin = $this->getCacheValue($ie->id, 'folders', "robin.cache.php", 'robin');
1794 function setLastRobin($ie, $lastRobin) {
1795 global $sugar_config;
1796 $cacheFolderPath = sugar_cached("modules/Emails/{$ie->id}/folders");
1797 if (!file_exists($cacheFolderPath)) {
1798 mkdir_recursive($cacheFolderPath);
1800 $this->writeCacheFile('robin', $lastRobin, $ie->id, 'folders', "robin.cache.php");
1804 * returns the metadata defining a single email message for display. Uses cache file if it exists
1807 function getSingleMessage($ie) {
1810 global $app_strings,$mod_strings;
1811 $ie->retrieve($_REQUEST['ieId']);
1814 $ie->mailbox = $_REQUEST['mbox'];
1815 $filename = $_REQUEST['mbox'].$_REQUEST['uid'].".php";
1817 if ($ie->isPop3Protocol()) {
1818 $md5uidl = md5($_REQUEST['uid']);
1819 $filename = $_REQUEST['mbox'].$md5uidl.".php";
1822 if($this->validCacheFileExists($_REQUEST['ieId'], 'messages', $filename)) {
1823 $out = $this->getCacheValue($_REQUEST['ieId'], 'messages', $filename, 'out');
1826 // something fubar'd the cache?
1827 if(empty($out['meta']['email']['name']) && empty($out['meta']['email']['description'])) {
1830 // When sending data from cache, convert date into users preffered format
1831 $dateTimeInGMTFormat = $out['meta']['email']['date_start'];
1832 $out['meta']['email']['date_start'] = $timedate->to_display_date_time($dateTimeInGMTFormat);
1837 $writeToCacheFile = true;
1838 if ($ie->isPop3Protocol()) {
1839 $status = $ie->setEmailForDisplay($_REQUEST['uid'], true, true, true);
1841 $status = $ie->setEmailForDisplay($_REQUEST['uid'], false, true, true);
1843 $out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']);
1844 // modify the out object to store date in GMT format on the local cache file
1845 $dateTimeInUserFormat = $out['meta']['email']['date_start'];
1846 $out['meta']['email']['date_start'] = $timedate->to_db($dateTimeInUserFormat);
1847 if ($status == 'error') {
1848 $writeToCacheFile = false;
1850 if ($writeToCacheFile) {
1851 if ($ie->isPop3Protocol()) {
1852 $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$md5uidl}.php");
1854 $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$_REQUEST['uid']}.php");
1856 // restore date in the users preferred format to be send on to UI for diaply
1857 $out['meta']['email']['date_start'] = $dateTimeInUserFormat;
1860 $out['meta']['email']['toaddrs'] = $this->generateExpandableAddrs($out['meta']['email']['toaddrs']);
1861 if(!empty($out['meta']['email']['cc_addrs'])) {
1862 $ccs = $this->generateExpandableAddrs($out['meta']['email']['cc_addrs']);
1863 $out['meta']['cc'] = <<<eoq
1865 <td NOWRAP valign="top" class="displayEmailLabel">
1866 {$app_strings['LBL_EMAIL_CC']}:
1868 <td class="displayEmailValue">
1875 if(empty($out['meta']['email']['description']))
1876 $out['meta']['email']['description'] = $mod_strings['LBL_EMPTY_EMAIL_BODY'];
1879 $GLOBALS['log']->debug("EMAILUI: getSingleMessage() NOT using cache file");
1881 $GLOBALS['log']->debug("EMAILUI: getSingleMessage() using cache file [ ".$_REQUEST['mbox'].$_REQUEST['uid'].".php ]");
1884 $this->setReadFlag($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['uid']);
1890 * Returns the HTML for a list of emails in a given folder
1891 * @param GUID $ieId GUID to InboundEmail instance
1892 * @param string $mbox Mailbox path name in dot notation
1893 * @param int $folderListCacheOffset Seconds for valid cache file
1894 * @return string HTML render of list.
1896 function getListEmails($ieId, $mbox, $folderListCacheOffset, $forceRefresh='false') {
1897 global $sugar_config;
1900 $ie = new InboundEmail();
1901 $ie->retrieve($ieId);
1902 $list = $ie->displayFolderContents($mbox, $forceRefresh);
1908 * Returns the templatized compose screen. Used by reply, forwards and draft status messages.
1909 * @param object email Email bean in focus
1911 function displayComposeEmail($email) {
1913 global $current_user;
1916 $ea = new SugarEmailAddress();
1918 if(!empty($email)) {
1919 $email->cids2Links();
1920 $description = (empty($email->description_html)) ? $email->description : $email->description_html;
1923 //Get the most complete address list availible for this email
1924 $addresses = array('toAddresses' => 'to', 'ccAddresses' => 'cc', 'bccAddresses' => 'bcc');
1925 foreach($addresses as $var => $type)
1928 foreach (array("{$type}_addrs_names", "{$type}addrs", "{$type}_addrs") as $emailVar)
1930 if (!empty($email->$emailVar)) {
1931 $$var = $email->$emailVar;
1938 $ret['type'] = $email->type;
1939 $ret['name'] = $email->name;
1940 $ret['description'] = $description;
1941 $ret['from'] = (isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'forward') ? "" : $email->from_addr;
1942 $ret['to'] = from_html($toAddresses);
1943 $ret['uid'] = $email->id;
1944 $ret['parent_name'] = $email->parent_name;
1945 $ret['parent_type'] = $email->parent_type;
1946 $ret['parent_id'] = $email->parent_id;
1948 if ($email->type == 'draft') {
1949 $ret['cc'] = from_html($ccAddresses);
1950 $ret['bcc'] = $bccAddresses;
1953 if(isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'replyAll') {
1954 $ret['cc'] = from_html($ccAddresses);
1955 $ret['bcc'] = $bccAddresses;
1957 $userEmails = array();
1958 $userEmailsMeta = $ea->getAddressesByGUID($current_user->id, 'Users');
1959 foreach($userEmailsMeta as $emailMeta) {
1960 $userEmails[] = from_html(strtolower(trim($emailMeta['email_address'])));
1962 $userEmails[] = from_html(strtolower(trim($email->from_addr)));
1964 $ret['cc'] = from_html($email->cc_addrs);
1965 $toAddresses = from_html($toAddresses);
1966 $to = str_replace($this->addressSeparators, "::", $toAddresses);
1967 $exTo = explode("::", $to);
1969 if(is_array($exTo)) {
1970 foreach($exTo as $addr) {
1971 $addr = strtolower(trim($addr));
1972 if(!in_array($addr, $userEmails)) {
1973 if(!empty($ret['cc'])) {
1974 $ret['cc'] = $ret['cc'].", ";
1976 $ret['cc'] = $ret['cc'].trim($addr);
1979 } elseif(!empty($exTo)) {
1980 $exTo = trim($exTo);
1981 if(!in_array($exTo, $userEmails)) {
1982 $ret['cc'] = $ret['cc'].", ".$exTo;
1989 * Formats email body on reply/forward
1990 * @param object email Email object in focus
1991 * @param string type
1992 * @return object email
1994 function handleReplyType($email, $type) {
1995 global $mod_strings;
1996 $GLOBALS['log']->debug("****At Handle Reply Type: $type");
2000 $header = $email->getReplyHeader();
2001 if(!preg_match('/^(re:)+/i', $email->name)) {
2002 $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
2004 if ($type == "reply") {
2005 $email->cc_addrs = "";
2006 if (!empty($email->reply_to_addr)) {
2007 $email->from_addr = $email->reply_to_addr;
2010 if (!empty($email->reply_to_addr)) {
2011 $email->to_addrs = $email->to_addrs . "," . $email->reply_to_addr;
2017 $header = $email->getForwardHeader();
2018 if(!preg_match('/^(fw:)+/i', $email->name)) {
2019 $email->name = "{$mod_strings['LBL_FW']} {$email->name}";
2021 $email->cc_addrs = "";
2025 $GLOBALS['log']->debug("EMAILUI: At reply case");
2026 $header = $email->getReplyHeader();
2028 $myCase = new aCase();
2029 $myCase->retrieve($email->parent_id);
2030 $myCaseMacro = $myCase->getEmailSubjectMacro();
2031 $email->parent_name = $myCase->name;
2032 $GLOBALS['log']->debug("****Case # : {$myCase->case_number} macro: $myCaseMacro");
2033 if(!strpos($email->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) {
2034 $GLOBALS['log']->debug("Replacing");
2035 $email->name = str_replace('%1',$myCase->case_number,$myCaseMacro) . ' '. $email->name;
2037 $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
2041 $html = trim($email->description_html);
2042 $plain = trim($email->description);
2044 $desc = (!empty($html)) ? $html : $plain;
2046 $email->description = $header.$email->quoteHtmlEmailForNewEmailUI($desc);
2051 ///////////////////////////////////////////////////////////////////////////
2052 //// PRIVATE HELPERS
2054 * Generates a UNION query to get one list of users, contacts, leads, and
2055 * prospects; used specifically for the addressBook
2057 function _getPeopleUnionQuery($whereArr , $person) {
2058 global $current_user , $app_strings;
2060 if(!isset($person) || $person === 'LBL_DROPDOWN_LIST_ALL'){
2061 $peopleTables = array("users",
2068 $peopleTables = array($person);
2074 foreach($whereArr as $column => $clause) {
2075 if(!empty($whereAdd)) {
2076 $whereAdd .= " AND ";
2078 $clause = $current_user->db->quote($clause);
2079 $whereAdd .= "{$column} LIKE '{$clause}%'";
2083 foreach($peopleTables as $table) {
2084 $module = ucfirst($table);
2085 $class = substr($module, 0, strlen($module) - 1);
2086 require_once("modules/{$module}/{$class}.php");
2087 $person = new $class();
2088 if (!$person->ACLAccess('list')) {
2091 $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id <> '{$current_user->id}')";
2093 if (ACLController::requireOwner($module, 'list')) {
2094 $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
2096 if(!empty($whereAdd)) {
2097 $where .= " AND ({$whereAdd})";
2100 if ($person === 'accounts') {
2101 $t = "SELECT {$table}.id, '' first_name, {$table}.name, eabr.primary_address, ea.email_address, '{$module}' module ";
2103 $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2105 $t .= "FROM {$table} ";
2106 $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
2107 $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
2108 $t .= " WHERE {$where}";
2111 $q .= "\n UNION ALL \n";
2116 $countq = "SELECT count(people.id) c from ($q) people";
2117 $q .= "ORDER BY last_name";
2119 return array('query' => $q, 'countQuery' => $countq);
2123 * get emails of related bean for a given bean id
2125 * @param $condition array of conditions inclued bean id
2126 * @return array('query' => $q, 'countQuery' => $countq);
2128 function getRelatedEmail($beanType, $whereArr, $relatedBeanInfoArr = ''){
2129 global $beanList, $current_user, $app_strings, $db;
2131 $searchBeans = null;
2132 if($beanType === 'LBL_DROPDOWN_LIST_ALL')
2133 $searchBeans = array("users",
2140 if ($relatedBeanInfoArr == '' || empty($relatedBeanInfoArr['related_bean_type']) )
2142 if ($searchBeans != null)
2145 foreach ($searchBeans as $searchBean)
2147 $searchq = $this->findEmailFromBeanIds('', $searchBean, $whereArr);
2148 if(!empty($searchq)) {
2149 $q[] = "($searchq)";
2153 $finalQuery .= implode("\n UNION ALL \n", $q);
2156 $finalQuery = $this->findEmailFromBeanIds('', $beanType, $whereArr);
2160 $class = $beanList[$relatedBeanInfoArr['related_bean_type']];
2161 $focus = new $class();
2162 $focus->retrieve($relatedBeanInfoArr['related_bean_id']);
2163 if ($searchBeans != null)
2166 foreach ($searchBeans as $searchBean)
2168 if ($focus->load_relationship($searchBean))
2170 $data = $focus->$searchBean->get();
2171 if (count($data) != 0)
2172 $q[] = '('.$this->findEmailFromBeanIds($data, $searchBean, $whereArr).')';
2176 $finalQuery .= implode("\n UNION ALL \n", $q);
2180 if ($focus->load_relationship($beanType))
2182 $data = $focus->$beanType->get();
2183 if (count($data) != 0)
2184 $finalQuery = $this->findEmailFromBeanIds($data, $beanType, $whereArr);
2188 $countq = "SELECT count(people.id) c from ($finalQuery) people";
2189 return array('query' => $finalQuery, 'countQuery' => $countq);
2192 function findEmailFromBeanIds($beanIds, $beanType, $whereArr) {
2193 global $current_user;
2197 if ($beanIds != '') {
2198 foreach ($beanIds as $key => $value) {
2199 $beanIds[$key] = '\''.$value.'\'';
2201 $relatedIDs = implode(',', $beanIds);
2204 if ($beanType == 'accounts') {
2205 if (isset($whereArr['first_name'])) {
2206 $whereArr['name'] = $whereArr['first_name'];
2208 unset($whereArr['last_name']);
2209 unset($whereArr['first_name']);
2212 foreach($whereArr as $column => $clause) {
2213 if(!empty($whereAdd)) {
2214 $whereAdd .= " OR ";
2216 $clause = $current_user->db->quote($clause);
2217 $whereAdd .= "{$column} LIKE '{$clause}%'";
2220 $module = ucfirst($table);
2221 $class = substr($module, 0, strlen($module) - 1);
2222 require_once("modules/{$module}/{$class}.php");
2223 $person = new $class();
2224 if ($person->ACLAccess('list')) {
2225 if ($relatedIDs != '') {
2226 $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id in ($relatedIDs))";
2228 $where = "({$table}.deleted = 0 AND eabr.primary_address = 1)";
2231 if (ACLController::requireOwner($module, 'list')) {
2232 $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
2234 if(!empty($whereAdd)) {
2235 $where .= " AND ({$whereAdd})";
2238 if ($beanType === 'accounts') {
2239 $t = "SELECT {$table}.id, '' first_name, {$table}.name last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2241 $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2244 $t .= "FROM {$table} ";
2245 $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
2246 $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
2247 $t .= " WHERE {$where}";
2254 * @param mixed $uids
2255 * @param bool $returnString False will return an array
2258 function _cleanUIDList($uids, $returnString=false) {
2259 global $app_strings;
2260 $GLOBALS['log']->debug("_cleanUIDList: before - [ {$uids} ]");
2262 if(!is_array($uids)) {
2263 $returnString = true;
2265 $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
2269 $cleanUids = array();
2270 foreach($uids as $uid) {
2271 $cleanUids[$uid] = $uid;
2277 $cleanImplode = implode($app_strings['LBL_EMAIL_DELIMITER'], $cleanUids);
2278 $GLOBALS['log']->debug("_cleanUIDList: after - [ {$cleanImplode} ]");
2279 return $cleanImplode;
2286 * Creates defaults for the User
2287 * @param object $user User in focus
2289 function preflightUser(&$user) {
2290 global $mod_strings;
2292 $goodToGo = $user->getPreference("email2Preflight", "Emails");
2293 $q = "SELECT count(*) count FROM folders f where f.created_by = '{$user->id}' AND f.folder_type = 'inbound' AND f.deleted = 0";
2294 $r = $user->db->query($q);
2295 $a = $user->db->fetchByAssoc($r);
2297 if($a['count'] < 1) {
2298 require_once("include/SugarFolders/SugarFolders.php");
2300 $folder = new SugarFolder();
2301 $folder->new_with_id = true;
2302 $folder->id = create_guid();
2303 $folder->name = $mod_strings['LNK_MY_INBOX'];
2304 $folder->has_child = 1;
2305 $folder->created_by = $user->id;
2306 $folder->modified_by = $user->id;
2307 $folder->is_dynamic = 1;
2308 $folder->folder_type = "inbound";
2309 $folder->dynamic_query = $this->generateDynamicFolderQuery('inbound', $user->id);
2313 $drafts = new SugarFolder();
2314 $drafts->name = $mod_strings['LNK_MY_DRAFTS'];
2315 $drafts->has_child = 0;
2316 $drafts->parent_folder = $folder->id;
2317 $drafts->created_by = $user->id;
2318 $drafts->modified_by = $user->id;
2319 $drafts->is_dynamic = 1;
2320 $drafts->folder_type = "draft";
2321 $drafts->dynamic_query = $this->generateDynamicFolderQuery('draft', $user->id);
2326 $archived = new SugarFolder();
2327 $archived->name = $mod_strings['LNK_SENT_EMAIL_LIST'];
2328 $archived->has_child = 0;
2329 $archived->parent_folder = $folder->id;
2330 $archived->created_by = $user->id;
2331 $archived->modified_by = $user->id;
2332 $archived->is_dynamic = 1;
2333 $archived->folder_type = "sent";
2334 $archived->dynamic_query = $this->generateDynamicFolderQuery('sent', $user->id);
2338 $archived = new SugarFolder();
2339 $archived->name = $mod_strings['LBL_LIST_TITLE_MY_ARCHIVES'];
2340 $archived->has_child = 0;
2341 $archived->parent_folder = $folder->id;
2342 $archived->created_by = $user->id;
2343 $archived->modified_by = $user->id;
2344 $archived->is_dynamic = 1;
2345 $archived->folder_type = "archived";
2346 $archived->dynamic_query = '';
2349 // set flag to show that this was run
2350 $user->setPreference("email2Preflight", true, 1, "Emails");
2355 * Parses the core dynamic folder query
2356 * @param string $type 'inbound', 'draft', etc.
2357 * @param string $userId
2360 function generateDynamicFolderQuery($type, $userId) {
2361 $q = $this->coreDynamicFolderQuery;
2365 if($type == "sent") {
2369 $replacee = array("::TYPE::", "::STATUS::", "::USER_ID::");
2370 $replacer = array($type, $status, $userId);
2372 $ret = str_replace($replacee, $replacer, $q);
2374 if($type == 'inbound') {
2375 $ret .= " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
2377 $ret .= " AND status NOT IN ('archived') AND type NOT IN ('archived')";
2384 * Preps the User's cache dir
2386 function preflightUserCache() {
2387 $path = clean_path($this->userCacheDir);
2388 if(!file_exists($this->userCacheDir))
2389 mkdir_recursive($path);
2391 $files = findAllFiles($path, array());
2393 foreach($files as $file) {
2398 function clearInboundAccountCache($ieId) {
2399 global $sugar_config;
2400 $cacheRoot = sugar_cached("modules/Emails/{$ieId}");
2401 $files = findAllFiles($cacheRoot."/messages/", array());
2402 foreach($files as $file) {
2405 $files = findAllFiles($cacheRoot."/attachments/", array());
2406 foreach($files as $file) {
2412 * returns an array of EmailTemplates that the user has access to for the compose email screen
2415 function getEmailTemplatesArray() {
2417 global $app_strings;
2419 if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) {
2420 $et = new EmailTemplate();
2421 $etResult = $et->db->query($et->create_new_list_query('',"(type IS NULL OR type='' OR type='email')",array(),array(),''));
2422 $email_templates_arr = array('' => $app_strings['LBL_NONE']);
2423 while($etA = $et->db->fetchByAssoc($etResult)) {
2424 $email_templates_arr[$etA['id']] = $etA['name'];
2427 $email_templates_arr = array('' => $app_strings['LBL_NONE']);
2430 return $email_templates_arr;
2433 function getFromAccountsArray($ie) {
2434 global $current_user;
2435 global $app_strings;
2437 $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
2438 $ieAccountsFrom= array();
2440 $oe = new OutboundEmail();
2441 $system = $oe->getSystemMailerSettings();
2442 $ret = $current_user->getUsersNameAndEmail();
2443 $ret['name'] = from_html($ret['name']);
2444 $useMyAccountString = true;
2446 if(empty($ret['email'])) {
2447 $systemReturn = $current_user->getSystemDefaultNameAndEmail();
2448 $ret['email'] = $systemReturn['email'];
2449 $ret['name'] = from_html($systemReturn['name']);
2450 $useMyAccountString = false;
2453 $myAccountString = '';
2454 if ($useMyAccountString) {
2455 $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
2458 //Check to make sure that the user has set the associated inbound email account -> outbound account is active.
2459 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2460 $sf = new SugarFolder();
2461 $groupSubs = $sf->getSubscriptions($current_user);
2463 foreach($ieAccountsFull as $k => $v)
2465 $personalSelected = (!empty($showFolders) && in_array($v->id, $showFolders));
2467 $allowOutboundGroupUsage = $v->get_stored_options('allow_outbound_group_usage',FALSE);
2468 $groupSelected = ( in_array($v->groupfolder_id, $groupSubs) && $allowOutboundGroupUsage);
2469 $selected = ( $personalSelected || $groupSelected );
2473 $GLOBALS['log']->debug("Inbound Email {$v->name}, not selected and will not be available for selection within compose UI.");
2477 $name = $v->get_stored_options('from_name');
2478 $addr = $v->get_stored_options('from_addr');
2479 if ($name != null && $addr != null) {
2480 $name = from_html($name);
2481 if (!$v->is_personal) {
2482 $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
2484 $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr})");
2490 $userSystemOverride = $oe->getUsersMailerForSystemOverride($current_user->id);
2491 //Substitute in the users system override if its available.
2492 if($userSystemOverride != null)
2493 $system = $userSystemOverride;
2495 if( !empty($system->mail_smtpserver) )
2497 $admin = new Administration();
2498 $admin->retrieveSettings(); //retrieve all admin settings.
2499 $ieAccountsFrom[] = array("value" => $system->id, "text" =>
2500 "{$ret['name']} ({$ret['email']}){$myAccountString}");
2503 return $ieAccountsFrom;
2507 * This function will return all the accounts this user has access to based on the
2508 * match of the emailId passed in as a parameter
2510 * @param unknown_type $ie
2513 function getFromAllAccountsArray($ie, $ret) {
2514 global $current_user;
2515 global $app_strings;
2517 $ret['fromAccounts'] = array();
2518 if (!isset($ret['to']) && !empty($ret['from'])) {
2519 $ret['fromAccounts']['status'] = false;
2522 $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
2523 $foundInPersonalAccounts = false;
2524 $foundInGroupAccounts = false;
2525 $foundInSystemAccounts = false;
2527 //$toArray = array();
2528 if ($ret['type'] == "draft") {
2529 $toArray = explode(",", $ret['from']);
2531 $toArray = $ie->email->email2ParseAddressesForAddressesOnly($ret['to']);
2533 foreach($ieAccountsFull as $k => $v) {
2534 $storedOptions = unserialize(base64_decode($v->stored_options));
2535 if ( array_search_insensitive($storedOptions['from_addr'], $toArray)) {
2536 if ($v->is_personal) {
2537 $foundInPersonalAccounts = true;
2540 $foundInGroupAccounts = true;
2545 $oe = new OutboundEmail();
2546 $system = $oe->getSystemMailerSettings();
2548 $return = $current_user->getUsersNameAndEmail();
2549 $return['name'] = from_html($return['name']);
2550 $useMyAccountString = true;
2552 if(empty($return['email'])) {
2553 $systemReturn = $current_user->getSystemDefaultNameAndEmail();
2554 $return['email'] = $systemReturn['email'];
2555 $return['name'] = from_html($systemReturn['name']);
2556 $useMyAccountString = false;
2559 $myAccountString = '';
2560 if ($useMyAccountString) {
2561 $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
2564 if(!empty($system->id)) {
2566 $admin = new Administration();
2567 $admin->retrieveSettings(); //retrieve all admin settings.
2568 if (in_array(trim($return['email']), $toArray)) {
2569 $foundInSystemAccounts = true;
2573 if (!$foundInPersonalAccounts && !$foundInGroupAccounts && !$foundInSystemAccounts) {
2574 $ret['fromAccounts']['status'] = false;
2578 $ieAccountsFrom= array();
2579 foreach($ieAccountsFull as $k => $v) {
2580 $storedOptions = unserialize(base64_decode($v->stored_options));
2581 $storedOptionsName = from_html($storedOptions['from_name']);
2584 if (array_search_insensitive($storedOptions['from_addr'], $toArray)) {
2585 //if ($ret['to'] == $storedOptions['from_addr']) {
2588 if ($foundInPersonalAccounts) {
2589 if ($v->is_personal) {
2590 $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']})");
2593 $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
2597 if(!empty($system->id)) {
2598 if (!$foundInPersonalAccounts && !$foundInGroupAccounts && $foundInSystemAccounts) {
2599 $ieAccountsFrom[] = array("value" => $system->id, "selected" => true, "text" =>
2600 "{$return['name']} ({$return['email']}){$myAccountString}");
2602 $ieAccountsFrom[] = array("value" => $system->id, "text" =>
2603 "{$return['name']} ({$return['email']}){$myAccountString}");
2607 $ret['fromAccounts']['status'] = ($foundInPersonalAccounts || $foundInGroupAccounts || $foundInSystemAccounts) ? true : false;
2608 $ret['fromAccounts']['data'] = $ieAccountsFrom;
2614 * takes an array and creates XML
2615 * @param array Array to convert
2616 * @param string Name to wrap highest level items in array
2617 * @return string XML
2619 function arrayToXML($a, $paramName) {
2623 $bad = array("<",">","'",'"',"&");
2624 $good = array("<", ">", "'", ""","&");
2628 for($i=0; $i<count($a); $i++) {
2630 $ret .= "\n<{$paramName}>";
2632 foreach($email as $k => $v) {
2633 $ret .= "\n\t<{$k}>".str_replace($bad, $good, $v)."</{$k}>";
2635 $ret .= "\n</{$paramName}>";
2641 * Re-used option getter for Show Accounts multiselect pane
2643 function getShowAccountsOptions(&$ie) {
2644 global $current_user;
2645 global $app_strings;
2646 global $mod_strings;
2648 $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
2649 $ieAccountsShowOptionsMeta = array();
2650 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2652 $defaultIEAccount = $ie->getUsersDefaultOutboundServerId($current_user);
2654 foreach($ieAccountsFull as $k => $v) {
2655 $selected = (!empty($showFolders) && in_array($v->id, $showFolders)) ? true : false;
2656 $default = ($defaultIEAccount == $v->id) ? TRUE : FALSE;
2657 $has_groupfolder = !empty($v->groupfolder_id) ? TRUE : FALSE;
2658 $type = ($v->is_personal) ? $mod_strings['LBL_MAILBOX_TYPE_PERSONAL'] : $mod_strings['LBL_MAILBOX_TYPE_GROUP'];
2660 $ieAccountsShowOptionsMeta[] = array("id" => $v->id, "name" => $v->name, 'is_active' => $selected,
2661 'server_url' => $v->server_url, 'is_group' => !$v->is_personal,'group_id' => $v->group_id,
2662 'is_default' => $default, 'has_groupfolder' => $has_groupfolder,'type' => $type );
2665 //Retrieve the grou folders
2666 $f = new SugarFolder();
2667 $groupFolders = $f->getGroupFoldersForSettings($current_user);
2669 foreach ($groupFolders as $singleGroup)
2671 //Retrieve the related IE accounts.
2672 $relatedIEAccounts = $ie->retrieveByGroupFolderId($singleGroup['id']);
2674 if(count($relatedIEAccounts) == 0)
2675 $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY'];
2676 else if(count($relatedIEAccounts) == 1)
2678 if($relatedIEAccounts[0]->status != 'Active' || $relatedIEAccounts[0]->mailbox_type == 'bounce')
2681 $server_url = $relatedIEAccounts[0]->server_url;
2684 $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS'];
2686 $type = $mod_strings['LBL_MAILBOX_TYPE_GROUP_FOLDER'];
2687 $ieAccountsShowOptionsMeta[] = array("id" => $singleGroup['id'], "name" => $singleGroup['origName'], 'is_active' => $singleGroup['selected'],
2688 'server_url' => $server_url, 'is_group' => true,'group_id' => $singleGroup['id'],
2689 'is_default' => FALSE, 'has_groupfolder' => true,'type' => $type);
2693 return $ieAccountsShowOptionsMeta;
2696 function getShowAccountsOptionsForSearch(&$ie) {
2697 global $current_user;
2698 global $app_strings;
2700 $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
2701 //$ieAccountsShowOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
2702 $ieAccountsShowOptionsMeta = array();
2703 $ieAccountsShowOptionsMeta[] = array("value" => "", "text" => $app_strings['LBL_NONE'], 'selected' => '');
2704 $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2706 foreach($ieAccountsFull as $k => $v) {
2707 if(!in_array($v->id, $showFolders)) {
2710 $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
2711 $ieAccountsShowOptionsMeta[] = array("value" => $v->id, "text" => $group.$v->name, 'protocol' => $v->protocol);
2714 return $ieAccountsShowOptionsMeta;
2717 * Formats a display message on successful async call
2718 * @param string $type Type of message to display
2720 function displaySuccessMessage($type) {
2721 global $app_strings;
2725 $message = $app_strings['LBL_EMAIL_DELETE_SUCCESS'];
2729 $message = "NOOP: invalid type";
2733 $this->smarty->assign('app_strings', $app_strings);
2734 $this->smarty->assign('message', $message);
2735 echo $this->smarty->fetch("modules/Emails/templates/successMessage.tpl");
2739 * Validates existence and expiration of a cache file
2740 * @param string $ieId
2741 * @param string $type Type of cache file: folders, messages, etc.
2742 * @param string $file The cachefile name
2743 * @param int refreshOffset Refresh time in secs.
2746 function validCacheFileExists($ieId, $type, $file, $refreshOffset=-1) {
2747 global $sugar_config;
2749 if($refreshOffset == -1) {
2750 $refreshOffset = $this->cacheTimeouts[$type]; // use defaults
2753 $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2754 if(file_exists($cacheFilePath)) {
2762 * retrieves the cached value
2763 * @param string $ieId
2764 * @param string $type Type of cache file: folders, messages, etc.
2765 * @param string $file The cachefile name
2766 * @param string $key name of cache value
2769 function getCacheValue($ieId, $type, $file, $key) {
2770 global $sugar_config;
2772 $cleanIeId = cleanDirName($ieId);
2773 $cleanType = cleanDirName($type);
2774 $cleanFile = cleanFileName($file);
2775 $cacheFilePath = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
2776 $cacheFile = array();
2778 if(file_exists($cacheFilePath)) {
2779 include($cacheFilePath); // provides $cacheFile
2781 if(isset($cacheFile[$key])) {
2782 $ret = unserialize($cacheFile[$key]);
2786 $GLOBALS['log']->debug("EMAILUI: cache file not found [ {$cacheFilePath} ] - creating blank cache file");
2787 $this->writeCacheFile('retArr', array(), $ieId, $type, $file);
2794 * retrieves the cache file last touched time
2795 * @param string $ieId
2796 * @param string $type Type of cache file: folders, messages, etc.
2797 * @param string $file The cachefile name
2800 function getCacheTimestamp($ieId, $type, $file) {
2801 global $sugar_config;
2803 $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2804 $cacheFile = array();
2806 if(file_exists($cacheFilePath)) {
2807 include($cacheFilePath); // provides $cacheFile['timestamp']
2809 if(isset($cacheFile['timestamp'])) {
2810 $GLOBALS['log']->debug("EMAILUI: found timestamp [ {$cacheFile['timestamp']} ]");
2811 return $cacheFile['timestamp'];
2819 * Updates the timestamp for a cache file - usually to mark a "check email"
2821 * @param string $ieId
2822 * @param string $type Type of cache file: folders, messages, etc.
2823 * @param string $file The cachefile name
2825 function setCacheTimestamp($ieId, $type, $file) {
2826 global $sugar_config;
2828 $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2829 $cacheFile = array();
2831 if(file_exists($cacheFilePath)) {
2832 include($cacheFilePath); // provides $cacheFile['timestamp']
2834 if(isset($cacheFile['timestamp'])) {
2835 $cacheFile['timestamp'] = strtotime('now');
2836 $GLOBALS['log']->debug("EMAILUI: setting updated timestamp [ {$cacheFile['timestamp']} ]");
2837 return $this->_writeCacheFile($cacheFile, $cacheFilePath);
2844 * Writes caches to flat file in cache dir.
2845 * @param string $key Key to the main cache entry (not timestamp)
2846 * @param mixed $var Variable to be cached
2847 * @param string $ieId I-E focus ID
2848 * @param string $type Folder in cache
2849 * @param string $file Cache file name
2851 function writeCacheFile($key, $var, $ieId, $type, $file) {
2852 global $sugar_config;
2854 $cleanIeId = cleanDirName($ieId);
2855 $cleanType = cleanDirName($type);
2856 $cleanFile = cleanFileName($file);
2857 $the_file = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
2858 $timestamp = strtotime('now');
2860 $array['timestamp'] = $timestamp;
2861 $array[$key] = serialize($var); // serialized since varexport_helper() can't handle PHP objects
2863 return $this->_writeCacheFile($array, $the_file);
2867 * Performs the actual file write. Abstracted from writeCacheFile() for
2869 * @param array $array The array to write to the cache
2870 * @param string $file Full path (relative) with cache file name
2873 function _writeCacheFile($array, $file) {
2874 global $sugar_config;
2876 $arrayString = var_export_helper($array);
2880 <?php // created: {$date}
2881 \$cacheFile = {$arrayString};
2884 if($fh = @sugar_fopen($file, "w")) {
2885 fputs($fh, $the_string);
2889 $GLOBALS['log']->debug("EMAILUI: Could not write cache file [ {$file} ]");
2895 * Generate JSON encoded data to be consumed by yui datatable.
2897 * @param array $data
2898 * @param string $resultsParam The resultsList name
2901 function jsonOuput($data, $resultsParam, $count=0, $fromCache=true, $unread=-1) {
2902 global $app_strings;
2904 $count = ($count > 0) ? $count : 0;
2906 if(isset($a['fromCache']))
2907 $cached = ($a['fromCache'] == 1) ? 1 : 0;
2909 $cached = ($fromCache) ? 1 : 0;
2911 if($data['mbox'] == 'undefined' || empty($data['mbox']))
2912 $data['mbox'] = $app_strings['LBL_NONE'];
2914 $jsonOut = array('TotalCount' => $count, 'FromCache' => $cached, 'UnreadCount' => $unread, $resultsParam => $data['out']);
2916 return json_encode($jsonOut);
2919 * generates XML output from an array
2921 * @param string master list Item
2924 function xmlOutput($a, $paramName, $count=0, $fromCache=true, $unread=-1) {
2925 global $app_strings;
2926 $count = ($count > 0) ? $count : 0;
2928 if(isset($a['fromCache'])) {
2929 $cached = ($a['fromCache'] == 1) ? 1 : 0;
2931 $cached = ($fromCache) ? 1 : 0;
2934 if($a['mbox'] == 'undefined' || empty($a['mbox'])) {
2935 $a['mbox'] = $app_strings['LBL_NONE'];
2938 $xml = $this->arrayToXML($a['out'], $paramName);
2941 <?xml version="1.0" encoding="UTF-8"?>
2943 <TotalCount>{$count}</TotalCount>
2944 <UnreadCount>{$unread}</UnreadCount>
2945 <FromCache> {$cached} </FromCache>
2955 * Generate to/cc addresses string in email detailview.
2957 * @param string $str
2958 * @param string $target values: to, cc
2959 * @param int $defaultNum
2960 * @return string $str
2962 function generateExpandableAddrs($str) {
2963 global $mod_strings;
2964 $tempStr = $str.',';
2965 $tempStr = html_entity_decode($tempStr);
2966 $tempStr = $this->unifyEmailString($tempStr);
2968 $pattern = '/@.*,/U';
2969 preg_match_all($pattern, $tempStr, $matchs);
2970 $totalCount = count($matchs[0]);
2972 if(!empty($matchs[0]) && $totalCount > $defaultNum) {
2973 $position = strpos($tempStr, $matchs[0][$defaultNum]);
2974 $hiddenCount = $totalCount - $defaultNum;
2975 $frontStr = substr($tempStr, 0, $position);
2976 $backStr = substr($tempStr, $position, -1);
2977 $str = htmlentities($frontStr) . '<a class="utilsLink" onclick="javascript: SUGAR.email2.detailView.displayAllAddrs(this);">...['.$mod_strings['LBL_EMAIL_DETAIL_VIEW_SHOW'].$hiddenCount.$mod_strings['LBL_EMAIL_DETAIL_VIEW_MORE'].']</a><span style="display: none;">' .htmlentities($backStr).'</span>';
2984 * Unify the seperator as ,
2986 * @param String $str email address string
2987 * @return String converted string
2989 function unifyEmailString($str) {
2990 preg_match_all('/@.*;/U', $str, $matches);
2991 if(!empty($matches[0])) {
2992 foreach($matches[0] as $key => $value) {
2993 $new[] = str_replace(";",",",$value);
2995 return str_replace($matches[0], $new, $str);