PageRenderTime 88ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 1ms

/modules/Emails/EmailUI.php

https://bitbucket.org/cviolette/sugarcrm
PHP | 2989 lines | 2546 code | 203 blank | 240 comment | 72 complexity | bf9d7d8e7db8e0cb6ed638eb5c42ca8c MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  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.
  6. *
  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.
  13. *
  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
  17. * details.
  18. *
  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
  22. * 02110-1301 USA.
  23. *
  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.
  26. *
  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.
  30. *
  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. ********************************************************************************/
  37. /*********************************************************************************
  38. * Description:
  39. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
  40. * Reserved. Contributor(s): ______________________________________..
  41. *********************************************************************************/
  42. require_once("include/ytree/Tree.php");
  43. require_once("include/ytree/ExtNode.php");
  44. require_once("include/SugarFolders/SugarFolders.php");
  45. class EmailUI {
  46. var $db;
  47. var $folder; // place holder for SugarFolder object
  48. var $folderStates = array(); // array of folderPath names and their states (1/0)
  49. var $smarty;
  50. var $addressSeparators = array(";", ",");
  51. 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";
  52. var $groupCss = "<span class='groupInbox'>";
  53. var $cacheTimeouts = array(
  54. 'messages' => 86400, // 24 hours
  55. 'folders' => 300, // 5 mins
  56. 'attachments' => 86400, // 24 hours
  57. );
  58. var $userCacheDir = '';
  59. var $coreDynamicFolderQuery = "SELECT emails.id polymorphic_id, 'Emails' polymorphic_module FROM emails
  60. JOIN emails_text on emails.id = emails_text.email_id
  61. WHERE (type = '::TYPE::' OR status = '::STATUS::') AND assigned_user_id = '::USER_ID::' AND emails.deleted = '0'";
  62. /**
  63. * Sole constructor
  64. */
  65. function EmailUI() {
  66. global $sugar_config;
  67. global $current_user;
  68. $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
  69. if(!empty($folderStateSerial)) {
  70. $this->folderStates = unserialize($folderStateSerial);
  71. }
  72. $this->smarty = new Sugar_Smarty();
  73. $this->folder = new SugarFolder();
  74. $this->userCacheDir = sugar_cached("modules/Emails/{$current_user->id}");
  75. $this->db = DBManagerFactory::getInstance();
  76. }
  77. ///////////////////////////////////////////////////////////////////////////
  78. //// CORE
  79. /**
  80. * Renders the frame for emails
  81. */
  82. function displayEmailFrame() {
  83. require_once("include/OutboundEmail/OutboundEmail.php");
  84. global $app_strings, $app_list_strings;
  85. global $mod_strings;
  86. global $sugar_config;
  87. global $current_user;
  88. global $locale;
  89. global $timedate;
  90. global $theme;
  91. global $sugar_version;
  92. global $sugar_flavor;
  93. global $current_language;
  94. global $server_unique_key;
  95. $this->preflightUserCache();
  96. $ie = new InboundEmail();
  97. // focus listView
  98. $list = array(
  99. 'mbox' => 'Home',
  100. 'ieId' => '',
  101. 'name' => 'Home',
  102. 'unreadChecked' => 0,
  103. 'out' => array(),
  104. );
  105. $this->_generateComposeConfigData('email_compose');
  106. //Check quick create module access
  107. $QCAvailableModules = $this->_loadQuickCreateModules();
  108. //Get the quickSearch js needed for assigned user id on Search Tab
  109. require_once('include/QuickSearchDefaults.php');
  110. $qsd = QuickSearchDefaults::getQuickSearchDefaults();
  111. $qsd->setFormName('advancedSearchForm');
  112. $quicksearchAssignedUser = "if(typeof sqs_objects == 'undefined'){var sqs_objects = new Array;}";
  113. $quicksearchAssignedUser .= "sqs_objects['advancedSearchForm_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
  114. $qsd->setFormName('Distribute');
  115. $quicksearchAssignedUser .= "sqs_objects['Distribute_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
  116. $this->smarty->assign('quickSearchForAssignedUser', $quicksearchAssignedUser);
  117. ///////////////////////////////////////////////////////////////////////
  118. //// BASIC ASSIGNS
  119. $this->smarty->assign("currentUserId",$current_user->id);
  120. $this->smarty->assign("CURRENT_USER_EMAIL",$current_user->email1);
  121. $this->smarty->assign("currentUserName",$current_user->name);
  122. $this->smarty->assign('yuiPath', 'modules/Emails/javascript/yui-ext/');
  123. $this->smarty->assign('app_strings', $app_strings);
  124. $this->smarty->assign('mod_strings', $mod_strings);
  125. $this->smarty->assign('theme', $theme);
  126. $this->smarty->assign('sugar_config', $sugar_config);
  127. $this->smarty->assign('is_admin', $current_user->is_admin);
  128. $this->smarty->assign('sugar_version', $sugar_version);
  129. $this->smarty->assign('sugar_flavor', $sugar_flavor);
  130. $this->smarty->assign('current_language', $current_language);
  131. $this->smarty->assign('server_unique_key', $server_unique_key);
  132. $this->smarty->assign('qcModules', json_encode($QCAvailableModules));
  133. $extAllDebugValue = "ext-all.js";
  134. $this->smarty->assign('extFileName', $extAllDebugValue);
  135. // settings: general
  136. $e2UserPreferences = $this->getUserPrefsJS();
  137. $emailSettings = $e2UserPreferences['emailSettings'];
  138. ///////////////////////////////////////////////////////////////////////
  139. //// USER SETTINGS
  140. // settings: accounts
  141. $cuDatePref = $current_user->getUserDateTimePreferences();
  142. $this->smarty->assign('dateFormat', $cuDatePref['date']);
  143. $this->smarty->assign('dateFormatExample', str_replace(array("Y", "m", "d"), array("yyyy", "mm", "dd"), $cuDatePref['date']));
  144. $this->smarty->assign('calFormat', $timedate->get_cal_date_format());
  145. $this->smarty->assign('TIME_FORMAT', $timedate->get_user_time_format());
  146. $ieAccounts = $ie->retrieveByGroupId($current_user->id);
  147. $ieAccountsOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
  148. foreach($ieAccounts as $k => $v) {
  149. $disabled = (!$v->is_personal) ? "DISABLED" : "";
  150. $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
  151. $ieAccountsOptions .= "<option value='{$v->id}' $disabled>{$group}{$v->name}</option>\n";
  152. }
  153. $this->smarty->assign('ieAccounts', $ieAccountsOptions);
  154. $this->smarty->assign('rollover', $this->rolloverStyle);
  155. $protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']);
  156. $this->smarty->assign('PROTOCOL', get_select_options_with_id($protocol, ''));
  157. $this->smarty->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], ''));
  158. $this->smarty->assign('ie_mod_strings', return_module_language($current_language, 'InboundEmail'));
  159. $charsetSelectedValue = isset($emailSettings['defaultOutboundCharset']) ? $emailSettings['defaultOutboundCharset'] : false;
  160. if (!$charsetSelectedValue) {
  161. $charsetSelectedValue = $current_user->getPreference('default_export_charset', 'global');
  162. if (!$charsetSelectedValue) {
  163. $charsetSelectedValue = $locale->getPrecedentPreference('default_email_charset');
  164. }
  165. }
  166. $charset = array(
  167. 'options' => $locale->getCharsetSelect(),
  168. 'selected' => $charsetSelectedValue,
  169. );
  170. $this->smarty->assign('charset', $charset);
  171. $emailCheckInterval = array('options' => $app_strings['LBL_EMAIL_CHECK_INTERVAL_DOM'], 'selected' => $emailSettings['emailCheckInterval']);
  172. $this->smarty->assign('emailCheckInterval', $emailCheckInterval);
  173. $this->smarty->assign('attachmentsSearchOptions', $app_list_strings['checkbox_dom']);
  174. $this->smarty->assign('sendPlainTextChecked', ($emailSettings['sendPlainText'] == 1) ? 'CHECKED' : '');
  175. $this->smarty->assign('showNumInList', get_select_options_with_id($app_list_strings['email_settings_num_dom'], $emailSettings['showNumInList']));
  176. //// END USER SETTINGS
  177. ///////////////////////////////////////////////////////////////////////
  178. ///////////////////////////////////////////////////////////////////////
  179. //// SIGNATURES
  180. $prependSignature = ($current_user->getPreference('signature_prepend')) ? 'true' : 'false';
  181. $defsigID = $current_user->getPreference('signature_default');
  182. $this->smarty->assign('signatures', $current_user->getSignatures(false, $defsigID));
  183. $this->smarty->assign('signaturesSettings', $current_user->getSignatures(false, $defsigID, false));
  184. $signatureButtons = $current_user->getSignatureButtons('SUGAR.email2.settings.createSignature', !empty($defsigID));
  185. if (!empty($defsigID)) {
  186. $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">&nbsp;
  187. </span>';
  188. } else {
  189. $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">&nbsp;
  190. </span>';
  191. }
  192. $this->smarty->assign('signatureButtons', $signatureButtons);
  193. $this->smarty->assign('signaturePrepend', $prependSignature == 'true' ? 'CHECKED' : '');
  194. //// END SIGNATURES
  195. ///////////////////////////////////////////////////////////////////////
  196. ///////////////////////////////////////////////////////////////////////
  197. //// EMAIL TEMPLATES
  198. $email_templates_arr = $this->getEmailTemplatesArray();
  199. natcasesort($email_templates_arr);
  200. $this->smarty->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, ''));
  201. //// END EMAIL TEMPLATES
  202. ///////////////////////////////////////////////////////////////////////
  203. ///////////////////////////////////////////////////////////////////////
  204. //// FOLDERS & TreeView
  205. $this->smarty->assign('groupUserOptions', $ie->getGroupsWithSelectOptions(array('' => $app_strings['LBL_EMAIL_CREATE_NEW'])));
  206. $tree = $this->getMailboxNodes();
  207. // preloaded folder
  208. $preloadFolder = 'lazyLoadFolder = ';
  209. $focusFolderSerial = $current_user->getPreference('focusFolder', 'Emails');
  210. if(!empty($focusFolderSerial)) {
  211. $focusFolder = unserialize($focusFolderSerial);
  212. //$focusFolder['ieId'], $focusFolder['folder']
  213. $preloadFolder .= json_encode($focusFolder).";";
  214. } else {
  215. $preloadFolder .= "new Object();";
  216. }
  217. //// END FOLDERS
  218. ///////////////////////////////////////////////////////////////////////
  219. $out = "";
  220. $out .= $this->smarty->fetch("modules/Emails/templates/_baseEmail.tpl");
  221. $out .= $tree->generate_header();
  222. $out .= $tree->generateNodesNoInit(true, 'email2treeinit');
  223. $out .=<<<eoq
  224. <script type="text/javascript" language="javascript">
  225. var loader = new YAHOO.util.YUILoader({
  226. require : [
  227. "layout", "element", "tabview", "menu",
  228. "cookie", "sugarwidgets"
  229. ],
  230. loadOptional: true,
  231. skin: { base: 'blank', defaultSkin: '' },
  232. onSuccess: email2init,
  233. allowRollup: true,
  234. base: "include/javascript/yui/build/"
  235. });
  236. loader.addModule({
  237. name :"sugarwidgets",
  238. type : "js",
  239. fullpath: "include/javascript/sugarwidgets/SugarYUIWidgets.js",
  240. varName: "YAHOO.SUGAR",
  241. requires: ["datatable", "dragdrop", "treeview", "tabview", "calendar"]
  242. });
  243. loader.insert();
  244. {$preloadFolder};
  245. </script>
  246. eoq;
  247. return $out;
  248. }
  249. /**
  250. * Generate the frame needed for the quick compose email UI. This frame is loaded dynamically
  251. * by an ajax call.
  252. *
  253. * @return JSON An object containing html markup and js script variables.
  254. */
  255. function displayQuickComposeEmailFrame()
  256. {
  257. $this->preflightUserCache();
  258. $this->_generateComposeConfigData('email_compose_light');
  259. $javascriptOut = $this->smarty->fetch("modules/Emails/templates/_baseConfigData.tpl");
  260. $divOut = $this->smarty->fetch("modules/Emails/templates/overlay.tpl");
  261. $divOut .= $this->smarty->fetch("modules/Emails/templates/addressSearchContent.tpl");
  262. $outData = array('jsData' => $javascriptOut,'divData'=> $divOut);
  263. $out = json_encode($outData);
  264. return $out;
  265. }
  266. /**
  267. * Load the modules from the metadata file and include in a custom one if it exists
  268. *
  269. * @return array
  270. */
  271. protected function _loadQuickCreateModules()
  272. {
  273. $QCAvailableModules = array();
  274. $QCModules = array();
  275. include('modules/Emails/metadata/qcmodulesdefs.php');
  276. if (file_exists('custom/modules/Emails/metadata/qcmodulesdefs.php')) {
  277. include('custom/modules/Emails/metadata/qcmodulesdefs.php');
  278. }
  279. foreach($QCModules as $module) {
  280. $seed = SugarModule::get($module)->loadBean();
  281. if ( ( $seed instanceOf SugarBean ) && $seed->ACLAccess('edit') ) {
  282. $QCAvailableModules[] = $module;
  283. }
  284. }
  285. return $QCAvailableModules;
  286. }
  287. /**
  288. * Given an email link url (eg. index.php?action=Compose&parent_type=Contacts...) break up the
  289. * request components and create a compose package that can be used by the quick compose UI. The
  290. * result is typically passed into the js call SUGAR.quickCompose.init which initalizes the quick compose
  291. * UI.
  292. *
  293. * @param String $emailLinkUrl
  294. * @return JSON Object containing the composePackage and full link url
  295. */
  296. function generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, $lazyLoad=false)
  297. {
  298. $composeData = explode("&",$emailLinkUrl);
  299. $a_composeData = array();
  300. foreach ($composeData as $singleRequest)
  301. {
  302. $tmp = explode("=",$singleRequest);
  303. $a_composeData[$tmp[0]] = urldecode($tmp[1]);
  304. }
  305. return $this->generateComposePackageForQuickCreate($a_composeData,$emailLinkUrl, $lazyLoad);
  306. }
  307. /**
  308. * Generate the composePackage for the quick compose email UI. The package contains
  309. * key/value pairs generated by the Compose.php file which are then set into the
  310. * quick compose email UI (eg. to addr, parent id, parent type, etc)
  311. *
  312. * @param Array $composeData Associative array read and processed by generateComposeDataPackage.
  313. * @param String $fullLinkUrl A link that contains all pertinant information so the user can be
  314. * directed to the full compose screen if needed
  315. * @param SugarBean $bean Optional - the parent object bean with data
  316. * @return JSON Object containg composePackage and fullLinkUrl
  317. */
  318. function generateComposePackageForQuickCreate($composeData,$fullLinkUrl, $lazyLoad=false, $bean = null)
  319. {
  320. $_REQUEST['forQuickCreate'] = true;
  321. if(!$lazyLoad){
  322. require_once('modules/Emails/Compose.php');
  323. $composePackage = generateComposeDataPackage($composeData,FALSE, $bean);
  324. }else{
  325. $composePackage = $composeData;
  326. }
  327. // JSON object is passed into the function defined within the a href onclick event
  328. // which is delimeted by '. Need to escape all single quotes and &, <, >
  329. // but not double quotes since json would escape them
  330. foreach ($composePackage as $key => $singleCompose)
  331. {
  332. if (is_string($singleCompose))
  333. $composePackage[$key] = str_replace("&nbsp;", " ", from_html($singleCompose));
  334. }
  335. $quickComposeOptions = array('fullComposeUrl' => $fullLinkUrl,'composePackage' => $composePackage);
  336. $j_quickComposeOptions = JSON::encode($quickComposeOptions, false ,true);
  337. return $j_quickComposeOptions;
  338. }
  339. /**
  340. * Generate the config data needed for the Full Compose UI and the Quick Compose UI. The set of config data
  341. * returned is the minimum set needed by the quick compose UI.
  342. *
  343. * @param String $type Drives which tinyMCE options will be included.
  344. */
  345. function _generateComposeConfigData($type = "email_compose_light" )
  346. {
  347. global $app_list_strings,$current_user, $app_strings, $mod_strings,$current_language,$locale;
  348. //Link drop-downs
  349. $parent_types = $app_list_strings['record_type_display'];
  350. $disabled_parent_types = ACLController::disabledModuleList($parent_types, false, 'list');
  351. foreach($disabled_parent_types as $disabled_parent_type) {
  352. unset($parent_types[$disabled_parent_type]);
  353. }
  354. asort($parent_types);
  355. $linkBeans = json_encode(get_select_options_with_id($parent_types, ''));
  356. //TinyMCE Config
  357. require_once("include/SugarTinyMCE.php");
  358. $tiny = new SugarTinyMCE();
  359. $tinyConf = $tiny->getConfig($type);
  360. //Generate Language Packs
  361. $lang = "var app_strings = new Object();\n";
  362. foreach($app_strings as $k => $v) {
  363. if(strpos($k, 'LBL_EMAIL_') !== false) {
  364. $lang .= "app_strings.{$k} = '{$v}';\n";
  365. }
  366. }
  367. //Get the email mod strings but don't use the global variable as this may be overridden by
  368. //other modules when the quick create is rendered.
  369. $email_mod_strings = return_module_language($current_language,'Emails');
  370. $modStrings = "var mod_strings = new Object();\n";
  371. foreach($email_mod_strings as $k => $v) {
  372. $v = str_replace("'", "\'", $v);
  373. $modStrings .= "mod_strings.{$k} = '{$v}';\n";
  374. }
  375. $lang .= "\n\n{$modStrings}\n";
  376. //Grab the Inboundemail language pack
  377. $ieModStrings = "var ie_mod_strings = new Object();\n";
  378. $ie_mod_strings = return_module_language($current_language,'InboundEmail');
  379. foreach($ie_mod_strings as $k => $v) {
  380. $v = str_replace("'", "\'", $v);
  381. $ieModStrings .= "ie_mod_strings.{$k} = '{$v}';\n";
  382. }
  383. $lang .= "\n\n{$ieModStrings}\n";
  384. $this->smarty->assign('linkBeans', $linkBeans);
  385. $this->smarty->assign('linkBeansOptions', $parent_types);
  386. $this->smarty->assign('tinyMCE', $tinyConf);
  387. $this->smarty->assign('lang', $lang);
  388. $this->smarty->assign('app_strings', $app_strings);
  389. $this->smarty->assign('mod_strings', $email_mod_strings);
  390. $ie1 = new InboundEmail();
  391. //Signatures
  392. $defsigID = $current_user->getPreference('signature_default');
  393. $defaultSignature = $current_user->getDefaultSignature();
  394. $sigJson = !empty($defaultSignature) ? json_encode(array($defaultSignature['id'] => from_html($defaultSignature['signature_html']))) : "new Object()";
  395. $this->smarty->assign('defaultSignature', $sigJson);
  396. $this->smarty->assign('signatureDefaultId', (isset($defaultSignature['id'])) ? $defaultSignature['id'] : "");
  397. //User Preferences
  398. $this->smarty->assign('userPrefs', json_encode($this->getUserPrefsJS()));
  399. //Get the users default outbound id
  400. $defaultOutID = $ie1->getUsersDefaultOutboundServerId($current_user);
  401. $this->smarty->assign('defaultOutID', $defaultOutID);
  402. //Character Set
  403. $charsets = json_encode($locale->getCharsetSelect());
  404. $this->smarty->assign('emailCharsets', $charsets);
  405. //Relateable List of People for address book search
  406. //#20776 jchi
  407. $peopleTables = array("users",
  408. "contacts",
  409. "leads",
  410. "prospects",
  411. "accounts");
  412. $filterPeopleTables = array();
  413. global $app_list_strings, $app_strings;
  414. $filterPeopleTables['LBL_DROPDOWN_LIST_ALL'] = $app_strings['LBL_DROPDOWN_LIST_ALL'];
  415. foreach($peopleTables as $table) {
  416. $module = ucfirst($table);
  417. $class = substr($module, 0, strlen($module) - 1);
  418. require_once("modules/{$module}/{$class}.php");
  419. $person = new $class();
  420. if (!$person->ACLAccess('list')) continue;
  421. $filterPeopleTables[$person->table_name] = $app_list_strings['moduleList'][$person->module_dir];
  422. }
  423. $this->smarty->assign('listOfPersons' , get_select_options_with_id($filterPeopleTables,''));
  424. }
  425. //// END CORE
  426. ///////////////////////////////////////////////////////////////////////////
  427. ///////////////////////////////////////////////////////////////////////////
  428. //// ADDRESS BOOK
  429. /**
  430. * Retrieves all relationship metadata for a user's address book
  431. * @return array
  432. */
  433. function getContacts() {
  434. global $current_user;
  435. $q = "SELECT * FROM address_book WHERE assigned_user_id = '{$current_user->id}' ORDER BY bean DESC";
  436. $r = $this->db->query($q);
  437. $ret = array();
  438. while($a = $this->db->fetchByAssoc($r)) {
  439. $ret[$a['bean_id']] = array(
  440. 'id' => $a['bean_id'],
  441. 'module' => $a['bean'],
  442. );
  443. }
  444. return $ret;
  445. }
  446. /**
  447. * Saves changes to a user's address book
  448. * @param array contacts
  449. */
  450. function setContacts($contacts) {
  451. global $current_user;
  452. $oldContacts = $this->getContacts();
  453. foreach($contacts as $cid => $contact) {
  454. if(!in_array($contact['id'], $oldContacts)) {
  455. $q = "INSERT INTO address_book (assigned_user_id, bean, bean_id) VALUES ('{$current_user->id}', '{$contact['module']}', '{$contact['id']}')";
  456. $r = $this->db->query($q, true);
  457. }
  458. }
  459. }
  460. /**
  461. * Removes contacts from the user's address book
  462. * @param array ids
  463. */
  464. function removeContacts($ids) {
  465. global $current_user;
  466. $concat = "";
  467. foreach($ids as $id) {
  468. if(!empty($concat))
  469. $concat .= ", ";
  470. $concat .= "'{$id}'";
  471. }
  472. $q = "DELETE FROM address_book WHERE assigned_user_id = '{$current_user->id}' AND bean_id IN ({$concat})";
  473. $r = $this->db->query($q);
  474. }
  475. /**
  476. * saves editted Contact info
  477. * @param string $str JSON serialized object
  478. */
  479. function saveContactEdit($str) {
  480. $json = getJSONobj();
  481. $str = from_html($str);
  482. $obj = $json->decode($str);
  483. $contact = new Contact();
  484. $contact->retrieve($obj['contact_id']);
  485. $contact->first_name = $obj['contact_first_name'];
  486. $contact->last_name = $obj['contact_last_name'];
  487. $contact->save();
  488. // handle email address changes
  489. $addresses = array();
  490. foreach($obj as $k => $req) {
  491. if(strpos($k, 'emailAddress') !== false) {
  492. $addresses[$k] = $req;
  493. }
  494. }
  495. // prefill some REQUEST vars for emailAddress save
  496. $_REQUEST['emailAddressOptOutFlag'] = $obj['optOut'];
  497. $_REQUEST['emailAddressInvalidFlag'] = $obj['invalid'];
  498. $contact->emailAddress->save($obj['contact_id'], 'Contacts', $addresses, $obj['primary'], '');
  499. }
  500. /**
  501. * Prepares the Edit Contact mini-form via template assignment
  502. * @param string id ID of contact in question
  503. * @param string module Module in focus
  504. * @return array
  505. */
  506. function getEditContact($id, $module) {
  507. global $app_strings;
  508. if(!class_exists("Contact")) {
  509. }
  510. $contact = new Contact();
  511. $contact->retrieve($_REQUEST['id']);
  512. $ret = array();
  513. if($contact->ACLAccess('edit')) {
  514. $contactMeta = array();
  515. $contactMeta['id'] = $contact->id;
  516. $contactMeta['module'] = $contact->module_dir;
  517. $contactMeta['first_name'] = $contact->first_name;
  518. $contactMeta['last_name'] = $contact->last_name;
  519. $this->smarty->assign("app_strings", $app_strings);
  520. $this->smarty->assign("contact_strings", return_module_language($_SESSION['authenticated_user_language'], 'Contacts'));
  521. $this->smarty->assign("contact", $contactMeta);
  522. $ea = new SugarEmailAddress();
  523. $newEmail = $ea->getEmailAddressWidgetEditView($id, $module, true);
  524. $this->smarty->assign("emailWidget", $newEmail['html']);
  525. $ret['form'] = $this->smarty->fetch("modules/Emails/templates/editContact.tpl");
  526. $ret['prefillData'] = $newEmail['prefillData'];
  527. } else {
  528. $id = "";
  529. $ret['form'] = $app_strings['LBL_EMAIL_ERROR_NO_ACCESS'];
  530. $ret['prefillData'] = '{}';
  531. }
  532. $ret['id'] = $id;
  533. $ret['contactName'] = $contact->full_name;
  534. return $ret;
  535. }
  536. /**
  537. * Retrieves a concatenated list of contacts, those with assigned_user_id = user's id and those in the address_book
  538. * table
  539. * @param array $contacts Array of contact types -> IDs
  540. * @param object $user User in focus
  541. * @return array
  542. */
  543. function getUserContacts($contacts, $user=null) {
  544. global $current_user;
  545. global $locale;
  546. if(empty($user)) {
  547. $user = $current_user;
  548. }
  549. $emailAddress = new SugarEmailAddress();
  550. $ret = array();
  551. $union = '';
  552. $modules = array();
  553. foreach($contacts as $contact) {
  554. if(!isset($modules[$contact['module']])) {
  555. $modules[$contact['module']] = array();
  556. }
  557. $modules[$contact['module']][] = $contact;
  558. }
  559. foreach($modules as $module => $contacts) {
  560. if(!empty($union)) {
  561. $union .= " UNION ALL ";
  562. }
  563. $table = strtolower($module);
  564. $idsSerial = '';
  565. foreach($contacts as $contact) {
  566. if(!empty($idsSerial)) {
  567. $idsSerial .= ",";
  568. }
  569. $idsSerial .= "'{$contact['id']}'";
  570. }
  571. $union .= "(SELECT id, first_name, last_name, title, '{$module}' module FROM {$table} WHERE id IN({$idsSerial}) AND deleted = 0 )";
  572. }
  573. if(!empty($union)) {
  574. $union .= " ORDER BY last_name";
  575. }
  576. $r = $user->db->query($union);
  577. //_pp($union);
  578. while($a = $user->db->fetchByAssoc($r)) {
  579. $c = array();
  580. $c['name'] = $locale->getLocaleFormattedName($a['first_name'], "<b>{$a['last_name']}</b>", '', $a['title'], '', $user);
  581. $c['id'] = $a['id'];
  582. $c['module'] = $a['module'];
  583. $c['email'] = $emailAddress->getAddressesByGUID($a['id'], $a['module']);
  584. $ret[$a['id']] = $c;
  585. }
  586. return $ret;
  587. }
  588. //// END ADDRESS BOOK
  589. ///////////////////////////////////////////////////////////////////////////
  590. ///////////////////////////////////////////////////////////////////////////
  591. //// EMAIL 2.0 Preferences
  592. function getUserPrefsJS() {
  593. global $current_user;
  594. global $locale;
  595. // sort order per mailbox view
  596. $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
  597. $sortArray = array();
  598. if(!empty($sortSerial)) {
  599. $sortArray = unserialize($sortSerial);
  600. }
  601. // treeview collapsed/open states
  602. $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
  603. $folderStates = array();
  604. if(!empty($folderStateSerial)) {
  605. $folderStates = unserialize($folderStateSerial);
  606. }
  607. // subscribed accounts
  608. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  609. // general settings
  610. $emailSettings = $current_user->getPreference('emailSettings', 'Emails');
  611. if(empty($emailSettings)) {
  612. $emailSettings = array();
  613. $emailSettings['emailCheckInterval'] = -1;
  614. $emailSettings['autoImport'] = '';
  615. $emailSettings['alwaysSaveOutbound'] = '1';
  616. $emailSettings['sendPlainText'] = '';
  617. $emailSettings['defaultOutboundCharset'] = $GLOBALS['sugar_config']['default_email_charset'];
  618. $emailSettings['showNumInList'] = 20;
  619. }
  620. // focus folder
  621. $focusFolder = $current_user->getPreference('focusFolder', 'Emails');
  622. $focusFolder = !empty($focusFolder) ? unserialize($focusFolder) : array();
  623. // unread only flag
  624. $showUnreadOnly = $current_user->getPreference('showUnreadOnly', 'Emails');
  625. $listViewSort = array(
  626. "sortBy" => 'date',
  627. "sortDirection" => 'DESC',
  628. );
  629. // signature prefs
  630. $signaturePrepend = $current_user->getPreference('signature_prepend') ? 'true' : 'false';
  631. $signatureDefault = $current_user->getPreference('signature_default');
  632. $signatures = array(
  633. 'signature_prepend' => $signaturePrepend,
  634. 'signature_default' => $signatureDefault
  635. );
  636. // current_user
  637. $user = array(
  638. 'emailAddresses' => $current_user->emailAddress->getAddressesByGUID($current_user->id, 'Users'),
  639. 'full_name' => from_html($current_user->full_name),
  640. );
  641. $userPreferences = array();
  642. $userPreferences['sort'] = $sortArray;
  643. $userPreferences['folderStates'] = $folderStates;
  644. $userPreferences['showFolders'] = $showFolders;
  645. $userPreferences['emailSettings'] = $emailSettings;
  646. $userPreferences['focusFolder'] = $focusFolder;
  647. $userPreferences['showUnreadOnly'] = $showUnreadOnly;
  648. $userPreferences['listViewSort'] = $listViewSort;
  649. $userPreferences['signatures'] = $signatures;
  650. $userPreferences['current_user'] = $user;
  651. return $userPreferences;
  652. }
  653. ///////////////////////////////////////////////////////////////////////////
  654. //// FOLDER FUNCTIONS
  655. /**
  656. * Creates a new Sugar folder
  657. * @param string $nodeLabel New sugar folder name
  658. * @param string $parentLabel Parent folder name
  659. */
  660. function saveNewFolder($nodeLabel, $parentId, $isGroup=0) {
  661. global $current_user;
  662. $this->folder->name = $nodeLabel;
  663. $this->folder->is_group = $isGroup;
  664. $this->folder->parent_folder = ($parentId == 'Home') ? "" : $parentId;
  665. $this->folder->has_child = 0;
  666. $this->folder->created_by = $current_user->id;
  667. $this->folder->modified_by = $current_user->id;
  668. $this->folder->date_modified = $this->folder->date_created = TimeDate::getInstance()->nowDb();
  669. $this->folder->save();
  670. return array(
  671. 'action' => 'newFolderSave',
  672. 'id' => $this->folder->id,
  673. 'name' => $this->folder->name,
  674. 'is_group' => $this->folder->is_group,
  675. 'is_dynamic' => $this->folder->is_dynamic
  676. );
  677. }
  678. /**
  679. * Saves user sort prefernces
  680. */
  681. function saveListViewSortOrder($ieId, $focusFolder, $sortBy, $sortDir) {
  682. global $current_user;
  683. $sortArray = array();
  684. $sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
  685. if(!empty($sortSerial)) {
  686. $sortArray = unserialize($sortSerial);
  687. }
  688. $sortArray[$ieId][$focusFolder]['current']['sort'] = $sortBy;
  689. $sortArray[$ieId][$focusFolder]['current']['direction'] = $sortDir;
  690. $sortSerial = serialize($sortArray);
  691. $current_user->setPreference('folderSortOrder', $sortSerial, '', 'Emails');
  692. }
  693. /**
  694. * Stickies folder collapse/open state
  695. */
  696. function saveFolderOpenState($focusFolder, $focusFolderOpen) {
  697. global $current_user;
  698. $folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
  699. $folderStates = array();
  700. if(!empty($folderStateSerial)) {
  701. $folderStates = unserialize($folderStateSerial);
  702. }
  703. $folderStates[$focusFolder] = $focusFolderOpen;
  704. $newFolderStateSerial = serialize($folderStates);
  705. $current_user->setPreference('folderOpenState', $newFolderStateSerial, '', 'Emails');
  706. }
  707. /**
  708. * saves a folder's view state
  709. */
  710. function saveListView($ieId, $folder) {
  711. global $current_user;
  712. $saveState = array();
  713. $saveState['ieId'] = $ieId;
  714. $saveState['folder'] = $folder;
  715. $saveStateSerial = serialize($saveState);
  716. $current_user->setPreference('focusFolder', $saveStateSerial, '', 'Emails');
  717. }
  718. /**
  719. * Generates cache folder structure
  720. */
  721. function preflightEmailCache($cacheRoot) {
  722. // base
  723. if(!file_exists($cacheRoot))
  724. mkdir_recursive(clean_path($cacheRoot));
  725. // folders
  726. if(!file_exists($cacheRoot."/folders"))
  727. mkdir_recursive(clean_path("{$cacheRoot}/folders"));
  728. // messages
  729. if(!file_exists($cacheRoot."/messages"))
  730. mkdir_recursive(clean_path("{$cacheRoot}/messages"));
  731. // attachments
  732. if(!file_exists($cacheRoot."/attachments"))
  733. mkdir_recursive(clean_path("{$cacheRoot}/attachments"));
  734. }
  735. function deleteEmailCacheForFolders($cacheRoot) {
  736. $filePath = $cacheRoot."/folders/folders.php";
  737. if (file_exists($filePath)) {
  738. unlink($filePath);
  739. }
  740. }
  741. ///////////////////////////////////////////////////////////////////////////
  742. //// IMAP FUNCTIONS
  743. /**
  744. * Identifies subscribed mailboxes and empties the trash
  745. * @param object $ie InboundEmail
  746. */
  747. function emptyTrash(&$ie) {
  748. global $current_user;
  749. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  750. if(is_array($showFolders)) {
  751. foreach($showFolders as $ieId) {
  752. if(!empty($ieId)) {
  753. $ie->retrieve($ieId);
  754. $ie->emptyTrash();
  755. }
  756. }
  757. }
  758. }
  759. /**
  760. * returns an array of nodes that correspond to IMAP mailboxes.
  761. * @param bool $forceRefresh
  762. * @return object TreeView object
  763. */
  764. function getMailboxNodes() {
  765. global $sugar_config;
  766. global $current_user;
  767. global $app_strings;
  768. $tree = new Tree("frameFolders");
  769. $tree->tree_style= 'include/ytree/TreeView/css/check/tree.css';
  770. $nodes = array();
  771. $ie = new InboundEmail();
  772. $refreshOffset = $this->cacheTimeouts['folders']; // 5 mins. this will be set via user prefs
  773. $rootNode = new ExtNode($app_strings['LBL_EMAIL_HOME_FOLDER'], $app_strings['LBL_EMAIL_HOME_FOLDER']);
  774. $rootNode->dynamicloadfunction = '';
  775. $rootNode->expanded = true;
  776. $rootNode->dynamic_load = true;
  777. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  778. if(empty($showFolders)) {
  779. $showFolders = array();
  780. }
  781. // INBOX NODES
  782. if($current_user->hasPersonalEmail()) {
  783. $personals = $ie->retrieveByGroupId($current_user->id);
  784. foreach($personals as $k => $personalAccount) {
  785. if(in_array($personalAccount->id, $showFolders)) {
  786. // check for cache value
  787. $cacheRoot = sugar_cached("modules/Emails/{$personalAccount->id}");
  788. $this->preflightEmailCache($cacheRoot);
  789. if($this->validCacheFileExists($personalAccount->id, 'folders', "folders.php")) {
  790. $mailboxes = $this->getMailBoxesFromCacheValue($personalAccount);
  791. } else {
  792. $mailboxes = $personalAccount->getMailboxes();
  793. }
  794. $acctNode = new ExtNode('Home::' . $personalAccount->name, $personalAccount->name);
  795. $acctNode->dynamicloadfunction = '';
  796. $acctNode->expanded = false;
  797. $acctNode->set_property('cls', 'ieFolder');
  798. $acctNode->set_property('ieId', $personalAccount->id);
  799. $acctNode->set_property('protocol', $personalAccount->protocol);
  800. if(array_key_exists('Home::'.$personalAccount->name, $this->folderStates)) {
  801. if($this->folderStates['Home::'.$personalAccount->name] == 'open') {
  802. $acctNode->expanded = true;
  803. }
  804. }
  805. $acctNode->dynamic_load = true;
  806. $nodePath = $acctNode->_properties['id'];
  807. foreach($mailboxes as $k => $mbox) {
  808. $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $personalAccount->id,
  809. $nodePath, false, $personalAccount));
  810. }
  811. $rootNode->add_node($acctNode);
  812. }
  813. }
  814. }
  815. // GROUP INBOX NODES
  816. $beans = $ie->retrieveAllByGroupId($current_user->id, false);
  817. foreach($beans as $k => $groupAccount) {
  818. if(in_array($groupAccount->id, $showFolders)) {
  819. // check for cache value
  820. $cacheRoot = sugar_cached("modules/Emails/{$groupAccount->id}");
  821. $this->preflightEmailCache($cacheRoot);
  822. //$groupAccount->connectMailserver();
  823. if($this->validCacheFileExists($groupAccount->id, 'folders', "folders.php")) {
  824. $mailboxes = $this->getMailBoxesFromCacheValue($groupAccount);
  825. } else {
  826. $mailboxes = $groupAccount->getMailBoxesForGroupAccount();
  827. }
  828. $acctNode = new ExtNode($groupAccount->name, "group.{$groupAccount->name}");
  829. $acctNode->dynamicloadfunction = '';
  830. $acctNode->expanded = false;
  831. $acctNode->set_property('isGroup', 'true');
  832. $acctNode->set_property('ieId', $groupAccount->id);
  833. $acctNode->set_property('protocol', $groupAccount->protocol);
  834. if(array_key_exists('Home::'.$groupAccount->name, $this->folderStates)) {
  835. if($this->folderStates['Home::'.$groupAccount->name] == 'open') {
  836. $acctNode->expanded = true;
  837. }
  838. }
  839. $acctNode->dynamic_load = true;
  840. $nodePath = $rootNode->_properties['id']."::".$acctNode->_properties['id'];
  841. foreach($mailboxes as $k => $mbox) {
  842. $acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $groupAccount->id,
  843. $nodePath, true, $groupAccount));
  844. }
  845. $rootNode->add_node($acctNode);
  846. }
  847. }
  848. // SugarFolder nodes
  849. /* SugarFolders are built at onload when the UI renders */
  850. $tree->add_node($rootNode);
  851. return $tree;
  852. }
  853. function getMailBoxesFromCacheValue($mailAccount) {
  854. $foldersCache = $this->getCacheValue($mailAccount->id, 'folders', "folders.php", 'foldersCache');
  855. $mailboxes = $foldersCache['mailboxes'];
  856. $mailboxesArray = $mailAccount->generateFlatArrayFromMultiDimArray($mailboxes, $mailAccount->retrieveDelimiter());
  857. $mailAccount->saveMailBoxFolders($mailboxesArray);
  858. $this->deleteEmailCacheForFolders($cacheRoot);
  859. return $mailboxes;
  860. } // fn
  861. /**
  862. * Builds up a TreeView Node object
  863. * @param mixed
  864. * @param mixed
  865. * @param string
  866. * @param string ID of InboundEmail instance
  867. * @param string nodePath Serialized path from root node to current node
  868. * @param bool isGroup
  869. * @param bool forceRefresh
  870. * @return mixed
  871. */
  872. function buildTreeNode($key, $label, $mbox, $ieId, $nodePath, $isGroup, $ie) {
  873. global $sugar_config;
  874. // get unread counts
  875. $exMbox = explode("::", $nodePath);
  876. $unseen = 0;
  877. $GLOBALS['log']->debug("$key --- $nodePath::$label");
  878. if(count($exMbox) >= 2) {
  879. $mailbox = "";
  880. for($i=2; $i<count($exMbox); $i++) {
  881. if($mailbox != "") {
  882. $mailbox .= ".";
  883. }
  884. $mailbox .= "{$exMbox[$i]}";
  885. }
  886. $mailbox = substr($key, strpos($key, '.'));
  887. $unseen = $this->getUnreadCount($ie, $mailbox);
  888. if($unseen > 0) {
  889. //$label = " <span id='span{$ie->id}{$ie->mailbox}' style='font-weight:bold'>{$label} (<span id='span{$ie->id}{$ie->mailbox}nums'>{$unseen}</span>)</span>";
  890. }
  891. }
  892. $nodePath = $nodePath."::".$label;
  893. $node = new ExtNode($nodePath, $label);
  894. $node->dynamicloadfunction = '';
  895. $node->expanded = false;
  896. $node->set_property('labelStyle', "remoteFolder");
  897. if(array_key_exists($nodePath, $this->folderStates)) {
  898. if($this->folderStates[$nodePath] == 'open') {
  899. $node->expanded = true;
  900. }
  901. }
  902. $group = ($isGroup) ? 'true' : 'false';
  903. $node->dynamic_load = true;
  904. //$node->set_property('href', " SUGAR.email2.listView.populateListFrame(YAHOO.namespace('frameFolders').selectednode, '{$ieId}', 'false');");
  905. $node->set_property('isGroup', $group);
  906. $node->set_property('isDynamic', 'false');
  907. $node->set_property('ieId', $ieId);
  908. $node->set_property('mbox', $key);
  909. $node->set_property('unseen', $unseen);
  910. $node->set_property('cls', 'ieFolder');
  911. if(is_array($mbox)) {
  912. foreach($mbox as $k => $v) {
  913. $node->add_node($this->buildTreeNode("$key.$k", $k, $v, $ieId, $nodePath, $isGroup, $ie));
  914. }
  915. }
  916. return $node;
  917. }
  918. /**
  919. * Totals the unread emails
  920. */
  921. function getUnreadCount(&$ie, $mailbox) {
  922. global $sugar_config;
  923. $unseen = 0;
  924. // use cache
  925. return $ie->getCacheUnreadCount($mailbox);
  926. }
  927. ///////////////////////////////////////////////////////////////////////////
  928. //// DISPLAY CODE
  929. /**
  930. * Used exclusively by draft code. Returns Notes and Documents as attachments.
  931. * @param array $ret
  932. * @return array
  933. */
  934. function getDraftAttachments($ret) {
  935. global $db;
  936. // $ret['uid'] is the draft Email object's GUID
  937. $ret['attachments'] = array();
  938. $q = "SELECT id, filename FROM notes WHERE parent_id = '{$ret['uid']}' AND deleted = 0";
  939. $r = $db->query($q);
  940. while($a = $db->fetchByAssoc($r)) {
  941. $ret['attachments'][$a['id']] = array(
  942. 'id' => $a['id'],
  943. 'filename' => $a['filename'],
  944. );
  945. }
  946. return $ret;
  947. }
  948. function createCopyOfInboundAttachment($ie, $ret, $uid) {
  949. global $sugar_config;
  950. if ($ie->isPop3Protocol()) {
  951. // get the UIDL from database;
  952. $cachedUIDL = md5($uid);
  953. $cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$cachedUIDL}.php");
  954. } else {
  955. $cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$uid}.php");
  956. }
  957. if(file_exists($cache)) {
  958. include($cache); // profides $cacheFile
  959. $metaOut = unserialize($cacheFile['out']);
  960. $meta = $metaOut['meta']['email'];
  961. if (isset($meta['attachments'])) {
  962. $attachmentHtmlData = $meta['attachments'];
  963. $actualAttachmentInfo = array();
  964. $this->parseAttachmentInfo($actualAttachmentInfo, $attachmentHtmlData);
  965. if (sizeof($actualAttachmentInfo) > 0) {
  966. foreach($actualAttachmentInfo as $key => $value) {
  967. $info_vars = array();
  968. parse_str($value, $info_vars);
  969. $fileName = $info_vars['tempName'];
  970. $attachmentid = $info_vars['id'];
  971. $guid = create_guid();
  972. $destination = clean_path("{$this->userCacheDir}/{$guid}");
  973. $attachmentFilePath = sugar_cached("modules/Emails/{$ie->id}/attachments/{$attachmentid}");
  974. copy($attachmentFilePath, $destination);
  975. $ret['attachments'][$guid] = array();
  976. $ret['attachments'][$guid]['id'] = $guid . $fileName;
  977. $ret['attachments'][$guid]['filename'] = $fileName;
  978. } // for
  979. } // if
  980. } // if
  981. } // if
  982. return $ret;
  983. } // fn
  984. function parseAttachmentInfo(&$actualAttachmentInfo, $attachmentHtmlData) {
  985. $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
  986. while ($downLoadPHP) {
  987. $attachmentHtmlData = substr($attachmentHtmlData, $downLoadPHP+30);
  988. $final = strpos($attachmentHtmlData, "\">");
  989. $actualAttachmentInfo[] = substr($attachmentHtmlData, 0, $final);
  990. $attachmentHtmlData = substr($attachmentHtmlData, $final);
  991. $downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
  992. } // while
  993. }
  994. /**
  995. * Renders the QuickCreate form from Smarty and returns HTML
  996. * @param array $vars request variable global
  997. * @param object $email Fetched email object
  998. * @param bool $addToAddressBook
  999. * @return array
  1000. */
  1001. function getQuickCreateForm($vars, $email, $addToAddressBookButton=false) {
  1002. require_once("include/EditView/EditView2.php");
  1003. global $app_strings;
  1004. global $mod_strings;
  1005. global $current_user;
  1006. global $beanList;
  1007. global $beanFiles;
  1008. global $current_language;
  1009. //Setup the current module languge
  1010. $mod_strings = return_module_language($current_language, $_REQUEST['qc_module']);
  1011. $bean = $beanList[$_REQUEST['qc_module']];
  1012. $class = $beanFiles[$bean];
  1013. require_once($class);
  1014. $focus = new $bean();
  1015. $people = array(
  1016. 'Contact'
  1017. ,'Lead'
  1018. );
  1019. $emailAddress = array();
  1020. // people
  1021. if(in_array($bean, $people)) {
  1022. // lead specific
  1023. $focus->lead_source = 'Email';
  1024. $focus->lead_source_description = trim($email->name);
  1025. $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr;
  1026. if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail']))
  1027. $from = (isset($email->to_addrs_names) && !empty($email->to_addrs_names)) ? $email->to_addrs_names : $email->to_addrs;
  1028. $name = explode(" ", trim($from));
  1029. $address = trim(array_pop($name));
  1030. $address = str_replace(array("<",">","&lt;","&gt;"), "", $address);
  1031. $emailAddress[] = array(
  1032. 'email_address' => $address,
  1033. 'primary_address' => 1,
  1034. 'invalid_email' => 0,
  1035. 'opt_out' => 0,
  1036. 'reply_to_address' => 1
  1037. );
  1038. $focus->email1 = $address;
  1039. if(!empty($name)) {
  1040. $focus->last_name = trim(array_pop($name));
  1041. foreach($name as $first) {
  1042. if(!empty($focus->first_name)) {
  1043. $focus->first_name .= " ";
  1044. }
  1045. $focus->first_name .= trim($first);
  1046. }
  1047. }
  1048. } else {
  1049. // bugs, cases, tasks
  1050. $focus->name = trim($email->name);
  1051. }
  1052. $focus->description = trim(strip_tags($email->description));
  1053. $focus->assigned_user_id = $current_user->id;
  1054. $EditView = new EditView();
  1055. $EditView->ss = new Sugar_Smarty();
  1056. //MFH BUG#20283 - checks for custom quickcreate fields
  1057. $EditView->setup($_REQUEST['qc_module'], $focus, 'custom/modules/'.$focus->module_dir.'/metadata/editviewdefs.php', 'include/EditView/EditView.tpl');
  1058. $EditView->process();
  1059. $EditView->render();
  1060. $EditView->defs['templateMeta']['form']['buttons'] = array(
  1061. 'email2save' => array(
  1062. 'id' => 'e2AjaxSave',
  1063. 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_SAVE_BUTTON_LABEL']
  1064. . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(false);" />'
  1065. ),
  1066. 'email2saveandreply' => array(
  1067. 'id' => 'e2SaveAndReply',
  1068. 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_SAVE_AND_REPLY']
  1069. . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(\'reply\');" />'
  1070. ),
  1071. 'email2cancel' => array(
  1072. 'id' => 'e2cancel',
  1073. 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_CANCEL']
  1074. . ' " onclick="SUGAR.email2.detailView.quickCreateDialog.hide();" />'
  1075. )
  1076. );
  1077. if($addToAddressBookButton) {
  1078. $EditView->defs['templateMeta']['form']['buttons']['email2saveAddToAddressBook'] = array(
  1079. 'id' => 'e2addToAddressBook',
  1080. 'customCode' => '<input type="button" class="button" value=" '.$app_strings['LBL_EMAIL_ADDRESS_BOOK_SAVE_AND_ADD']
  1081. . ' " onclick="SUGAR.email2.detailView.saveQuickCreate(true);" />'
  1082. );
  1083. }
  1084. //Get the module language for javascript
  1085. if(!is_file(sugar_cached('jsLanguage/') . $_REQUEST['qc_module'] . '/' . $GLOBALS['current_language'] . '.js')) {
  1086. require_once('include/language/jsLanguage.php');
  1087. jsLanguage::createModuleStringsCache($_REQUEST['qc_module'], $GLOBALS['current_language']);
  1088. }
  1089. $jsLanguage = getVersionedScript("cache/jsLanguage/{$_REQUEST['qc_module']}/{$GLOBALS['current_language']}.js", $GLOBALS['sugar_config']['js_lang_version']);
  1090. $EditView->view = 'EmailQCView';
  1091. $EditView->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl';
  1092. $EditView->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl';
  1093. $meta = array();
  1094. $meta['html'] = $jsLanguage . $EditView->display(false, true);
  1095. $meta['html'] = str_replace("src='".getVersionedPath('include/SugarEmailAddress/SugarEmailAddress.js')."'", '', $meta['html']);
  1096. $meta['emailAddress'] = $emailAddress;
  1097. $mod_strings = return_module_language($current_language, 'Emails');
  1098. return $meta;
  1099. }
  1100. /**
  1101. * Renders the Import form from Smarty and returns HTML
  1102. * @param array $vars request variable global
  1103. * @param object $email Fetched email object
  1104. * @param bool $addToAddressBook
  1105. * @return array
  1106. */
  1107. function getImportForm($vars, $email, $formName = 'ImportEditView') {
  1108. require_once("include/EditView/EditView2.php");
  1109. require_once("include/TemplateHandler/TemplateHandler.php");
  1110. require_once('include/QuickSearchDefaults.php');
  1111. $qsd = QuickSearchDefaults::getQuickSearchDefaults();
  1112. $qsd->setFormName($formName);
  1113. global $app_strings;
  1114. global $current_user;
  1115. global $app_list_strings;
  1116. $sqs_objects = array(
  1117. "{$formName}_parent_name" => $qsd->getQSParent(),
  1118. );
  1119. $smarty = new Sugar_Smarty();
  1120. $smarty->assign("APP",$app_strings);
  1121. $smarty->assign('formName',$formName);
  1122. $showAssignTo = false;
  1123. if (!isset($vars['showAssignTo']) || $vars['showAssignTo'] == true) {
  1124. $showAssignTo = true;
  1125. } // if
  1126. if ($showAssignTo) {
  1127. if(empty($email->assigned_user_id) && empty($email->id))
  1128. $email->assigned_user_id = $current_user->id;
  1129. if(empty($email->assigned_name) && empty($email->id))
  1130. $email->assigned_user_name = $current_user->user_name;
  1131. $sqs_objects["{$formName}_assigned_user_name"] = $qsd->getQSUser();
  1132. }
  1133. $smarty->assign("showAssignedTo",$showAssignTo);
  1134. $showDelete = false;
  1135. if (!isset($vars['showDelete']) || $vars['showDelete'] == true) {
  1136. $showDelete = true;
  1137. }
  1138. $smarty->assign("showDelete",$showDelete);
  1139. $smarty->assign("userId",$email->assigned_user_id);
  1140. $smarty->assign("userName",$email->assigned_user_name);
  1141. $parent_types = $app_list_strings['record_type_display'];
  1142. $smarty->assign('parentOptions', get_select_options_with_id($parent_types, $email->parent_type));
  1143. $quicksearch_js = '<script type="text/javascript" language="javascript">sqs_objects = ' . json_encode($sqs_objects) . '</script>';
  1144. $smarty->assign('SQS', $quicksearch_js);
  1145. $meta = array();
  1146. $meta['html'] = $smarty->fetch("modules/Emails/templates/importRelate.tpl");
  1147. return $meta;
  1148. }
  1149. /**
  1150. * This function returns the detail view for email in new 2.0 interface
  1151. *
  1152. */
  1153. function getDetailViewForEmail2($emailId) {
  1154. require_once('include/DetailView/DetailView.php');
  1155. global $app_strings, $app_list_strings;
  1156. global $mod_strings;
  1157. $smarty = new Sugar_Smarty();
  1158. // SETTING DEFAULTS
  1159. $focus = new Email();
  1160. $focus->retrieve($emailId);
  1161. $detailView->ss = new Sugar_Smarty();
  1162. $detailView = new DetailView();
  1163. $title = "";
  1164. $offset = 0;
  1165. if($focus->type == 'out') {
  1166. $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true);
  1167. } elseif ($focus->type == 'draft') {
  1168. $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true);
  1169. } elseif($focus->type == 'inbound') {
  1170. $title = getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true);
  1171. }
  1172. $smarty->assign("emailTitle", $title);
  1173. // DEFAULT TO TEXT IF NO HTML CONTENT:
  1174. $html = trim(from_html($focus->description_html));
  1175. if(empty($html)) {
  1176. $smarty->assign('SHOW_PLAINTEXT', 'true');
  1177. } else {
  1178. $smarty->assign('SHOW_PLAINTEXT', 'false');
  1179. }
  1180. //if not empty or set to test (from test campaigns)
  1181. if (!empty($focus->parent_type) && $focus->parent_type !='test') {
  1182. $smarty->assign('PARENT_MODULE', $focus->parent_type);
  1183. $smarty->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ":");
  1184. }
  1185. global $gridline;
  1186. $smarty->assign('MOD', $mod_strings);
  1187. $smarty->assign('APP', $app_strings);
  1188. $smarty->assign('GRIDLINE', $gridline);
  1189. $smarty->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']);
  1190. $smarty->assign('ID', $focus->id);
  1191. $smarty->assign('TYPE', $focus->type);
  1192. $smarty->assign('PARENT_NAME', $focus->parent_name);
  1193. $smarty->assign('PARENT_ID', $focus->parent_id);
  1194. $smarty->assign('NAME', $focus->name);
  1195. $smarty->assign('ASSIGNED_TO', $focus->assigned_user_name);
  1196. $smarty->assign('DATE_MODIFIED', $focus->date_modified);
  1197. $smarty->assign('DATE_ENTERED', $focus->date_entered);
  1198. $smarty->assign('DATE_START', $focus->date_start);
  1199. $smarty->assign('TIME_START', $focus->time_start);
  1200. $smarty->assign('FROM', $focus->from_addr);
  1201. $smarty->assign('TO', nl2br($focus->to_addrs));
  1202. $smarty->assign('CC', nl2br($focus->cc_addrs));
  1203. $smarty->assign('BCC', nl2br($focus->bcc_addrs));
  1204. $smarty->assign('CREATED_BY', $focus->created_by_name);
  1205. $smarty->assign('MODIFIED_BY', $focus->modified_by_name);
  1206. $smarty->assign('DATE_SENT', $focus->date_entered);
  1207. $smarty->assign('EMAIL_NAME', 'RE: '.$focus->name);
  1208. $smarty->assign("TAG", $focus->listviewACLHelper());
  1209. $smarty->assign("SUGAR_VERSION", $GLOBALS['sugar_version']);
  1210. $smarty->assign("JS_CUSTOM_VERSION", $GLOBALS['sugar_config']['js_custom_version']);
  1211. if(!empty($focus->reply_to_email)) {
  1212. $replyTo = "
  1213. <tr>
  1214. <td class=\"tabDetailViewDL\"><slot>".$mod_strings['LBL_REPLY_TO_NAME']."</slot></td>
  1215. <td colspan=3 class=\"tabDetailViewDF\"><slot>".$focus->reply_to_addr."</slot></td>
  1216. </tr>";
  1217. $smarty->assign("REPLY_TO", $replyTo);
  1218. }
  1219. ///////////////////////////////////////////////////////////////////////////////
  1220. //// JAVASCRIPT VARS
  1221. $jsVars = '';
  1222. $jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';";
  1223. $jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';";
  1224. $smarty->assign("JS_VARS", $jsVars);
  1225. ///////////////////////////////////////////////////////////////////////////////
  1226. //// NOTES (attachements, etc.)
  1227. ///////////////////////////////////////////////////////////////////////////////
  1228. $note = new Note();
  1229. $where = "notes.parent_id='{$focus->id}'";
  1230. //take in account if this is from campaign and the template id is stored in the macros.
  1231. if(isset($macro_values) && isset($macro_values['email_template_id'])){
  1232. $where = "notes.parent_id='{$macro_values['email_template_id']}'";
  1233. }
  1234. $notes_list = $note->get_full_list("notes.name", $where, true);
  1235. if(! isset($notes_list)) {
  1236. $notes_list = array();
  1237. }
  1238. $attachments = '';
  1239. for($i=0; $i<count($notes_list); $i++) {
  1240. $the_note = $notes_list[$i];
  1241. $attachments .= "<a href=\"index.php?entryPoint=download&id={$the_note->id}&type=Notes\">".$the_note->name."</a><br />";
  1242. $focus->cid2Link($the_note->id, $the_note->file_mime_type);
  1243. }
  1244. $smarty->assign('DESCRIPTION', nl2br($focus->description));
  1245. $smarty->assign('DESCRIPTION_HTML', from_html($focus->description_html));
  1246. $smarty->assign("ATTACHMENTS", $attachments);
  1247. ///////////////////////////////////////////////////////////////////////////////
  1248. //// SUBPANELS
  1249. ///////////////////////////////////////////////////////////////////////////////
  1250. $show_subpanels = true;
  1251. if ($show_subpanels) {
  1252. require_once('include/SubPanel/SubPanelTiles.php');
  1253. $subpanel = new SubPanelTiles($focus, 'Emails');
  1254. $smarty->assign("SUBPANEL", $subpanel->display());
  1255. }
  1256. $meta['html'] = $smarty->fetch("modules/Emails/templates/emailDetailView.tpl");
  1257. return $meta;
  1258. } // fn
  1259. /**
  1260. * Sets the "read" flag in the overview cache
  1261. */
  1262. function setReadFlag($ieId, $mbox, $uid) {
  1263. $this->markEmails('read', $ieId, $mbox, $uid);
  1264. }
  1265. /**
  1266. * Marks emails with the passed flag type. This will be applied to local
  1267. * cache files as well as remote emails.
  1268. * @param string $type Flag type
  1269. * @param string $ieId
  1270. * @param string $folder IMAP folder structure or SugarFolder GUID
  1271. * @param string $uids Comma sep list of UIDs or GUIDs
  1272. */
  1273. function markEmails($type, $ieId, $folder, $uids) {
  1274. global $app_strings;
  1275. $uids = $this->_cleanUIDList($uids);
  1276. $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
  1277. if(strpos($folder, 'sugar::') !== false) {
  1278. // dealing with a sugar email object, uids are GUIDs
  1279. foreach($exUids as $id) {
  1280. $email = new Email();
  1281. $email->retrieve($id);
  1282. // BUG FIX BEGIN
  1283. // Bug 50973 - marking unread in group inbox removes message
  1284. if (empty($email->assigned_user_id))
  1285. {
  1286. $email->setFieldNullable('assigned_user_id');
  1287. }
  1288. // BUG FIX END
  1289. switch($type) {
  1290. case "unread":
  1291. $email->status = 'unread';
  1292. $email->save();
  1293. break;
  1294. case "read":
  1295. $email->status = 'read';
  1296. $email->save();
  1297. break;
  1298. case "deleted":
  1299. $email->delete();
  1300. break;
  1301. case "flagged":
  1302. $email->flagged = 1;
  1303. $email->save();
  1304. break;
  1305. case "unflagged":
  1306. $email->flagged = 0;
  1307. $email->save();
  1308. break;
  1309. }
  1310. // BUG FIX BEGIN
  1311. // Bug 50973 - reset assigned_user_id field defs
  1312. if (empty($email->assigned_user_id))
  1313. {
  1314. $email->revertFieldNullable('assigned_user_id');
  1315. }
  1316. // BUG FIX END
  1317. }
  1318. } else {
  1319. /* dealing with IMAP email, uids are IMAP uids */
  1320. global $ie; // provided by EmailUIAjax.php
  1321. if(empty($ie)) {
  1322. $ie = new InboundEmail();
  1323. }
  1324. $ie->retrieve($ieId);
  1325. $ie->mailbox = $folder;
  1326. $ie->connectMailserver();
  1327. // mark cache files
  1328. if($type == 'deleted') {
  1329. $ie->deleteMessageOnMailServer($uids);
  1330. $ie->deleteMessageFromCache($uids);
  1331. } else {
  1332. $overviews = $ie->getCacheValueForUIDs($ie->mailbox, $exUids);
  1333. $manipulated = array();
  1334. foreach($overviews['retArr'] as $k => $overview) {
  1335. if(in_array($overview->uid, $exUids)) {
  1336. switch($type) {
  1337. case "unread":
  1338. $overview->seen = 0;
  1339. break;
  1340. case "read":
  1341. $overview->seen = 1;
  1342. break;
  1343. case "flagged":
  1344. $overview->flagged = 1;
  1345. break;
  1346. case "unflagged":
  1347. $overview->flagged = 0;
  1348. break;
  1349. }
  1350. $manipulated[] = $overview;
  1351. }
  1352. }
  1353. if(!empty($manipulated)) {
  1354. $ie->setCacheValue($ie->mailbox, array(), $manipulated);
  1355. /* now mark emails on email server */
  1356. $ie->markEmails(implode(",", explode($app_strings['LBL_EMAIL_DELIMITER'], $uids)), $type);
  1357. }
  1358. } // end not type == deleted
  1359. }
  1360. }
  1361. function doAssignment($distributeMethod, $ieid, $folder, $uids, $users) {
  1362. global $app_strings;
  1363. $users = explode(",", $users);
  1364. $emailIds = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
  1365. $out = "";
  1366. if($folder != 'sugar::Emails') {
  1367. $emailIds = array();
  1368. $uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
  1369. $ie = new InboundEmail();
  1370. $ie->retrieve($ieid);
  1371. $messageIndex = 1;
  1372. // dealing with an inbound email data so we need to import an email and then
  1373. foreach($uids as $uid) {
  1374. $ie->mailbox = $folder;
  1375. $ie->connectMailserver();
  1376. $msgNo = $uid;
  1377. if (!$ie->isPop3Protocol()) {
  1378. $msgNo = imap_msgno($ie->conn, $uid);
  1379. } else {
  1380. $msgNo = $ie->getCorrectMessageNoForPop3($uid);
  1381. }
  1382. if(!empty($msgNo)) {
  1383. if ($ie->importOneEmail($msgNo, $uid)) {
  1384. $emailIds[] = $ie->email->id;
  1385. $ie->deleteMessageOnMailServer($uid);
  1386. //$ie->retrieve($ieid);
  1387. //$ie->connectMailserver();
  1388. $ie->mailbox = $folder;
  1389. $ie->deleteMessageFromCache(($uids[] = $uid));
  1390. } else {
  1391. $out = $out . "Message No : " . $messageIndex . " failed. Reason : Message already imported \r\n";
  1392. }
  1393. }
  1394. $messageIndex++;
  1395. } // for
  1396. } // if
  1397. if (count($emailIds) > 0) {
  1398. $this->doDistributionWithMethod($users, $emailIds, $distributeMethod);
  1399. } // if
  1400. return $out;
  1401. } // fn
  1402. /**
  1403. * get team id and team set id from request
  1404. * @return array
  1405. */
  1406. function getTeams() {
  1407. }
  1408. function doDistributionWithMethod($users, $emailIds, $distributionMethod) {
  1409. // we have users and the items to distribute
  1410. if($distributionMethod == 'roundRobin') {
  1411. $this->distRoundRobin($users, $emailIds);
  1412. } elseif($distributionMethod == 'leastBusy') {
  1413. $this->distLeastBusy($users, $emailIds);
  1414. } elseif($distributionMethod == 'direct') {
  1415. if(count($users) > 1) {
  1416. // only 1 user allowed in direct assignment
  1417. $error = 1;
  1418. } else {
  1419. $user = $users[0];
  1420. $this->distDirect($user, $emailIds);
  1421. } // else
  1422. } // elseif
  1423. } // fn
  1424. /**
  1425. * distributes emails to users on Round Robin basis
  1426. * @param $userIds array of users to dist to
  1427. * @param $mailIds array of email ids to push on those users
  1428. * @return boolean true on success
  1429. */
  1430. function distRoundRobin($userIds, $mailIds) {
  1431. // check if we have a 'lastRobin'
  1432. $lastRobin = $userIds[0];
  1433. foreach($mailIds as $k => $mailId) {
  1434. $userIdsKeys = array_flip($userIds); // now keys are values
  1435. $thisRobinKey = $userIdsKeys[$lastRobin] + 1;
  1436. if(!empty($userIds[$thisRobinKey])) {
  1437. $thisRobin = $userIds[$thisRobinKey];
  1438. $lastRobin = $userIds[$thisRobinKey];
  1439. } else {
  1440. $thisRobin = $userIds[0];
  1441. $lastRobin = $userIds[0];
  1442. }
  1443. $email = new Email();
  1444. $email->retrieve($mailId);
  1445. $email->assigned_user_id = $thisRobin;
  1446. $email->status = 'unread';
  1447. $email->save();
  1448. }
  1449. return true;
  1450. }
  1451. /**
  1452. * distributes emails to users on Least Busy basis
  1453. * @param $userIds array of users to dist to
  1454. * @param $mailIds array of email ids to push on those users
  1455. * @return boolean true on success
  1456. */
  1457. function distLeastBusy($userIds, $mailIds) {
  1458. foreach($mailIds as $k => $mailId) {
  1459. $email = new Email();
  1460. $email->retrieve($mailId);
  1461. foreach($userIds as $k => $id) {
  1462. $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '.$id.' AND status = 'unread'");
  1463. $a = $this->db->fetchByAssoc($r);
  1464. $counts[$id] = $a['c'];
  1465. }
  1466. asort($counts); // lowest to highest
  1467. $countsKeys = array_flip($counts); // keys now the 'count of items'
  1468. $leastBusy = array_shift($countsKeys); // user id of lowest item count
  1469. $email->assigned_user_id = $leastBusy;
  1470. $email->status = 'unread';
  1471. $email->save();
  1472. }
  1473. return true;
  1474. }
  1475. /**
  1476. * distributes emails to 1 user
  1477. * @param $user users to dist to
  1478. * @param $mailIds array of email ids to push
  1479. * @return boolean true on success
  1480. */
  1481. function distDirect($user, $mailIds) {
  1482. foreach($mailIds as $k => $mailId) {
  1483. $email = new Email();
  1484. $email->retrieve($mailId);
  1485. $email->assigned_user_id = $user;
  1486. $email->status = 'unread';
  1487. $email->save();
  1488. }
  1489. return true;
  1490. }
  1491. function getAssignedEmailsCountForUsers($userIds) {
  1492. $counts = array();
  1493. foreach($userIds as $id) {
  1494. $r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '$id' AND status = 'unread'");
  1495. $a = $this->db->fetchByAssoc($r);
  1496. $counts[$id] = $a['c'];
  1497. } // foreach
  1498. return $counts;
  1499. } // fn
  1500. function getLastRobin($ie) {
  1501. $lastRobin = "";
  1502. if($this->validCacheFileExists($ie->id, 'folders', "robin.cache.php")) {
  1503. $lastRobin = $this->getCacheValue($ie->id, 'folders', "robin.cache.php", 'robin');
  1504. } // if
  1505. return $lastRobin;
  1506. } // fn
  1507. function setLastRobin($ie, $lastRobin) {
  1508. global $sugar_config;
  1509. $cacheFolderPath = sugar_cached("modules/Emails/{$ie->id}/folders");
  1510. if (!file_exists($cacheFolderPath)) {
  1511. mkdir_recursive($cacheFolderPath);
  1512. }
  1513. $this->writeCacheFile('robin', $lastRobin, $ie->id, 'folders', "robin.cache.php");
  1514. } // fn
  1515. /**
  1516. * returns the metadata defining a single email message for display. Uses cache file if it exists
  1517. * @return array
  1518. */
  1519. function getSingleMessage($ie) {
  1520. global $timedate;
  1521. global $app_strings,$mod_strings;
  1522. $ie->retrieve($_REQUEST['ieId']);
  1523. $noCache = true;
  1524. $ie->mailbox = $_REQUEST['mbox'];
  1525. $filename = $_REQUEST['mbox'].$_REQUEST['uid'].".php";
  1526. $md5uidl = "";
  1527. if ($ie->isPop3Protocol()) {
  1528. $md5uidl = md5($_REQUEST['uid']);
  1529. $filename = $_REQUEST['mbox'].$md5uidl.".php";
  1530. } // if
  1531. if($this->validCacheFileExists($_REQUEST['ieId'], 'messages', $filename)) {
  1532. $out = $this->getCacheValue($_REQUEST['ieId'], 'messages', $filename, 'out');
  1533. $noCache = false;
  1534. // something fubar'd the cache?
  1535. if(empty($out['meta']['email']['name']) && empty($out['meta']['email']['description'])) {
  1536. $noCache = true;
  1537. } else {
  1538. // When sending data from cache, convert date into users preffered format
  1539. $dateTimeInGMTFormat = $out['meta']['email']['date_start'];
  1540. $out['meta']['email']['date_start'] = $timedate->to_display_date_time($dateTimeInGMTFormat);
  1541. } // else
  1542. }
  1543. if($noCache) {
  1544. $writeToCacheFile = true;
  1545. if ($ie->isPop3Protocol()) {
  1546. $status = $ie->setEmailForDisplay($_REQUEST['uid'], true, true, true);
  1547. } else {
  1548. $status = $ie->setEmailForDisplay($_REQUEST['uid'], false, true, true);
  1549. }
  1550. $out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']);
  1551. // modify the out object to store date in GMT format on the local cache file
  1552. $dateTimeInUserFormat = $out['meta']['email']['date_start'];
  1553. $out['meta']['email']['date_start'] = $timedate->to_db($dateTimeInUserFormat);
  1554. if ($status == 'error') {
  1555. $writeToCacheFile = false;
  1556. }
  1557. if ($writeToCacheFile) {
  1558. if ($ie->isPop3Protocol()) {
  1559. $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$md5uidl}.php");
  1560. } else {
  1561. $this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$_REQUEST['uid']}.php");
  1562. } // else
  1563. // restore date in the users preferred format to be send on to UI for diaply
  1564. $out['meta']['email']['date_start'] = $dateTimeInUserFormat;
  1565. } // if
  1566. }
  1567. $out['meta']['email']['toaddrs'] = $this->generateExpandableAddrs($out['meta']['email']['toaddrs']);
  1568. if(!empty($out['meta']['email']['cc_addrs'])) {
  1569. $ccs = $this->generateExpandableAddrs($out['meta']['email']['cc_addrs']);
  1570. $out['meta']['cc'] = <<<eoq
  1571. <tr>
  1572. <td NOWRAP valign="top" class="displayEmailLabel">
  1573. {$app_strings['LBL_EMAIL_CC']}:
  1574. </td>
  1575. <td class="displayEmailValue">
  1576. {$ccs}
  1577. </td>
  1578. </tr>
  1579. eoq;
  1580. }
  1581. if(empty($out['meta']['email']['description']))
  1582. $out['meta']['email']['description'] = $mod_strings['LBL_EMPTY_EMAIL_BODY'];
  1583. if($noCache) {
  1584. $GLOBALS['log']->debug("EMAILUI: getSingleMessage() NOT using cache file");
  1585. } else {
  1586. $GLOBALS['log']->debug("EMAILUI: getSingleMessage() using cache file [ ".$_REQUEST['mbox'].$_REQUEST['uid'].".php ]");
  1587. }
  1588. $this->setReadFlag($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['uid']);
  1589. return $out;
  1590. }
  1591. /**
  1592. * Returns the HTML for a list of emails in a given folder
  1593. * @param GUID $ieId GUID to InboundEmail instance
  1594. * @param string $mbox Mailbox path name in dot notation
  1595. * @param int $folderListCacheOffset Seconds for valid cache file
  1596. * @return string HTML render of list.
  1597. */
  1598. function getListEmails($ieId, $mbox, $folderListCacheOffset, $forceRefresh='false') {
  1599. global $sugar_config;
  1600. $ie = new InboundEmail();
  1601. $ie->retrieve($ieId);
  1602. $list = $ie->displayFolderContents($mbox, $forceRefresh);
  1603. return $list;
  1604. }
  1605. /**
  1606. * Returns the templatized compose screen. Used by reply, forwards and draft status messages.
  1607. * @param object email Email bean in focus
  1608. */
  1609. function displayComposeEmail($email) {
  1610. global $locale;
  1611. global $current_user;
  1612. $ea = new SugarEmailAddress();
  1613. if(!empty($email)) {
  1614. $email->cids2Links();
  1615. $description = (empty($email->description_html)) ? $email->description : $email->description_html;
  1616. }
  1617. //Get the most complete address list availible for this email
  1618. $addresses = array('toAddresses' => 'to', 'ccAddresses' => 'cc', 'bccAddresses' => 'bcc');
  1619. foreach($addresses as $var => $type)
  1620. {
  1621. $$var = "";
  1622. foreach (array("{$type}_addrs_names", "{$type}addrs", "{$type}_addrs") as $emailVar)
  1623. {
  1624. if (!empty($email->$emailVar)) {
  1625. $$var = $email->$emailVar;
  1626. break;
  1627. }
  1628. }
  1629. }
  1630. $ret = array();
  1631. $ret['type'] = $email->type;
  1632. $ret['name'] = $email->name;
  1633. $ret['description'] = $description;
  1634. $ret['from'] = (isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'forward') ? "" : $email->from_addr;
  1635. $ret['to'] = from_html($toAddresses);
  1636. $ret['uid'] = $email->id;
  1637. $ret['parent_name'] = $email->parent_name;
  1638. $ret['parent_type'] = $email->parent_type;
  1639. $ret['parent_id'] = $email->parent_id;
  1640. // reply all
  1641. if(isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'replyAll') {
  1642. $ret['cc'] = from_html($ccAddresses);
  1643. $ret['bcc'] = $bccAddresses;
  1644. $userEmails = array();
  1645. $userEmailsMeta = $ea->getAddressesByGUID($current_user->id, 'Users');
  1646. foreach($userEmailsMeta as $emailMeta) {
  1647. $userEmails[] = from_html(strtolower(trim($emailMeta['email_address'])));
  1648. }
  1649. $userEmails[] = from_html(strtolower(trim($email->from_addr)));
  1650. $ret['cc'] = from_html($email->cc_addrs);
  1651. $toAddresses = from_html($toAddresses);
  1652. $to = str_replace($this->addressSeparators, "::", $toAddresses);
  1653. $exTo = explode("::", $to);
  1654. if(is_array($exTo)) {
  1655. foreach($exTo as $addr) {
  1656. $addr = strtolower(trim($addr));
  1657. if(!in_array($addr, $userEmails)) {
  1658. if(!empty($ret['cc'])) {
  1659. $ret['cc'] = $ret['cc'].", ";
  1660. }
  1661. $ret['cc'] = $ret['cc'].trim($addr);
  1662. }
  1663. }
  1664. } elseif(!empty($exTo)) {
  1665. $exTo = trim($exTo);
  1666. if(!in_array($exTo, $userEmails)) {
  1667. $ret['cc'] = $ret['cc'].", ".$exTo;
  1668. }
  1669. }
  1670. }
  1671. return $ret;
  1672. }
  1673. /**
  1674. * Formats email body on reply/forward
  1675. * @param object email Email object in focus
  1676. * @param string type
  1677. * @return object email
  1678. */
  1679. function handleReplyType($email, $type) {
  1680. global $mod_strings;
  1681. $GLOBALS['log']->debug("****At Handle Reply Type: $type");
  1682. switch($type) {
  1683. case "reply":
  1684. case "replyAll":
  1685. $header = $email->getReplyHeader();
  1686. if(!preg_match('/^(re:)+/i', $email->name)) {
  1687. $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
  1688. }
  1689. if ($type == "reply") {
  1690. $email->cc_addrs = "";
  1691. if (!empty($email->reply_to_addr)) {
  1692. $email->from_addr = $email->reply_to_addr;
  1693. } // if
  1694. } else {
  1695. if (!empty($email->reply_to_addr)) {
  1696. $email->to_addrs = $email->to_addrs . "," . $email->reply_to_addr;
  1697. } // if
  1698. } // else
  1699. break;
  1700. case "forward":
  1701. $header = $email->getForwardHeader();
  1702. if(!preg_match('/^(fw:)+/i', $email->name)) {
  1703. $email->name = "{$mod_strings['LBL_FW']} {$email->name}";
  1704. }
  1705. $email->cc_addrs = "";
  1706. break;
  1707. case "replyCase":
  1708. $GLOBALS['log']->debug("EMAILUI: At reply case");
  1709. $header = $email->getReplyHeader();
  1710. $myCase = new aCase();
  1711. $myCase->retrieve($email->parent_id);
  1712. $myCaseMacro = $myCase->getEmailSubjectMacro();
  1713. $email->parent_name = $myCase->name;
  1714. $GLOBALS['log']->debug("****Case # : {$myCase->case_number} macro: $myCaseMacro");
  1715. if(!strpos($email->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) {
  1716. $GLOBALS['log']->debug("Replacing");
  1717. $email->name = str_replace('%1',$myCase->case_number,$myCaseMacro) . ' '. $email->name;
  1718. }
  1719. $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
  1720. break;
  1721. }
  1722. $html = trim($email->description_html);
  1723. $plain = trim($email->description);
  1724. $desc = (!empty($html)) ? $html : $plain;
  1725. $email->description = $header.$email->quoteHtmlEmailForNewEmailUI($desc);
  1726. return $email;
  1727. }
  1728. ///////////////////////////////////////////////////////////////////////////
  1729. //// PRIVATE HELPERS
  1730. /**
  1731. * Generates a UNION query to get one list of users, contacts, leads, and
  1732. * prospects; used specifically for the addressBook
  1733. */
  1734. function _getPeopleUnionQuery($whereArr , $person) {
  1735. global $current_user , $app_strings;
  1736. global $db;
  1737. if(!isset($person) || $person === 'LBL_DROPDOWN_LIST_ALL'){
  1738. $peopleTables = array("users",
  1739. "contacts",
  1740. "leads",
  1741. "prospects",
  1742. "accounts"
  1743. );
  1744. }else{
  1745. $peopleTables = array($person);
  1746. }
  1747. $q = '';
  1748. $whereAdd = "";
  1749. foreach($whereArr as $column => $clause) {
  1750. if(!empty($whereAdd)) {
  1751. $whereAdd .= " AND ";
  1752. }
  1753. $clause = $current_user->db->quote($clause);
  1754. $whereAdd .= "{$column} LIKE '{$clause}%'";
  1755. }
  1756. foreach($peopleTables as $table) {
  1757. $module = ucfirst($table);
  1758. $class = substr($module, 0, strlen($module) - 1);
  1759. require_once("modules/{$module}/{$class}.php");
  1760. $person = new $class();
  1761. if (!$person->ACLAccess('list')) {
  1762. continue;
  1763. } // if
  1764. $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id <> '{$current_user->id}')";
  1765. if (ACLController::requireOwner($module, 'list')) {
  1766. $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
  1767. } // if
  1768. if(!empty($whereAdd)) {
  1769. $where .= " AND ({$whereAdd})";
  1770. }
  1771. if ($person === 'accounts') {
  1772. $t = "SELECT {$table}.id, '' first_name, {$table}.name, eabr.primary_address, ea.email_address, '{$module}' module ";
  1773. } else {
  1774. $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
  1775. }
  1776. $t .= "FROM {$table} ";
  1777. $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
  1778. $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
  1779. $t .= " WHERE {$where}";
  1780. if(!empty($q)) {
  1781. $q .= "\n UNION ALL \n";
  1782. }
  1783. $q .= "({$t})";
  1784. }
  1785. $countq = "SELECT count(people.id) c from ($q) people";
  1786. $q .= "ORDER BY last_name";
  1787. return array('query' => $q, 'countQuery' => $countq);
  1788. }
  1789. /**
  1790. * get emails of related bean for a given bean id
  1791. * @param $beanType
  1792. * @param $condition array of conditions inclued bean id
  1793. * @return array('query' => $q, 'countQuery' => $countq);
  1794. */
  1795. function getRelatedEmail($beanType, $whereArr, $relatedBeanInfoArr = ''){
  1796. global $beanList, $current_user, $app_strings, $db;
  1797. $finalQuery = '';
  1798. $searchBeans = null;
  1799. if($beanType === 'LBL_DROPDOWN_LIST_ALL')
  1800. $searchBeans = array("users",
  1801. "contacts",
  1802. "leads",
  1803. "prospects",
  1804. "accounts"
  1805. );
  1806. if ($relatedBeanInfoArr == '' || empty($relatedBeanInfoArr['related_bean_type']) )
  1807. {
  1808. if ($searchBeans != null)
  1809. {
  1810. $q = array();
  1811. foreach ($searchBeans as $searchBean)
  1812. {
  1813. $searchq = $this->findEmailFromBeanIds('', $searchBean, $whereArr);
  1814. if(!empty($searchq)) {
  1815. $q[] = "($searchq)";
  1816. }
  1817. }
  1818. if (!empty($q))
  1819. $finalQuery .= implode("\n UNION ALL \n", $q);
  1820. }
  1821. else
  1822. $finalQuery = $this->findEmailFromBeanIds('', $beanType, $whereArr);
  1823. }
  1824. else
  1825. {
  1826. $class = $beanList[$relatedBeanInfoArr['related_bean_type']];
  1827. $focus = new $class();
  1828. $focus->retrieve($relatedBeanInfoArr['related_bean_id']);
  1829. if ($searchBeans != null)
  1830. {
  1831. $q = array();
  1832. foreach ($searchBeans as $searchBean)
  1833. {
  1834. if ($focus->load_relationship($searchBean))
  1835. {
  1836. $data = $focus->$searchBean->get();
  1837. if (count($data) != 0)
  1838. $q[] = '('.$this->findEmailFromBeanIds($data, $searchBean, $whereArr).')';
  1839. }
  1840. }
  1841. if (!empty($q))
  1842. $finalQuery .= implode("\n UNION ALL \n", $q);
  1843. }
  1844. else
  1845. {
  1846. if ($focus->load_relationship($beanType))
  1847. {
  1848. $data = $focus->$beanType->get();
  1849. if (count($data) != 0)
  1850. $finalQuery = $this->findEmailFromBeanIds($data, $beanType, $whereArr);
  1851. }
  1852. }
  1853. }
  1854. $countq = "SELECT count(people.id) c from ($finalQuery) people";
  1855. return array('query' => $finalQuery, 'countQuery' => $countq);
  1856. }
  1857. function findEmailFromBeanIds($beanIds, $beanType, $whereArr) {
  1858. global $current_user;
  1859. $q = '';
  1860. $whereAdd = "";
  1861. $relatedIDs = '';
  1862. if ($beanIds != '') {
  1863. foreach ($beanIds as $key => $value) {
  1864. $beanIds[$key] = '\''.$value.'\'';
  1865. }
  1866. $relatedIDs = implode(',', $beanIds);
  1867. }
  1868. if ($beanType == 'accounts') {
  1869. if (isset($whereArr['first_name'])) {
  1870. $whereArr['name'] = $whereArr['first_name'];
  1871. }
  1872. unset($whereArr['last_name']);
  1873. unset($whereArr['first_name']);
  1874. }
  1875. foreach($whereArr as $column => $clause) {
  1876. if(!empty($whereAdd)) {
  1877. $whereAdd .= " OR ";
  1878. }
  1879. $clause = $current_user->db->quote($clause);
  1880. $whereAdd .= "{$column} LIKE '{$clause}%'";
  1881. }
  1882. $table = $beanType;
  1883. $module = ucfirst($table);
  1884. $class = substr($module, 0, strlen($module) - 1);
  1885. require_once("modules/{$module}/{$class}.php");
  1886. $person = new $class();
  1887. if ($person->ACLAccess('list')) {
  1888. if ($relatedIDs != '') {
  1889. $where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id in ($relatedIDs))";
  1890. } else {
  1891. $where = "({$table}.deleted = 0 AND eabr.primary_address = 1)";
  1892. }
  1893. if (ACLController::requireOwner($module, 'list')) {
  1894. $where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
  1895. } // if
  1896. if(!empty($whereAdd)) {
  1897. $where .= " AND ({$whereAdd})";
  1898. }
  1899. if ($beanType === 'accounts') {
  1900. $t = "SELECT {$table}.id, '' first_name, {$table}.name last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
  1901. } else {
  1902. $t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
  1903. }
  1904. $t .= "FROM {$table} ";
  1905. $t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
  1906. $t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
  1907. $t .= " WHERE {$where}";
  1908. } // if
  1909. return $t;
  1910. }
  1911. /**
  1912. * Cleans UID lists
  1913. * @param mixed $uids
  1914. * @param bool $returnString False will return an array
  1915. * @return mixed
  1916. */
  1917. function _cleanUIDList($uids, $returnString=false) {
  1918. global $app_strings;
  1919. $GLOBALS['log']->debug("_cleanUIDList: before - [ {$uids} ]");
  1920. if(!is_array($uids)) {
  1921. $returnString = true;
  1922. $exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
  1923. $uids = $exUids;
  1924. }
  1925. $cleanUids = array();
  1926. foreach($uids as $uid) {
  1927. $cleanUids[$uid] = $uid;
  1928. }
  1929. sort($cleanUids);
  1930. if($returnString) {
  1931. $cleanImplode = implode($app_strings['LBL_EMAIL_DELIMITER'], $cleanUids);
  1932. $GLOBALS['log']->debug("_cleanUIDList: after - [ {$cleanImplode} ]");
  1933. return $cleanImplode;
  1934. }
  1935. return $cleanUids;
  1936. }
  1937. /**
  1938. * Creates defaults for the User
  1939. * @param object $user User in focus
  1940. */
  1941. function preflightUser(&$user) {
  1942. global $mod_strings;
  1943. $goodToGo = $user->getPreference("email2Preflight", "Emails");
  1944. $q = "SELECT count(*) count FROM folders f where f.created_by = '{$user->id}' AND f.folder_type = 'inbound' AND f.deleted = 0";
  1945. $r = $user->db->query($q);
  1946. $a = $user->db->fetchByAssoc($r);
  1947. if($a['count'] < 1) {
  1948. require_once("include/SugarFolders/SugarFolders.php");
  1949. // My Emails
  1950. $folder = new SugarFolder();
  1951. $folder->new_with_id = true;
  1952. $folder->id = create_guid();
  1953. $folder->name = $mod_strings['LNK_MY_INBOX'];
  1954. $folder->has_child = 1;
  1955. $folder->created_by = $user->id;
  1956. $folder->modified_by = $user->id;
  1957. $folder->is_dynamic = 1;
  1958. $folder->folder_type = "inbound";
  1959. $folder->dynamic_query = $this->generateDynamicFolderQuery('inbound', $user->id);
  1960. $folder->save();
  1961. // My Drafts
  1962. $drafts = new SugarFolder();
  1963. $drafts->name = $mod_strings['LNK_MY_DRAFTS'];
  1964. $drafts->has_child = 0;
  1965. $drafts->parent_folder = $folder->id;
  1966. $drafts->created_by = $user->id;
  1967. $drafts->modified_by = $user->id;
  1968. $drafts->is_dynamic = 1;
  1969. $drafts->folder_type = "draft";
  1970. $drafts->dynamic_query = $this->generateDynamicFolderQuery('draft', $user->id);
  1971. $drafts->save();
  1972. // Sent Emails
  1973. $archived = new SugarFolder();
  1974. $archived->name = $mod_strings['LNK_SENT_EMAIL_LIST'];
  1975. $archived->has_child = 0;
  1976. $archived->parent_folder = $folder->id;
  1977. $archived->created_by = $user->id;
  1978. $archived->modified_by = $user->id;
  1979. $archived->is_dynamic = 1;
  1980. $archived->folder_type = "sent";
  1981. $archived->dynamic_query = $this->generateDynamicFolderQuery('sent', $user->id);
  1982. $archived->save();
  1983. // Archived Emails
  1984. $archived = new SugarFolder();
  1985. $archived->name = $mod_strings['LBL_LIST_TITLE_MY_ARCHIVES'];
  1986. $archived->has_child = 0;
  1987. $archived->parent_folder = $folder->id;
  1988. $archived->created_by = $user->id;
  1989. $archived->modified_by = $user->id;
  1990. $archived->is_dynamic = 1;
  1991. $archived->folder_type = "archived";
  1992. $archived->dynamic_query = '';
  1993. $archived->save();
  1994. // set flag to show that this was run
  1995. $user->setPreference("email2Preflight", true, 1, "Emails");
  1996. }
  1997. }
  1998. /**
  1999. * Parses the core dynamic folder query
  2000. * @param string $type 'inbound', 'draft', etc.
  2001. * @param string $userId
  2002. * @return string
  2003. */
  2004. function generateDynamicFolderQuery($type, $userId) {
  2005. $q = $this->coreDynamicFolderQuery;
  2006. $status = $type;
  2007. if($type == "sent") {
  2008. $type = "out";
  2009. }
  2010. $replacee = array("::TYPE::", "::STATUS::", "::USER_ID::");
  2011. $replacer = array($type, $status, $userId);
  2012. $ret = str_replace($replacee, $replacer, $q);
  2013. if($type == 'inbound') {
  2014. $ret .= " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
  2015. } else {
  2016. $ret .= " AND status NOT IN ('archived') AND type NOT IN ('archived')";
  2017. }
  2018. return $ret;
  2019. }
  2020. /**
  2021. * Preps the User's cache dir
  2022. */
  2023. function preflightUserCache() {
  2024. $path = clean_path($this->userCacheDir);
  2025. if(!file_exists($this->userCacheDir))
  2026. mkdir_recursive($path);
  2027. $files = findAllFiles($path, array());
  2028. foreach($files as $file) {
  2029. unlink($file);
  2030. }
  2031. }
  2032. function clearInboundAccountCache($ieId) {
  2033. global $sugar_config;
  2034. $cacheRoot = sugar_cached("modules/Emails/{$ieId}");
  2035. $files = findAllFiles($cacheRoot."/messages/", array());
  2036. foreach($files as $file) {
  2037. unlink($file);
  2038. } // fn
  2039. $files = findAllFiles($cacheRoot."/attachments/", array());
  2040. foreach($files as $file) {
  2041. unlink($file);
  2042. } // for
  2043. } // fn
  2044. /**
  2045. * returns an array of EmailTemplates that the user has access to for the compose email screen
  2046. * @return array
  2047. */
  2048. function getEmailTemplatesArray() {
  2049. global $app_strings;
  2050. if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) {
  2051. $et = new EmailTemplate();
  2052. $etResult = $et->db->query($et->create_new_list_query('',"(type IS NULL OR type='' OR type='email')",array(),array(),''));
  2053. $email_templates_arr = array('' => $app_strings['LBL_NONE']);
  2054. while($etA = $et->db->fetchByAssoc($etResult)) {
  2055. $email_templates_arr[$etA['id']] = $etA['name'];
  2056. }
  2057. } else {
  2058. $email_templates_arr = array('' => $app_strings['LBL_NONE']);
  2059. }
  2060. return $email_templates_arr;
  2061. }
  2062. function getFromAccountsArray($ie) {
  2063. global $current_user;
  2064. global $app_strings;
  2065. $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
  2066. $ieAccountsFrom= array();
  2067. $oe = new OutboundEmail();
  2068. $system = $oe->getSystemMailerSettings();
  2069. $ret = $current_user->getUsersNameAndEmail();
  2070. $ret['name'] = from_html($ret['name']);
  2071. $useMyAccountString = true;
  2072. if(empty($ret['email'])) {
  2073. $systemReturn = $current_user->getSystemDefaultNameAndEmail();
  2074. $ret['email'] = $systemReturn['email'];
  2075. $ret['name'] = from_html($systemReturn['name']);
  2076. $useMyAccountString = false;
  2077. } // if
  2078. $myAccountString = '';
  2079. if ($useMyAccountString) {
  2080. $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
  2081. } // if
  2082. //Check to make sure that the user has set the associated inbound email account -> outbound account is active.
  2083. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  2084. $sf = new SugarFolder();
  2085. $groupSubs = $sf->getSubscriptions($current_user);
  2086. foreach($ieAccountsFull as $k => $v)
  2087. {
  2088. $personalSelected = (!empty($showFolders) && in_array($v->id, $showFolders));
  2089. $allowOutboundGroupUsage = $v->get_stored_options('allow_outbound_group_usage',FALSE);
  2090. $groupSelected = ( in_array($v->groupfolder_id, $groupSubs) && $allowOutboundGroupUsage);
  2091. $selected = ( $personalSelected || $groupSelected );
  2092. if(!$selected)
  2093. {
  2094. $GLOBALS['log']->debug("Inbound Email {$v->name}, not selected and will not be available for selection within compose UI.");
  2095. continue;
  2096. }
  2097. $name = $v->get_stored_options('from_name');
  2098. $addr = $v->get_stored_options('from_addr');
  2099. if ($name != null && $addr != null) {
  2100. $name = from_html($name);
  2101. if (!$v->is_personal) {
  2102. $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
  2103. } else {
  2104. $ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr})");
  2105. } // else
  2106. } // if
  2107. } // foreach
  2108. $userSystemOverride = $oe->getUsersMailerForSystemOverride($current_user->id);
  2109. //Substitute in the users system override if its available.
  2110. if($userSystemOverride != null)
  2111. $system = $userSystemOverride;
  2112. if( !empty($system->mail_smtpserver) )
  2113. {
  2114. $admin = new Administration();
  2115. $admin->retrieveSettings(); //retrieve all admin settings.
  2116. $ieAccountsFrom[] = array("value" => $system->id, "text" =>
  2117. "{$ret['name']} ({$ret['email']}){$myAccountString}");
  2118. }
  2119. return $ieAccountsFrom;
  2120. } // fn
  2121. /**
  2122. * This function will return all the accounts this user has access to based on the
  2123. * match of the emailId passed in as a parameter
  2124. *
  2125. * @param unknown_type $ie
  2126. * @return unknown
  2127. */
  2128. function getFromAllAccountsArray($ie, $ret) {
  2129. global $current_user;
  2130. global $app_strings;
  2131. $ret['fromAccounts'] = array();
  2132. if (!isset($ret['to']) && !empty($ret['from'])) {
  2133. $ret['fromAccounts']['status'] = false;
  2134. return $ret;
  2135. }
  2136. $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
  2137. $foundInPersonalAccounts = false;
  2138. $foundInGroupAccounts = false;
  2139. $foundInSystemAccounts = false;
  2140. //$toArray = array();
  2141. if ($ret['type'] == "draft") {
  2142. $toArray = explode(",", $ret['from']);
  2143. } else {
  2144. $toArray = $ie->email->email2ParseAddressesForAddressesOnly($ret['to']);
  2145. } // else
  2146. foreach($ieAccountsFull as $k => $v) {
  2147. $storedOptions = unserialize(base64_decode($v->stored_options));
  2148. if ( array_search_insensitive($storedOptions['from_addr'], $toArray)) {
  2149. if ($v->is_personal) {
  2150. $foundInPersonalAccounts = true;
  2151. break;
  2152. } else {
  2153. $foundInGroupAccounts = true;
  2154. } // else
  2155. } // if
  2156. } // foreach
  2157. $oe = new OutboundEmail();
  2158. $system = $oe->getSystemMailerSettings();
  2159. $return = $current_user->getUsersNameAndEmail();
  2160. $return['name'] = from_html($return['name']);
  2161. $useMyAccountString = true;
  2162. if(empty($return['email'])) {
  2163. $systemReturn = $current_user->getSystemDefaultNameAndEmail();
  2164. $return['email'] = $systemReturn['email'];
  2165. $return['name'] = from_html($systemReturn['name']);
  2166. $useMyAccountString = false;
  2167. } // if
  2168. $myAccountString = '';
  2169. if ($useMyAccountString) {
  2170. $myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
  2171. } // if
  2172. if(!empty($system->id)) {
  2173. $admin = new Administration();
  2174. $admin->retrieveSettings(); //retrieve all admin settings.
  2175. if (in_array(trim($return['email']), $toArray)) {
  2176. $foundInSystemAccounts = true;
  2177. } // if
  2178. } // if
  2179. if (!$foundInPersonalAccounts && !$foundInGroupAccounts && !$foundInSystemAccounts) {
  2180. $ret['fromAccounts']['status'] = false;
  2181. return $ret;
  2182. } // if
  2183. $ieAccountsFrom= array();
  2184. foreach($ieAccountsFull as $k => $v) {
  2185. $storedOptions = unserialize(base64_decode($v->stored_options));
  2186. $storedOptionsName = from_html($storedOptions['from_name']);
  2187. $selected = false;
  2188. if (array_search_insensitive($storedOptions['from_addr'], $toArray)) {
  2189. //if ($ret['to'] == $storedOptions['from_addr']) {
  2190. $selected = true;
  2191. } // if
  2192. if ($foundInPersonalAccounts) {
  2193. if ($v->is_personal) {
  2194. $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']})");
  2195. } // if
  2196. } else {
  2197. $ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
  2198. } // else
  2199. } // foreach
  2200. if(!empty($system->id)) {
  2201. if (!$foundInPersonalAccounts && !$foundInGroupAccounts && $foundInSystemAccounts) {
  2202. $ieAccountsFrom[] = array("value" => $system->id, "selected" => true, "text" =>
  2203. "{$return['name']} ({$return['email']}){$myAccountString}");
  2204. } else {
  2205. $ieAccountsFrom[] = array("value" => $system->id, "text" =>
  2206. "{$return['name']} ({$return['email']}){$myAccountString}");
  2207. } // else
  2208. } // if
  2209. $ret['fromAccounts']['status'] = ($foundInPersonalAccounts || $foundInGroupAccounts || $foundInSystemAccounts) ? true : false;
  2210. $ret['fromAccounts']['data'] = $ieAccountsFrom;
  2211. return $ret;
  2212. } // fn
  2213. /**
  2214. * takes an array and creates XML
  2215. * @param array Array to convert
  2216. * @param string Name to wrap highest level items in array
  2217. * @return string XML
  2218. */
  2219. function arrayToXML($a, $paramName) {
  2220. if(!is_array($a))
  2221. return '';
  2222. $bad = array("<",">","'",'"',"&");
  2223. $good = array("&lt;", "&gt;", "&#39;", "&quot;","&amp;");
  2224. $ret = "";
  2225. for($i=0; $i<count($a); $i++) {
  2226. $email = $a[$i];
  2227. $ret .= "\n<{$paramName}>";
  2228. foreach($email as $k => $v) {
  2229. $ret .= "\n\t<{$k}>".str_replace($bad, $good, $v)."</{$k}>";
  2230. }
  2231. $ret .= "\n</{$paramName}>";
  2232. }
  2233. return $ret;
  2234. }
  2235. /**
  2236. * Re-used option getter for Show Accounts multiselect pane
  2237. */
  2238. function getShowAccountsOptions(&$ie) {
  2239. global $current_user;
  2240. global $app_strings;
  2241. global $mod_strings;
  2242. $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
  2243. $ieAccountsShowOptionsMeta = array();
  2244. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  2245. $defaultIEAccount = $ie->getUsersDefaultOutboundServerId($current_user);
  2246. foreach($ieAccountsFull as $k => $v) {
  2247. $selected = (!empty($showFolders) && in_array($v->id, $showFolders)) ? true : false;
  2248. $default = ($defaultIEAccount == $v->id) ? TRUE : FALSE;
  2249. $has_groupfolder = !empty($v->groupfolder_id) ? TRUE : FALSE;
  2250. $type = ($v->is_personal) ? $mod_strings['LBL_MAILBOX_TYPE_PERSONAL'] : $mod_strings['LBL_MAILBOX_TYPE_GROUP'];
  2251. $ieAccountsShowOptionsMeta[] = array("id" => $v->id, "name" => $v->name, 'is_active' => $selected,
  2252. 'server_url' => $v->server_url, 'is_group' => !$v->is_personal,'group_id' => $v->group_id,
  2253. 'is_default' => $default, 'has_groupfolder' => $has_groupfolder,'type' => $type );
  2254. }
  2255. //Retrieve the grou folders
  2256. $f = new SugarFolder();
  2257. $groupFolders = $f->getGroupFoldersForSettings($current_user);
  2258. foreach ($groupFolders as $singleGroup)
  2259. {
  2260. //Retrieve the related IE accounts.
  2261. $relatedIEAccounts = $ie->retrieveByGroupFolderId($singleGroup['id']);
  2262. if(count($relatedIEAccounts) == 0)
  2263. $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY'];
  2264. else if(count($relatedIEAccounts) == 1)
  2265. {
  2266. if($relatedIEAccounts[0]->status != 'Active' || $relatedIEAccounts[0]->mailbox_type == 'bounce')
  2267. continue;
  2268. $server_url = $relatedIEAccounts[0]->server_url;
  2269. }
  2270. else
  2271. $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS'];
  2272. $type = $mod_strings['LBL_MAILBOX_TYPE_GROUP_FOLDER'];
  2273. $ieAccountsShowOptionsMeta[] = array("id" => $singleGroup['id'], "name" => $singleGroup['origName'], 'is_active' => $singleGroup['selected'],
  2274. 'server_url' => $server_url, 'is_group' => true,'group_id' => $singleGroup['id'],
  2275. 'is_default' => FALSE, 'has_groupfolder' => true,'type' => $type);
  2276. }
  2277. return $ieAccountsShowOptionsMeta;
  2278. }
  2279. function getShowAccountsOptionsForSearch(&$ie) {
  2280. global $current_user;
  2281. global $app_strings;
  2282. $ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
  2283. //$ieAccountsShowOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
  2284. $ieAccountsShowOptionsMeta = array();
  2285. $ieAccountsShowOptionsMeta[] = array("value" => "", "text" => $app_strings['LBL_NONE'], 'selected' => '');
  2286. $showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
  2287. foreach($ieAccountsFull as $k => $v) {
  2288. if(!in_array($v->id, $showFolders)) {
  2289. continue;
  2290. }
  2291. $group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
  2292. $ieAccountsShowOptionsMeta[] = array("value" => $v->id, "text" => $group.$v->name, 'protocol' => $v->protocol);
  2293. }
  2294. return $ieAccountsShowOptionsMeta;
  2295. }
  2296. /**
  2297. * Formats a display message on successful async call
  2298. * @param string $type Type of message to display
  2299. */
  2300. function displaySuccessMessage($type) {
  2301. global $app_strings;
  2302. switch($type) {
  2303. case "delete":
  2304. $message = $app_strings['LBL_EMAIL_DELETE_SUCCESS'];
  2305. break;
  2306. default:
  2307. $message = "NOOP: invalid type";
  2308. break;
  2309. }
  2310. $this->smarty->assign('app_strings', $app_strings);
  2311. $this->smarty->assign('message', $message);
  2312. echo $this->smarty->fetch("modules/Emails/templates/successMessage.tpl");
  2313. }
  2314. /**
  2315. * Validates existence and expiration of a cache file
  2316. * @param string $ieId
  2317. * @param string $type Type of cache file: folders, messages, etc.
  2318. * @param string $file The cachefile name
  2319. * @param int refreshOffset Refresh time in secs.
  2320. * @return mixed.
  2321. */
  2322. function validCacheFileExists($ieId, $type, $file, $refreshOffset=-1) {
  2323. global $sugar_config;
  2324. if($refreshOffset == -1) {
  2325. $refreshOffset = $this->cacheTimeouts[$type]; // use defaults
  2326. }
  2327. $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
  2328. if(file_exists($cacheFilePath)) {
  2329. return true;
  2330. }
  2331. return false;
  2332. }
  2333. /**
  2334. * retrieves the cached value
  2335. * @param string $ieId
  2336. * @param string $type Type of cache file: folders, messages, etc.
  2337. * @param string $file The cachefile name
  2338. * @param string $key name of cache value
  2339. * @return mixed
  2340. */
  2341. function getCacheValue($ieId, $type, $file, $key) {
  2342. global $sugar_config;
  2343. $cleanIeId = cleanDirName($ieId);
  2344. $cleanType = cleanDirName($type);
  2345. $cleanFile = cleanFileName($file);
  2346. $cacheFilePath = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
  2347. $cacheFile = array();
  2348. if(file_exists($cacheFilePath)) {
  2349. include($cacheFilePath); // provides $cacheFile
  2350. if(isset($cacheFile[$key])) {
  2351. $ret = unserialize($cacheFile[$key]);
  2352. return $ret;
  2353. }
  2354. } else {
  2355. $GLOBALS['log']->debug("EMAILUI: cache file not found [ {$cacheFilePath} ] - creating blank cache file");
  2356. $this->writeCacheFile('retArr', array(), $ieId, $type, $file);
  2357. }
  2358. return null;
  2359. }
  2360. /**
  2361. * retrieves the cache file last touched time
  2362. * @param string $ieId
  2363. * @param string $type Type of cache file: folders, messages, etc.
  2364. * @param string $file The cachefile name
  2365. * @return string
  2366. */
  2367. function getCacheTimestamp($ieId, $type, $file) {
  2368. global $sugar_config;
  2369. $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
  2370. $cacheFile = array();
  2371. if(file_exists($cacheFilePath)) {
  2372. include($cacheFilePath); // provides $cacheFile['timestamp']
  2373. if(isset($cacheFile['timestamp'])) {
  2374. $GLOBALS['log']->debug("EMAILUI: found timestamp [ {$cacheFile['timestamp']} ]");
  2375. return $cacheFile['timestamp'];
  2376. }
  2377. }
  2378. return '';
  2379. }
  2380. /**
  2381. * Updates the timestamp for a cache file - usually to mark a "check email"
  2382. * process
  2383. * @param string $ieId
  2384. * @param string $type Type of cache file: folders, messages, etc.
  2385. * @param string $file The cachefile name
  2386. */
  2387. function setCacheTimestamp($ieId, $type, $file) {
  2388. global $sugar_config;
  2389. $cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
  2390. $cacheFile = array();
  2391. if(file_exists($cacheFilePath)) {
  2392. include($cacheFilePath); // provides $cacheFile['timestamp']
  2393. if(isset($cacheFile['timestamp'])) {
  2394. $cacheFile['timestamp'] = strtotime('now');
  2395. $GLOBALS['log']->debug("EMAILUI: setting updated timestamp [ {$cacheFile['timestamp']} ]");
  2396. return $this->_writeCacheFile($cacheFile, $cacheFilePath);
  2397. }
  2398. }
  2399. }
  2400. /**
  2401. * Writes caches to flat file in cache dir.
  2402. * @param string $key Key to the main cache entry (not timestamp)
  2403. * @param mixed $var Variable to be cached
  2404. * @param string $ieId I-E focus ID
  2405. * @param string $type Folder in cache
  2406. * @param string $file Cache file name
  2407. */
  2408. function writeCacheFile($key, $var, $ieId, $type, $file) {
  2409. global $sugar_config;
  2410. $cleanIeId = cleanDirName($ieId);
  2411. $cleanType = cleanDirName($type);
  2412. $cleanFile = cleanFileName($file);
  2413. $the_file = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
  2414. $timestamp = strtotime('now');
  2415. $array = array();
  2416. $array['timestamp'] = $timestamp;
  2417. $array[$key] = serialize($var); // serialized since varexport_helper() can't handle PHP objects
  2418. return $this->_writeCacheFile($array, $the_file);
  2419. }
  2420. /**
  2421. * Performs the actual file write. Abstracted from writeCacheFile() for
  2422. * flexibility
  2423. * @param array $array The array to write to the cache
  2424. * @param string $file Full path (relative) with cache file name
  2425. * @return bool
  2426. */
  2427. function _writeCacheFile($array, $file) {
  2428. global $sugar_config;
  2429. $arrayString = var_export_helper($array);
  2430. $date = date("r");
  2431. $the_string =<<<eoq
  2432. <?php // created: {$date}
  2433. \$cacheFile = {$arrayString};
  2434. ?>
  2435. eoq;
  2436. if($fh = @sugar_fopen($file, "w")) {
  2437. fputs($fh, $the_string);
  2438. fclose($fh);
  2439. return true;
  2440. } else {
  2441. $GLOBALS['log']->debug("EMAILUI: Could not write cache file [ {$file} ]");
  2442. return false;
  2443. }
  2444. }
  2445. /**
  2446. * Generate JSON encoded data to be consumed by yui datatable.
  2447. *
  2448. * @param array $data
  2449. * @param string $resultsParam The resultsList name
  2450. * @return string
  2451. */
  2452. function jsonOuput($data, $resultsParam, $count=0, $fromCache=true, $unread=-1) {
  2453. global $app_strings;
  2454. $count = ($count > 0) ? $count : 0;
  2455. if(isset($a['fromCache']))
  2456. $cached = ($a['fromCache'] == 1) ? 1 : 0;
  2457. else
  2458. $cached = ($fromCache) ? 1 : 0;
  2459. if($data['mbox'] == 'undefined' || empty($data['mbox']))
  2460. $data['mbox'] = $app_strings['LBL_NONE'];
  2461. $jsonOut = array('TotalCount' => $count, 'FromCache' => $cached, 'UnreadCount' => $unread, $resultsParam => $data['out']);
  2462. return json_encode($jsonOut);
  2463. }
  2464. /**
  2465. * generates XML output from an array
  2466. * @param array
  2467. * @param string master list Item
  2468. * @return string
  2469. */
  2470. function xmlOutput($a, $paramName, $count=0, $fromCache=true, $unread=-1) {
  2471. global $app_strings;
  2472. $count = ($count > 0) ? $count : 0;
  2473. if(isset($a['fromCache'])) {
  2474. $cached = ($a['fromCache'] == 1) ? 1 : 0;
  2475. } else {
  2476. $cached = ($fromCache) ? 1 : 0;
  2477. }
  2478. if($a['mbox'] == 'undefined' || empty($a['mbox'])) {
  2479. $a['mbox'] = $app_strings['LBL_NONE'];
  2480. }
  2481. $xml = $this->arrayToXML($a['out'], $paramName);
  2482. $ret =<<<eoq
  2483. <?xml version="1.0" encoding="UTF-8"?>
  2484. <EmailPage>
  2485. <TotalCount>{$count}</TotalCount>
  2486. <UnreadCount>{$unread}</UnreadCount>
  2487. <FromCache> {$cached} </FromCache>
  2488. <{$paramName}s>
  2489. {$xml}
  2490. </{$paramName}s>
  2491. </EmailPage>
  2492. eoq;
  2493. return $ret;
  2494. }
  2495. /**
  2496. * Generate to/cc addresses string in email detailview.
  2497. *
  2498. * @param string $str
  2499. * @param string $target values: to, cc
  2500. * @param int $defaultNum
  2501. * @return string $str
  2502. */
  2503. function generateExpandableAddrs($str) {
  2504. global $mod_strings;
  2505. $tempStr = $str.',';
  2506. $tempStr = html_entity_decode($tempStr);
  2507. $tempStr = $this->unifyEmailString($tempStr);
  2508. $defaultNum = 2;
  2509. $pattern = '/@.*,/U';
  2510. preg_match_all($pattern, $tempStr, $matchs);
  2511. $totalCount = count($matchs[0]);
  2512. if(!empty($matchs[0]) && $totalCount > $defaultNum) {
  2513. $position = strpos($tempStr, $matchs[0][$defaultNum]);
  2514. $hiddenCount = $totalCount - $defaultNum;
  2515. $frontStr = substr($tempStr, 0, $position);
  2516. $backStr = substr($tempStr, $position, -1);
  2517. $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>';
  2518. }
  2519. return $str;
  2520. }
  2521. /**
  2522. * Unify the seperator as ,
  2523. *
  2524. * @param String $str email address string
  2525. * @return String converted string
  2526. */
  2527. function unifyEmailString($str) {
  2528. preg_match_all('/@.*;/U', $str, $matches);
  2529. if(!empty($matches[0])) {
  2530. foreach($matches[0] as $key => $value) {
  2531. $new[] = str_replace(";",",",$value);
  2532. }
  2533. return str_replace($matches[0], $new, $str);
  2534. }
  2535. return $str;
  2536. }
  2537. } // end class def