diff --git a/.travis.yml b/.travis.yml index 565143c14..eb685e549 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,15 +4,12 @@ os: linux matrix: fast_finish: true include: - - name: "PHP 7.3 / MySQL 5.7" - php: "7.3" - dist: xenial - name: "PHP 7.4 / MySQL 5.7" php: "7.4" dist: xenial # Run composer validate to make sure the composer.json and composer.lock are in sync. - name: "composer validate" - php: "7.3" + php: "7.4" dist: xenial before_script: composer install script: composer validate diff --git a/ModuleInstall/extensions.php b/ModuleInstall/extensions.php index 69faf31c6..b07338457 100755 --- a/ModuleInstall/extensions.php +++ b/ModuleInstall/extensions.php @@ -68,6 +68,7 @@ if (!defined('sugarEntry') || !sugarEntry) { "filtermappers" => array("section" => "filter_mappers","extdir" => "FilterMappers", "file" => 'filter_mappers.ext.php'), "classicviewroutingexclusions" => array("section" => "classicview_routing_exclusions","extdir" => "ClassicViewRoutingExclusions", "file" => 'classicview_routing_exclusions.ext.php'), "pdf" => array("section" => "pdfs", "extdir" => "PDF", "file" => 'pdfs.ext.php', "module" => "application"), + "externaloauthproviders" => array("section" => "external_oauth_providers", "extdir" => "ExternalOAuthProviders", "file" => 'externaloauthproviders.ext.php', "module" => "application"), ); if (file_exists("custom/application/Ext/Extensions/extensions.ext.php")) { include("custom/application/Ext/Extensions/extensions.ext.php"); diff --git a/README.md b/README.md index 93d7fc981..1e8c3393b 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -# SuiteCRM 7.12.8 +# SuiteCRM 7.13.0 [![LICENSE](https://img.shields.io/github/license/suitecrm/suitecrm.svg)](https://github.com/salesagility/suitecrm/blob/hotfix/LICENSE.txt) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/salesagility/SuiteCRM-Core/issues) diff --git a/data/SugarBean.php b/data/SugarBean.php index bd285e4c0..d0f7fd35c 100755 --- a/data/SugarBean.php +++ b/data/SugarBean.php @@ -2712,6 +2712,11 @@ class SugarBean default: //do nothing } + + + if ($def['type'] !== 'encrypt' && isTrue($def['db_encrypted'] ?? false)) { + $this->$field = $this->encrpyt_before_save($this->$field); + } } if ($reformatted) { $GLOBALS['log']->info('Formatting correction: ' . $this->module_dir . '->' . $field . @@ -3220,10 +3225,10 @@ class SugarBean * function NAME(&$bean, $event, $arguments) * $bean - $this bean passed in by reference. * $event - The string for the current event (i.e. before_save) - * $arguments - An array of arguments that are specific to the event. + * $arguments - An object or array of arguments that are specific to the event. * * @param string $event - * @param array $arguments + * @param object|array $arguments */ public function call_custom_logic($event, $arguments = null) { @@ -3585,22 +3590,7 @@ class SugarBean if (isset($_SESSION['show_deleted'])) { $show_deleted = 1; } - - if ($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list')) { - global $current_user; - $owner_where = $this->getOwnerWhere($current_user->id); - - //rrs - because $this->getOwnerWhere() can return '' we need to be sure to check for it and - //handle it properly else you could get into a situation where you are create a where stmt like - //WHERE .. AND '' - if (!empty($owner_where)) { - if (empty($where)) { - $where = $owner_where; - } else { - $where .= ' AND ' . $owner_where; - } - } - } + $query = $this->create_new_list_query( $order_by, $where, @@ -3632,6 +3622,56 @@ class SugarBean return ''; } + + /** + * @param string $view + * @param User $user + * @return string + */ + public function buildAccessWhere($view, $user = null) + { + global $current_user, $sugar_config; + + $conditions = []; + $user = $user === null ? $current_user : $user; + + if ($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, $view)) { + $ownerWhere = $this->getOwnerWhere($user->id); + if (!empty($ownerWhere)) { + $conditions['owner'] = $ownerWhere; + } + } + + /* BEGIN - SECURITY GROUPS */ + $SecurityGroupFile = BeanFactory::getBeanFile('SecurityGroups'); + require_once $SecurityGroupFile; + if ($view === 'list' && $this->module_dir === 'Users' && !is_admin($user) + && isset($sugar_config['securitysuite_filter_user_list']) + && $sugar_config['securitysuite_filter_user_list'] + ) { + $groupWhere = SecurityGroup::getGroupUsersWhere($user->id); + $conditions['group'] = $groupWhere; + } elseif ($this->bean_implements('ACL') && ACLController::requireSecurityGroup($this->module_dir, $view)) { + $ownerWhere = $this->getOwnerWhere($user->id); + $groupWhere = SecurityGroup::getGroupWhere($this->table_name, $this->module_dir, $user->id); + if (!empty($ownerWhere)) { + $conditions['group'] = " (" . $ownerWhere . " or " . $groupWhere . ") "; + } else { + $conditions['group'] = $groupWhere; + } + } + /* END - SECURITY GROUPS */ + + $args = new stdClass(); + $args->view = $view; + $args->user = $user; + $args->conditions = $conditions; + + $this->call_custom_logic('before_acl_query', $args); + + return implode(' AND ', $args->conditions); + } + /** * Return the list query used by the list views and export button. * Next generation of create_new_list_query function. @@ -3667,45 +3707,12 @@ class SugarBean $secondarySelectedFields = array(); $ret_array = array(); $distinct = ''; - if ($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list')) { - global $current_user; - $owner_where = $this->getOwnerWhere($current_user->id); - if (empty($where)) { - $where = $owner_where; - } else { - $where .= ' AND ' . $owner_where; - } + + $accessWhere = $this->buildAccessWhere('list'); + if (!empty($accessWhere)) { + $where .= empty($where) ? $accessWhere : ' AND ' . $accessWhere; } - /* BEGIN - SECURITY GROUPS */ - global $current_user, $sugar_config; - if ($this->module_dir == 'Users' && !is_admin($current_user) - && isset($sugar_config['securitysuite_filter_user_list']) - && $sugar_config['securitysuite_filter_user_list'] - ) { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $group_where = SecurityGroup::getGroupUsersWhere($current_user->id); - if (empty($where)) { - $where = " (" . $group_where . ") "; - } else { - $where .= " AND (" . $group_where . ") "; - } - } elseif ($this->bean_implements('ACL') && ACLController::requireSecurityGroup($this->module_dir, 'list')) { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $owner_where = $this->getOwnerWhere($current_user->id); - $group_where = SecurityGroup::getGroupWhere($this->table_name, $this->module_dir, $current_user->id); - if (!empty($owner_where)) { - if (empty($where)) { - $where = " (" . $owner_where . " or " . $group_where . ") "; - } else { - $where .= " AND (" . $owner_where . " or " . $group_where . ") "; - } - } else { - $where .= ' AND ' . $group_where; - } - } - /* END - SECURITY GROUPS */ + if (!empty($params['distinct'])) { $distinct = ' DISTINCT '; } @@ -4546,35 +4553,7 @@ class SugarBean if (isset($_SESSION['show_deleted'])) { $show_deleted = 1; } - - if ($this->bean_implements('ACL') && ACLController::requireOwner($this->module_dir, 'list')) { - global $current_user; - $owner_where = $this->getOwnerWhere($current_user->id); - - if (empty($where)) { - $where = $owner_where; - } else { - $where .= ' AND ' . $owner_where; - } - } - - /* BEGIN - SECURITY GROUPS */ - if ($this->bean_implements('ACL') && ACLController::requireSecurityGroup($this->module_dir, 'list')) { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $owner_where = $this->getOwnerWhere($current_user->id); - $group_where = SecurityGroup::getGroupWhere($this->table_name, $this->module_dir, $current_user->id); - if (!empty($owner_where)) { - if (empty($where)) { - $where = " (" . $owner_where . " or " . $group_where . ") "; - } else { - $where .= " AND (" . $owner_where . " or " . $group_where . ") "; - } - } else { - $where .= ' AND ' . $group_where; - } - } - /* END - SECURITY GROUPS */ + $query = $this->create_new_list_query($order_by, $where, array(), array(), $show_deleted, $offset); return $this->process_detail_query($query, $row_offset, $limit, $max, $where, $offset); @@ -4937,7 +4916,7 @@ class SugarBean $this->$field = $timedate->to_display_time($this->$field, true, false); } } - } elseif ($type == 'encrypt' && empty($disable_date_format)) { + } elseif (($type == 'encrypt' && empty($disable_date_format)) || isTrue($fieldDef['db_encrypted'] ?? false)) { $this->$field = $this->decrypt_after_retrieve($this->$field); } } @@ -6248,7 +6227,28 @@ class SugarBean require_once("modules/SecurityGroups/SecurityGroup.php"); $in_group = SecurityGroup::groupHasAccess($this->module_dir, $this->id, $view); } - return ACLController::checkAccess($this->module_dir, $view, $is_owner, $this->acltype, $in_group); + + $args = new stdClass(); + $args->view = $view; + $args->is_owner = $is_owner; + $args->in_group = $in_group; + $args->access = true; + $args->override_acl_check = false; + + $this->call_custom_logic('before_acl_check', $args); + + if ($args->override_acl_check) { + return $args->access; + } + + return $args->access + && ACLController::checkAccess( + $this->module_dir, + $args->view, + $args->is_owner, + $this->acltype, + $args->in_group + ); } /** diff --git a/files.md5 b/files.md5 index dafe4c2bf..d1dcf34d7 100644 --- a/files.md5 +++ b/files.md5 @@ -1,5 +1,5 @@ '69a1e7b3d7755a2a63499a16ddae81cf', './Api/Core/Config/slim.php' => 'b134e68765e6a1403577e2a5a06322b8', @@ -115,8 +115,8 @@ $md5_string = array ( './ModuleInstall/PackageManager/tpls/PackageForm.tpl' => 'bffd280ab5cd7381a5b0da41a9c1f34f', './ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl' => 'df5e267d1df5ce08fb9406e42d5b4816', './ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl' => '98e396c0aa57329731fda19c790fffb2', - './ModuleInstall/extensions.php' => '094f4650261f6efbab1b90b119829388', - './README.md' => '76ec8409ea1fa360d1255f693dfd5a40', + './ModuleInstall/extensions.php' => 'de30837895f67175b7fbc04274a837a6', + './README.md' => '54743d8cbb99f27a15c42be076e7c293', './RoboFile.php' => '045b82c1df69553824d0e4ffcce6e03c', './SugarSecurity.php' => '47e316b2d408e8c5192c8ea4a4f921b3', './TreeData.php' => '32873e20cb5fd33f9d1cdaf18c3cac5c', @@ -507,8 +507,8 @@ $md5_string = array ( './build/push_output.sh' => 'cde8cd38e3b0c4e988ec4be7d81faa89', './build/travis-ci-apache' => 'e1e212c4eaf679b6ec620cd0b12f4571', './campaign_tracker.php' => '321e43ca8b664e6ca57ae5589e8c0667', - './composer.json' => 'db3d5c1d78b364766bf171d0374b23f3', - './composer.lock' => '060badb951dc9a03fe4f77d748a56b12', + './composer.json' => '6bd6f8c467d45fa7b42f41a565c3c15b', + './composer.lock' => '7651f60b1796ac7aec447c2c341ebcba', './cron.php' => '0b8b6bd839a2232a8da074b31feaa708', './crossdomain.xml' => '24b7711640c652b21aa89c9d83d6ec13', './data/BeanFactory.php' => '84b7c36b6a59ea8c5c4069659cc72950', @@ -522,7 +522,7 @@ $md5_string = array ( './data/Relationships/One2OneRelationship.php' => 'c46d3067d5651fbc928763600d5e1a51', './data/Relationships/RelationshipFactory.php' => '98a46e44186f2d2db23be9b894a4f1e2', './data/Relationships/SugarRelationship.php' => 'a71b96492ee7457826fc91a2356c4ebd', - './data/SugarBean.php' => 'ccf600118e4ad9437e82efb376443ea4', + './data/SugarBean.php' => 'b5426bf71a4779ded1955c2eefa9cbd1', './deprecated.php' => 'f5f507fd6314f38d29c97e2cc2c62239', './dictionary.php' => 'b7c1370fb75a2940c04db74627c4462c', './download.php' => 'ffc5806938cc1f888c7ddedb79f7bedf', @@ -543,14 +543,14 @@ $md5_string = array ( './include/Dashlets/DashletHeader.tpl' => '8b8ce31451810ba6e2df4da49ab1eed2', './include/Dashlets/DashletRssFeedTitle.php' => '40032748c6a72a8d0929c608ea16f6a7', './include/DatabaseTransactions.php' => '430f1e917f9d65f1304f6094e946bb1a', - './include/DetailView/DetailView.php' => '89a6d36cd323c0b79a53e405281703a8', + './include/DetailView/DetailView.php' => 'd10f95d0b370f1fdb67b9bfff7540deb', './include/DetailView/DetailView.tpl' => 'd58cd38e065ff5b213e152408d4b900c', './include/DetailView/DetailView2.php' => '73b01c85a6b55d203db8bf2be98df9bf', './include/DetailView/footer.tpl' => 'b63d62eac5c99afa3497881c59da906b', './include/DetailView/header.tpl' => '79e5e7385483e4486ac1f20d739d8cd5', './include/EditView/EditView.php' => '6bd1f5815f5c674416efd1e71a67bd65', './include/EditView/EditView.tpl' => '4458f5584adfdb8d54e74b8e867e048c', - './include/EditView/EditView2.php' => 'b2684fe27ec214563d935d5080dd9742', + './include/EditView/EditView2.php' => '7ad84a44d52c2d5ae9a7e51d170a0efc', './include/EditView/Panels.js' => '580266b80716d8e7003807189565e557', './include/EditView/PopupQuickCreate.php' => '09b22d51578ba228a89ba6a7e5f403c8', './include/EditView/QuickCreate.php' => 'dbd2c8b5be42047ada748e073b87ff90', @@ -584,13 +584,14 @@ $md5_string = array ( './include/HTTP_WebDAV_Server/dav.txt' => 'c5235ed64efa685da638c6dcdb6a9708', './include/HTTP_WebDAV_Server/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', './include/HtmlSanitizer.php' => 'efcd753e725f16eb9212bc3bb2ed2cff', - './include/Imap/ImapHandler.php' => 'dbabb67c1d5c7d66dd0e9848a5d1956a', + './include/Imap/Imap2Handler.php' => '847bc7709b73a75b700e5acca59a5819', + './include/Imap/ImapHandler.php' => '29e289d005995cde4a35144bfe176fb0', './include/Imap/ImapHandlerException.php' => '43d045dace421f51ad30eab02e1d1e91', - './include/Imap/ImapHandlerFactory.php' => '0b015e476295d1edaa6bd55fe0717cf7', - './include/Imap/ImapHandlerFake.php' => '944f354c498721810af1e37c32f9c6f2', - './include/Imap/ImapHandlerFakeCalls.php' => '040b64de74e02accf657087177ea182f', + './include/Imap/ImapHandlerFactory.php' => '3690854b3f23f1f7e3e73f98a5fa3655', + './include/Imap/ImapHandlerFake.php' => '836493c75c86459f9449809f9dc6d010', + './include/Imap/ImapHandlerFakeCalls.php' => '78bb2e1e21c97feab44c1e274050c050', './include/Imap/ImapHandlerFakeData.php' => '8269f4b291c9a24abedfc4aee98f1d0e', - './include/Imap/ImapHandlerInterface.php' => 'ee29799b42b6e32762a35f5bbe32b701', + './include/Imap/ImapHandlerInterface.php' => '8472059ae0b7f2c79f06d8fef7249e63', './include/Imap/ImapTestSettingsEntry.php' => '3d95c35c794247f3a4109704867eb202', './include/Imap/ImapTestSettingsEntryHandler.php' => '3292a309c3331e60ab13f48c56e672c8', './include/Imap.php' => '0f93494ddbae70f85acdcbac5e92dbc5', @@ -617,7 +618,7 @@ $md5_string = array ( './include/ListView/ListViewPagination.tpl' => '33063ccce1750e85762c3f0910c29a6a', './include/ListView/ListViewSearchLink.tpl' => '9cd943804ef3db4fa47ba41c99f5a12f', './include/ListView/ListViewSelectObjects.tpl' => '04b1d6d2c02f649966e9b4d26f46a430', - './include/ListView/ListViewSmarty.php' => '3eed8e14bc3ede6151ccd475b3068278', + './include/ListView/ListViewSmarty.php' => '4e3b9e5afb52ef4a0e4c375bf0137668', './include/ListView/ListViewSubPanel.php' => '689b69b240c6177cbd1da575a0eb6c65', './include/ListView/ListViewXTPL.php' => '6a32cb0d7c7bce48c8d6eee6ea76a1f7', './include/Localization/Localization.php' => '2ae644ee0562e38287e5804bcdab32ad', @@ -625,7 +626,7 @@ $md5_string = array ( './include/MVC/Controller/SugarController.php' => 'fddd4ec4cb64ba9450f82f84e9730aac', './include/MVC/Controller/action_file_map.php' => '890a7903fc8c66e372f365bddc530cba', './include/MVC/Controller/action_view_map.php' => 'fb0f1173db35edb1ed4ed191896f6274', - './include/MVC/Controller/entry_point_registry.php' => 'c107d0eb8f9f32c4af3ae12bb43ac87f', + './include/MVC/Controller/entry_point_registry.php' => 'b8b8fb6e4f432de3b996fbbc6acb7a73', './include/MVC/Controller/file_access_control_map.php' => '86baf77effe4eb6167c4557c481c2f5f', './include/MVC/SugarApplication.php' => '0aebe6f78a37464d305522abfcd09f36', './include/MVC/SugarModule.php' => '7ffbda56ac7bd074795034533ef93c1a', @@ -679,7 +680,7 @@ $md5_string = array ( './include/MySugar/tpls/dashletsSearchResults.tpl' => '687c3a1ef953e103fa5cfc91adac2b1e', './include/MySugar/tpls/retrievePage.tpl' => 'e4f99a0c96f4b9af18ff4e16b35ebc83', './include/MySugar/tpls/retrieveReportCharts.tpl' => 'eae923db515b990099e897c335560dc8', - './include/OutboundEmail/OutboundEmail.php' => 'b67350f1a16e4b072d2b9ce7128360ad', + './include/OutboundEmail/OutboundEmail.php' => 'e4292d317ca83921c2d798e1bf441fc9', './include/Pear/Crypt_Blowfish/Blowfish/DefaultKey.php' => '71c33c848e1219ea3cfad5795f02f3cd', './include/Pear/Crypt_Blowfish/Blowfish.php' => '0c73a6dbf2fa10ae60ecb7dde76c67eb', './include/Pear/Crypt_Blowfish/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', @@ -704,6 +705,7 @@ $md5_string = array ( './include/Services/Batch/BatchJob.php' => 'bada8d2023e3824673b3a709a54e76f7', './include/Services/NormalizeRecords/NormalizeRecords.php' => '0daac688a03ca6212dee84f6411a8b30', './include/Services/NormalizeRecords/NormalizeRecordsSchedulerJob.php' => '8931bcef83a853868bd8f0dc934818d1', + './include/Services/ScriptLoader/SuiteScriptLoader.php' => 'ceb2826ba8881fefea8db6b2462ce4d3', './include/Smarty/plugins/block.minify.php' => 'a4a8771c5a8a48c7ab030b0b552957dd', './include/Smarty/plugins/block.nocache.php' => '66bb941778de43b9e52d06a47becb9f5', './include/Smarty/plugins/block.textformat.php' => 'f4e1cc15997ff132066f5e4e09e92054', @@ -767,6 +769,7 @@ $md5_string = array ( './include/Smarty/plugins/function.sugarvar.php' => 'b4322c3942894bb10263ff2f36d9f0b8', './include/Smarty/plugins/function.sugarvar_connector.php' => '1dd5d26b7b0984843d9005f7bf90d33e', './include/Smarty/plugins/function.suite_check_access.php' => '3d2d528bdfdeafa4cd24fd773f1c3497', + './include/Smarty/plugins/function.suite_combinescripts.php' => 'c9c6797941fae76654f679535b385574', './include/Smarty/plugins/modifier.capitalize.php' => '70f58c49c5bd2851be11a3d67a92d2a4', './include/Smarty/plugins/modifier.cat.php' => '9dbc6c2d6d78165d9d0ffae481509b6a', './include/Smarty/plugins/modifier.count_characters.php' => '91694b84f8b86aa551ff49ced16dbd11', @@ -782,6 +785,7 @@ $md5_string = array ( './include/Smarty/plugins/modifier.in_array.php' => 'f5aabe01841e76d205eec79f091ded5f', './include/Smarty/plugins/modifier.indent.php' => 'ea1f5db88c00e850c3968e434eadb074', './include/Smarty/plugins/modifier.json.php' => 'a63f703e849949d7960e8511d91573e8', + './include/Smarty/plugins/modifier.json_decode.php' => 'e42b68aacb908034f615471f16263bd2', './include/Smarty/plugins/modifier.lookup.php' => 'e9867a0ffb18f7be9aaea8fba75b41cd', './include/Smarty/plugins/modifier.lower.php' => '5520933762ceac07d49e658c52587279', './include/Smarty/plugins/modifier.multienum_to_ac.php' => '2a1c9c5feb31d24f7f2f5f832941ff4e', @@ -872,7 +876,7 @@ $md5_string = array ( './include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php' => '7cac00ee300243213c08527325b8a7e9', './include/SugarFields/Fields/Base/DetailView.tpl' => 'f5f751c593d52a5161f3c6995cc25181', './include/SugarFields/Fields/Base/DetailViewFunction.tpl' => 'f1699feaa5a9dd4bfbb7b7439fe64016', - './include/SugarFields/Fields/Base/EditView.tpl' => 'b5254733554c9f672222bf8367cafa8f', + './include/SugarFields/Fields/Base/EditView.tpl' => 'fde178f65e2a19d264736800c298d3a2', './include/SugarFields/Fields/Base/EditViewFunction.tpl' => '155f1d12fee72306ef962041219d4beb', './include/SugarFields/Fields/Base/ImportViewFunction.tpl' => '155f1d12fee72306ef962041219d4beb', './include/SugarFields/Fields/Base/InlineEdit.tpl' => '87eade8699bf0f65b4868efdef9b12c3', @@ -921,7 +925,7 @@ $md5_string = array ( './include/SugarFields/Fields/EmailBody/SugarFieldEmailBody.php' => '96c3842013034dc88da2d2f6d3271639', './include/SugarFields/Fields/Enum/DetailView.tpl' => 'f68d242afc933f84f80bcf035a378193', './include/SugarFields/Fields/Enum/DetailViewFunction.tpl' => 'fd1aa861ebf16be11b53350c2cb0914c', - './include/SugarFields/Fields/Enum/EditView.tpl' => '4fe49b7c57e7e3d68bbdeb0989edf374', + './include/SugarFields/Fields/Enum/EditView.tpl' => '5f2f2c61a31b72cf2d9f7de6a072c1e1', './include/SugarFields/Fields/Enum/EditViewFunction.tpl' => '083913c40c0cb1015acd2012ba7bb8e8', './include/SugarFields/Fields/Enum/SearchView.tpl' => '42aafd0812c443c10d37f84ce05aefa8', './include/SugarFields/Fields/Enum/SugarFieldEnum.php' => '9f702dee447a05073e55c270bc827517', @@ -967,7 +971,7 @@ $md5_string = array ( './include/SugarFields/Fields/Parent/EditView.tpl' => 'a9fa8c11ad879f4c4f0b545d7d33467e', './include/SugarFields/Fields/Parent/SearchView.tpl' => '7cc8ff9ee4939ce0301d25f188089f51', './include/SugarFields/Fields/Parent/SugarFieldParent.php' => '6786883a41a2645e343522685df23d79', - './include/SugarFields/Fields/Password/EditView.tpl' => 'fa98991bce7296a82929356d9bbff76a', + './include/SugarFields/Fields/Password/EditView.tpl' => '8173b48e432bb9e83802566e9e426f4e', './include/SugarFields/Fields/Password/SugarFieldPassword.php' => 'ccb4a64dc91636e6a8eef1c3bba90692', './include/SugarFields/Fields/Phone/DetailView.tpl' => '5b227d36a93c3600f3cfeed0e6addf7d', './include/SugarFields/Fields/Phone/EditView.tpl' => 'edd6e93c04eab6a52d873c3340b1073c', @@ -981,9 +985,14 @@ $md5_string = array ( './include/SugarFields/Fields/Relate/EditView.tpl' => 'dcb2bc4266af61b62b8f8ba684443e2e', './include/SugarFields/Fields/Relate/SearchView.tpl' => '3358b13b5f65f59f39f122e99b864ef8', './include/SugarFields/Fields/Relate/SugarFieldRelate.php' => '4994983d4481579977f46d04181bc6b1', + './include/SugarFields/Fields/Stringmap/DetailView.tpl' => '43b65b8a95fa14fbb56014a12015342f', + './include/SugarFields/Fields/Stringmap/EditView.tpl' => 'a66fa4934c14fc9db8861ab58073c848', + './include/SugarFields/Fields/Stringmap/SugarFieldStringmap.php' => 'd77ce6924d528309d253ed860d01d84c', + './include/SugarFields/Fields/Stringmap/js/stringmap-factory.js' => '87d4bf9d3326a346a8058d7e99b19164', + './include/SugarFields/Fields/Stringmap/js/stringmap.js' => '57fa98bc5a0967be038f53c22efdb133', './include/SugarFields/Fields/Text/ClassicEditView.tpl' => '8b3eb086dd74cef40e61faae361d8776', './include/SugarFields/Fields/Text/DetailView.tpl' => '92021168bdfa2a630fa02962c9618dec', - './include/SugarFields/Fields/Text/EditView.tpl' => '72271a7a85ca15433f71f9993f74fed6', + './include/SugarFields/Fields/Text/EditView.tpl' => '200c18ec02c03c84fc55813e309edf89', './include/SugarFields/Fields/Text/SugarFieldText.php' => '0a800255ce21f9dfa927e5f80ba521d5', './include/SugarFields/Fields/Time/EditView.tpl' => 'e3eb06cfa4f9845eaa7b63b8fb62e1fd', './include/SugarFields/Fields/Time/SugarFieldTime.php' => 'c8b01634167a9509625413c6d956e8cb', @@ -1027,7 +1036,7 @@ $md5_string = array ( './include/SugarFields/Parsers/SearchFormMetaParser.php' => '732eecf76268b82b84667f6d00a905f5', './include/SugarFields/SugarFieldHandler.php' => '73b2605cef98e6b0b03880d299a49e92', './include/SugarFolders/SugarFolderEmptyException.php' => 'd8052a2f3abf6ff8db9563bf3e22842e', - './include/SugarFolders/SugarFolders.php' => '4b79dc7fc655f6fe17210eb93191beb4', + './include/SugarFolders/SugarFolders.php' => 'a2323abcfb7ead79b307e05c8739512c', './include/SugarHtml/SugarHtml.php' => 'b457a731768480ce81d6e709d920e2cb', './include/SugarHttpClient.php' => 'bf0aedbad0c73763186e37fb9107d3d7', './include/SugarLogger/LoggerManager.php' => 'd30492d39dc1aecce2e9cabdc4c148e8', @@ -1199,7 +1208,7 @@ $md5_string = array ( './include/SugarObjects/templates/sale/metadata/subpanels/default.php' => '933ed06ff0fd822b455b6c05d3526b35', './include/SugarObjects/templates/sale/vardefs.php' => '0594cbe418f268edf893cced47b022f3', './include/SugarObjects/translated_prefix.php' => 'ba8e90a225dfa38f779119b10c366d40', - './include/SugarPHPMailer.php' => 'f3e4df19eab7a1ec3023c62dc383a85e', + './include/SugarPHPMailer.php' => '7f75d0acba639a135c7ab3f7b9f88fb0', './include/SugarQueue/SugarCronJobs.php' => 'ee32b208de3d393fa352f4f578a5b746', './include/SugarQueue/SugarCronRemoteJobs.php' => '07feac4c96f9cb8c0e00a8d9f075f841', './include/SugarQueue/SugarJobQueue.php' => 'ed2f9154587957a89b85121039a05fed', @@ -1209,7 +1218,7 @@ $md5_string = array ( './include/SugarTheme/SugarThemeRegistry.php' => '437a775ba6ef36dc87cb59d5ae1a3b14', './include/SugarTheme/cssmin.php' => 'ff649bb50d5dafcce509ed9d340b6d06', './include/SugarTheme/getImage.php' => 'd7963d20b0365d62c7d1c84ea3faf3ed', - './include/SugarTinyMCE.php' => '3e1df6fa7bcbb9e3caf75d97e1d8924b', + './include/SugarTinyMCE.php' => '9be7450638b50efe57ccc33bfbb35eb0', './include/Sugar_Smarty.php' => '9ce2f82df09600f42ccd1eee7bf78294', './include/Sugarpdf/FontManager.php' => '4f3e178b643571961d9f2590122342cc', './include/Sugarpdf/Sugarpdf.php' => '10f553017faf60a1ba027c96dea2d43d', @@ -1336,12 +1345,12 @@ $md5_string = array ( './include/database/FreeTDSManager.php' => '23ec109e38260e0ffa2a1676d486fd62', './include/database/MssqlManager.php' => '8ec8ad4bd3df1c19aa96b228f3b356a7', './include/database/MysqlManager.php' => 'e291bd0e38fde596a8bd1f6c75688eaa', - './include/database/MysqliManager.php' => '31cf1de8eba53e933ea116870129da12', + './include/database/MysqliManager.php' => '19025de16a37f6bb8ffb1b8c4e0ab34d', './include/database/SqlsrvManager.php' => 'ad3f8e07dce347f8cf1906e7e91ec776', './include/dir_inc.php' => '4ec954313ef7c8b164ec1232a1ec1bd7', './include/entryPoint.php' => '6c03ccc488eae94ac702743421951115', './include/entryPointConfirmOptInConnector.php' => '66fed04564c4f4182f3b277d5b6dfafc', - './include/export_utils.php' => 'b8144b36a084682de435bfa26a66259b', + './include/export_utils.php' => '5f539efced9a07f53e78663126d1fc5d', './include/externalAPI/Base/ExternalAPIBase.php' => 'e52639773bbdaa1d9e3308fd7a41e392', './include/externalAPI/Base/ExternalAPIPlugin.php' => '9f8d318d518a9f950fd0d80a6bac7c20', './include/externalAPI/Base/ExternalOAuthAPIPlugin.php' => 'fd065e2de29e6fa0dfc86956e2c86230', @@ -1675,7 +1684,7 @@ $md5_string = array ( './include/javascript/quickCompose.js' => '047d7eea0263fa0c2cd9bdb53ecf6258', './include/javascript/quicksearch.js' => '97475c83c2614b54f3a0dd63edb2dfb2', './include/javascript/report_additionals.js' => '094fef2462c9d640ee3ef4dc7af613d0', - './include/javascript/sugar_3.js' => '37dafba08d7a447439882819e54de1e1', + './include/javascript/sugar_3.js' => '1648c3c6a4f2e6ba8eecb9425f897251', './include/javascript/sugar_connection_event_listener.js' => 'c8a148e865988e17f9b0328de44803a7', './include/javascript/sugar_yui_overrides.js' => 'd99ea792b967d53cef54e0b870acdd88', './include/javascript/sugarwidgets/SugarYUILoader.js' => '959d552199b65eab09ed534ade65b064', @@ -2280,11 +2289,11 @@ $md5_string = array ( './include/javascript/yui/build/yuitest/yuitest_core.js' => 'ed5230a0f4a885d8ea51c2fe78895d07', './include/javascript/yui/ygDDList.js' => '0cd9051a220de7e8c79bf5b9cccce10f', './include/json_config.php' => 'ba7fb6f2fb1df51bc367835406ef7ba5', - './include/language/en_us.lang.php' => '6963637150f1b221f9f70dd45d63bf87', + './include/language/en_us.lang.php' => 'ce7095b341f605c0fedb300f9ad95ab6', './include/language/en_us.notify_template.html' => 'c6a897ace7af46a44889dfab1a9d44c5', './include/language/getJSLanguage.php' => '1bc910bd5a9953fbf443d3d97fddbffa', './include/language/jsLanguage.php' => '3d27819dc00f2fe5426f72733a7edca1', - './include/modules.php' => '3223205c71cf9365281b9807c518c137', + './include/modules.php' => 'a2dbb8cc5bb27724399b6133f51f0fc9', './include/nusoap/changelog' => 'd75ed67ec93c02e5bce94eee8205b425', './include/nusoap/class.nusoap_base.php' => '7cf46001fe52a1abe276ce3874937cd6', './include/nusoap/class.soap_fault.php' => '9055e7b0b5962c47ddffe3607736d18c', @@ -2372,7 +2381,7 @@ $md5_string = array ( './include/templates/TemplateGroupChooser.php' => '7fa25dfd4b6667dbb94d30f65e50544a', './include/upload_file.php' => '10cfcf529e92e2ce1411ae5e111d79a6', './include/utils/BaseHandler.php' => '449516b84f4160f2c8880f7a06cd325f', - './include/utils/LogicHook.php' => '5f5e285b41b00ccf5f1972d159ce0e7a', + './include/utils/LogicHook.php' => '5c5bf9de49d7c37daedff422f5f846ff', './include/utils/activity_utils.php' => '8ffd9e9af5ca08e8aa26dbd014d499d5', './include/utils/additional_details.php' => 'cbb4ffe2c86d7644707cf88035cb2966', './include/utils/array_utils.php' => '50b2476acbfe22a61197dd7ee67e0260', @@ -2391,7 +2400,7 @@ $md5_string = array ( './include/utils/recaptcha_utils.php' => '73f5eddf707788c1dff4b7d07dc82656', './include/utils/security_utils.php' => 'e953d0b673df3df313ecf1ac975e8f57', './include/utils/sugar_file_utils.php' => '1c1915cad8c88feb0edbf5bbaee106c4', - './include/utils.php' => '55b02dfc0dc39c73996597a598b96264', + './include/utils.php' => '7ef07e3591bf75669eb1fc8359cbfff0', './include/vCard.php' => '44052bbedcdaba3fdf67cfc10a112e75', './include/ytree/ExtNode.php' => '000d4ccbdb6e0a7628c636128781b5e3', './include/ytree/JQueryTree.php' => '3712d2224b93818b990b876f8405b745', @@ -2484,7 +2493,7 @@ $md5_string = array ( './install/install_defaults.php' => 'd25503407f0db14fa875b295d0f34ae5', './install/install_utils.php' => '9910d3f9f63ac7fafd1ed474f8a773b1', './install/lang.config.php' => 'cb3e68fdb0600481497dcd60f0746aca', - './install/language/en_us.lang.php' => '443a21c6c24b089d6dc085a3ebb588d8', + './install/language/en_us.lang.php' => 'ab18c27ce23d99ef25fcf9602be1804c', './install/license.js' => '305c727ac2bd20adb6c169bf07b18a8e', './install/license.php' => '73aecaa43ecaf1743897049f991fb785', './install/licensePrint.php' => 'd8e905c5b6c769cd726ad94399118d88', @@ -2496,7 +2505,7 @@ $md5_string = array ( './install/populateSeedData.php' => '08323b30a68541fb5dc5b0b757e1051a', './install/processing.gif' => 'd7c43fc19181ee59862601bfce100b41', './install/ready.css' => '31c31392abb65459827b0761723b8e33', - './install/ready.php' => 'b717d12a149dc161790c6b953a2f569e', + './install/ready.php' => 'aa4832e4667e05b7b5eb8aff7ca8829f', './install/register.js' => 'b35a76c2a52053d5f9128fa78aa3adb0', './install/register.php' => '3c6e5671e698af7b372a6b0e8e783c54', './install/seed_data/Advanced_Password_SeedData.php' => '5e5384ab0fb37868c705172967993406', @@ -2564,7 +2573,7 @@ $md5_string = array ( './jssource/src_files/include/javascript/quickCompose.js' => '31c8e3efcf325c0c805018587fa585cb', './jssource/src_files/include/javascript/quicksearch.js' => '0329400df3d1b8e4eab0765f8fe9f2e4', './jssource/src_files/include/javascript/report_additionals.js' => 'baca991df446eaf401dda47d1685fad1', - './jssource/src_files/include/javascript/sugar_3.js' => '1013320f0f4e078b999641d94e979fb6', + './jssource/src_files/include/javascript/sugar_3.js' => '6dc9b5bab2dd6bf363cec7dff16aa248', './jssource/src_files/include/javascript/sugar_connection_event_listener.js' => '431e88e62c5a7005693189d1e9d8e916', './jssource/src_files/include/javascript/sugar_yui_overrides.js' => 'efbf74aa5e7d0af070ae7faab7725538', './jssource/src_files/include/javascript/sugarwidgets/SugarYUILoader.js' => 'abc59adf77cf85c0424dbcb6c356bee8', @@ -2604,7 +2613,7 @@ $md5_string = array ( './jssource/src_files/modules/EAPM/EAPMEdit.js' => '0e4186b5358b2b403e6c6ef717ee7aa4', './jssource/src_files/modules/EmailTemplates/EmailTemplate.js' => '6e48b43a26a1a16d3b7925001408b338', './jssource/src_files/modules/Home/tour.js' => '8d3968fbeb138587fbd6ab2e6bf565b9', - './jssource/src_files/modules/InboundEmail/InboundEmail.js' => 'c0c026adb789b2344ee1fdeb6f399be1', + './jssource/src_files/modules/InboundEmail/InboundEmail.js' => '1644be1f7b1854367142c261dcb2b2be', './jssource/src_files/modules/Leads/Lead.js' => '976776af2d77794460dc8bec9a0eab89', './jssource/src_files/modules/Meetings/duration_dependency.js' => '6fdc91648e92f1198bcf6f5ff4fae049', './jssource/src_files/modules/Meetings/jsclass_scheduler.js' => 'fbaac9e2b6ac6866a543232509f09eb5', @@ -2791,9 +2800,9 @@ $md5_string = array ( './lib/Search/AOD/LuceneSearchEngine.php' => '7a589c07fae355ad81ba1893e40e1bb9', './lib/Search/BasicSearch/BasicSearchEngine.php' => '1f6ecd5faa8a58cd6d2e06da6ca35cd3', './lib/Search/ElasticSearch/ElasticSearchClientBuilder.php' => '4743c29fa00cb5d4025c974af7b79156', - './lib/Search/ElasticSearch/ElasticSearchEngine.php' => '89b2b27ef2c5dd8e7482360a8e499bfc', + './lib/Search/ElasticSearch/ElasticSearchEngine.php' => '728d22251a99bf9606170fc1b48279ef', './lib/Search/ElasticSearch/ElasticSearchHooks.php' => '8898cc8d7cec43f13352397be9397f3e', - './lib/Search/ElasticSearch/ElasticSearchIndexer.php' => '580d41b2ebfb016fff416f9cea38dd57', + './lib/Search/ElasticSearch/ElasticSearchIndexer.php' => '3775a9343fb6e0323a35a592c5b94f87', './lib/Search/ElasticSearch/ElasticSearchModuleDataPuller.php' => 'ad1144c9e9f58af496714d6dcdbdbaa5', './lib/Search/ElasticSearch/elasticsearch.example.json' => 'cd776b60993b4521cd5cfd79db95af46', './lib/Search/Exceptions/SearchEngineNotFoundException.php' => '4f83830aea088643ee87f82bd173d96d', @@ -2811,7 +2820,7 @@ $md5_string = array ( './lib/Search/SearchConfigurator.php' => '3da51dc9e7b6d9b8fcbd45c0a8db5759', './lib/Search/SearchEngine.php' => '92775fe01a004fb58f1bf6edcc9f3dc8', './lib/Search/SearchModules.php' => '5261f4a9ab7a7d690618aefa08c6ca76', - './lib/Search/SearchQuery.php' => 'ccc5b48e33c5bd4c1cc51be8f5889466', + './lib/Search/SearchQuery.php' => '523292cc81871ec25ac17a7ab96bc888', './lib/Search/SearchResults.php' => 'bdcdd0018e1fa375dc9c0344dd00b14e', './lib/Search/SearchWrapper.php' => '2aaaa78656373bbdb2f0187a208d60eb', './lib/Search/SqlSearch/SimpleSqlSearchEngine.php' => 'db160c7c333582c7028a59f2bed03fcb', @@ -2819,7 +2828,7 @@ $md5_string = array ( './lib/Search/UI/MVC/View.php' => '060017bf23671e429cca7187b72ddd2a', './lib/Search/UI/SearchFormController.php' => '2cf159703562da6348ece57ef68313b4', './lib/Search/UI/SearchFormView.php' => '15662e4bd9237044fe1b74f41632660d', - './lib/Search/UI/SearchResultsController.php' => '4670567daea7e976e25cd215150f79ed', + './lib/Search/UI/SearchResultsController.php' => '788728a30dc77334a9682e49ff9f0307', './lib/Search/UI/SearchResultsView.php' => 'ce2615a6390cfe62924d44fdfc7a18fa', './lib/Search/UI/SearchThrowableHandler.php' => '14cd2232a5a73df32a755e85a52cd7fd', './lib/Search/UI/templates/search.form.tpl' => '8a03f27dd8860270f7c91d64c211fffe', @@ -2829,7 +2838,7 @@ $md5_string = array ( './lib/Utility/AntiMalware/Providers/ClamTCP.php' => 'f5eab54f8e3bcaa605a036a69bbb99b1', './lib/Utility/AntiMalware/Providers/Sophos.php' => '6edbdf87006927ea647395bc945238f5', './lib/Utility/ApplicationLanguage.php' => '5bc996ea12af48ba0f167a50f699483a', - './lib/Utility/ArrayMapper.php' => '128538045d9530d999a46b90ed14c3c1', + './lib/Utility/ArrayMapper.php' => '03c31accfe841c560daafe3d2d86c672', './lib/Utility/BeanJsonSerializer.php' => 'f12bad930b18f23e5270139f46966733', './lib/Utility/BeanJsonSerializer.yml' => 'c9f6e3dae78a0061d5ed1612eb50c02d', './lib/Utility/Configuration.php' => '97f895c91d3f247b6fe7be7f063efbfa', @@ -2949,7 +2958,7 @@ $md5_string = array ( './modules/ACLActions/language/en_us.lang.php' => '5fbb977deea129f58673a1a899dd19e5', './modules/ACLActions/metadata/subpaneldefs.php' => 'eeb92f8d430ef3fcc134cf83dc972497', './modules/ACLActions/vardefs.php' => 'fa9d7e17b81d212f1c5634714ebb6c0c', - './modules/ACLRoles/ACLRole.php' => '34d51d437972618a5068bfb279f31670', + './modules/ACLRoles/ACLRole.php' => 'a0de0c7d873bea9a4f15f6e5cb4b1e64', './modules/ACLRoles/ACLRoles.js' => '6a8acb939b3a059dea0ddf298f63123b', './modules/ACLRoles/Delete.php' => 'cddba6f5e193634d70a709c46445b57c', './modules/ACLRoles/DetailUserAccess.php' => 'cc3dfdcf77f5151b165959e5d9906d4d', @@ -3255,7 +3264,7 @@ $md5_string = array ( './modules/AOP_Case_Updates/metadata/quickcreatedefs.php' => '2ad09f9d04ec4e060eec43c51f189a17', './modules/AOP_Case_Updates/metadata/searchdefs.php' => '02962dadabd5f9ebb1a8d8f7e0821a43', './modules/AOP_Case_Updates/tpl/caseUpdateForm.tpl' => '090a89e828774dde4b9b744b3b73c4f9', - './modules/AOP_Case_Updates/util.php' => '98b2f2b14fea00af615f25f4fec404b5', + './modules/AOP_Case_Updates/util.php' => '70f248d011f0b5ad5f6ace48e762da70', './modules/AOP_Case_Updates/vardefs.php' => '20f0fcc9b6261db648076addc1e9c3a3', './modules/AOR_Charts/AOR_Chart.php' => 'e157566b99b62f4958dfff96c286410c', './modules/AOR_Charts/chartLines.js' => '4aa11696fc23f9c1d4f300e29334dbab', @@ -3308,7 +3317,7 @@ $md5_string = array ( './modules/AOR_Fields/language/en_us.lang.php' => '50a4309bdae43ce819c1a9bf95db1393', './modules/AOR_Fields/vardefs.php' => '385d0f1955e9e46e276159b67c716eb1', './modules/AOR_Reports/AOR_Report.js' => 'f95623b1ab32a4325a3f1c2649b63702', - './modules/AOR_Reports/AOR_Report.php' => '8f4cb0629e02de58e997250d6a01bb64', + './modules/AOR_Reports/AOR_Report.php' => '90c1567df1f72d4a19982213a727f13b', './modules/AOR_Reports/AOR_Report_After.js' => 'ab77afb81f872f96f22bc676d0ae4beb', './modules/AOR_Reports/AOR_Report_Before.js' => 'ab5397e1ca56871cb28514092029fd90', './modules/AOR_Reports/Dashlets/AORReportsDashlet/AORReportsDashlet.js' => '95fb8234d31774e011b0984229dca16a', @@ -3655,8 +3664,8 @@ $md5_string = array ( './modules/Activities/tpls/PopupHeader.tpl' => 'a5d6e208e7df413a1247c17b59402e41', './modules/Activities/views/view.list.php' => '2f8f97ee242f1c60f80f18c23456c4e5', './modules/Activities/views/view.modulelistmenu.php' => 'b287fb1055865e6fe47ad46d584e054a', - './modules/Administration/AOPAdmin.php' => 'c5467f61940b965c61147e8de0cb0aeb', - './modules/Administration/AOPAdmin.tpl' => 'a29e010dc42642c97eb6bc45b77586ca', + './modules/Administration/AOPAdmin.php' => '52db79bb630ad53239ac17c5e260a61a', + './modules/Administration/AOPAdmin.tpl' => '04391325ff3ba9d2d16d427f0a60d0ab', './modules/Administration/AOSAdmin.php' => 'd7e75c25af0a4e4a9bd954280b7450ec', './modules/Administration/AOSAdmin.tpl' => 'ee8d38886e9253512b0d9db8d9613b5a', './modules/Administration/Administration.php' => 'afb22cff58476d164e61eb4000ac3133', @@ -3667,7 +3676,7 @@ $md5_string = array ( './modules/Administration/CustomizeFields.php' => '2b4c96aa7706703e25d7b7e5d03dd78f', './modules/Administration/Development.php' => '7b8cf54f333836a77c267f35dca137bc', './modules/Administration/Diagnostic.php' => 'f8042639887cc4fddef0ca3b7297b8a6', - './modules/Administration/Diagnostic.tpl' => '667ba5c34e72f0ebcdcc32e1c0d031d0', + './modules/Administration/Diagnostic.tpl' => '187755da9831dc3eedd0597df03b5b4d', './modules/Administration/DiagnosticDelete.php' => '3c4c57016ab9af8d9210f4066c0a6373', './modules/Administration/DiagnosticDownload.php' => 'adf38059f96a770e1f6f0e86c801a142', './modules/Administration/DiagnosticRun.php' => '03b55085e82e81362ca91a275a0cd84d', @@ -3689,10 +3698,10 @@ $md5_string = array ( './modules/Administration/PDF/buttons.tpl' => '4e87ffb6b8826843f3cb222cfada0315', './modules/Administration/PDF/view.tpl' => '140212a6ce199fe89ae220027628081c', './modules/Administration/PDFSettings.php' => '4f30b105dd71eed4c92dcc390beda5b7', - './modules/Administration/PasswordManager.php' => 'e997d11ecfbfe0352f863a814176efe9', + './modules/Administration/PasswordManager.php' => 'db2a2eca793f1d7330af29a5f4ff52fd', './modules/Administration/PasswordManager.tpl' => '88d1898cf0bae5d3e053eb21ffc34ade', './modules/Administration/PasswordManagerSecurity.tpl' => '5010789c306f4c665e0ebe0466c9f50d', - './modules/Administration/QuickRepairAndRebuild.php' => '44b428d870c178243326bbf1d51cb6dd', + './modules/Administration/QuickRepairAndRebuild.php' => '14a4e14865732a12f4cbda21add1c8cc', './modules/Administration/RebuildAudit.php' => '7b1c137ae149d763e44053ae542a4432', './modules/Administration/RebuildConfig.php' => 'd1b925885ca4b6da62add9d26548c35c', './modules/Administration/RebuildDashlets.php' => 'e549bd62a92ffac96744a113a50835f0', @@ -3731,9 +3740,9 @@ $md5_string = array ( './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsInvalidMethodTypeException.php' => 'd8465264b9d4c195aa1936552f93b5a7', './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsInvalidSubActionArgumentsException.php' => '0c7dccc07b1f188b0c9e0a2aa7e56a51', './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsNoMethodException.php' => 'f631b9edef8522ef9a897c47e77831fe', - './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsPage.php' => '7c958075bb8dc2dde8b54db9519426c3', - './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsSubActionHandler.php' => '0cc2feed6130ad15f81be89c352968b5', - './modules/Administration/SyncInboundEmailAccounts.php' => '12d7e813df836c9791c0335e4f04bbe5', + './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsPage.php' => '5ca9d5a6db5588469337b0be3267d66f', + './modules/Administration/SyncInboundEmailAccounts/SyncInboundEmailAccountsSubActionHandler.php' => '899bd94ee1f6348798230e9654d1e6f3', + './modules/Administration/SyncInboundEmailAccounts.php' => 'f8080077b58070025c9dda11561537f5', './modules/Administration/Updater.html' => '41dafda58b09eb9893644d0e6b13499f', './modules/Administration/Updater.php' => '8c6ed7adff356877fd3a52525e42f7fe', './modules/Administration/Upgrade.php' => '0923bd7f06f07a793d75099119a8a582', @@ -3755,9 +3764,9 @@ $md5_string = array ( './modules/Administration/index.tpl' => 'e2267cd142b9509c13eaed32180e5e88', './modules/Administration/javascript/Administration.js' => '3548a43145e0b00b880d50fce62126f6', './modules/Administration/javascript/Async.js' => '7cda344ae778c0633b8941dcc6fd2bd6', - './modules/Administration/language/en_us.lang.php' => 'd8ccac3816ffad28005a4a4ab0bbd0da', + './modules/Administration/language/en_us.lang.php' => '634ef77b8cd3ef0bb22c7eb2c062e65e', './modules/Administration/metadata/SearchFields.php' => '678fb87cfc3b3e95d7e7ea8a72d8da16', - './modules/Administration/metadata/adminpaneldefs.php' => 'f4a4741b7165c657d017869bdc10bc67', + './modules/Administration/metadata/adminpaneldefs.php' => '31fee9f25c4a34fca0e18fed684af9fb', './modules/Administration/ncc_config.php' => '643e7a46ad14a6aed7431c6679362b95', './modules/Administration/repairDatabase.php' => '237183a42ea27d8a3fddccc3f448d8a6', './modules/Administration/repairSelectModule.php' => '9588bcfaff9028bf6849038f108079f1', @@ -4026,7 +4035,7 @@ $md5_string = array ( './modules/CampaignTrackers/vardefs.php' => 'bc3f35b69c922008f5ed3f71d1e7e557', './modules/Campaigns/Campaign.php' => '83dda271352bdaf2c2741bd91e81e681', './modules/Campaigns/CampaignDiagnostic.html' => '60080d757c3e55758872387e86ad3b6a', - './modules/Campaigns/CampaignDiagnostic.php' => '79c01f4b173f139a0b7eaa514128f37d', + './modules/Campaigns/CampaignDiagnostic.php' => '838ca95c838d4648b198866503ded0ed', './modules/Campaigns/CaptchaValidate.php' => 'b3120831810a3081319b8b741104724f', './modules/Campaigns/Charts.php' => '0ec076f700155b1261e7fa8b9eb05093', './modules/Campaigns/Charts1.php' => '0e0f100a44c3d70add09f7cf978e63a4', @@ -4075,7 +4084,7 @@ $md5_string = array ( './modules/Campaigns/WebToPersonCapture.php' => '27e24a36a16897c8a4fac043c8b85516', './modules/Campaigns/WizardCampaignSave.php' => 'f7a73bc932dcf289d4d5d94eee3ad138', './modules/Campaigns/WizardEmailSetup.html' => 'bdf9ae5e62512fba93fc6660ecc9bf64', - './modules/Campaigns/WizardEmailSetup.php' => '5f7a49cf10fa319d90c32310a76fdce9', + './modules/Campaigns/WizardEmailSetup.php' => '2a27180993e401a90335777939309d90', './modules/Campaigns/WizardEmailSetupSave.php' => '863bd22c85e4e401fab39c8c2464372b', './modules/Campaigns/WizardHome.html' => '347b5be091dfc343497a518fd5aae913', './modules/Campaigns/WizardHome.php' => 'ec5b6e745550bd1c61b1127dc96c4a12', @@ -4111,7 +4120,7 @@ $md5_string = array ( './modules/Campaigns/tpls/WizardNewsletter.tpl' => '168198cad6b844c66c1f1b7bc0c0d7e3', './modules/Campaigns/tpls/campaign-inactive.tpl' => 'fa6ad86dabbbb0350649cdd48bda9801', './modules/Campaigns/tpls/progressStepsStyle.html' => '188a9323131c1665062b361e1a26df10', - './modules/Campaigns/utils.php' => 'ec1404fdd8f9051b132b776b08472854', + './modules/Campaigns/utils.php' => '30877564f0bc47a307586bbf0faf2c78', './modules/Campaigns/vardefs.php' => '3356dc662190231795ec344641c886ab', './modules/Campaigns/views/view.classic.php' => 'd3dd10e40e7e6a9d5d0168996c80792f', './modules/Campaigns/views/view.detail.php' => '21ab18453038a4f2ee5458eea0a94ed9', @@ -4494,7 +4503,7 @@ $md5_string = array ( './modules/EmailAddresses/vardefs.php' => 'b812f8828d28cb7e09240773674f033a', './modules/EmailMan/EmailImage.php' => 'b48af6ba51f94bbb96a28008bd90522f', './modules/EmailMan/EmailMan.php' => '5e785f21cb6debd7139f0339be236e56', - './modules/EmailMan/EmailManDelivery.php' => '389efe1bb53c7ae08e9620df8ee14139', + './modules/EmailMan/EmailManDelivery.php' => 'e6b2c2d356c5e787f0a30919582f63ff', './modules/EmailMan/Forms.php' => 'd939f3555ef708f533a77c77b696ccd8', './modules/EmailMan/Menu.php' => '9fec01e70c034091a9fe652a61407886', './modules/EmailMan/action_view_map.php' => 'e4b8e3c021d90ed66c74caa7e1f8e4c5', @@ -4569,19 +4578,19 @@ $md5_string = array ( './modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.meta.php' => '31dc1ea85cee70a8abab57f66cd77684', './modules/Emails/Dashlets/MyEmailsDashlet/MyEmailsDashlet.php' => 'ca55901c82bab1060a87e98af0ca524f', './modules/Emails/Delete.php' => '9c783f1e16850cfe4de22d719d7ce8ca', - './modules/Emails/Email.php' => 'da0933084b76101c68fec1d4d355d78d', + './modules/Emails/Email.php' => 'e79b83979c605cc261a93fdd855dee6c', './modules/Emails/EmailException.php' => '360377b7b2b00fc5d6bb9935c3c92a3f', './modules/Emails/EmailFromValidator.php' => '275e4e1167d68361483e18bae111fdc3', './modules/Emails/EmailUI.css' => '79ef2b93606dc4b6d4e04b679c0b898f', - './modules/Emails/EmailUI.php' => 'f8b37b1db23d7baaa64d8eb4a99d2d02', + './modules/Emails/EmailUI.php' => '7cc23aa2caa633911ea7db193a6f2a70', './modules/Emails/EmailUIAjax.php' => '474940d575ae666cd0b00437f75e76d4', './modules/Emails/EmailValidatorException.php' => 'cb225382f8842456d005769be4f3752d', - './modules/Emails/EmailsController.php' => '9a70756105e5fba7221fd7d77f02ae45', + './modules/Emails/EmailsController.php' => '08748fffab0b9bc0d757b8aee13a766a', './modules/Emails/EmailsControllerActionGetFromFields.php' => 'b9d8167b00bff53cf76503c5023207f7', './modules/Emails/EmailsDataAddress.php' => 'ba1274fe0f3bc27f4cb6d397adf42de7', - './modules/Emails/EmailsDataAddressCollector.php' => '35e502fadb385a66d71bc44ddd62a259', + './modules/Emails/EmailsDataAddressCollector.php' => '2ff867b7e4b76f10e983af57030ddd45', './modules/Emails/EmailsSignatureResolver.php' => '67c883763451b6ff65741fc0c3b1029e', - './modules/Emails/Folder.php' => '7b869a8d8f462d08656cf5cd8005e1a5', + './modules/Emails/Folder.php' => '1c15b4b4c6f541b65009384c1936bf0e', './modules/Emails/GenerateQuickComposeFrame.php' => 'b3c126bee579c9db56e11f3c3d3fdee0', './modules/Emails/Grab.php' => '95b21789d0a259bd4dff2e1e50752051', './modules/Emails/Menu.php' => '25ef132c32614fb9dff1c2ff9b399899', @@ -4616,10 +4625,10 @@ $md5_string = array ( './modules/Emails/include/ListView/DeleteEmailAction.js' => 'f55735d833d2a77bea56b63e97d5d610', './modules/Emails/include/ListView/FoldersViewModal.js' => '3bd4d38fa4b6d5db35423005004d8d66', './modules/Emails/include/ListView/ImportEmailAction.js' => 'a658f8cb5a4bb0d17a635c7631fad088', - './modules/Emails/include/ListView/ListViewDataEmails.php' => '0f4002220cfd3da8cc0ed9fab91cfb52', + './modules/Emails/include/ListView/ListViewDataEmails.php' => '8838985127b9e0e08b33d6bb30063f99', './modules/Emails/include/ListView/ListViewDataEmailsSearchAbstract.php' => '0c79defa61814a8ad7d5c6607068ac6e', './modules/Emails/include/ListView/ListViewDataEmailsSearchOnCrm.php' => '4a61d87963a828e96aaae4a6305194d4', - './modules/Emails/include/ListView/ListViewDataEmailsSearchOnIMap.php' => 'a41fb7a4a002db7e75bbc4f33f0b53db', + './modules/Emails/include/ListView/ListViewDataEmailsSearchOnIMap.php' => 'd9c498549e2f25ff601f53854ce6b8ba', './modules/Emails/include/ListView/ListViewHeader.js' => 'a74d18ab45171fb85502d9777c6404d9', './modules/Emails/include/ListView/ListViewHeader.tpl' => '548957f43d54966db79f8c03127a8560', './modules/Emails/include/ListView/ListViewSmartyEmails.php' => 'b832e8aa4a47555934cdd5c292d716c0', @@ -4631,7 +4640,7 @@ $md5_string = array ( './modules/Emails/include/displayIndicatorField.php' => '1fad0b67cf02e4d9d922915374851814', './modules/Emails/include/displaySubjectField.php' => '5586ded7c7471bfc36bb12397e0a68e7', './modules/Emails/javascript/Email.js' => 'eec2d71e9610ad46c94bc7ae9851c746', - './modules/Emails/javascript/EmailUI.js' => '9bdd220de280920ba9ca09d0f94429f3', + './modules/Emails/javascript/EmailUI.js' => '0d81e92bbc32af59c0e03c596e382489', './modules/Emails/javascript/EmailUICompose.js' => '47c90104973369fa9b454e614662a1a9', './modules/Emails/javascript/EmailUIShared.js' => 'dd25ff03a2af3d6f51d15892bb4e8e91', './modules/Emails/javascript/ajax.js' => '6c29f87276d59cd1ec23f246e7dd9432', @@ -4652,7 +4661,7 @@ $md5_string = array ( './modules/Emails/metadata/detailviewdefs.php' => '0e6b0bc4f9e006978b6d33dc902a6779', './modules/Emails/metadata/editviewdefs.php' => 'ab93b79de12963a9ca0e112d50477958', './modules/Emails/metadata/importviewdefs.php' => '393b8a7c1f9d5b23bc75ce5d6dfdfc51', - './modules/Emails/metadata/listviewdefs.php' => '6352a475112c82070f741f5f6386aff3', + './modules/Emails/metadata/listviewdefs.php' => 'a5eb4fb66965e791efad9f4bf491ff3a', './modules/Emails/metadata/metafiles.php' => '9876f3a92c8fffb0b7d3aec6993c370d', './modules/Emails/metadata/nonimporteddetailviewdefs.php' => 'ae75f85d07dc926ff8a489cfad6c27a0', './modules/Emails/metadata/popupdefs.php' => 'ba85426b428b440975b08f5e9a016ece', @@ -4709,7 +4718,7 @@ $md5_string = array ( './modules/Emails/views/view.detailnonimported.php' => '9db1a37dd52c269a3f98963379704a11', './modules/Emails/views/view.edit.php' => 'b550b1b4445d88eec112ae13ce5deae8', './modules/Emails/views/view.import.php' => 'c736c9992c0401643e8a15250bc7ce73', - './modules/Emails/views/view.list.php' => 'c21e4087255556ec8e9038780d6591c5', + './modules/Emails/views/view.list.php' => '27cd5ecc7b270683e629e702eef03430', './modules/Emails/views/view.popup.php' => '4ff1e52f105970c29fed966e2f058dd3', './modules/Emails/views/view.savedraftemail.php' => '000c8d786c87e0ad997fc5de443d9b2c', './modules/Emails/views/view.sendemail.php' => '78784b11ddb5257b0f3f5c59c9db17a1', @@ -4739,6 +4748,43 @@ $md5_string = array ( './modules/Employees/views/view.detail.php' => '2914878ea39a317773d9619d18b7c5ef', './modules/Employees/views/view.edit.php' => 'af1290ff28c858906d705a21a0f9590d', './modules/Employees/views/view.list.php' => '3fac70b690d87e7e7dd95f5e2602d129', + './modules/ExternalOAuthConnection/ExternalOAuthConnection.php' => 'cbb2e64b88e64434b92fd0fcbd8e2ac4', + './modules/ExternalOAuthConnection/Menu.php' => '6ae8433d8a70354ed103bf6c9c227b8a', + './modules/ExternalOAuthConnection/controller.php' => 'bfc8e833c3a36ac58f6ffa562573ae55', + './modules/ExternalOAuthConnection/entrypoint/redirectToExternalOAuth.php' => '5c7689fab50bbb50b2b10c9a5bf497c8', + './modules/ExternalOAuthConnection/entrypoint/setExternalOAuthToken.php' => '7b079da4660ddb159a9b529bd05905f8', + './modules/ExternalOAuthConnection/js/authenticate.js' => '2f9c2092d9fe9735c3b860d693d87969', + './modules/ExternalOAuthConnection/js/fields.js' => '41c33c39973e488bf1c34ada8305f433', + './modules/ExternalOAuthConnection/language/en_us.lang.php' => '827b4374757a8a78b6a8c22d489e4e88', + './modules/ExternalOAuthConnection/metadata/SearchFields.php' => 'fb3470c35919d6b84d0cdfb9f7290e3c', + './modules/ExternalOAuthConnection/metadata/detailviewdefs.php' => '25b2cf0f9fc6d780b7f085efa4b85dda', + './modules/ExternalOAuthConnection/metadata/editviewdefs.php' => '591963a075e340aa2b8462b6a2503a77', + './modules/ExternalOAuthConnection/metadata/listviewdefs.php' => '71cf23498927393829df9ab78132ab96', + './modules/ExternalOAuthConnection/metadata/metafiles.php' => '5cc48e251ba234ba9985072185d10c8c', + './modules/ExternalOAuthConnection/metadata/searchdefs.php' => 'a2c59ab32c118fcf194bf0d22587f51e', + './modules/ExternalOAuthConnection/metadata/subpaneldefs.php' => 'd6c6da8edcab19e164820493779963b3', + './modules/ExternalOAuthConnection/provider/ExternalOAuthProviderConnector.php' => '6f2936a4d7161d29fae83110cf321131', + './modules/ExternalOAuthConnection/provider/ExternalOAuthProviderConnectorInterface.php' => '6b49d82a98f9015cb2e40af139ab930e', + './modules/ExternalOAuthConnection/provider/Generic/GenericOAuthProviderConnector.php' => 'aef335448cc29998d0a5feecad88d666', + './modules/ExternalOAuthConnection/provider/Microsoft/MicrosoftOAuthProviderConnector.php' => '5a3fa092bdbdd57e5b33e9786624302a', + './modules/ExternalOAuthConnection/services/OAuthAuthorizationService.php' => '98bd48935353a426768816b220700997', + './modules/ExternalOAuthConnection/tpl/setToken.tpl' => '3001ed5ecb6ccfe3a967c1f3a45f042f', + './modules/ExternalOAuthConnection/vardefs.php' => '10926d5ab08f56277f12ca8bb4fe644f', + './modules/ExternalOAuthConnection/views/view.list.php' => 'bf6a7674a1b649099afa941fb7d2e0ba', + './modules/ExternalOAuthProvider/ExternalOAuthProvider.php' => 'ff4f5725e6ea98b07c06317087b54d30', + './modules/ExternalOAuthProvider/Menu.php' => '1d5f42e855c60778bb371e2451bd7c44', + './modules/ExternalOAuthProvider/controller.php' => '4092c7ff3987c1df62c2180a0708c7de', + './modules/ExternalOAuthProvider/language/en_us.lang.php' => '250b259d406bce7a9bf834e1b9a4c936', + './modules/ExternalOAuthProvider/metadata/SearchFields.php' => '0238216ef6c3eb39b0a71e70bb58d592', + './modules/ExternalOAuthProvider/metadata/detailviewdefs.php' => 'de6eaf9ac35fe3ae956553769281345d', + './modules/ExternalOAuthProvider/metadata/editviewdefs.php' => 'ae452aa2d0eb15915882283766d41a33', + './modules/ExternalOAuthProvider/metadata/listviewdefs.php' => '55d6f8fd42cfd23161cf72c2e9eef220', + './modules/ExternalOAuthProvider/metadata/metafiles.php' => 'faee880023fe8aa5ee96680fffc52aaf', + './modules/ExternalOAuthProvider/metadata/searchdefs.php' => 'fdd1f160af740c9519bb7bc6618e097d', + './modules/ExternalOAuthProvider/metadata/subpaneldefs.php' => '7b74cbeac99be4dbe347dec438d65745', + './modules/ExternalOAuthProvider/utils.php' => 'bcc88930505c62d88b0c4f9d51425401', + './modules/ExternalOAuthProvider/vardefs.php' => 'f37309817977dfa9d68685cd62450208', + './modules/ExternalOAuthProvider/views/view.list.php' => 'f521fd6146ff159ef6e3933713b84617', './modules/FP_Event_Locations/Dashlets/FP_Event_LocationsDashlet/FP_Event_LocationsDashlet.meta.php' => '1cc320528f655f9caf565c5202f27f08', './modules/FP_Event_Locations/Dashlets/FP_Event_LocationsDashlet/FP_Event_LocationsDashlet.php' => 'e59a23bd3847471f45e86ef0cb5e40dc', './modules/FP_Event_Locations/FP_Event_Locations.php' => 'f53d7a7f39aec1199b7637f05be58b6b', @@ -4939,30 +4985,46 @@ $md5_string = array ( './modules/Import/views/view.step4.php' => '8694e2f07e6ddc9128af648d42aa802d', './modules/Import/views/view.undo.php' => '0f11a824c733c819214ef88f666358b5', './modules/InboundEmail/AOPInboundEmail.php' => '2c74ce41273c1982b221a8862dfcc997', - './modules/InboundEmail/Delete.php' => 'e0672cbf0ad18846fb8303e8bd908629', - './modules/InboundEmail/DetailView.html' => '9eec384f2d5c6409dae36b9b8abd9a3c', - './modules/InboundEmail/DetailView.php' => '0e82f93d3caf1577d75e15eefb0bd598', + './modules/InboundEmail/Delete.php' => '2dec384b7a0c8bc29bf2dcfdfc26506c', './modules/InboundEmail/EditGroupFolder.php' => 'd7c41e935f01bfe5b6ce52c2f0385c9b', - './modules/InboundEmail/EditView.html' => '785f83b87c343cc1d8fbf27e5208472a', - './modules/InboundEmail/EditView.php' => '220f324796e33920332b9b432c7a952f', - './modules/InboundEmail/InboundEmail.js' => 'f37733f6ef00da52b9230d9168f13a29', - './modules/InboundEmail/InboundEmail.php' => 'fa4e3077620acf2dd5359f494bd6a2f7', - './modules/InboundEmail/ListView.html' => '8b0dd15b6993338cccd5bb39ae7184d4', - './modules/InboundEmail/ListView.php' => 'dda0cffd64113ebf057d34ab35e637e6', - './modules/InboundEmail/Menu.php' => 'eed62ccb742c392298bc1dfe9878eb97', + './modules/InboundEmail/InboundEmail.js' => 'f5d19901b247cdc225a999b08204cf45', + './modules/InboundEmail/InboundEmail.php' => '14c6126769c4e9afd7ae88e46c45e1c8', + './modules/InboundEmail/Menu.php' => 'bfb4c000e482ae7206a9c0dea76acafe', './modules/InboundEmail/Overview.php' => 'e12117e0d20035b2c04dad6526783f07', - './modules/InboundEmail/Popup.php' => '42167ecdc28380ccaefe89a3e5ab1a4d', - './modules/InboundEmail/Save.php' => '100686ad555581fffc3e8f54fc8c999c', + './modules/InboundEmail/Popup.php' => 'b37711aaab32543d3a6a1fb0386c679e', + './modules/InboundEmail/PostSave.php' => 'bc1907c89fd2dc22e2ce13ada5f5c62a', + './modules/InboundEmail/Save.php' => 'cac8ae11bba0f6d9512a835a81355d1a', './modules/InboundEmail/SaveGroupFolder.php' => '6894a715a39d2074b652a30a1463a430', - './modules/InboundEmail/ShowInboundFoldersList.php' => '5b52d96db389a50cd7fbd6d2c1c9a952', + './modules/InboundEmail/ShowInboundFoldersList.php' => '7c94ce6fa12d6e5ebefd5c1746e20662', './modules/InboundEmail/View.html' => 'aeaf0daf6157c5a74738a47145576ee0', - './modules/InboundEmail/field_arrays.php' => '8daa51b73ea6499fbf2ab18767c0fe78', - './modules/InboundEmail/index.php' => '22be0681c56292809306913fb48f3178', - './modules/InboundEmail/language/en_us.lang.php' => 'bfa663d5408d00baaa1631d53ff123a2', + './modules/InboundEmail/controller.php' => 'b41d298f9bb2ac68235d7a12f7714de8', + './modules/InboundEmail/field_arrays.php' => '92ec96b7f8a11b5cb6a89892406c94b6', + './modules/InboundEmail/js/auth_type_fields_toggle.js' => 'c7a860d744eb86c30a892a2277a2f673', + './modules/InboundEmail/js/case_create_toggle.js' => '562861c813aeeff13ebbc12861ef360a', + './modules/InboundEmail/js/distribution_toggle.js' => 'f138273ae9801f2e59350ac844097f67', + './modules/InboundEmail/js/fields.js' => '3234a04a145438bad3d2560f2e3deb75', + './modules/InboundEmail/js/fields_toggle.js' => '3e81efcbb518185f29a58f4f4cef3eac', + './modules/InboundEmail/js/mail_folders.js' => '365df2f5552c3ca4fb83338920db1617', + './modules/InboundEmail/js/owner_toggle.js' => '439227988acf9cddae78496d4ffe3fd6', + './modules/InboundEmail/js/panel_toggle.js' => '9f939fcd54b840e766ad90e903dc2445', + './modules/InboundEmail/js/ssl_port_set.js' => 'f44377e9d154de21127af16b31fd5418', + './modules/InboundEmail/js/test_configuration.js' => 'c6698de64dcea19490323d074aab6dc8', + './modules/InboundEmail/language/en_us.lang.php' => 'cfa041c826f2607e34bd7a0ec150bf26', + './modules/InboundEmail/metadata/SearchFields.php' => '6f2e27a576a956001693c7af731539dc', + './modules/InboundEmail/metadata/detailviewdefs.php' => 'eac3ee94aecb8d0ade34281f6aab1bb4', + './modules/InboundEmail/metadata/editviewdefs.php' => 'c21d08248f7ea73f1595c1c074679b8a', + './modules/InboundEmail/metadata/listviewdefs.php' => '1c2356b61d6a96ec253251df20849673', + './modules/InboundEmail/metadata/metafiles.php' => '8fcde39fad982363c862e4fbf53eb35e', + './modules/InboundEmail/metadata/searchdefs.php' => '28102b46db74ae6a90fcb93d70cc1cba', + './modules/InboundEmail/metadata/subpaneldefs.php' => 'd177016155e0874dd6a4791f1fb35e76', './modules/InboundEmail/temp.php' => '181b066ddeb4e0acbd93ec891ab2fb6f', './modules/InboundEmail/tpls/checkImap.tpl' => 'e6ffd2a625f24091435894426d47016c', './modules/InboundEmail/tpls/systemSettingsForm.tpl' => 'f9fd7244167a1822c4673637ba9db2ba', - './modules/InboundEmail/vardefs.php' => '98bea685916f0a87055942750906e953', + './modules/InboundEmail/utils.php' => '1f5c1737a6682c63c60aa6270d99d8ed', + './modules/InboundEmail/vardefs.php' => 'f5222a3d914a052c979391357d92168a', + './modules/InboundEmail/views/view.detail.php' => 'c542825b80e41328a0fee82baa891873', + './modules/InboundEmail/views/view.edit.php' => '7325f9bae56b6fa44a15bbdfa01e09bf', + './modules/InboundEmail/views/view.list.php' => '0e9f5d43a7400362cee323a7bc332b94', './modules/LabelEditor/EditView.html' => 'fe93e6a7e2174ae321be14378465dfa2', './modules/LabelEditor/EditView.php' => 'cdec2e48a8882ecdd8d32b508390ba2f', './modules/LabelEditor/Forms.php' => 'baf0abfa37e381f3bebb62a873304f1f', @@ -5091,7 +5153,7 @@ $md5_string = array ( './modules/MergeRecords/Menu.php' => 'adeb546c41b28fcde1b26c0e79993212', './modules/MergeRecords/Merge.js' => 'c946baecd2cea038c1c7dc05d39ec159', './modules/MergeRecords/MergeField.html' => 'e922f12b0857d30cc780d9a9602deadd', - './modules/MergeRecords/MergeRecord.php' => '994b83feb69353895bb2233fe5ac7c3b', + './modules/MergeRecords/MergeRecord.php' => 'dfdca4a622af8fca66135ba64561bfb4', './modules/MergeRecords/SaveMerge.php' => '675144d12d12c459180418739f16ee69', './modules/MergeRecords/SearchForm.html' => 'bd7522bd9e435d7ba158d9ec8b0476e0', './modules/MergeRecords/Step1.html' => '2835549086784cde9d01e493766f64b4', @@ -5374,22 +5436,32 @@ $md5_string = array ( './modules/OptimisticLock/language/en_us.lang.php' => '281cfcb6abc4854f792867d135927942', './modules/OutboundEmailAccounts/Dashlets/OutboundEmailAccountsDashlet/OutboundEmailAccountsDashlet.meta.php' => '564160df3adaa9773a86a2a244df28a2', './modules/OutboundEmailAccounts/Dashlets/OutboundEmailAccountsDashlet/OutboundEmailAccountsDashlet.php' => '22ef1ad6261d81c6c1b28409629a3d0a', - './modules/OutboundEmailAccounts/OutboundEmailAccounts.php' => 'cc7bccd0ed8d8ec335b1d4e9a28e2ccc', - './modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php' => '2db44e3dff97dd2498c9621b4718bae7', - './modules/OutboundEmailAccounts/language/en_us.lang.php' => '9b9becdbac51bb11ec5009007f7aa682', - './modules/OutboundEmailAccounts/metadata/SearchFields.php' => 'b1d3821e188938066156f0c85d4e37fe', + './modules/OutboundEmailAccounts/Menu.php' => 'ba722ed3aadca9ab1b969b70b9fbb519', + './modules/OutboundEmailAccounts/OutboundEmailAccounts.php' => 'a3381c6d65dbbf0e7fb4d7d4c687ef4b', + './modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php' => '20b589d798825ca87ddc5456bcb96ff2', + './modules/OutboundEmailAccounts/controller.php' => '7ca3815b742cdd6c05566610b4d77171', + './modules/OutboundEmailAccounts/js/fields.js' => '07c9e6fb4762f099f79477d27f562439', + './modules/OutboundEmailAccounts/js/owner_toggle.js' => '8e5defb59d799779164997733f7991c5', + './modules/OutboundEmailAccounts/js/smtp_auth_toggle.js' => 'b0d4e2ad9d7a92eb57702613d67dfedd', + './modules/OutboundEmailAccounts/js/ssl_port_set.js' => '97d8f0bef082f24e9fb2dd0d9446c626', + './modules/OutboundEmailAccounts/language/en_us.lang.php' => 'ea2f58968b90e3e6996e236d2542c499', + './modules/OutboundEmailAccounts/metadata/SearchFields.php' => '8c105dc9670943e3677c33ef51b4a61e', './modules/OutboundEmailAccounts/metadata/dashletviewdefs.php' => '93e262245007ffc79f1ff9938e8bbac9', - './modules/OutboundEmailAccounts/metadata/detailviewdefs.php' => '948df4801e3d229ea4bac06e247fd643', - './modules/OutboundEmailAccounts/metadata/editviewdefs.php' => 'f28a1bf18ca13bcfe8229c1d5fa6eee4', - './modules/OutboundEmailAccounts/metadata/listviewdefs.php' => '82a5ef5ac3d3c79f653e91f2b2b4a7b8', + './modules/OutboundEmailAccounts/metadata/detailviewdefs.php' => '7e4c8f1bfbd71405a426a403cf820c3f', + './modules/OutboundEmailAccounts/metadata/editviewdefs.php' => '37225d9f8027552f058bb386de7bc5dc', + './modules/OutboundEmailAccounts/metadata/listviewdefs.php' => '428a7fcfcac94e9e1875629f2d898f92', './modules/OutboundEmailAccounts/metadata/metafiles.php' => 'd163cfdaa7fa3d697326f798bbcc6867', - './modules/OutboundEmailAccounts/metadata/popupdefs.php' => '3464601d89e63838c93f7bfcd2142eec', + './modules/OutboundEmailAccounts/metadata/popupdefs.php' => 'ccb60aa6a4e11726dab4e1bc99000b34', './modules/OutboundEmailAccounts/metadata/quickcreatedefs.php' => 'c738540479456935212e6b806706002a', './modules/OutboundEmailAccounts/metadata/searchdefs.php' => '76ceb98b2e64281d411caec3e3bfed07', './modules/OutboundEmailAccounts/metadata/studio.php' => 'd1a4aee4586f29bc1d22f2719b156bd1', + './modules/OutboundEmailAccounts/metadata/subpaneldefs.php' => '5928a4543d2c06d6ba9e032e01fc5081', './modules/OutboundEmailAccounts/metadata/subpanels/default.php' => 'a58b6710e2acc338ef0712175eb95cf5', './modules/OutboundEmailAccounts/smtpPreselection.tpl' => 'f3d86727a10f3fd50e16fa88769478fd', - './modules/OutboundEmailAccounts/vardefs.php' => '07d0609b4814572d07a781fb75c5e70a', + './modules/OutboundEmailAccounts/vardefs.php' => '1e9b9038a810365377df4f7beabfc152', + './modules/OutboundEmailAccounts/views/view.detail.php' => 'c71af76cd203a164fe5a99e7c0f8db10', + './modules/OutboundEmailAccounts/views/view.edit.php' => '3fe1866151f37a6a42b9a224b1b65876', + './modules/OutboundEmailAccounts/views/view.list.php' => 'e2b1a1bd2a9a517fe5eb0bf17f6cf4d5', './modules/Project/Dashlets/MyProjectDashlet/MyProjectDashlet.data.php' => 'cece42df3c32ba5e9670cbdc7edefd0e', './modules/Project/Dashlets/MyProjectDashlet/MyProjectDashlet.meta.php' => 'f77f6be351839075a309369c4f307877', './modules/Project/Dashlets/MyProjectDashlet/MyProjectDashlet.php' => 'e86a9ace71623a867f5e87adc31121e1', @@ -5504,7 +5576,7 @@ $md5_string = array ( './modules/ProspectLists/Save.php' => '9b3bad7aff47a312451e34a44f63fee8', './modules/ProspectLists/SubPanelView.html' => '12a8e783bd44a156e193bc1be8247cda', './modules/ProspectLists/SubPanelView.php' => 'c2f9c067fc5a8b04272ea96b2b865ddc', - './modules/ProspectLists/TargetListUpdate.php' => '6352f71bf03f199ddd91f3ae64371169', + './modules/ProspectLists/TargetListUpdate.php' => 'fb273882f80b2dacdcb28239ddfe8e97', './modules/ProspectLists/field_arrays.php' => '42da48c616f237ba884f341a4551fe26', './modules/ProspectLists/language/en_us.lang.php' => '1ab6bf758e61bbd13edf2afb01ab9273', './modules/ProspectLists/metadata/SearchFields.php' => 'f7608542836f425b5cfdbfe00b739aff', @@ -5683,7 +5755,7 @@ $md5_string = array ( './modules/Spots/ShowSpots.php' => 'dc81e1537a1d3d3d8a2d063f84184af1', './modules/Spots/Spots.php' => 'a707ccbea20d9e14c12fc8a88a5e57a6', './modules/Spots/SpotsListViewSmarty.php' => 'ec027fa39cee8950725bb157729b66d0', - './modules/Spots/controller.php' => '324cd1f78df1e6e48c693803d74494fc', + './modules/Spots/controller.php' => 'ca2928ff26f679beb52d16e4c08f95e9', './modules/Spots/language/en_us.lang.php' => '72b4e079d7757eb0547316da3a508191', './modules/Spots/metadata/SearchFields.php' => 'f716711d5b9fd7aa06ac3ba79454a00d', './modules/Spots/metadata/dashletviewdefs.php' => 'b780c4bbdd632f137e0ff8b672d7fc17', @@ -5712,13 +5784,13 @@ $md5_string = array ( './modules/Studio/TabGroups.php' => '0b53258e874bf76af6ba4e698fe1faf2', './modules/Studio/config.php' => 'ffcfb2aaf49f4c2735abdbd8116db4b3', './modules/Studio/language/en_us.lang.php' => 'e5d8138b1cb0465f26e362de69a02b51', - './modules/Studio/parsers/StudioParser.php' => '3df803d50e322cea269673d0f6c5470d', + './modules/Studio/parsers/StudioParser.php' => 'dbd08a554f38f79d34a44e36c6477dc8', './modules/Studio/studio.js' => '4fb625bbde873e47be7230e1fd1bb067', './modules/Studio/studiodd.js' => '88e575cd322889b4d300152eb11bc3ee', './modules/Studio/studiotabgroups.js' => '612e25ce77d7bb265511698814e7f03c', './modules/Studio/wizard.php' => '6b65a4ab3c4bea9b981d46cea203ecbf', - './modules/Studio/wizards/EditDropDownWizard.php' => 'c70983bbbb5f7ca928a64a7c571a69d8', - './modules/Studio/wizards/RenameModules.php' => '264e7c1b70d9dce1dba021f1be2d5e01', + './modules/Studio/wizards/EditDropDownWizard.php' => '3a9ac695701a4c1f9ef892f533d28f92', + './modules/Studio/wizards/RenameModules.php' => '330fd7843edf5f764f4311d40bdf90cf', './modules/Studio/wizards/RenameModules.tpl' => '9c2a4a726f39081a0b574990bb63a5da', './modules/Studio/wizards/StudioWizard.php' => 'df3f9698f44033c0ef8475efa9975758', './modules/Studio/ygDDListStudio.js' => '149762df3f1f2648f44a06af06480030', @@ -5827,7 +5899,7 @@ $md5_string = array ( './modules/Surveys/Entry/SurveySubmit.php' => '973c1a318b9a9d95d72d56037b68c04f', './modules/Surveys/Entry/Thanks.php' => '6eff234e04438f049e4e4b9d8758f633', './modules/Surveys/Lines/Lines.php' => '0332378d16368686f29d959eac1842ed', - './modules/Surveys/Menu.php' => 'ecfbb08b99bb8e379eecd436b4922856', + './modules/Surveys/Menu.php' => 'ba18e736af4a1d2a261fbf67d3f174b2', './modules/Surveys/Surveys.php' => 'e9d5c639799ac830281414c7f38d1272', './modules/Surveys/Utils/utils.php' => 'a83853c0fe095b0c2d6b2296a0d9ab42', './modules/Surveys/controller.php' => '0dd5f1a9f4feca78ee0d64f124f47285', @@ -5982,7 +6054,7 @@ $md5_string = array ( './modules/Users/LoggedOut.tpl' => '9537c8e192b86a038ba3177d9e2fdff1', './modules/Users/Login.php' => 'efa7ccf3e685d1dcdfaf7b34baebd134', './modules/Users/Logout.php' => 'dd93eeb56baa9fa101b8237da3c7ec99', - './modules/Users/Menu.php' => 'a422cdd4f82ca22cdb0c9a4da07a1b24', + './modules/Users/Menu.php' => '452985da4fc294ef9be055ddf363253b', './modules/Users/PasswordRequirementBox.css' => '836245343f059e04a8bcf40eed8672cc', './modules/Users/PasswordRequirementBox.js' => 'e6ebfc550a17aa8bf9249cb528b018bd', './modules/Users/PopupSignature.php' => 'da9e47509bcbc63d0a32a6896d446f8f', @@ -6026,7 +6098,7 @@ $md5_string = array ( './modules/Users/entryPointSaveGoogleApiKey.php' => 'af2395a659fbe4c935ac555e4f3b592b', './modules/Users/field_arrays.php' => 'b2de6918c313caef59c28582475ab3a6', './modules/Users/googleApiKeySaverEntryPointError.tpl' => '5b45b5ce045c459e3e6c571d43eef873', - './modules/Users/language/en_us.lang.php' => '7cf5849bd441e65eb84ae48067c4a47b', + './modules/Users/language/en_us.lang.php' => '6300b22349c2b3ee79d98d856c44f694', './modules/Users/login.css' => '2c43ea9ba2bed908c545bde7ee7c4575', './modules/Users/login.js' => 'f54ae3775635f5cf93b7854e6dde656d', './modules/Users/login.tpl' => '76e56647f4334e8ee80ec2defa4d1659', @@ -6054,7 +6126,7 @@ $md5_string = array ( './modules/Users/password_utils.php' => 'c445ba371decfae7afb76ad09c060e8a', './modules/Users/reassignUserRecords.php' => '0db6428f348ea8ab23a1bd88a5725339', './modules/Users/tpls/DetailView.tpl' => '2b5edc433a18eab9e1dc24f55c015ced', - './modules/Users/tpls/EditViewFooter.tpl' => '3468ee673ada79bdb8129aeca2a739b6', + './modules/Users/tpls/EditViewFooter.tpl' => '09e287fec2fef683c1aedd71598e52e5', './modules/Users/tpls/EditViewGroup.tpl' => '97bbb48546d0b13a60dac111abb8358a', './modules/Users/tpls/EditViewHeader.tpl' => '099f5e4896d623b64d44f243c33941b2', './modules/Users/tpls/QuickEditFooter.tpl' => 'b7a9c930f9e885fcc51b7da358411c31', @@ -6215,7 +6287,7 @@ $md5_string = array ( './modules/vCals/vCal.php' => 'e20c0d7ec2b900ce37c8d621db8835ad', './modules/vCals/vardefs.php' => 'aa722f4d5a1fa352bc808da9fce072bd', './pdf.php' => '9c17ce70f633f699b8f5accd104f7e67', - './php_version.php' => '928257f676637cf31a03032c3e661e27', + './php_version.php' => 'b22ff00eccf1b700d0ff2fe495a12e65', './phpcs.xml' => '49c142cb59dc75e074493c3718b42528', './robots.txt' => 'fce2c714b591aa9b36ed1e1b1d8ef900', './run_job.php' => 'f790368883c1f979df13359bde217944', @@ -6254,7 +6326,7 @@ $md5_string = array ( './service/v3/rest.php' => 'e972697761509f2ac0caca7e0db74fe4', './service/v3/soap.php' => '9b15d3b080a2d27256b7e3c0094e882a', './service/v3_1/SugarWebServiceImplv3_1.php' => '8aada8ef2732e366319e8f98779bbee3', - './service/v3_1/SugarWebServiceUtilv3_1.php' => 'ee1179dd3cc6f121652c93717095595e', + './service/v3_1/SugarWebServiceUtilv3_1.php' => 'd81be16dc13e28aa64a27ef01fb0b206', './service/v3_1/registry.php' => 'c7690074b2106e368881e0fb7f728fcf', './service/v3_1/rest.php' => '3607b4865ee496046f1a6583f40c23e7', './service/v3_1/soap.php' => 'cedfe09f86b6a9e921940924786d68e9', @@ -6277,12 +6349,12 @@ $md5_string = array ( './soap/SoapPortalUsers.php' => '49a5b68e0cd8ecec6dce4ecc155a4629', './soap/SoapRelationshipHelper.php' => '37d9a8052ff34d9197ce121c19c5bd0e', './soap/SoapStudio.php' => '321282965d0108d7198a22d98b9b52fe', - './soap/SoapSugarUsers.php' => '24b1d06f162af2c641ec6cda2fe025f2', + './soap/SoapSugarUsers.php' => '6480c73b0988eff5c512570aa511de29', './soap/SoapTypes.php' => '6620161d7b9c96ac37df5f9d04a7118d', './soap.php' => 'e28988c2e0b8e2c484587b537a710525', './sugar_version.json' => 'bdfbcefae2f9af559bef6a36367df7bb', './sugar_version.php' => 'db7b6c8d51f87879fce1e6172eedfbed', - './suitecrm_version.php' => 'e2ddbf9c955577640332b6c21101478a', + './suitecrm_version.php' => '01090b9e33bc845e4138231c914b133e', './themes/SuiteP/css/Dawn/color-palette.scss' => 'e64677d79e1d68c069bdc2dc661c4f99', './themes/SuiteP/css/Dawn/icons.scss' => 'd59f8c5855e7a8df09542a663835a196', './themes/SuiteP/css/Dawn/select.ico' => '22393ad23f16c3f1462455bae8f20279', @@ -7707,7 +7779,7 @@ $md5_string = array ( './themes/SuiteP/include/EditView/header.tpl' => '132ace198c0a390b2000408fdde3457f', './themes/SuiteP/include/EditView/tab_panel_content.tpl' => 'e74279dc0e6d4185121b699d9d76750f', './themes/SuiteP/include/ListView/ListViewDCMenu.tpl' => 'bc847c86bae071f507e486acfd05fa31', - './themes/SuiteP/include/ListView/ListViewGeneric.tpl' => '39476db9d89d53d776fe5833d3a33eec', + './themes/SuiteP/include/ListView/ListViewGeneric.tpl' => '67001b6016d7a4065d33cbeed3e049d1', './themes/SuiteP/include/ListView/ListViewNoMassUpdate.tpl' => '4f238f8e41ce9479193be0cf537728a6', './themes/SuiteP/include/ListView/ListViewPagination.tpl' => '80ff62f8b828bde2ee846d42206dc00f', './themes/SuiteP/include/ListView/ListViewPaginationBottom.tpl' => '11147ef51e845a60fe1b29ab1b304d2b', @@ -7748,7 +7820,7 @@ $md5_string = array ( './themes/SuiteP/modules/Meetings/tpls/header.tpl' => '33fd4689fc13c9aacc72008edbfdede1', './themes/SuiteP/modules/ModuleBuilder/tpls/includes.tpl' => '168d710713885364a3834143d23ef129', './themes/SuiteP/modules/ModuleBuilder/tpls/layoutView.tpl' => 'b74115723b4ed2c26563b857bb6fc413', - './themes/SuiteP/modules/SavedSearch/SavedSearchForm.tpl' => 'f9a26d05295563e6ef7dd649307dd688', + './themes/SuiteP/modules/SavedSearch/SavedSearchForm.tpl' => 'a0add8999a51448085ac82f092d9441a', './themes/SuiteP/modules/Studio/TabGroups/EditViewTabs.tpl' => '8a66a691000f7b9af5caed0a71f43eb5', './themes/SuiteP/modules/Users/tpls/DetailView-advanced-tab-content.tpl' => 'c58912bb9157ca237992f13bc5cd82f5', './themes/SuiteP/modules/Users/tpls/DetailView.tpl' => '6c83f2aead0405c152b2ff9936b65d33', @@ -9208,4 +9280,4 @@ $md5_string = array ( './themes/default/less/wells.less' => '07cc7d04d7f7f344742f23886cbe5683', './vCard.php' => '3f5273501c464563e5b1247be28b69de', './vcal_server.php' => 'ce4752597ba62a99f791c467339d2500', -); \ No newline at end of file +); diff --git a/include/DetailView/DetailView.php b/include/DetailView/DetailView.php index 20165c427..5a27f4333 100755 --- a/include/DetailView/DetailView.php +++ b/include/DetailView/DetailView.php @@ -65,6 +65,12 @@ class DetailView extends ListView + /** + * @param string $html_varName + * @param SugarBean $seed + * @param int $offset + * @return SugarBean + */ public function processSugarBean($html_varName, $seed, $offset) { global $row_count, $sugar_config; @@ -152,27 +158,11 @@ class DetailView extends ListView $db_offset=$offset-1; $this->populateQueryWhere($isFirstView, $html_varName); - if (ACLController::requireOwner($seed->module_dir, 'view')) { - global $current_user; - $seed->getOwnerWhere($current_user->id); - if (!empty($this->query_where)) { - $this->query_where .= ' AND '; - } - $this->query_where .= $seed->getOwnerWhere($current_user->id); + + $accessWhere = $seed->buildAccessWhere('view'); + if (!empty($accessWhere)) { + $this->query_where .= empty($this->query_where) ? $accessWhere : ' AND ' . $accessWhere; } - /* BEGIN - SECURITY GROUPS */ - if (ACLController::requireSecurityGroup($seed->module_dir, 'view')) { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $owner_where = $seed->getOwnerWhere($current_user->id); - $group_where = SecurityGroup::getGroupWhere($seed->table_name, $seed->module_dir, $current_user->id); - if (empty($this->query_where)) { - $this->query_where = " (".$owner_where." or ".$group_where.")"; - } else { - $this->query_where .= " AND (".$owner_where." or ".$group_where.")"; - } - } - /* END - SECURITY GROUPS */ $order = $this->getLocalSessionVariable($seed->module_dir.'2_'.$html_varName, "ORDER_BY"); $orderBy = ''; diff --git a/include/EditView/EditView2.php b/include/EditView/EditView2.php index ec66f76d2..625dd5ae7 100755 --- a/include/EditView/EditView2.php +++ b/include/EditView/EditView2.php @@ -936,7 +936,7 @@ class EditView //if popup select add panel if user is a member of multiple groups to metadataFile global $sugar_config; if(isset($sugar_config['securitysuite_popup_select']) && $sugar_config['securitysuite_popup_select'] == true - && empty($this->focus->fetched_row['id']) && $this->focus->module_dir != "Users" && $this->focus->module_dir != "SugarFeed") { + && (empty($this->focus->fetched_row['id']) || $_REQUEST['isDuplicate'] == true) && $this->focus->module_dir != "Users" && $this->focus->module_dir != "SugarFeed") { //there are cases such as uploading an attachment to an email template where the request module may //not be the same as the current bean module. If that happens we can just skip it diff --git a/include/Imap/Imap2Handler.php b/include/Imap/Imap2Handler.php new file mode 100644 index 000000000..78b23ffb7 --- /dev/null +++ b/include/Imap/Imap2Handler.php @@ -0,0 +1,1318 @@ +logCall(__FUNCTION__, func_get_args()); + $this->logErrors = $logErrors; + $this->logCalls = $logCalls; + $this->logger = LoggerManager::getLogger(); + $this->charset = $charset; + } + + /** + * + * @param mixed $stream + * @param bool $validate + */ + protected function setStream($stream, $validate = true) + { + if ($validate && !is_a($stream, Connection::class)) { + $this->logger->warn('ImapHandler trying to set a non valid resource az stream.'); + } + $this->stream = $stream; + } + + /** + * + * @param bool $validate + * @return resource + */ + protected function getStream($validate = true) + { + if ($validate && !is_a($this->stream, Connection::class)) { + $this->logger->fatal('ImapHandler trying to use a non valid resource stream.'); + } + + return $this->stream; + } + + /** + * + * @param array|string $errors + */ + protected function log($errors) + { + if (empty($this->logger)) { + return; + } + + if (is_string($errors)) { + $this->log([$errors]); + } elseif (!empty($errors) && $this->logErrors) { + foreach ($errors as $error) { + if ($error) { + $this->logger->fatal('An Imap error detected: ' . json_encode($error)); + } + } + } + } + + /** + * + * @param string $func + * @param array $args + */ + protected function logCall($func, $args) + { + if ($this->logCalls) { + $this->logger->debug('IMAP wrapper called: ' . __CLASS__ . "::$func(" . json_encode($args) . ')'); + } + } + + /** + * + * @param string $func + * @param mixed $ret + */ + protected function logReturn($func, $ret) + { + if ($this->logCalls) { + $this->logger->debug('IMAP wrapper return: ' . __CLASS__ . "::$func(...) => " . json_encode($ret)); + } + } + + /** + * + * @return boolean + */ + public function close() + { + $this->logCall(__FUNCTION__, func_get_args()); + if (!$ret = imap2_close($this->getStream())) { + $this->log('IMAP close error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @return array + */ + public function getAlerts() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_alerts(); + $this->log($ret); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @return resource|boolean + */ + public function getConnection() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = $this->getStream(); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @return array + */ + public function getErrors() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_errors(); + $this->log($ret); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @return string|boolean + */ + public function getLastError() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_last_error(); + $this->log($ret); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $ref + * @param string $pattern + * @return array + */ + public function getMailboxes($ref, $pattern) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_getmailboxes($this->getStream(), $ref, $pattern); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @return boolean + */ + public function isAvailable() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = function_exists('imap2_open') && function_exists('imap2_timeout'); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @param string $username + * @param string $password + * @param int $options + * @param int $n_retries + * @param array|null $params + * @return resource|boolean + */ + public function open($mailbox, $username, $password, $options = 0, $n_retries = 0, $params = null) + { + $this->logCall(__FUNCTION__, func_get_args()); + + $mbh = imap2_open($mailbox, $username, $password, $options, $n_retries, $params); + $this->setStream($mbh); + + if (empty($mbh) || !is_a($mbh, Connection::class)) { + $this->log([ + 'IMAP open error: ' . imap2_last_error(), + 'IMAP open error | debug data', + 'ImapHandler:open: ' . $mailbox, + 'ImapHandler:open: ' . $username, + 'ImapHandler:open: password is empty: ' . (empty($password) ? 'yes' : 'no'), + 'ImapHandler:open: ' . $options, + 'IMAP open error | debug data end ' + ]); + } + + if (!$this->getStream()) { + $this->log('IMAP open error:' . imap2_last_error()); + } + + $this->logReturn(__FUNCTION__, $this->getStream()); + + return $this->getStream(); + } + + /** + * + * @return boolean + */ + public function ping() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_ping($this->getStream()); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @param int $options + * @param int $n_retries + * @return boolean + */ + public function reopen($mailbox, $options = 0, $n_retries = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_reopen($this->getStream(), $mailbox, $options, $n_retries); + if (!$ret) { + $this->log('IMAP reopen error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $timeout_type + * @param int $timeout + * @return mixed + */ + public function setTimeout($timeout_type, $timeout = -1) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_timeout($timeout_type, $timeout); + if (!$ret) { + $this->log('IMAP set timeout error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * Execute callback and check IMAP errors for retry + * @param callback $callback + * @param string|null $charset + * @return array + */ + protected function executeImapCmd($callback, $charset = null) + { + + // Default to class charset if none is specified + $emailCharset = !empty($charset) ? $charset : $this->charset; + + $ret = false; + + try { + $ret = $callback($emailCharset); + + // catch if we have BADCHARSET as exception is not thrown + if (empty($ret) || $ret === false) { + $err = imap2_last_error(); + if (strpos($err, 'BADCHARSET')) { + imap2_errors(); + throw new Exception($err); + } + } + } catch (Exception $e) { + if (strpos($e, ' [BADCHARSET (US-ASCII)]')) { + LoggerManager::getLogger()->debug("Encoding changed dynamically from {$emailCharset} to US-ASCII"); + $emailCharset = 'US-ASCII'; + $this->charset = $emailCharset; + $ret = $callback($emailCharset); + } + } + + return $ret; + } + + /** + * + * @param int $criteria + * @param int $reverse + * @param int $options + * @param string $search_criteria + * @param string $charset + * @return array + */ + public function sort($criteria, $reverse, $options = 0, $search_criteria = null, $charset = null) + { + $this->logCall(__FUNCTION__, func_get_args()); + + $call = function ($charset) use ($criteria, $reverse, $options, $search_criteria) { + + if (!$this->isValidStream($this->getStream())) { + return false; + } + $client = $this->getStream()->getClient(); + + $result = $client->sort($this->getStream()->getMailboxName(), $criteria, $search_criteria, + $options & SE_UID); + + if (empty($result->count())) { + $this->log('IMAP sort: empty result'); + + return false; + } + + $messages = $result->get(); + foreach ($messages as &$message) { + $message = is_numeric($message) ? (int)$message : $message; + } + + return $messages; + }; + + $ret = $this->executeImapCmd($call, $charset); + + if (!$ret) { + $this->log('IMAP sort error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $uid + * @return int + */ + public function getMessageNo($uid) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_msgno($this->getStream(), $uid); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param int $fromLength + * @param int $subjectLength + * @param string $defaultHost + * @return bool|object Returns FALSE on error or, if successful, the information in an object + */ + public function getHeaderInfo($msg_number, $fromLength = 0, $subjectLength = 0, $defaultHost = null) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_headerinfo($this->getStream(), $msg_number, $fromLength, $subjectLength, $defaultHost); + if (!$ret) { + $this->log('IMAP get header info error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param int $options + * @return string + */ + public function fetchHeader($msg_number, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_fetchheader($this->getStream(), $msg_number, $options); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @param string $message + * @param string $options + * @param string $internal_date + * @return bool + */ + public function append($mailbox, $message, $options = null, $internal_date = null) + { + $this->logCall(__FUNCTION__, func_get_args()); + + // ..to evolve a warning about an invalid internal date format + // BUG at: https://github.com/php/php-src/blob/master/ext/imap/php_imap.c#L1357 + // --> + if (null === $internal_date) { + $ret = imap2_append($this->getStream(), $mailbox, $message, $options); + } else { + $ret = imap2_append($this->getStream(), $mailbox, $message, $options, $internal_date); + } + + if (!$ret) { + $this->log('IMAP append error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @return int + */ + public function getUid($msg_number) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_uid($this->getStream(), $msg_number); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * @return bool + */ + public function expunge() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_expunge($this->getStream()); + if (!$ret) { + $this->log('IMAP expunge error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * @return object|bool Returns FALSE on failure. + */ + public function check() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_check($this->getStream()); + if (!$ret) { + $this->log('IMAP check error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $sequence + * @param string $flag + * @param int $options + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function clearFlagFull($sequence, $flag, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_clearflag_full($this->getStream(), $sequence, $flag, $options); + if (!$ret) { + $this->log('IMAP clearFlagFull error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function createMailbox($mailbox) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_createmailbox($this->getStream(), $mailbox); + if (!$ret) { + $this->log('IMAP createMailbox error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param int $options + * @return bool Returns TRUE. + */ + public function delete($msg_number, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_delete($this->getStream(), $msg_number, $options); + if (!$ret) { + $this->log('IMAP delete error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function deleteMailbox($mailbox) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_deletemailbox($this->getStream(), $mailbox); + if (!$ret) { + $this->log('IMAP deleteMailbox error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param string $section + * @param int $options + * @return string + */ + public function fetchBody($msg_number, $section, $options = 0) + { + + $this->logCall(__FUNCTION__, func_get_args()); + $ret = $this->internalFetchBody($this->getStream(), $msg_number, $section, $options); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * Override to the imap2_fetch_body function + * @param $imap + * @param $messageNum + * @param $section + * @param $flags + * @return false|mixed|null + */ + protected function internalFetchBody($imap, $messageNum, $section, $flags = 0) + { + if (!$this->isValidStream($imap)) { + return Errors::invalidImapConnection(debug_backtrace(), 1, false); + } + + $client = $imap->getClient(); + + $isUid = (bool)($flags & FT_UID); + + $query = ['BODY[' . $section . ']']; + + if ($isUid) { + $query[] = 'UID'; + } + + $messages = $client->fetch($imap->getMailboxName(), $messageNum, $isUid, $query); + + if (empty($messages)) { + trigger_error(Errors::badMessageNumber(debug_backtrace(), 1), E_USER_WARNING); + + return false; + } + + $targetMessage = null; + if ($isUid) { + foreach ($messages as $message) { + if (!empty($message->uid) && ((int)$messageNum === (int)$message->uid)) { + $targetMessage = $message; + break; + } + } + } else { + $targetMessage = $messages[$messageNum]; + } + + if (empty($targetMessage)) { + return null; + } + + if ($section) { + return $targetMessage->bodypart[$section]; + } + + return $targetMessage->body; + } + + /** + * + * @param string $sequence + * @param int $options + * @return array + */ + public function fetchOverview($sequence, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + + $ret = $this->fetchList($sequence, $options); + + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param int $options + * @return object + */ + public function fetchStructure($msg_number, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_fetchstructure($this->getStream(), $msg_number, $options); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param int $msg_number + * @param int $options + * @return string + */ + public function getBody($msg_number, $options) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_body($this->getStream(), $msg_number, $options); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * @return int|bool Return the number of messages in the current mailbox, as an integer, or FALSE on error. + */ + public function getNumberOfMessages() + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_num_msg($this->getStream()); + if (!$ret) { + $this->log('IMAP getNumberOfMessages error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @param int $options + * @return object + */ + public function getStatus($mailbox, $options) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_status($this->getStream(), $mailbox, $options); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $msgList + * @param string $mailbox + * @param int $options + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function mailCopy($msgList, $mailbox, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_mail_copy($this->getStream(), $msgList, $mailbox, $options); + if (!$ret) { + $this->log('IMAP mailCopy error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $msgList + * @param string $mailbox + * @param int $options + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function mailMove($msgList, $mailbox, $options = 0) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_mail_move($this->getStream(), $msgList, $mailbox, $options); + if (!$ret) { + $this->log('IMAP mailMove error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $text + * @return array + */ + public function mimeHeaderDecode($text) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_mime_header_decode($text); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $old_mbox + * @param string $new_mbox + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function renameMailbox($old_mbox, $new_mbox) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_renamemailbox($this->getStream(), $old_mbox, $new_mbox); + if (!$ret) { + $this->log('IMAP renameMailbox error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $headers + * @param string $defaultHost + * @return object + */ + public function rfc822ParseHeaders($headers, $defaultHost = 'UNKNOWN') + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_rfc822_parse_headers($headers, $defaultHost); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $criteria + * @param int $options + * @param string $charset + * @return array|bool Return FALSE if it does not understand the search criteria or no messages have been found. + */ + public function search($criteria, $options = SE_FREE, $charset = null) + { + $this->logCall(__FUNCTION__, func_get_args()); + + $call = function ($charset) use ($criteria, $options) { + return imap2_search($this->getStream(), $criteria, $options, $charset); + }; + + $ret = $this->executeImapCmd($call, $charset); + + if (!$ret) { + $this->log('IMAP search error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $sequence + * @param string $flag + * @param int $options + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function setFlagFull($sequence, $flag, $options = NIL) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_setflag_full($this->getStream(), $sequence, $flag, $options); + if (!$ret) { + $this->log('IMAP setFlagFull error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function subscribe($mailbox) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_subscribe($this->getStream(), $mailbox); + if (!$ret) { + $this->log('IMAP subscribe error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mailbox + * @return bool Returns TRUE on success or FALSE on failure. + */ + public function unsubscribe($mailbox) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_unsubscribe($this->getStream(), $mailbox); + if (!$ret) { + $this->log('IMAP unsubscribe error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $data + * @return string|bool FALSE if text contains invalid modified UTF-7 sequence or text contains a character that is not part of ISO-8859-1 character set. + */ + public function utf7Encode($data) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_utf7_decode($data); + if (!$ret) { + $this->log('IMAP utf7Encode error'); + } + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * + * @param string $mime_encoded_text + * @return string + */ + public function utf8($mime_encoded_text) + { + $this->logCall(__FUNCTION__, func_get_args()); + $ret = imap2_utf8($mime_encoded_text); + $this->logReturn(__FUNCTION__, $ret); + + return $ret; + } + + /** + * @param $stream + * @return bool + */ + public function isValidStream($stream): bool + { + return is_a($stream, Connection::class); + } + + /** + * Fetch list of emails. Overrides imap2_fetch_override function + * @param string $sequence + * @param int $options + * @param bool $retrieveStructure + * @return array|mixed + */ + protected function fetchList(string $sequence, int $options = 0, bool $retrieveStructure = false) + { + if (!$this->isValidStream($this->getStream())) { + return Errors::invalidImapConnection(debug_backtrace(), 1, false); + } + + $client = $this->getStream()->getClient(); + + $bodyRequest = 'BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO CC REPLYTO MESSAGEID DATE SIZE REFERENCES)]'; + + $query = [ + $bodyRequest, + 'UID', + 'FLAGS', + 'INTERNALDATE', + 'RFC822.SIZE', + 'ENVELOPE', + 'RFC822.HEADER' + ]; + + if ($retrieveStructure === true) { + $query[] = 'BODYSTRUCTURE'; + } + + $useUid = $options & FT_UID; + + $messages = $client->fetch($this->getStream()->getMailboxName(), $sequence, $useUid, $query); + + $overview = []; + foreach ($messages as $message) { + $messageEntry = (object)[ + 'subject' => $message->envelope[1], + 'from' => Functions::writeAddressFromEnvelope($message->envelope[2]), + 'to' => $message->get('to'), + 'date' => $message->date, + 'message_id' => $message->envelope[9], + 'references' => $message->references, + 'in_reply_to' => $message->envelope[8], + 'size' => $message->size, + 'uid' => $message->uid, + 'msgno' => $message->id, + 'recent' => (int)($message->flags['RECENT'] ?? 0), + 'flagged' => (int)($message->flags['FLAGGED'] ?? 0), + 'answered' => (int)($message->flags['ANSWERED'] ?? 0), + 'deleted' => (int)($message->flags['DELETED'] ?? 0), + 'seen' => (int)($message->flags['SEEN'] ?? 0), + 'draft' => (int)($message->flags['DRAFT'] ?? 0), + 'udate' => strtotime($message->internaldate), + 'bodystructure' => $message->bodystructure ?? '', + ]; + + if (empty($messageEntry->subject)) { + unset($messageEntry->subject); + } + + if (empty($messageEntry->references)) { + unset($messageEntry->references); + } + + if (empty($messageEntry->in_reply_to)) { + unset($messageEntry->in_reply_to); + } + + if (empty($messageEntry->to)) { + unset($messageEntry->to); + } + + $indexField = (int)$message->id; + if ($useUid) { + $indexField = (int)$message->uid; + } + + $overview[$indexField] = $messageEntry; + } + + return $overview; + } + + /** + * Fetch list of emails. Overrides imap2_fetch_override function + * @param string $sequence + * @param int $options + * @return array|mixed + */ + protected function fetchListWithStructure(string $sequence, int $options = 0) + { + return $this->fetchList($sequence, $options, true); + } + + /** + * @param string $field + * @param int $start + * @param int $end + * @param $messageSet + * @param bool $returnUid + * @return array|false + */ + protected function getSortedMessageIds( + string $field = 'ARRIVAL', + int $start = 1, + int $end = 1, + $messageSet = null, + bool $returnUid = true + ) { + if (!$this->isValidStream($this->getStream())) { + return []; + } + $client = $this->getStream()->getClient(); + + if ($messageSet === null && $client->getCapability('SORT') !== false) { + + $result = $client->sort($this->getStream()->getMailboxName(), 'REVERSE ' . $field, "$start:$end", + $returnUid, 'UTF-8'); + + if (empty($result) || empty($result->count())) { + return []; + } + $ids = $result->get(); + + } else { + $ids = $this->getAllIdsSorted($field, $returnUid, $messageSet); + + if (!empty($ids)) { + + $ids = array_slice($ids, $start - 1, $end); + } + } + + return $ids; + } + + /** + * @inheritDoc + */ + public function getMessageList( + ?string $filterCriteria, + $sortCriteria, + $sortOrder, + int $offset, + int $pageSize, + array &$mailboxInfo, + array $columns + ): array { + + $uids = null; + + if (!empty($filterCriteria)) { + // Filtered case and other sorting cases + // Returns an array of msgno's which are sorted and filtered + $emailSortedHeaders = $this->search( + $filterCriteria, + SE_UID, + ); + + if ($emailSortedHeaders === false) { + return []; + } + + $lastSequenceNumber = $mailboxInfo['Nmsgs'] = count($emailSortedHeaders); + + // paginate + if ($offset === "end") { + $offset = $lastSequenceNumber - $pageSize; + } elseif ($offset <= 0) { + $offset = 0; + } + + $pageOffSet = $offset + 1; + $pageLast = $pageOffSet + $pageSize; + + if (!empty($emailSortedHeaders) && is_array($emailSortedHeaders)) { + $uids = $this->getSortedMessageIds('ARRIVAL', $pageOffSet, $pageLast, $emailSortedHeaders); + } + + + + if (empty($uids)) { + return []; + } + } + + $shouldFetchAttachments = isset($columns['has_attachment']) && !empty($columns['has_attachment']); + + $fetchMethod = 'fetchList'; + if ($shouldFetchAttachments === true) { + $fetchMethod = 'fetchListWithStructure'; + } + + $emailHeaders = []; + if ($uids === null) { + + $totalMsgs = $this->getNumberOfMessages(); + $mailboxInfo['Nmsgs'] = $totalMsgs; + + if ($offset > (int)$totalMsgs) { + $offset = 0; + } + + $pageOffSet = $offset + 1; + $pageLast = $pageOffSet + $pageSize; + $sequence = "$pageOffSet:$pageLast"; + + $sorteUids = $this->getSortedMessageIds('ARRIVAL', $pageOffSet, $pageLast); + $sequence = implode(',', $sorteUids); + + $mailList = $this->$fetchMethod($sequence, FT_UID); + + $emailHeaders = []; + foreach ($sorteUids as $id) { + $emailHeaders[] = $mailList[(int)$id]; + } + + } elseif (is_array($uids)) { + + $mailList = $this->$fetchMethod(implode(',', $uids), FT_UID); + + $emailHeaders = []; + foreach ($uids as $id) { + $emailHeaders[] = $mailList[(int)$id]; + } + } + + $emailHeaders = json_decode(json_encode($emailHeaders), true); + + + if ($shouldFetchAttachments === true) { + // get attachment status + foreach ($emailHeaders as $i => $emailHeader) { + + $emailHeaders[$i]['has_attachment'] = false; + if (empty($emailHeader['bodystructure']) || !is_array($emailHeader['bodystructure'])) { + continue; + } + + if (!is_array($emailHeader['bodystructure'][0])) { + continue; + } + + $emailHeaders[$i]['has_attachment'] = $this->bodyStructureHasAttachment($emailHeader['bodystructure']); + } + } + + return $emailHeaders; + } + + + /** + * Check if body structure has attachment + * @param $structure + * @return bool + */ + protected function bodyStructureHasAttachment($structure): bool + { + + if (empty($structure) || !is_array($structure)) { + return false; + } + + foreach ($structure as $item) { + if (!is_array($item)) { + continue; + } + + if ($this->isAttachmentPart($item) === true) { + return true; + } + } + + return false; + } + + /** + * check if it is an attachment part + * @param array $item + * @return bool + */ + protected function isAttachmentPart(array $item): bool + { + foreach ($item as $subItem) { + if (!is_array($subItem)) { + continue; + } + $subItemType = $subItem[0] ?? ''; + + if ($subItemType === 'attachment') { + return true; + } + } + + return false; + } + + /** + * Get sorted ids by specified field + * @param string $field + * @param bool $returnUid + * @param null $messageSet + * @return array + */ + protected function getAllIdsSorted(string $field = 'ARRIVAL', bool $returnUid = true, $messageSet = null): array + { + $client = $this->getStream()->getClient(); + + if (empty($messageSet)) { + $messageSet = '1:*'; + } + + $result = $client->index($this->getStream()->getMailboxName(), $messageSet, $field, true, $returnUid, + $returnUid); + + if (empty($result) || empty($result->count())) { + return []; + } + + $ids = $result->get(); + + return array_reverse($ids); + } + +} diff --git a/include/Imap/ImapHandler.php b/include/Imap/ImapHandler.php index 92d6c305c..90895df7b 100644 --- a/include/Imap/ImapHandler.php +++ b/include/Imap/ImapHandler.php @@ -351,7 +351,7 @@ class ImapHandler implements ImapHandlerInterface return $ret; } - + /** * Execute callback and check IMAP errors for retry * @param callback $callback @@ -360,15 +360,15 @@ class ImapHandler implements ImapHandlerInterface */ protected function executeImapCmd($callback, $charset=null) { - + // Default to class charset if none is specified $emailCharset = !empty($charset) ? $charset : $this->charset; - + $ret = false; - + try { $ret = $callback($emailCharset); - + // catch if we have BADCHARSET as exception is not thrown if (empty($ret) || $ret === false){ $err = imap_last_error(); @@ -385,9 +385,9 @@ class ImapHandler implements ImapHandlerInterface $ret = $callback($emailCharset); } } - + return $ret; - } + } /** * @@ -401,18 +401,18 @@ class ImapHandler implements ImapHandlerInterface public function sort($criteria, $reverse, $options = 0, $search_criteria = null, $charset = null) { $this->logCall(__FUNCTION__, func_get_args()); - + $call = function($charset) use ($criteria, $reverse, $options, $search_criteria){ return imap_sort($this->getStream(), $criteria, $reverse, $options, $search_criteria, $charset); }; - + $ret = $this->executeImapCmd($call, $charset); if (!$ret) { $this->log('IMAP sort error'); } $this->logReturn(__FUNCTION__, $ret); - + return $ret; } @@ -795,13 +795,13 @@ class ImapHandler implements ImapHandlerInterface public function search($criteria, $options = SE_FREE, $charset = null) { $this->logCall(__FUNCTION__, func_get_args()); - + $call = function($charset) use ($criteria, $options){ return imap_search($this->getStream(), $criteria, $options, $charset); }; - + $ret = $this->executeImapCmd($call, $charset); - + if (!$ret) { $this->log('IMAP search error'); } @@ -894,4 +894,156 @@ class ImapHandler implements ImapHandlerInterface return $ret; } + /** + * @param $stream + * @return bool + */ + public function isValidStream($stream): bool + { + return is_resource($stream); + } + + /** + * @inheritDoc + */ + public function getMessageList( + ?string $filterCriteria, + $sortCriteria, + $sortOrder, + int $offset, + int $pageSize, + array &$mailboxInfo, + array $columns + ): array { + + if (empty($filterCriteria) && $sortCriteria === SORTDATE) { + // Performance fix when no filters are enabled + $totalMsgs = $this->getNumberOfMessages(); + $mailboxInfo['Nmsgs'] = $totalMsgs; + + if ($sortOrder === 0) { + // Ascending order + if ($offset === "end") { + $firstMsg = $totalMsgs - (int)$pageSize; + $lastMsg = $totalMsgs; + } elseif ($offset <= 0) { + $firstMsg = 1; + $lastMsg = $firstMsg + (int)$pageSize; + } else { + $firstMsg = (int)$offset; + $lastMsg = $firstMsg + (int)$pageSize; + } + } else { + // Descending order + if ($offset === "end") { + $firstMsg = 1; + $lastMsg = $firstMsg + (int)$pageSize; + } elseif ($offset <= 0) { + $firstMsg = $totalMsgs - (int)$pageSize; + $lastMsg = $totalMsgs; + } else { + $offset = ($totalMsgs - (int)$offset) - (int)$pageSize; + $firstMsg = $offset; + $lastMsg = $firstMsg + (int)$pageSize; + } + } + $firstMsg = $firstMsg < 1 ? 1 : $firstMsg; + $firstMsg = $firstMsg > $totalMsgs ? $totalMsgs : $firstMsg; + $lastMsg = $lastMsg < $firstMsg ? $firstMsg : $lastMsg; + $lastMsg = $lastMsg > $totalMsgs ? $totalMsgs : $lastMsg; + + $sequence = $firstMsg . ':' . $lastMsg; + $emailSortedHeaders = $this->fetchOverview($sequence); + + $uids = []; + if (!empty($emailSortedHeaders)) { + $uids = array_map( + function ($x) { + return $x->uid; + }, + $emailSortedHeaders // TODO: this should be an array! + ); + } + + } else { + // Filtered case and other sorting cases + // Returns an array of msgno's which are sorted and filtered + $emailSortedHeaders = $this->sort( + $sortCriteria, + $sortOrder, + SE_UID, + $filterCriteria + ); + + if ($emailSortedHeaders === false) { + return []; + } + + $uids = array_slice($emailSortedHeaders, $offset, $pageSize); + + $lastSequenceNumber = $mailboxInfo['Nmsgs'] = count($emailSortedHeaders); + + // paginate + if ($offset === "end") { + $offset = $lastSequenceNumber - $pageSize; + } elseif ($offset <= 0) { + $offset = 0; + } + } + + if (empty($uids)) { + return []; + } + + + // TODO: uids could be invalid for implode! + $uids = implode(',', $uids); + + // Get result + $emailHeaders = $this->fetchOverview( + $uids, + FT_UID + ); + $emailHeaders = json_decode(json_encode($emailHeaders), true); + if (isset($columns['has_attachment'])) { + // get attachment status + foreach ($emailHeaders as $i => $emailHeader) { + $structure = $this->fetchStructure($emailHeader['uid'], FT_UID); + + $emailHeaders[$i]['has_attachment'] = $this->messageStructureHasAttachment($structure); + } + } + + return $emailHeaders; + } + + /** + * @param $structure + * @return bool + */ + public function messageStructureHasAttachment($structure): bool + { + if (($structure->type !== 0) && ($structure->type !== 1)) { + return true; + } + + + $attachments = []; + + if (empty($structure->parts)) { + return false; + } + + foreach ($structure->parts as $i => $part) { + if (empty($part) || empty($part->dparameters[0])) { + continue; + } + + if (is_string($part->dparameters[0]->value)) { + $attachments[] = $part->dparameters[0]->value; + } + } + + return !empty($attachments); + } } diff --git a/include/Imap/ImapHandlerFactory.php b/include/Imap/ImapHandlerFactory.php index 095e51afc..da79ac13f 100644 --- a/include/Imap/ImapHandlerFactory.php +++ b/include/Imap/ImapHandlerFactory.php @@ -43,6 +43,7 @@ if (!defined('sugarEntry') || !sugarEntry) { } require_once __DIR__ . '/ImapHandler.php'; +require_once __DIR__ . '/Imap2Handler.php'; require_once __DIR__ . '/ImapHandlerException.php'; /** @@ -56,13 +57,13 @@ class ImapHandlerFactory { const SETTINGS_KEY_FILE = '/ImapTestSettings.txt'; const DEFAULT_SETTINGS_KEY = 'testSettingsOk'; - + /** * * @var ImapHandlerInterface */ protected $interfaceObject = null; - + /** * * @var array @@ -72,7 +73,7 @@ class ImapHandlerFactory 'class' => 'ImapHandlerFake', 'calls' => 'include/Imap/ImapHandlerFakeCalls.php', ]; - + /** * * @param ImapHandlerInterface $interfaceObject @@ -83,7 +84,7 @@ class ImapHandlerFactory LoggerManager::getLogger()->debug('ImapHandlerFactory will using a ' . $class); $this->interfaceObject = $interfaceObject; } - + /** * */ @@ -93,7 +94,7 @@ class ImapHandlerFactory require_once $this->imapHandlerTestInterface['file']; } } - + /** * * @global array $sugar_config @@ -125,7 +126,7 @@ class ImapHandlerFactory $interfaceFakeData->retrieve($interfaceCalls); $this->setInterfaceObject(new $interfaceClass($interfaceFakeData)); } - + /** * * @return string @@ -155,7 +156,7 @@ class ImapHandlerFactory unlink(__DIR__ . self::SETTINGS_KEY_FILE); } } - + /** * * @param string $key @@ -168,7 +169,7 @@ class ImapHandlerFactory $type = gettype($key); throw new InvalidArgumentException('Key should be a non-empty string, ' . ($type == 'string' ? 'empty string' : $type) . ' given.'); } - + $calls = include $this->imapHandlerTestInterface['calls']; if (!isset($calls[$key])) { @@ -185,18 +186,17 @@ class ImapHandlerFactory } return false; } - + /** - * - * @global array $sugar_config - * @param string $testSettings + * Get Handler + * @param string|null $testSettings * @return ImapHandlerInterface * @throws ImapHandlerException */ - public function getImapHandler($testSettings = null) + public function getImapHandler(string $testSettings = null, string $handlerType = 'native' ) { if (null === $this->interfaceObject) { - global $sugar_config; + global $sugar_config, $log; $test = (isset($sugar_config['imap_test']) && $sugar_config['imap_test']) || $testSettings; $charset = (isset($sugar_config['default_email_charset'])) ? $sugar_config['default_email_charset'] : null; @@ -209,7 +209,8 @@ class ImapHandlerFactory $logCalls = false; } - $interfaceClass = ImapHandler::class; + $interfaceClass = $this->getHandlerClass($handlerType); + $log->fatal('Using imap handler class: ' . $interfaceClass); if ($test) { $this->loadTestSettings($testSettings); } else { @@ -218,4 +219,46 @@ class ImapHandlerFactory } return $this->interfaceObject; } + + /** + * Check if all handlers are available + * @return bool + */ + public function areAllHandlersAvailable(): bool { + foreach ($this->getHandlers() as $handlerClass) { + $available = (new $handlerClass())->isAvailable(); + if ($available === false) { + return false; + } + } + + return true; + } + + /** + * Get Handler + * @param string $handlerType + * @return string + */ + protected function getHandlerClass(string $handlerType): string + { + $handlers = $this->getHandlers(); + + if (!empty($handlers[$handlerType])) { + return $handlers[$handlerType]; + } + + return ImapHandler::class; + } + + /** + * @return ImapHandlerInterface[] + */ + protected function getHandlers(): array + { + return [ + 'native' => ImapHandler::class, + 'imap2' => Imap2Handler::class, + ]; + } } diff --git a/include/Imap/ImapHandlerFake.php b/include/Imap/ImapHandlerFake.php index 11cfe9d88..cb89d647b 100644 --- a/include/Imap/ImapHandlerFake.php +++ b/include/Imap/ImapHandlerFake.php @@ -54,7 +54,7 @@ include_once __DIR__ . '/ImapHandlerFakeData.php'; class ImapHandlerFake implements ImapHandlerInterface { protected $fakes; - + /** * * @param ImapHandlerFakeData $fakeData @@ -63,7 +63,7 @@ class ImapHandlerFake implements ImapHandlerInterface { $this->fakes = $fakeData; } - + /** * * @return boolean @@ -90,7 +90,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getConnection'); } - + /** * * @return array @@ -99,7 +99,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getErrors'); } - + /** * * @return string|boolean @@ -108,7 +108,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getLastError'); } - + /** * * @param string $ref @@ -128,7 +128,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('isAvailable'); } - + /** * * @param string $mailbox @@ -143,7 +143,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('open', [$mailbox, $username, $password, $options, $n_retries, $params]); } - + /** * * @return boolean @@ -152,7 +152,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('ping'); } - + /** * * @param string $mailbox @@ -164,7 +164,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('reopen', [$mailbox, $options, $n_retries]); } - + /** * * @param int $timeout_type @@ -175,7 +175,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('setTimeout', [$timeout_type, $timeout]); } - + /** * * @param int $criteria @@ -199,7 +199,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getMessageNo', [$uid]); } - + /** * * @param int $msg_number @@ -212,7 +212,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getHeaderInfo', [$msg_number, $fromlength, $subjectlength, $defaulthost]); } - + /** * * @param type $msg_number @@ -235,7 +235,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('append', [$mailbox, $message, $options, $internal_date]); } - + /** * * @param int $msg_number @@ -245,7 +245,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('getUid', [$msg_number]); } - + /** * @return bool */ @@ -254,7 +254,7 @@ class ImapHandlerFake implements ImapHandlerInterface return $this->fakes->call('expunge', []); } - + /** * @return object|bool Returns FALSE on failure. */ @@ -274,7 +274,7 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('clearFlagFull', [$sequence, $flag, $options]); } - + /** * * @param string $mailbox @@ -489,4 +489,30 @@ class ImapHandlerFake implements ImapHandlerInterface { return $this->fakes->call('utf8', [$mime_encoded_text]); } + + /** + * @param $stream + * @return bool + * @throws Exception + */ + public function isValidStream($stream): bool + { + return $this->fakes->call('isValidStream', [$stream]); + } + + /** + * @param string|null $filterCriteria + * @param $sortCriteria + * @param $sortOrder + * @param int $offset + * @param int $pageSize + * @param array $mailboxInfo + * @param array $columns + * @return array + * @throws Exception + */ + public function getMessageList(?string $filterCriteria, $sortCriteria, $sortOrder, int $offset, int $pageSize, array &$mailboxInfo, array $columns): array + { + return $this->fakes->call('getMessageList', [$filterCriteria, $sortCriteria, $sortOrder, $offset, $pageSize, $mailboxInfo, $columns]); + } } diff --git a/include/Imap/ImapHandlerFakeCalls.php b/include/Imap/ImapHandlerFakeCalls.php index a2f290f26..3fff04b5d 100644 --- a/include/Imap/ImapHandlerFakeCalls.php +++ b/include/Imap/ImapHandlerFakeCalls.php @@ -43,10 +43,10 @@ if (!defined('sugarEntry') || !sugarEntry) { // describes the face imap function return values for each function calls with a specific parameters in every test screnario. return $calls = [ - + // this case only for unit testing: 'testCaseExample' => [], - + 'testSettingsOk' => [ 'isAvailable' => [ ['args' => null, 'return' => [true]], @@ -82,8 +82,8 @@ return $calls = [ ], 'getConnection' => [], ], - - + + 'testSettingsWrongUser' => [ 'isAvailable' => [['args' => null, 'return' => [true]]], 'setTimeout' => [ @@ -110,7 +110,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls/validate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls/validate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -123,7 +123,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls/validate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/validate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -136,7 +136,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/validate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/validate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -149,7 +149,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/validate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -162,7 +162,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -175,7 +175,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/tls}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/novalidate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -188,7 +188,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/novalidate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/novalidate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -201,7 +201,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/novalidate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/novalidate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -214,7 +214,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/novalidate-cert/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/novalidate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -227,7 +227,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/novalidate-cert}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -240,7 +240,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -253,7 +253,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/notls}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -266,7 +266,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl/secure}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap/ssl}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, []], 'return' => [false], @@ -279,7 +279,7 @@ return $calls = [ 'args' => ['{imap.gmail.com:993/service=imap/ssl}INBOX', 'testuser_name_wrong', 'testuser_pass', 0, 0, ['DISABLE_AUTHENTICATOR' => 'NTLM']], 'return' => [false], ], - + [ 'args' => ['{imap.gmail.com:993/service=imap}INBOX', 'testuser_name_wrong', 'testuser_pass', 32768, 0, []], 'return' => [false], diff --git a/include/Imap/ImapHandlerInterface.php b/include/Imap/ImapHandlerInterface.php index d59aaff9f..09a9ebf29 100644 --- a/include/Imap/ImapHandlerInterface.php +++ b/include/Imap/ImapHandlerInterface.php @@ -50,19 +50,25 @@ if (!defined('sugarEntry') || !sugarEntry) { */ interface ImapHandlerInterface { - + /** * * @return boolean */ public function isAvailable(); - + + /** + * @param $stream mixed + * @return bool + */ + public function isValidStream($stream): bool; + /** * * @return string|boolean */ public function getLastError(); - + /** * * @return array @@ -74,7 +80,7 @@ interface ImapHandlerInterface * @return array */ public function getAlerts(); - + /** * * @param string $mailbox @@ -86,19 +92,19 @@ interface ImapHandlerInterface * @return resource|boolean */ public function open($mailbox, $username, $password, $options = 0, $n_retries = 0, $params = null); - + /** * * @return boolean */ public function close(); - + /** * * @return boolean */ public function ping(); - + /** * * @param string $mailbox @@ -110,10 +116,10 @@ interface ImapHandlerInterface /** * - * @return resource|boolean + * @return mixed */ public function getConnection(); - + /** * * @param int $timeout_type @@ -121,7 +127,7 @@ interface ImapHandlerInterface * @return mixed */ public function setTimeout($timeout_type, $timeout = -1); - + /** * * @param string $ref @@ -129,7 +135,7 @@ interface ImapHandlerInterface * @return array */ public function getMailboxes($ref, $pattern); - + /** * * @param int $criteria @@ -140,14 +146,14 @@ interface ImapHandlerInterface * @return array */ public function sort($criteria, $reverse, $options = 0, $search_criteria = null, $charset = null); - + /** * * @param int $uid * @return int */ public function getMessageNo($uid); - + /** * * @param int $msg_number @@ -157,7 +163,7 @@ interface ImapHandlerInterface * @return bool|object Returns FALSE on error or, if successful, the information in an object */ public function getHeaderInfo($msg_number, $fromlength = 0, $subjectlength = 0, $defaulthost = null); - + /** * * @param type $msg_number @@ -165,7 +171,7 @@ interface ImapHandlerInterface * @return string */ public function fetchHeader($msg_number, $options = 0); - + /** * * @param string $mailbox @@ -175,19 +181,19 @@ interface ImapHandlerInterface * @return bool */ public function append($mailbox, $message, $options = null, $internal_date = null); - + /** * * @param int $msg_number * @return int */ public function getUid($msg_number); - + /** * @return bool */ public function expunge(); - + /** * * @param string $old_mbox @@ -195,12 +201,12 @@ interface ImapHandlerInterface * @return bool Returns TRUE on success or FALSE on failure. */ public function renameMailbox($old_mbox, $new_mbox); - + /** * @return int|bool Return the number of messages in the current mailbox, as an integer, or FALSE on error. */ public function getNumberOfMessages(); - + /** * * @param string $sequence @@ -208,7 +214,7 @@ interface ImapHandlerInterface * @return array */ public function fetchOverview($sequence, $options = 0); - + /** * * @param int $msg_number @@ -216,7 +222,7 @@ interface ImapHandlerInterface * @return object */ public function fetchStructure($msg_number, $options = 0); - + /** * * @param int $msg_number @@ -224,7 +230,7 @@ interface ImapHandlerInterface * @return string */ public function getBody($msg_number, $options); - + /** * * @param string $criteria @@ -233,7 +239,7 @@ interface ImapHandlerInterface * @return array|bool Return FALSE if it does not understand the search criteria or no messages have been found. */ public function search($criteria, $options = SE_FREE, $charset = null); - + /** * * @param int $msg_number @@ -241,7 +247,7 @@ interface ImapHandlerInterface * @return bool Returns TRUE. */ public function delete($msg_number, $options = 0); - + /** * * @param string $sequence @@ -250,7 +256,7 @@ interface ImapHandlerInterface * @return bool Returns TRUE on success or FALSE on failure. */ public function clearFlagFull($sequence, $flag, $options = 0); - + /** * * @param string $sequence @@ -259,7 +265,7 @@ interface ImapHandlerInterface * @return bool Returns TRUE on success or FALSE on failure. */ public function setFlagFull($sequence, $flag, $options = NIL); - + /** * * @param string $mailbox @@ -273,28 +279,28 @@ interface ImapHandlerInterface * @return string|bool FALSE if text contains invalid modified UTF-7 sequence or text contains a character that is not part of ISO-8859-1 character set. */ public function utf7Encode($data); - + /** * * @param string $mailbox * @return bool Returns TRUE on success or FALSE on failure. */ public function deleteMailbox($mailbox); - + /** * * @param string $mailbox * @return bool Returns TRUE on success or FALSE on failure. */ public function createMailbox($mailbox); - + /** * * @param string $mailbox * @return bool Returns TRUE on success or FALSE on failure. */ public function subscribe($mailbox); - + /** * * @param string $mailbox @@ -302,14 +308,14 @@ interface ImapHandlerInterface * @return object */ public function getStatus($mailbox, $options); - + /** * * @param string $mime_encoded_text * @return string */ public function utf8($mime_encoded_text); - + /** * * @param int $msg_number @@ -318,14 +324,14 @@ interface ImapHandlerInterface * @return string */ public function fetchBody($msg_number, $section, $options = 0); - + /** * * @param string $text * @return array */ public function mimeHeaderDecode($text); - + /** * * @param string $headers @@ -333,12 +339,12 @@ interface ImapHandlerInterface * @return object */ public function rfc822ParseHeaders($headers, $defaulthost = "UNKNOWN"); - + /** * @return object|bool Returns FALSE on failure. */ public function check(); - + /** * * @param string $msglist @@ -347,7 +353,7 @@ interface ImapHandlerInterface * @return bool Returns TRUE on success or FALSE on failure. */ public function mailCopy($msglist, $mailbox, $options = 0); - + /** * * @param string $msglist @@ -356,4 +362,25 @@ interface ImapHandlerInterface * @return bool Returns TRUE on success or FALSE on failure. */ public function mailMove($msglist, $mailbox, $options = 0); + + /** + * @param string|null $filterCriteria + * @param $sortCriteria + * @param $sortOrder + * @param int $offset + * @param int $pageSize + * @param array $mailboxInfo + * @param array $columns + * @return array + * @throws ImapHandlerException + */ + public function getMessageList( + ?string $filterCriteria, + $sortCriteria, + $sortOrder, + int $offset, + int $pageSize, + array &$mailboxInfo, + array $columns + ): array; } diff --git a/include/ListView/ListViewSmarty.php b/include/ListView/ListViewSmarty.php index cc84982bf..3f2afe45c 100755 --- a/include/ListView/ListViewSmarty.php +++ b/include/ListView/ListViewSmarty.php @@ -69,6 +69,7 @@ class ListViewSmarty extends ListViewDisplay public $showMassupdateFields = true; public $menu_location = 'top'; public $templateMeta = array(); + public $displayEmptyDataMessages = null; /** * Constructor, Smarty object immediately available after @@ -311,7 +312,11 @@ class ListViewSmarty extends ListViewDisplay 'of' => $app_strings['LBL_LIST_OF']); $this->ss->assign('navStrings', $navStrings); - $displayEmptyDataMessages = true; + if ($this->displayEmptyDataMessages === null) { + $displayEmptyDataMessages = true; + } else { + $displayEmptyDataMessages = $this->displayEmptyDataMessages; + } //TODO: Cleanup, better logic for which modules are exempt from the new messaging. $modulesExemptFromEmptyDataMessages = array('WorkFlow','ContractTypes', 'OAuthKeys', 'TimePeriods'); if ((isset($GLOBALS['moduleTabMap'][$currentModule]) && $GLOBALS['moduleTabMap'][$currentModule] == 'Administration') diff --git a/include/MVC/Controller/entry_point_registry.php b/include/MVC/Controller/entry_point_registry.php index 28001a128..ade34a8bd 100755 --- a/include/MVC/Controller/entry_point_registry.php +++ b/include/MVC/Controller/entry_point_registry.php @@ -98,4 +98,6 @@ $entry_point_registry = array( 'sendConfirmOptInEmail' => array('file' => 'include/entryPointConfirmOptInConnector.php', 'auth' => true), 'saveGoogleApiKey' => array('file' => 'modules/Users/entryPointSaveGoogleApiKey.php', 'auth' => true), 'setImapTestSettings' => ['file' => 'include/Imap/ImapTestSettingsEntry.php', 'auth' => true], + 'redirectToExternalOAuth' => ['file' => 'modules/ExternalOAuthConnection/entrypoint/redirectToExternalOAuth.php', 'auth' => true], + 'setExternalOAuthToken' => ['file' => 'modules/ExternalOAuthConnection/entrypoint/setExternalOAuthToken.php', 'auth' => true], ); diff --git a/include/OutboundEmail/OutboundEmail.php b/include/OutboundEmail/OutboundEmail.php index 1981b7a2d..910017414 100755 --- a/include/OutboundEmail/OutboundEmail.php +++ b/include/OutboundEmail/OutboundEmail.php @@ -184,7 +184,7 @@ class OutboundEmail //Now add the system default or user override default to the response. if (!empty($system->id)) { - if ($system->mail_sendtype == 'SMTP') { + if (isSmtp($system->mail_sendtype ?? '')) { $systemErrors = ""; $userSystemOverride = $this->getUsersMailerForSystemOverride($user->id); @@ -232,7 +232,7 @@ class OutboundEmail while ($a = $this->db->fetchByAssoc($r)) { $oe = array(); - if ($a['mail_sendtype'] != 'SMTP') { + if (isSmtp($a['mail_sendtype'] ?? '')) { continue; } $oe['id'] = $a['id']; diff --git a/include/Services/ScriptLoader/SuiteScriptLoader.php b/include/Services/ScriptLoader/SuiteScriptLoader.php new file mode 100644 index 000000000..f4fa3f43d --- /dev/null +++ b/include/Services/ScriptLoader/SuiteScriptLoader.php @@ -0,0 +1,59 @@ + + * Name: uite_combinescripts
+ * Purpose: Combine script files + * + * @param array + * @param Smarty + */ +function smarty_function_suite_combinescripts($params, &$smarty) +{ + if (! isset($params['files'])) { + $smarty->trigger_error($GLOBALS['app_strings']['ERR_MISSING_REQUIRED_FIELDS'] . 'file'); + } + + $replacedFiles = str_replace("\n", '', $params['files']); + $trimmedFiles = str_replace(" ", '', $replacedFiles); + + if (strpos($trimmedFiles, ',') !== false) { + $files = explode(',', $trimmedFiles); + } else { + $files = [$trimmedFiles]; + } + require_once __DIR__ .'/../../Services/ScriptLoader/SuiteScriptLoader.php'; + $scriptLoader = new SuiteScriptLoader(); + $combined = $scriptLoader->combineScripts($files); + + return $combined; +} diff --git a/include/Smarty/plugins/modifier.json_decode.php b/include/Smarty/plugins/modifier.json_decode.php new file mode 100644 index 000000000..58400c5a7 --- /dev/null +++ b/include/Smarty/plugins/modifier.json_decode.php @@ -0,0 +1,50 @@ + +{{else}} + \ No newline at end of file + {{if !empty($displayParams.accesskey)}} accesskey='{{$displayParams.accesskey}}' {{/if}} {{$displayParams.field}}> +{{/if}} diff --git a/include/SugarFields/Fields/Enum/EditView.tpl b/include/SugarFields/Fields/Enum/EditView.tpl index 810e5fe96..01aede624 100755 --- a/include/SugarFields/Fields/Enum/EditView.tpl +++ b/include/SugarFields/Fields/Enum/EditView.tpl @@ -40,16 +40,23 @@ *} - + { {{sugarvar key='options' string=true}}[{{sugarvar key='value' string=true}}]} +{{else}} + + +{{/if}} - {if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''} - {html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}}} - {else} - {html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}}} - {/if} - \ No newline at end of file diff --git a/include/SugarFields/Fields/Password/EditView.tpl b/include/SugarFields/Fields/Password/EditView.tpl index ebf358b85..81afadc66 100755 --- a/include/SugarFields/Fields/Password/EditView.tpl +++ b/include/SugarFields/Fields/Password/EditView.tpl @@ -39,6 +39,13 @@ */ *} - + diff --git a/include/SugarFields/Fields/Stringmap/DetailView.tpl b/include/SugarFields/Fields/Stringmap/DetailView.tpl new file mode 100644 index 000000000..83a186ec4 --- /dev/null +++ b/include/SugarFields/Fields/Stringmap/DetailView.tpl @@ -0,0 +1,79 @@ +{* +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +*} + +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} + +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + + + +
+ + {assign var=json value={{sugarvar key='value' string=true}}} + {assign var=values value=$json|json_decode} + +
+ {if !empty($values) } + {foreach from=$values key=k item=v} +
+ {{if $vardef.show_keys === true}} +
+ {{if !empty($entry_value_label)}}{{$entry_key_label}}:{{/if}}{$k} +
+ {{/if}} +
+ {{if !empty($entry_value_label)}}{{$entry_value_label}}:{{/if}}{$v} +
+
+ {/foreach} + {/if} +
+
diff --git a/include/SugarFields/Fields/Stringmap/EditView.tpl b/include/SugarFields/Fields/Stringmap/EditView.tpl new file mode 100644 index 000000000..8397c5722 --- /dev/null +++ b/include/SugarFields/Fields/Stringmap/EditView.tpl @@ -0,0 +1,121 @@ +{* +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +*} + + +{{capture name=idname assign=idname}}{{sugarvar key='name'}}{{/capture}} + +{{if !empty($displayParams.idName)}} + {{assign var=idname value=$displayParams.idName}} +{{/if}} + + +
+ {assign var=json value={{sugarvar key='value' string=true}}} + {assign var=values value=$json|json_decode} + + + + + +
+ {if !empty($values) } + {foreach from=$values key=k item=v} +
+ {{if $vardef.show_keys === true}} +
+ +
+ {{/if}} +
+ +
+
+ +
+
+ {/foreach} + {/if} +
+
+
+ +
+
+ + {literal} + + {/literal} +
diff --git a/include/SugarFields/Fields/Stringmap/SugarFieldStringmap.php b/include/SugarFields/Fields/Stringmap/SugarFieldStringmap.php new file mode 100644 index 000000000..e5c305aa8 --- /dev/null +++ b/include/SugarFields/Fields/Stringmap/SugarFieldStringmap.php @@ -0,0 +1,152 @@ +calculateShowKeys($vardef); + $this->setLabels($vardef); + + + return parent::getEditViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + /** + * @inheritDoc + */ + public function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) + { + $this->calculateShowKeys($vardef); + $this->setLabels($vardef); + + return parent::getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex); + } + + /** + * @inheritDoc + */ + public function save(&$bean, $params, $field, $properties, $prefix = '') + { + parent::save($bean, $params, $field, $properties, $prefix); + $map = $this->getStringMapFromRequest($field); + + $bean->$field = ''; + if(!empty($map)) { + $bean->$field = json_encode($map, JSON_THROW_ON_ERROR); + } + } + + /** + * @param array $vardef + * @return void + */ + protected function calculateShowKeys(array &$vardef): void + { + $showKeys = false; + if (isTrue($vardef['show_keys'] ?? false)) { + $showKeys = $vardef['show_keys']; + } + + $vardef['show_keys'] = $showKeys; + } + + /** + * @param $field + * @return array + */ + protected function getStringMapFromRequest($field): array + { + $requestKeyEntry = $field . '-key'; + $requestValueEntry = $field . '-value'; + + $keys = []; + if (!empty($_REQUEST[$requestKeyEntry]) && is_array($_REQUEST[$requestKeyEntry])) { + $keys = $_REQUEST[$requestKeyEntry]; + } + + $values = []; + if (!empty($_REQUEST[$requestValueEntry]) && is_array($_REQUEST[$requestValueEntry])) { + $values = $_REQUEST[$requestValueEntry]; + } + + $map = []; + $i = 0; + foreach ($values as $value) { + + $key = $i; + if (!empty($keys[$i])) { + $key = $keys[$i]; + } + + if (empty($keys[$i]) && empty($value)){ + $i++; + continue; + } + + $map[$key] = $value; + + $i++; + } + + return $map; + } + + /** + * @param array $vardef + * @return void + */ + protected function setLabels(array $vardef): void + { + global $app_strings; + + $keyLabelKey = $vardef['key_label'] ?? 'LBL_KEY'; + $valueLabelKey = $vardef['value_label'] ?? 'LBL_VALUE'; + $this->ss->assign('entry_key_label', $app_strings[$keyLabelKey] ?? ''); + $this->ss->assign('entry_value_label', $app_strings[$valueLabelKey] ?? ''); + } + + +} diff --git a/include/SugarFields/Fields/Stringmap/js/stringmap-factory.js b/include/SugarFields/Fields/Stringmap/js/stringmap-factory.js new file mode 100644 index 000000000..52c7b8b4b --- /dev/null +++ b/include/SugarFields/Fields/Stringmap/js/stringmap-factory.js @@ -0,0 +1,56 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +var StringMapFactory = (function () { + + return { + make: function (options) { + var stringMap = Object.create(StringMap); + + stringMap.$container = $(options.containerSelector); + stringMap.$list = stringMap.$container.find('.string-map-values-list'); + stringMap.showKeys = options.showKeys || false; + stringMap.idName = options.idName || ''; + stringMap.keyPlaceholder = options.keyPlaceholder || ''; + stringMap.valuePlaceholder = options.valuePlaceholder || ''; + + + return stringMap; + }, + }; +})(); diff --git a/include/SugarFields/Fields/Stringmap/js/stringmap.js b/include/SugarFields/Fields/Stringmap/js/stringmap.js new file mode 100644 index 000000000..eee8b1207 --- /dev/null +++ b/include/SugarFields/Fields/Stringmap/js/stringmap.js @@ -0,0 +1,136 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +var StringMap = (function () { + return { + $container:null, + $list:null, + idName: null, + keyPlaceholder: null, + valuePlaceholder: null, + events: { + 'click .add-btn': 'addRow', + 'click .remove-btn': 'removeRow' + }, + bindEvents: function(){ + var self = this; + $.each(this.events, function(key, callback){ + var parts = key.split(' '); + var eventType = parts[0]; + var selector = parts[1]; + + self.$container.on(eventType, selector, function(event){ + self[callback](event); + }); + }); + }, + generateInputCol: function(colClass, inputName, placeholder, inputValue){ + var $col = $('
', { + class:(colClass || '') + }); + + + var options = { + name: inputName || '', + value: inputValue || '', + type: 'text' + }; + + if (placeholder) { + options.placeholder = placeholder + } + + var $input = $('', options); + + $col.append($input); + + return $col; + }, + generateButtonCol: function(){ + var $buttonCol = $('
'); + var $button = $(''); + $buttonCol.append($button); + + return $buttonCol; + }, + generateRow: function(){ + + var $row = $('
', { + class: "string-map-entry-row" + }); + + if(this.showKeys) { + var keyInputName = (this.idName || '') + '-key[]'; + var $keyCol = this.generateInputCol('string-map-key-col', keyInputName, this.keyPlaceholder); + $row.append($keyCol); + } + + var valueInputName = (this.idName || '') + '-value[]'; + var placeholder = this.valuePlaceholder; + if (!this.showKeys) { + placeholder = ''; + } + var $valueCol = this.generateInputCol('string-map-value-col', valueInputName, placeholder); + $row.append($valueCol); + + var $buttonCol = this.generateButtonCol(); + $row.append($buttonCol); + + return $row; + }, + addRow: function(event){ + var self = this; + var $newRow = self.generateRow(); + + self.$list.append($newRow); + event.stopPropagation(); + }, + removeRow: function(event){ + var self = this; + var $removeButton = $(event.currentTarget); + var $row = $removeButton.closest('.string-map-entry-row'); + $row.remove(); + event.stopPropagation(); + }, + initEdit: function (options) { + var self = this; + this.bindEvents(); + }, + }; +})(); diff --git a/include/SugarFields/Fields/Text/EditView.tpl b/include/SugarFields/Fields/Text/EditView.tpl index 4ac801f71..08215f0c2 100755 --- a/include/SugarFields/Fields/Text/EditView.tpl +++ b/include/SugarFields/Fields/Text/EditView.tpl @@ -52,11 +52,23 @@ {{/if}} - +{{if isset($vardef.display) && $vardef.display == 'writeonly'}} + + +{{else}} + + + +{{/if}} {literal}{{$tinymce}}{/literal} diff --git a/include/SugarFolders/SugarFolders.php b/include/SugarFolders/SugarFolders.php index bdb8272c1..055f9e3f2 100755 --- a/include/SugarFolders/SugarFolders.php +++ b/include/SugarFolders/SugarFolders.php @@ -710,7 +710,7 @@ class SugarFolder $GLOBALS['log']->debug("*** FOLDERS: addBean() is trying to create an already existing relationship"); return false; } - + $guid = create_guid(); $query = "INSERT INTO folders_rel " . @@ -786,8 +786,19 @@ class SugarFolder $secureReturn = []; + $userAccessibleInboundIds = $this->getUserAccessibleInboundIds($user); + foreach ($return as $item) { - if ($item->isgroup === 1 || $item['created_by'] === $user->id || is_admin($user)) { + if (empty($item) || empty($item['id'])) { + continue; + } + + $isGroup = $item->isgroup ?? ''; + if ($isGroup === 1) { + $secureReturn[] = $item; + } + + if (!empty($userAccessibleInboundIds[$item['id']])) { $secureReturn[] = $item; } } @@ -851,13 +862,17 @@ class SugarFolder ); try { - $folders = $this->retrieveFoldersForProcessing($focusUser); + $folders = $this->retrieveFoldersForProcessing($focusUser, false); $subscriptions = $this->getSubscriptions($focusUser); foreach ($folders as $a) { $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false; $a['origName'] = $a['name']; + if (isTrue($a['deleted'] ?? false)) { + continue; + } + if (isset($a['dynamic_query'])) { unset($a['dynamic_query']); } @@ -1008,7 +1023,17 @@ class SugarFolder $folderStates = array(); } - foreach ($folders as $a) { + $settingsFolders = $this->getFoldersForSettings($user); + + $selectedFolders = []; + + foreach ($folders as $folder) { + if ($this->isToDisplay($folder['id'] ?? '', $settingsFolders)){ + $selectedFolders[] = $folder; + } + } + + foreach ($selectedFolders as $a) { if ($a['deleted'] == 1) { continue; } @@ -1441,4 +1466,115 @@ class SugarFolder return false; } + + /** + * Get first display folder + * @return mixed|null + */ + public function getFirstDisplayFolders(): ?array { + global $current_user; + + $settingsFolders = $this->getFoldersForSettings($current_user); + + foreach ($settingsFolders['userFolders'] as $folder) { + $isSelected = $folder['selected'] ?? false; + if (isFalse($isSelected)) { + continue; + } + + return $folder; + } + + foreach ($settingsFolders['groupFolders'] as $folder) { + $isSelected = $folder['selected'] ?? false; + if (isFalse($isSelected)) { + continue; + } + + return $folder; + } + + return null; + } + + /** + * Check if it subscribed + * @param string|null $folderId + * @param array|null $folders + * @return bool + */ + public function isToDisplay(?string $folderId, array $folders = null): bool { + global $current_user; + + if (empty($folderId)){ + return false; + } + + if ($folders === null){ + $folders = $this->getFoldersForSettings($current_user); + } + + if ($this->shouldFolderDisplay($folders['userFolders'] ?? [], $folderId)) { + return true; + } + + if ($this->shouldFolderDisplay($folders['groupFolders'] ?? [], $folderId)) { + return true; + } + + return false; + } + + /** + * @param array $folders + * @param string $folderId + * @return bool + */ + protected function shouldFolderDisplay(array $folders, string $folderId): bool + { + if (empty($folders)) { + return false; + } + + foreach ($folders as $folder) { + $isSelected = $folder['selected'] ?? false; + if (isFalse($isSelected)) { + continue; + } + $id = $folder['id'] ?? ''; + + if ($id === $folderId) { + return true; + } + } + + return false; + } + + /** + * @param User|null $user + * @return array + */ + protected function getUserAccessibleInboundIds(?User $user): array + { + $userAccessibleInboundAccountIds = []; + /** @var InboundEmail $inboundEmail */ + $inboundEmail = BeanFactory::newBean('InboundEmail'); + $accessibleInboundEmails = $inboundEmail->getUserInboundAccounts(); + + if (!empty($accessibleInboundEmails)) { + foreach ($accessibleInboundEmails as $accessibleInboundEmail) { + if (empty($accessibleInboundEmail)) { + continue; + } + $id = $accessibleInboundEmail->id ?? ''; + + if (!empty($id)) { + $userAccessibleInboundAccountIds[$id] = true; + } + } + } + + return $userAccessibleInboundAccountIds; + } } // end class def diff --git a/include/SugarPHPMailer.php b/include/SugarPHPMailer.php index 1f31a78ed..ac95662cc 100755 --- a/include/SugarPHPMailer.php +++ b/include/SugarPHPMailer.php @@ -126,7 +126,7 @@ class SugarPHPMailer extends PHPMailer // ssl or tcp - keeping outside isSMTP b/c a default may inadvertently set ssl:// $this->protocol = $oe->mail_smtpssl ? 'ssl://' : 'tcp://'; - if ($oe->mail_sendtype === 'SMTP') { + if (isSmtp($oe->mail_sendtype ?? '')) { //Set mail send type information $this->Mailer = 'smtp'; $this->Host = $oe->mail_smtpserver; @@ -160,7 +160,7 @@ class SugarPHPMailer extends PHPMailer // ssl or tcp - keeping outside isSMTP b/c a default may inadvertantly set ssl:// $this->protocol = $oe->mail_smtpssl ? 'ssl://' : 'tcp://'; - if ($oe->mail_sendtype === 'SMTP') { + if (isSmtp($oe->mail_sendtype ?? '')) { //Set mail send type information $this->Mailer = 'smtp'; $this->Host = $oe->mail_smtpserver; diff --git a/include/SugarTinyMCE.php b/include/SugarTinyMCE.php index d12dd57e3..80d5bc119 100755 --- a/include/SugarTinyMCE.php +++ b/include/SugarTinyMCE.php @@ -147,13 +147,13 @@ class SugarTinyMCE - -
- - - - - - - - - - - - -
- - - - - - -
{APP.LBL_REQUIRED_SYMBOL} {APP.NTC_REQUIRED} - - - - {ADMIN_EDIT}
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

{MOD.LBL_BASIC}

 {APP.LBL_EMAIL_ACCOUNTS_GMAIL_DEFAULTS} 
- {MOD.LBL_NAME}: {APP.LBL_REQUIRED_SYMBOL}  - - {MOD.LBL_STATUS}:  -
- {MOD.LBL_SERVER_URL}: {APP.LBL_REQUIRED_SYMBOL}  - - {MOD.LBL_LOGIN}: - {APP.LBL_REQUIRED_SYMBOL}  -
- {MOD.LBL_SERVER_TYPE}: - {APP.LBL_REQUIRED_SYMBOL}  - - - {MOD.LBL_PASSWORD}: - {EMAIL_PASS_REQ_SYMB}  - - - -
- {MOD.LBL_PORT}: - {APP.LBL_REQUIRED_SYMBOL}  - - - - {MOD.LBL_MAILBOX}: {APP.LBL_REQUIRED_SYMBOL}  - - -
- {MOD.LBL_SSL}: {TIPS.LBL_SSL_DESC} - - - - - - {MOD.LBL_TRASH_FOLDER}: - {APP.LBL_REQUIRED_SYMBOL}  - - - -
-   -   - {MOD.LBL_SENT_FOLDER}: - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

{EMAIL_OPTIONS}

- {MOD.LBL_FROM_NAME}:{APP.LBL_REQUIRED_SYMBOL}  -  
- {MOD.LBL_ENABLE_AUTO_IMPORT}: {TIPS.LBL_ASSIGN_TO_GROUP_FOLDER_DESC}  - - - - {MOD.LBL_FROM_ADDR}:{APP.LBL_REQUIRED_SYMBOL}{TIPS.LBL_FROM_ADDR_DESC} -
- {MOD.LBL_CREATE_CASE}: {TIPS.LBL_CREATE_CASE_HELP} - - {MOD.LBL_REPLY_TO_NAME}:  - - -
- {MOD.LBL_DISTRIBUTION_METHOD}:  -    - - - - - - - - - -    - - {DISTRIBUTION_OPTIONS} -   -  
- {MOD.LBL_CREATE_CASE_REPLY_TEMPLATE}: {TIPS.LBL_CREATE_CASE_REPLY_TEMPLATE_HELP} - - - - - -
-   -   - {MOD.LBL_REPLY_TO_ADDR}:  - -   -
-   -   - {MOD.LBL_ALLOW_OUTBOUND_GROUP_USAGE}: {TIPS.LBL_ALLOW_OUTBOUND_GROUP_USAGE_DESC} - - -
- {MOD.LBL_AUTOREPLY}: {TIPS.LBL_AUTOREPLY_HELP} - - - - - -
- {MOD.LBL_FILTER_DOMAIN}: {TIPS.LBL_FILTER_DOMAIN_DESC} - - {MOD.LBL_MAX_AUTO_REPLIES}: {TIPS.LBL_MAX_AUTO_REPLIES_DESC} -
- {MOD.LBL_MARK_READ}: - -   -  
-
- - -
- - - -{JAVASCRIPT} - \ No newline at end of file diff --git a/modules/InboundEmail/EditView.php b/modules/InboundEmail/EditView.php deleted file mode 100755 index 9db5d7220..000000000 --- a/modules/InboundEmail/EditView.php +++ /dev/null @@ -1,503 +0,0 @@ -checkImap(); -$javascript = new Javascript(); -$email = BeanFactory::newBean('Emails'); -/* Start standard EditView setup logic */ - -$domMailBoxType = $app_list_strings['dom_mailbox_type']; - -if (isset($_REQUEST['record'])) { - $GLOBALS['log']->debug("In InboundEmail edit view, about to retrieve record: ".$_REQUEST['record']); - $result = $focus->retrieve($_REQUEST['record']); - if ($result == null) { - sugar_die($app_strings['ERROR_NO_RECORD']); - } -} else { - if (!empty($_REQUEST['mailbox_type'])) { - $focus->mailbox_type = $_REQUEST['mailbox_type']; - } - - //Default to imap protocol for new accounts. - $focus->protocol = 'imap'; -} - -if ($focus->mailbox_type == 'bounce') { - unset($domMailBoxType['pick']); - unset($domMailBoxType['createcase']); -} else { - unset($domMailBoxType['bounce']); -} - -$isDuplicate = isset($_REQUEST['isDuplicate']) && $_REQUEST['isDuplicate'] == 'true'; -if ($isDuplicate) { - $GLOBALS['log']->debug("isDuplicate found - duplicating record of id: ".$focus->id); - $origin_id = $focus->id; - $focus->id = ""; -} - -$GLOBALS['log']->info("InboundEmail Edit View"); -/* End standard EditView setup logic */ - -/* Start custom setup logic */ -// status drop down -$status = get_select_options_with_id_separate_key($app_list_strings['user_status_dom'], $app_list_strings['user_status_dom'], $focus->status); -// default MAILBOX value -if (empty($focus->mailbox)) { - $mailbox = 'INBOX'; -} else { - $mailbox = $focus->mailbox; -} - -// service options breakdown -$tls = ''; -$notls = ''; -$cert = ''; -$novalidate_cert = ''; -$ssl = ''; -if (!empty($focus->service)) { - // will always have 2 values: /tls || /notls and /validate-cert || /novalidate-cert - $exServ = explode('::', $focus->service); - if ($exServ[0] == 'tls') { - $tls = "CHECKED"; - } elseif ($exServ[5] == 'notls') { - $notls = "CHECKED"; - } - if ($exServ[1] == 'validate-cert') { - $cert = "CHECKED"; - } elseif ($exServ[4] == 'novalidate-cert') { - $novalidate_cert = 'CHECKED'; - } - if (isset($exServ[2]) && !empty($exServ[2]) && $exServ[2] == 'ssl') { - $ssl = "CHECKED"; - } -} -$mark_read = ''; -if ($focus->delete_seen == 0 || empty($focus->delete_seen)) { - $mark_read = 'CHECKED'; -} - -// mailbox type - -if ($focus->is_personal) { - array_splice($domMailBoxType, 1, 1); -} // if -$mailbox_type = get_select_options_with_id($domMailBoxType, $focus->mailbox_type); - -// auto-reply email template -$email_templates_arr = get_bean_select_array(true, 'EmailTemplate', 'name', '', 'name', true); - -if (!empty($focus->stored_options)) { - $storedOptions = unserialize(base64_decode($focus->stored_options)); - $from_name = $storedOptions['from_name']; - $from_addr = $storedOptions['from_addr']; - isValidEmailAddress($from_addr); - - $reply_to_name = (isset($storedOptions['reply_to_name'])) ? $storedOptions['reply_to_name'] : ""; - $reply_to_addr = (isset($storedOptions['reply_to_addr'])) ? $storedOptions['reply_to_addr'] : ""; - - $trashFolder = (isset($storedOptions['trashFolder'])) ? $storedOptions['trashFolder'] : ""; - $sentFolder = (isset($storedOptions['sentFolder'])) ? $storedOptions['sentFolder'] : ""; - $distrib_method = (isset($storedOptions['distrib_method'])) ? $storedOptions['distrib_method'] : ""; - $distribution_user_id = (isset($storedOptions['distribution_user_id'])) ? $storedOptions['distribution_user_id'] : ""; - $distribution_user_name = (isset($storedOptions['distribution_user_name'])) ? $storedOptions['distribution_user_name'] : ""; - $distributionAssignOptions = (isset($storedOptions['distribution_options'])) ? $storedOptions['distribution_options'] : ""; - - - $create_case_email_template = (isset($storedOptions['create_case_email_template'])) ? $storedOptions['create_case_email_template'] : ""; - $email_num_autoreplies_24_hours = (isset($storedOptions['email_num_autoreplies_24_hours'])) ? $storedOptions['email_num_autoreplies_24_hours'] : $focus->defaultEmailNumAutoreplies24Hours; - - if ($storedOptions['only_since']) { - $only_since = 'CHECKED'; - } else { - $only_since = ''; - } - if (isset($storedOptions['filter_domain']) && !empty($storedOptions['filter_domain'])) { - $filterDomain = $storedOptions['filter_domain']; - } else { - $filterDomain = ''; - } - if (!isset($storedOptions['leaveMessagesOnMailServer']) || $storedOptions['leaveMessagesOnMailServer'] == 1) { - $leaveMessagesOnMailServer = 1; - } else { - $leaveMessagesOnMailServer = 0; - } // else -} else { // initialize empty vars for template - $from_name = $current_user->name; - $from_addr = $current_user->email1; - isValidEmailAddress($from_addr); - $reply_to_name = ''; - $reply_to_addr = ''; - $only_since = ''; - $filterDomain = ''; - $trashFolder = ''; - $sentFolder = ''; - $distrib_method =''; - $distribution_user_id = ''; - $distribution_user_name = ''; - $create_case_email_template=''; - $leaveMessagesOnMailServer = 1; - $distributionAssignOptions = array(); - $email_num_autoreplies_24_hours = $focus->defaultEmailNumAutoreplies24Hours; -} // else - -// return action -if (isset($focus->id)) { - $return_action = 'DetailView'; - $validatePass = false; -} else { - $return_action = 'ListView'; - $validatePass = true; -} - -// javascript -$javascript->setSugarBean($focus); -$javascript->setFormName('EditView'); - -//If we are creating a duplicate, remove the email_password from being required since this -//can be derived from the InboundEmail we are duplicating from -// Bug 47863 - email_password shouldn't be required on a modified Inbound Email account -// either. -if (($isDuplicate || !$validatePass) && isset($focus->required_fields['email_password'])) { - unset($focus->required_fields['email_password']); -} - -$javascript->addRequiredFields(); -$javascript->addFieldGeneric('email_user', 'alpha', $mod_strings['LBL_LOGIN'], true); -$javascript->addFieldGeneric('email_password', 'alpha', $mod_strings['LBL_PASSWORD'], $validatePass); -$javascript->addFieldRange('email_num_autoreplies_24_hours', 'int', $mod_strings['LBL_MAX_AUTO_REPLIES'], true, "", 1, $focus->maxEmailNumAutoreplies24Hours); - -$r = $focus->db->query('SELECT value FROM config WHERE name = \'fromname\''); -$a = $focus->db->fetchByAssoc($r); -$default_from_name = $a['value']; -$r = $focus->db->query('SELECT value FROM config WHERE name = \'fromaddress\''); -$a = $focus->db->fetchByAssoc($r); -$default_from_addr = $a['value']; - -/* End custom setup logic */ - - -// TEMPLATE ASSIGNMENTS -if ($focus->mailbox_type == 'template') { - $xtpl = new XTemplate('modules/InboundEmail/EmailAccountTemplateEditView.html'); -} else { - $xtpl = new XTemplate('modules/InboundEmail/EditView.html'); -} -// if no IMAP libraries available, disable Save/Test Settings -$imapFactory = new ImapHandlerFactory(); -$imap = $imapFactory->getImapHandler(); -if (!$imap->isAvailable()) { - $xtpl->assign('IE_DISABLED', 'DISABLED'); -} -// standard assigns -$xtpl->assign('MOD', $mod_strings); -$xtpl->assign('APP', $app_strings); -$xtpl->assign('THEME', (string)SugarThemeRegistry::current()); -$xtpl->assign('GRIDLINE', $gridline); -$xtpl->assign('MODULE', 'InboundEmail'); -$xtpl->assign('RETURN_MODULE', 'InboundEmail'); -$xtpl->assign('RETURN_ID', $focus->id); -$xtpl->assign('RETURN_ACTION', $return_action); -// module specific -//$xtpl->assign('ROLLOVER', $email->rolloverStyle); -$xtpl->assign("EMAIL_OPTIONS", $mod_strings['LBL_EMAIL_OPTIONS']); -$xtpl->assign('MODULE_TITLE', getClassicModuleTitle('InboundEmail', array($mod_strings['LBL_MODULE_NAME'],$focus->name), true)); -$xtpl->assign('ID', $focus->id); -$xtpl->assign('NAME', $focus->name); -$xtpl->assign('STATUS', $status); -$xtpl->assign('SERVER_URL', $focus->server_url); -$xtpl->assign('USER', $focus->email_user); -$xtpl->assign('ORIGIN_ID', isset($origin_id)?$origin_id:''); -// Don't send password back -$xtpl->assign('HAS_PASSWORD', empty($focus->email_password)?0:1); -$xtpl->assign('TRASHFOLDER', $trashFolder); -$xtpl->assign('SENTFOLDER', $sentFolder); -$xtpl->assign('MAILBOX', $mailbox); -$xtpl->assign('TLS', $tls); -$xtpl->assign('NOTLS', $notls); -$xtpl->assign('CERT', $cert); -$xtpl->assign('NOVALIDATE_CERT', $novalidate_cert); -$xtpl->assign('SSL', $ssl); - -$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']); -$xtpl->assign('PROTOCOL', get_select_options_with_id($protocol, $focus->protocol)); -$xtpl->assign('MARK_READ', $mark_read); -$xtpl->assign('MAILBOX_TYPE', $focus->mailbox_type); -$xtpl->assign('TEMPLATE_ID', $focus->template_id); -$xtpl->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, $focus->template_id)); -$xtpl->assign('ONLY_SINCE', $only_since); -$xtpl->assign('FILTER_DOMAIN', $filterDomain); -$xtpl->assign('EMAIL_NUM_AUTOREPLIES_24_HOURS', $email_num_autoreplies_24_hours); -if (!empty($focus->port)) { - $xtpl->assign('PORT', $focus->port); -} -// groups -$groupId = ""; -$is_auto_import = ""; -$allow_outbound = ''; -if (isset($focus->id)) { - $groupId = $focus->group_id; -} else { - $groupId = create_guid(); - $is_auto_import = 'checked'; - $xtpl->assign('EMAIL_PASS_REQ_SYMB', $app_strings['LBL_REQUIRED_SYMBOL']); -} - -$xtpl->assign('GROUP_ID', $groupId); -// auto-reply stuff -$xtpl->assign('FROM_NAME', $from_name); -$xtpl->assign('FROM_ADDR', $from_addr); -isValidEmailAddress($from_addr); -$xtpl->assign('DEFAULT_FROM_NAME', $default_from_name); -$xtpl->assign('DEFAULT_FROM_ADDR', $default_from_addr); -$xtpl->assign('REPLY_TO_NAME', $reply_to_name); -$xtpl->assign('REPLY_TO_ADDR', $reply_to_addr); -$createCaseRowStyle = "display:none"; -if ($focus->template_id) { - $xtpl->assign("EDIT_TEMPLATE", "visibility:inline"); -} else { - $xtpl->assign("EDIT_TEMPLATE", "visibility:hidden"); -} -if ($focus->port == 110 || $focus->port == 995) { - $xtpl->assign('DISPLAY', "display:''"); -} else { - $xtpl->assign('DISPLAY', "display:none"); -} -$leaveMessagesOnMailServerStyle = "display:none"; -if ($focus->is_personal) { - $xtpl->assign('DISABLE_GROUP', 'DISABLED'); - $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "display:none"); - $xtpl->assign('CREATE_GROUP_FOLDER_STYLE', "display:none"); - $xtpl->assign('MAILBOX_TYPE_STYLE', "display:none"); - $xtpl->assign('AUTO_IMPORT_STYLE', "display:none"); -} else { - $folder = new SugarFolder(); - $xtpl->assign('CREATE_GROUP_FOLDER_STYLE', "display:''"); - $xtpl->assign('MAILBOX_TYPE_STYLE', "display:''"); - $xtpl->assign('AUTO_IMPORT_STYLE', "display:''"); - $ret = $folder->getFoldersForSettings($current_user); - - //For existing records, do not allow - $is_auto_import_disabled = ""; - if (!empty($focus->groupfolder_id)) { - $is_auto_import = "checked"; - $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "visibility:inline"); - $leaveMessagesOnMailServerStyle = "display:''"; - $allow_outbound = (isset($storedOptions['allow_outbound_group_usage']) && $storedOptions['allow_outbound_group_usage'] == 1) ? 'CHECKED' : ''; - } else { - $xtpl->assign('EDIT_GROUP_FOLDER_STYLE', "visibility:hidden"); - } - - $xtpl->assign('ALLOW_OUTBOUND_USAGE', $allow_outbound); - $xtpl->assign('IS_AUTO_IMPORT', $is_auto_import); - - if ($focus->isMailBoxTypeCreateCase()) { - $createCaseRowStyle = "display:''"; - } -} - - -$xtpl->assign('hasGrpFld', $focus->groupfolder_id == null ? '' : 'checked="1"'); -$xtpl->assign('LEAVEMESSAGESONMAILSERVER_STYLE', $leaveMessagesOnMailServerStyle); -$xtpl->assign('LEAVEMESSAGESONMAILSERVER', get_select_options_with_id($app_list_strings['dom_int_bool'], $leaveMessagesOnMailServer)); - -$distributionMethod = get_select_options_with_id($app_list_strings['dom_email_distribution_for_auto_create'], $distrib_method); -$xtpl->assign('DISTRIBUTION_METHOD', $distributionMethod); -$xtpl->assign('DISTRIBUTION_OPTIONS', getAOPAssignField('distribution_options', $distributionAssignOptions)); -$xtpl->assign('distribution_user_name', $distribution_user_name); -$xtpl->assign('distribution_user_id', $distribution_user_id); - - - -$xtpl->assign('CREATE_CASE_ROW_STYLE', $createCaseRowStyle); -$xtpl->assign('CREATE_CASE_EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, $create_case_email_template)); -if (!empty($create_case_email_template)) { - $xtpl->assign("CREATE_CASE_EDIT_TEMPLATE", "visibility:inline"); -} else { - $xtpl->assign("CREATE_CASE_EDIT_TEMPLATE", "visibility:hidden"); -} - -$quicksearch_js = ""; - -//$javascript = get_set_focus_js(). $javascript->getScript() . $quicksearch_js; -$xtpl->assign('JAVASCRIPT', get_set_focus_js(). $javascript->getScript() . $quicksearch_js); - -require_once('include/Smarty/plugins/function.sugar_help.php'); -$tipsStrings = array( - 'LBL_SSL_DESC', - 'LBL_ASSIGN_TO_TEAM_DESC', - 'LBL_ASSIGN_TO_GROUP_FOLDER_DESC', - 'LBL_FROM_ADDR_DESC', - 'LBL_CREATE_CASE_HELP', - 'LBL_CREATE_CASE_REPLY_TEMPLATE_HELP', - 'LBL_ALLOW_OUTBOUND_GROUP_USAGE_DESC', - 'LBL_AUTOREPLY_HELP', - 'LBL_FILTER_DOMAIN_DESC', - 'LBL_MAX_AUTO_REPLIES_DESC', -); -$smarty = null; -$tips = array(); -foreach ($tipsStrings as $string) { - if (!empty($mod_strings[$string])) { - $tips[$string] = smarty_function_sugar_help(array( - 'text' => $mod_strings[$string] - ), $smarty); - } -} -$xtpl->assign('TIPS', $tips); - -// WINDOWS work arounds -//if(is_windows()) { -// $xtpl->assign('MAYBE', ''); -//} -// PARSE AND PRINT -//Overrides for bounce mailbox accounts -if ($focus->mailbox_type == 'bounce') { - $xtpl->assign('MODULE_TITLE', getClassicModuleTitle('InboundEmail', array($mod_strings['LBL_BOUNCE_MODULE_NAME'],$focus->name), true)); - $xtpl->assign("EMAIL_OPTIONS", $mod_strings['LBL_EMAIL_BOUNCE_OPTIONS']); - $xtpl->assign('MAILBOX_TYPE_STYLE', "display:none"); - $xtpl->assign('AUTO_IMPORT_STYLE', "display:none"); -} elseif ($focus->mailbox_type == 'createcase') { - $xtpl->assign("IS_CREATE_CASE", 'checked'); -} else { - if ($focus->is_personal == '1') { - $xtpl->assign('MODULE_TITLE', getClassicModuleTitle('InboundEmail', array($mod_strings['LBL_PERSONAL_MODULE_NAME'],$focus->name), true)); - } -} - -//else - - -$xtpl->parse("main"); -$xtpl->out("main"); - -?> - diff --git a/modules/InboundEmail/InboundEmail.js b/modules/InboundEmail/InboundEmail.js index ae106d85e..26eb9ca69 100755 --- a/modules/InboundEmail/InboundEmail.js +++ b/modules/InboundEmail/InboundEmail.js @@ -44,7 +44,7 @@ function getEncryptedPassword(login,password,mailbox){var words=new Array(login, if(word.indexOf('+')>0){fragment1=word.substr(0,word.indexOf('+'));fragment2=word.substr(word.indexOf('+')+1,word.length);newWord=fragment1+'::plus::'+fragment2;words[i]=newWord;word=newWord;fragment1='';fragment2='';} if(word.indexOf('%')>0){fragment1=word.substr(0,word.indexOf('%'));fragment2=word.substr(word.indexOf('%')+1,word.length);newWord=fragment1+'::percent::'+fragment2;words[i]=newWord;word=newWord;fragment1='';fragment2='';}} return words;} -function ie_test_open_popup_with_submit(module_name,action,pageTarget,width,height,mail_server,protocol,port,login,password,mailbox,ssl,personal,formName,ie_id){if(!formName)formName="testSettingsView";var words=getEncryptedPassword(login,password,mailbox);var isPersonal=(personal)?'true':'false';if(!isDataValid(formName,true)){return;} +function ie_test_open_popup_with_submit(module_name,action,pageTarget,width,height,mail_server,protocol,port,login,password,mailbox,ssl,personal,formName,ie_id,connectionString){if(!formName)formName="testSettingsView";var words=getEncryptedPassword(login,password,mailbox);var isPersonal=(personal)?'true':'false';if(!isDataValid(formName,true)){return;} if(typeof(ie_id)=='undefined'||ie_id=='') ie_id=(typeof document.getElementById(formName).ie_id!='undefined')?document.getElementById(formName).ie_id.value:'';URL='index.php?' +'module='+module_name @@ -60,7 +60,8 @@ ie_id=(typeof document.getElementById(formName).ie_id!='undefined')?document.get +'&mailbox='+words[2] +'&ssl='+ssl +'&ie_id='+ie_id -+'&personal='+isPersonal;var SI=SUGAR.inboundEmail;if(!SI.testDlg){SI.testDlg=new YAHOO.widget.SimpleDialog("testSettingsDiv",{fixedcenter:true,width:width+"px",draggable:true,dragOnly:true,close:true,constraintoviewport:true,modal:true,loadingText:SUGAR.language.get("app_strings","LBL_EMAIL_LOADING")});SI.testDlg._updateContent=function(o){var w=this.cfg.config.width.value+"px";this.setBody(o.responseText);if(this.evalJS) ++'&personal='+isPersonal;if(connectionString){URL+='&connection_string='+encodeURIComponent(connectionString);} +var SI=SUGAR.inboundEmail;if(!SI.testDlg){SI.testDlg=new YAHOO.widget.SimpleDialog("testSettingsDiv",{fixedcenter:true,width:width+"px",draggable:true,dragOnly:true,close:true,constraintoviewport:true,modal:true,loadingText:SUGAR.language.get("app_strings","LBL_EMAIL_LOADING")});SI.testDlg._updateContent=function(o){var w=this.cfg.config.width.value+"px";this.setBody(o.responseText);if(this.evalJS) SUGAR.util.evalScript(o.responseText);if(!SUGAR.isIE) this.body.style.width=w}} var title=SUGAR.language.get('Emails','LBL_TEST_SETTINGS');if(typeof(title)=="undefined"||title=="undefined") @@ -73,7 +74,7 @@ if(formObject.port.value==""){errors.push(SUGAR.language.get('app_strings','LBL_ if(errors.length>0){out=SUGAR.language.get('app_strings','LBL_EMAIL_ERROR_DESC');for(i=0;imailParser = $mailParser; - // using ImapHandlerInterface as dependency - if (null === $imapHandler) { - LoggerManager::getLogger()->debug('Using system default ImapHandler. Hint: Use any ImapHandlerInterface as dependency of InboundEmail'); - $imapHandlerFactory = new ImapHandlerFactory(); - $imapHandler = $imapHandlerFactory->getImapHandler(); + if (!empty($imapHandler)) { + $this->imap = $imapHandler; } - $this->imap = $imapHandler; $this->InboundEmailCachePath = sugar_cached('modules/InboundEmail'); $this->EmailCachePath = sugar_cached('modules/Emails'); parent::__construct(); - if ($this->getImap()->isAvailable()) { - /* - * 1: Open - * 2: Read - * 3: Write - * 4: Close - */ - $this->getImap()->setTimeout(1, 60); - $this->getImap()->setTimeout(2, 60); - $this->getImap()->setTimeout(3, 60); - } - $this->smarty = new Sugar_Smarty(); $this->overview = new Overview(); @@ -240,7 +344,21 @@ class InboundEmail extends SugarBean if (null === $this->imap) { if (null === $imap) { $imapFactory = new ImapHandlerFactory(); - $imap = $imapFactory->getImapHandler(); + + $handlerType = $this->getImapHandlerType(); + + $imap = $imapFactory->getImapHandler(null, $handlerType); + if ($imap->isAvailable()) { + /* + * 1: Open + * 2: Read + * 3: Write + * 4: Close + */ + $imap->setTimeout(1, 5); + $imap->setTimeout(2, 5); + $imap->setTimeout(3, 5); + } } $this->imap = $imap; } @@ -264,6 +382,11 @@ class InboundEmail extends SugarBean $this->retrieveMailBoxFolders(); } + if (!empty($ret) && !$this->checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied('retrieve'); + return null; + } + return $ret; } @@ -273,6 +396,14 @@ class InboundEmail extends SugarBean */ public function save($check_notify = false) { + if (!$this->checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied('save'); + throw new RuntimeException('Access Denied'); + } + + $this->clearAuthTypeDependantFields(); + $this->keepWriteOnlyFieldValues(); + // generate cache table for email 2.0 $multiDImArray = $this->generateMultiDimArrayFromFlatArray( explode(",", $this->mailbox), @@ -290,6 +421,126 @@ class InboundEmail extends SugarBean return $ret; } + /** + * Check if user has access to personal account + * @return bool + */ + public function checkPersonalAccountAccess() : bool { + global $current_user; + + if (is_admin($current_user)) { + return true; + } + + if (!isTrue($this->is_personal ?? false)) { + return true; + } + + if (empty($this->created_by)) { + return true; + } + + if($this->created_by === $current_user->id) { + return true; + } + + return false; + } + + /** + * Log personal account access denied + * @param string $action + * @return void + */ + public function logPersonalAccountAccessDenied(string $action) : void { + global $log, $current_user; + + $log->fatal("InboundEmail | Access denied. Non-admin user trying to access personal account. Action: '" . $action . "' | Current user id: '" . $current_user->id . "' | record: '" . $this->id . "'" ); + } + + /** + * @inheritDoc + */ + public function ACLAccess($view, $is_owner = 'not_set', $in_group = 'not_set') + { + global $current_user; + + $isNotAllowAction = $this->isNotAllowedAction($view); + if ($isNotAllowAction === true) { + return false; + } + + if (!$this->checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied("ACLAccess-$view"); + return false; + } + + $isPersonal = isTrue($this->is_personal); + $isAdmin = is_admin($current_user); + + if ($isPersonal === true && $this->checkPersonalAccountAccess()) { + return true; + } + + $isAdminOnlyAction = $this->isAdminOnlyAction($view); + if (!$isPersonal && !$isAdmin && $isAdminOnlyAction === true) { + return false; + } + + $hasActionAclsDefined = has_group_action_acls_defined('InboundEmail', 'view'); + $isSecurityGroupBasedAction = $this->isSecurityGroupBasedAction($view); + + if (!$isPersonal && !$isAdmin && !$hasActionAclsDefined && $isSecurityGroupBasedAction === true) { + return false; + } + + return parent::ACLAccess($view, $is_owner, $in_group); + } + + /** + * @return void + */ + protected function keepWriteOnlyFieldValues(): void + { + if (empty($this->fetched_row)) { + return; + } + + foreach ($this->field_defs as $field => $field_def) { + if (empty($field_def['display']) || $field_def['display'] !== 'writeonly') { + continue; + } + + if (empty($this->fetched_row[$field])) { + continue; + } + + if (!empty($this->$field)) { + continue; + } + + $this->$field = $this->fetched_row[$field]; + } + } + + /** + * @return void + */ + protected function clearAuthTypeDependantFields(): void + { + if (empty($this->auth_type)) { + return; + } + + if ($this->auth_type === 'basic') { + $this->external_oauth_connection_id = ''; + } + + if ($this->auth_type === 'oauth') { + $this->email_password = ''; + } + } + public function filterMailBoxFromRaw($mailboxArray, $rawArray) { $newArray = array_intersect($mailboxArray, $rawArray); @@ -406,160 +657,18 @@ class InboundEmail extends SugarBean return false; } + [$sortCriteria, $sortCRM, $sortOrder] = $this->getSortCriteria($order); + $filterCriteria = $this->getFilterCriteria($filter); - // handle sorting - // Default: to sort the date in descending order - $sortCriteria = SORTDATE; - $sortCRM = 'udate'; - $sortOrder = 1; - if ($order['sortOrder'] == 'ASC') { - $sortOrder = 0; - } - - if (stristr($order['orderBy'], 'date') !== false) { - $sortCriteria = SORTDATE; - $sortCRM = 'udate'; - } elseif (stristr($order['orderBy'], 'to') !== false) { - $sortCriteria = SORTTO; - $sortCRM = 'to'; - } elseif (stristr($order['orderBy'], 'from') !== false) { - $sortCriteria = SORTFROM; - $sortCRM = 'from'; - } elseif (stristr($order['orderBy'], 'cc') !== false) { - $sortCriteria = SORTCC; - } elseif (stristr($order['orderBy'], 'name') !== false) { - $sortCriteria = SORTSUBJECT; - $sortCRM = 'subject'; - } elseif (stristr($order['orderBy'], 'subject') !== false) { - $sortCriteria = SORTSUBJECT; - $sortCRM = 'subject'; - } - - // handle filtering - $filterCriteria = null; - - - if (!empty($filter)) { - foreach ($filter as $filterField => $filterFieldValue) { - if (empty($filterFieldValue)) { - continue; - } - - // Convert to a blank string as NULL will break the IMAP request - if ($filterCriteria == null) { - $filterCriteria = ''; - } - - $filterCriteria .= ' ' . $filterField . ' "' . $filterFieldValue . '" '; - } - } - - if (empty($filterCriteria) && $sortCriteria === SORTDATE) { - // Performance fix when no filters are enabled - $totalMsgs = $this->getImap()->getNumberOfMessages(); - $mailboxInfo['Nmsgs'] = $totalMsgs; - - if ($sortOrder === 0) { - // Ascending order - if ($offset === "end") { - $firstMsg = $totalMsgs - (int)$pageSize; - $lastMsg = $totalMsgs; - } elseif ($offset <= 0) { - $firstMsg = 1; - $lastMsg = $firstMsg + (int)$pageSize; - } else { - $firstMsg = (int)$offset; - $lastMsg = $firstMsg + (int)$pageSize; - } - } else { - // Descending order - if ($offset === "end") { - $firstMsg = 1; - $lastMsg = $firstMsg + (int)$pageSize; - } elseif ($offset <= 0) { - $firstMsg = $totalMsgs - (int)$pageSize; - $lastMsg = $totalMsgs; - } else { - $offset = ($totalMsgs - (int)$offset) - (int)$pageSize; - $firstMsg = $offset; - $lastMsg = $firstMsg + (int)$pageSize; - } - } - $firstMsg = $firstMsg < 1 ? 1 : $firstMsg; - $firstMsg = $firstMsg > $totalMsgs ? $totalMsgs : $firstMsg; - $lastMsg = $lastMsg < $firstMsg ? $firstMsg : $lastMsg; - $lastMsg = $lastMsg > $totalMsgs ? $totalMsgs : $lastMsg; - - $sequence = $firstMsg . ':' . $lastMsg; - $emailSortedHeaders = $this->getImap()->fetchOverview($sequence); - - $uids = array_map( - function ($x) { - return $x->uid; - }, - $emailSortedHeaders // TODO: this should be an array! - ); - } else { - // Filtered case and other sorting cases - // Returns an array of msgno's which are sorted and filtered - $emailSortedHeaders = $this->getImap()->sort( - $sortCriteria, - $sortOrder, - SE_UID, - $filterCriteria - ); - - $uids = array_slice($emailSortedHeaders, $offset, $pageSize); - - $lastSequenceNumber = $mailboxInfo['Nmsgs'] = count($emailSortedHeaders); - - // paginate - if ($offset === "end") { - $offset = $lastSequenceNumber - $pageSize; - } elseif ($offset <= 0) { - $offset = 0; - } - } - - - // TODO: uids could be invalid for implode! - $uids = implode(',', $uids); - - // Get result - $emailHeaders = $this->getImap()->fetchOverview( - $uids, - FT_UID + $emailHeaders = $this->getImap()->getMessageList( + $filterCriteria, + $sortCriteria, + $sortOrder, + $offset, + $pageSize, + $mailboxInfo, + $columns ); - $emailHeaders = json_decode(json_encode($emailHeaders), true); - if (isset($columns['has_attachment'])) { - // get attachment status - foreach ($emailHeaders as $i => $emailHeader) { - $structure = $this->getImap()->fetchStructure($emailHeader['uid'], FT_UID); - - $emailHeaders[$i]['has_attachment'] = $this->messageStructureHasAttachment($structure); - } - } - - - // TODO: parameter 1 could be a bool but it should be an array! - usort( - $emailHeaders, - function ($a, $b) use ($sortCRM) { // defaults to DESC order - if ($a[$sortCRM] === $b[$sortCRM]) { - return 0; - } elseif ($a[$sortCRM] < $b[$sortCRM]) { - return 1; - } - - return -1; - } - ); - - // Make it ASC order - if (!$sortOrder) { - array_reverse($emailHeaders); - }; - return array( "data" => $emailHeaders, @@ -573,13 +682,25 @@ class InboundEmail extends SugarBean */ public function messageStructureHasAttachment($imapStructure) { + if(empty($imapStructure)){ + return false; + } + if (($imapStructure->type !== 0) && ($imapStructure->type !== 1)) { return true; } $attachments = []; + if(empty($imapStructure->parts)){ + return false; + } + foreach ($imapStructure->parts as $i => $part) { + if(empty($part->dparameters)){ + continue; + } + if (is_string($part->dparameters[0]->value)) { $attachments[] = $part->dparameters[0]->value; } @@ -650,7 +771,7 @@ class InboundEmail extends SugarBean if ($this->isPop3Protocol()) { $uid = $this->getCorrectMessageNoForPop3($uid); } - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email connection is not a resource for getting Formatted Raw Source'); return null; @@ -702,7 +823,7 @@ class InboundEmail extends SugarBean $uid = $this->getCorrectMessageNoForPop3($uid); } - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email connection is not a resource'); return null; @@ -749,7 +870,7 @@ class InboundEmail extends SugarBean } $this->connectMailserver(); - if (is_resource($this->conn)) { + if ($this->getImap()->isValidStream($this->conn)) { $uids = $this->getImap()->search("ALL", SE_UID); } else { LoggerManager::getLogger()->warn('connection is not a valid resource to empty trush'); @@ -1658,7 +1779,7 @@ class InboundEmail extends SugarBean { $fetchedOverviews = array(); if ($this->isPop3Protocol()) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Connection is not a valid resource but it is a POP3 Protocol'); } else { $fetchedOverviews = $this->getImap()->fetchOverview($msgno); @@ -1668,7 +1789,7 @@ class InboundEmail extends SugarBean } } } else { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Connection is not a valid resource'); } else { $fetchedOverviews = $this->getImap()->fetchOverview($uid, FT_UID); @@ -1715,7 +1836,7 @@ class InboundEmail extends SugarBean } $this->setCacheTimestamp($mailbox); $GLOBALS['log']->info("[EMAIL] Performing IMAP search using criteria [{$criteria}] on mailbox [{$mailbox}] for user [{$current_user->user_name}]"); - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->warn('checkEmailOneMailbox: connection is not a valid resource'); $searchResults = null; } else { @@ -1760,7 +1881,7 @@ class InboundEmail extends SugarBean } if ($this->mailbox != $trashFolder) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->warn('connection is not a valid resource for checkEmailOneMailbox()'); $searchResults = null; } else { @@ -1868,7 +1989,7 @@ class InboundEmail extends SugarBean } if ($this->mailbox != $trashFolder) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->warn('mailbox != trash folder but connection is not a valid resource for checkEmailOneMailbox()'); $searchResults = null; } else { @@ -1914,7 +2035,7 @@ class InboundEmail extends SugarBean } // if } // if if (!$cacheDataExists) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email Connection is not a valid resource.'); } else { $searchResults = $this->getImap()->search($criteria, SE_UID); @@ -2033,7 +2154,7 @@ class InboundEmail extends SugarBean } $GLOBALS['log']->info("INBOUNDEMAIL: using [ {$criteria} ]"); - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->warn('connection is not a valid resource for getMailboxProcessCount()'); $searchResults = null; } else { @@ -2344,7 +2465,6 @@ class InboundEmail extends SugarBean } } - // validate for IMAP flag type if (!$type) { @@ -2353,7 +2473,7 @@ class InboundEmail extends SugarBean return false; } - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email connection is not a valid resource for marking Emails'); return false; @@ -2418,7 +2538,7 @@ class InboundEmail extends SugarBean unlink($file); } - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inboun Email Connenction is not a valid resource for deleting Folder'); } elseif ($this->getImap()->unsubscribe($this->getImap()->utf7Encode($connectString))) { if ($this->getImap()->deleteMailbox($connectString)) { @@ -2481,7 +2601,7 @@ class InboundEmail extends SugarBean $mbox .= $delimiter . str_replace($delimiter, "_", $name); $connectString = $this->getConnectString('', $mbox); - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inboun Email Connectrion is not a valid resource for saving new folder'); } elseif ($this->getImap()->createMailbox($this->getImap()->utf7Encode($connectString))) { $this->getImap()->subscribe($this->getImap()->utf7Encode($connectString)); @@ -3058,35 +3178,22 @@ class InboundEmail extends SugarBean public function getFoldersListForMailBox() { - $return = array(); - $foldersList = $this->getSessionInboundFoldersString( - $this->server_url, - $this->email_user, - $this->port, - $this->protocol - ); - if (empty($foldersList)) { - global $mod_strings; - $msg = $this->connectMailserver(true); - if (strpos($msg, "successfully")) { - $foldersList = $this->getSessionInboundFoldersString( - $this->server_url, - $this->email_user, - $this->port, - $this->protocol - ); - $return['status'] = true; - $return['foldersList'] = $foldersList; - $return['statusMessage'] = ""; - } else { - $return['status'] = false; - $return['statusMessage'] = $msg; - } // else - } else { + global $mod_strings; + $msg = $this->connectMailserver(true); + if (strpos($msg, "successfully")) { + $foldersList = $this->getSessionInboundFoldersString( + $this->server_url, + $this->email_user, + $this->port, + $this->protocol + ); $return['status'] = true; $return['foldersList'] = $foldersList; $return['statusMessage'] = ""; - } + } else { + $return['status'] = false; + $return['statusMessage'] = $msg; + } // else return $return; } // fn @@ -3204,15 +3311,23 @@ class InboundEmail extends SugarBean "Mailbox is empty" ); $login = $this->email_user; - $passw = $this->email_password; + $imapConnectionOptions = 0; + [$passw, $imapConnectionOptions] = $this->getOAuthCredentials($this->email_password, $imapConnectionOptions); + if (!empty($this->connection_string)) { + $returnService = []; + $serviceArr = []; + $this->overrideConnectionConfigs($returnService, $serviceArr, $tmpMailbox); + } + $foundGoodConnection = false; foreach ($serviceArr as $k => $serviceTest) { $errors = ''; $alerts = ''; + $GLOBALS['log']->debug($l . ': I-E testing string: ' . $serviceTest); // Open the connection and try the test string - $this->conn = $this->getImapConnection($serviceTest, $login, $passw); + $this->conn = $this->getImapConnection($serviceTest, $login, $passw, $imapConnectionOptions); if (($errors = $this->getImap()->getLastError()) || ($alerts = $this->getImap()->getAlerts())) { // login failure means don't bother trying the rest @@ -3244,7 +3359,7 @@ class InboundEmail extends SugarBean $foundGoodConnection = true; } - if (is_resource($this->getImap()->getConnection())) { + if ($this->getImap()->isValidStream($this->getImap()->getConnection())) { if (!$this->isPop3Protocol()) { $serviceTest = str_replace("INBOX", "", $serviceTest); $boxes = $this->getImap()->getMailboxes($serviceTest, "*"); @@ -3322,6 +3437,9 @@ class InboundEmail extends SugarBean $testConnectString = str_replace('foo', '', $good); $testConnectString = '{' . $this->server_url . ':' . $this->port . '/service=' . $this->protocol . $testConnectString . '}'; + if (!empty($this->connection_string)) { + $testConnectString = '{' . $this->connection_string . '}'; + } $this->setSessionConnectionString( $this->server_url, $this->email_user, @@ -3917,7 +4035,7 @@ class InboundEmail extends SugarBean */ public function getMessageTextFromSingleMimePart($msgNo, $section, $structure) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email Connection in not a valid resource for getting message text from a single mime part.'); return false; @@ -4005,13 +4123,13 @@ class InboundEmail extends SugarBean $emailBody = $this->imap->fetchBody($uid, '', FT_UID); if (!empty($type) && strtolower($type) === 'text/plain') { - $emailMessage = $this->mailParser->parse($emailBody)->getTextContent(); + $emailMessage = $this->mailParser->parse($emailBody, false)->getTextContent(); $emailMessage = $this->handleInlineImages($emailBody, $emailMessage); $emailMessage = $this->customGetMessageText($emailMessage); return SugarCleaner::cleanHtml($emailMessage, false); } - $emailMessage = $this->mailParser->parse($emailBody)->getHtmlContent(); + $emailMessage = $this->mailParser->parse($emailBody, false)->getHtmlContent(); $emailMessage = $this->handleInlineImages($emailBody, $emailMessage); $emailMessage = $this->customGetMessageText($emailMessage); @@ -4026,7 +4144,7 @@ class InboundEmail extends SugarBean */ protected function handleInlineImages($email, $emailHTML) { - foreach ($this->mailParser->parse($email)->getAllAttachmentParts() as $attachment) { + foreach ($this->mailParser->parse($email, false)->getAllAttachmentParts() as $attachment) { $disposition = $attachment->getContentDisposition(); if ($disposition === 'inline') { $fileName = $attachment->getFilename(); @@ -4582,7 +4700,7 @@ class InboundEmail extends SugarBean // download the attachment if we didn't do it yet if (!file_exists($uploadDir . $fileName)) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbounc Email Connection is not valid resource for saving attachment binaries.'); return false; @@ -4886,7 +5004,7 @@ class InboundEmail extends SugarBean global $sugar_config; global $current_user; - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbounc Email Connection is not valid resource for getting duplicate email id.'); return false; @@ -4951,7 +5069,7 @@ class InboundEmail extends SugarBean // UNCOMMENT THIS IF YOU HAVE THIS PROBLEM! See notes on Bug # 45477 // $this->markEmails($uid, "read"); - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->warn('Connection is not a valid resource for importOneEmail()'); $header = null; $fullHeader = null; @@ -5380,7 +5498,7 @@ class InboundEmail extends SugarBean } $emailBody = $this->imap->fetchBody($uid, '', FT_UID); - $contentType = $this->mailParser->parse($emailBody)->getHeaderValue('Content-Type'); + $contentType = $this->mailParser->parse($emailBody, false)->getHeaderValue('Content-Type'); if (!empty($contentType) && strtolower($contentType) === 'text/plain') { $email->description = $this->getMessageTextWithUid( @@ -5650,7 +5768,7 @@ class InboundEmail extends SugarBean $oldPrefix = $this->imagePrefix; $emailBody = $this->imap->fetchBody($uid, '', FT_UID); - $contentType = $this->mailParser->parse($emailBody)->getHeaderValue('Content-Type'); + $contentType = $this->mailParser->parse($emailBody, false)->getHeaderValue('Content-Type'); if (!empty($contentType) && strtolower($contentType) === 'text/plain') { $email->description = $this->getMessageTextWithUid( @@ -6165,7 +6283,7 @@ class InboundEmail extends SugarBean $this->stored_options = base64_encode(serialize($storedOptions)); $this->save(); } else { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email Connection is not valid resource for getting New Message Ids.'); return false; @@ -6190,6 +6308,11 @@ class InboundEmail extends SugarBean $mbox = empty($mbox) ? $this->mailbox : $mbox; $connectString = '{' . $this->server_url . ':' . $this->port . '/service=' . $this->protocol . $service . '}'; + + if (!empty($this->connection_string)){ + $connectString = '{' . $this->connection_string . '}'; + } + $connectString .= ($includeMbox) ? $mbox : ""; return $connectString; @@ -6200,7 +6323,7 @@ class InboundEmail extends SugarBean */ public function disconnectMailserver() { - if (is_resource($this->conn)) { + if ($this->getImap()->isValidStream($this->conn)) { $this->getImap()->close(); } } @@ -6286,7 +6409,7 @@ class InboundEmail extends SugarBean /* * Try to recycle the current connection to reduce response times */ - if (is_resource($this->getImap()->getConnection())) { + if ($this->getImap()->isValidStream($this->getImap()->getConnection())) { if ($force) { // force disconnect $this->getImap()->close(); @@ -6299,22 +6422,30 @@ class InboundEmail extends SugarBean } // final test - if (!is_resource($this->getImap()->getConnection()) && !$test) { + if (!$this->getImap()->isValidStream($this->getImap()->getConnection()) && !$test) { + + $imapUser = $this->email_user; + [$imapPassword, $imapOAuthConnectionOptions] = $this->getOAuthCredentials($this->email_password, CL_EXPUNGE); + $this->conn = $this->getImapConnection( $connectString, - $this->email_user, - $this->email_password, - CL_EXPUNGE + $imapUser, + $imapPassword, + $imapOAuthConnectionOptions ); } if ($test) { - if ($opts === false && !is_resource($this->getImap()->getConnection())) { + if ($opts === false && !$this->getImap()->isValidStream($this->getImap()->getConnection())) { + + $imapUser = $this->email_user; + [$imapPassword, $imapOAuthConnectionOptions] = $this->getOAuthCredentials($this->email_password, CL_EXPUNGE); + $this->conn = $this->getImapConnection( $connectString, - $this->email_user, - $this->email_password, - CL_EXPUNGE + $imapUser, + $imapPassword, + $imapOAuthConnectionOptions ); } $errors = ''; @@ -6346,7 +6477,7 @@ class InboundEmail extends SugarBean $this->getImap()->getErrors(); // collapse error stack - if (is_resource($this->getImap()->getConnection())) { + if ($this->getImap()->isValidStream($this->getImap()->getConnection())) { $this->getImap()->close(); } else { LoggerManager::getLogger()->warn('Connection is not a valid resource.'); @@ -6354,8 +6485,8 @@ class InboundEmail extends SugarBean return $msg; - } elseif (!is_resource($this->getImap()->getConnection())) { - $GLOBALS['log']->info('Couldn\'t connect to mail server id: ' . $this->id); + } elseif (!$this->getImap()->isValidStream($this->getImap()->getConnection())) { + $GLOBALS['log']->fatal('Couldn\'t connect to mail server id: ' . $this->id); return "false"; } @@ -6398,6 +6529,17 @@ class InboundEmail extends SugarBean $connection = null; $authenticators = ['', 'GSSAPI', 'NTLM']; + $isOAuth = $this->isOAuth(); + if ($isOAuth === true) { + $token = $this->getOAuthToken($this->external_oauth_connection_id ?? ''); + + if ($token === null) { + return false; + } + + $password = $token; + } + while (!$connection && ($authenticator = array_shift($authenticators)) !== null) { if ($authenticator) { $params = [ @@ -6408,6 +6550,7 @@ class InboundEmail extends SugarBean } $connection = $this->getImap()->open($mailbox, $username, $password, $options, 0, $params); + } return $connection; @@ -6450,7 +6593,7 @@ class InboundEmail extends SugarBean $user = $GLOBALS['current_user']; } - $query = "SELECT count(*) as c FROM inbound_email WHERE deleted=0 AND is_personal='1' AND group_id='{$user->id}' AND status='Active'"; + $query = "SELECT count(*) as c FROM inbound_email WHERE deleted=0 AND is_personal='1' AND (group_id='{$user->id}' OR created_by='{$user->id}') AND status='Active'"; $rs = $this->db->query($query); $row = $this->db->fetchByAssoc($rs); @@ -6573,6 +6716,82 @@ class InboundEmail extends SugarBean return $this->create_new_list_query($order_by, $where, array(), array(), $show_deleted); } + /** + * @return array + */ + public function getUserInboundAccounts(): array { + global $current_user, $db; + + $where = ''; + if (is_admin($current_user)) { + $currentUserId = $db->quote($current_user->id); + $tableName = $db->quote($this->table_name); + $where = "(($tableName.is_personal IS NULL) OR ($tableName.is_personal = 0 ) OR ($tableName.is_personal = 1 AND $tableName.created_by = '$currentUserId'))"; + } + + return $this->get_list('', $where)['list'] ?? []; + } + + /** + * @inheritDoc + */ + public function create_new_list_query( + $order_by, + $where, + $filter = array(), + $params = array(), + $show_deleted = 0, + $join_type = '', + $return_array = false, + $parentbean = null, + $singleSelect = false, + $ifListForExport = false + ) { + global $current_user, $db; + + $ret_array = parent::create_new_list_query( + $order_by, + $where, + $filter, + $params , + $show_deleted, + $join_type, + true, + $parentbean, + $singleSelect, + $ifListForExport + ); + + if(is_admin($current_user)) { + if ($return_array) { + return $ret_array; + } + + return $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by']; + } + + if (is_array($ret_array) && !empty($ret_array['where'])){ + $tableName = $db->quote($this->table_name); + $currentUserId = $db->quote($current_user->id); + + $showGroupRecords = "($tableName.is_personal IS NULL) OR ($tableName.is_personal = 0) OR "; + + $hasActionAclsDefined = has_group_action_acls_defined('InboundEmail', 'list'); + + if($hasActionAclsDefined === false) { + $showGroupRecords = ''; + } + + $ret_array['where'] = $ret_array['where'] . " AND ( $showGroupRecords ($tableName.is_personal = 1 AND $tableName.created_by = '$currentUserId') )"; + } + + if ($return_array) { + return $ret_array; + } + + return $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by']; + } + /** * Override's SugarBean's */ @@ -6585,11 +6804,15 @@ class InboundEmail extends SugarBean global $mod_strings; global $app_list_strings; $temp_array = $this->get_list_view_array(); - if (!isset($app_list_strings['dom_mailbox_type'][$this->mailbox_type])) { - LoggerManager::getLogger()->fatal('Language string not found for app_list_string[dom_mailbox_type][' . $this->mailbox_type . ']'); + + $temp_array['MAILBOX_TYPE_NAME'] = ''; + if (!empty($this->mailbox_type)) { + if (!isset($app_list_strings['dom_mailbox_type'][$this->mailbox_type])) { + LoggerManager::getLogger()->fatal('Language string not found for app_list_string[dom_mailbox_type][' . $this->mailbox_type . ']'); + } + $temp_array['MAILBOX_TYPE_NAME'] = $app_list_strings['dom_mailbox_type'][$this->mailbox_type] ?? null; } - $temp_array['MAILBOX_TYPE_NAME'] = isset($app_list_strings['dom_mailbox_type'][$this->mailbox_type]) ? - $app_list_strings['dom_mailbox_type'][$this->mailbox_type] : null; + //cma, fix bug 21670. $temp_array['GLOBAL_PERSONAL_STRING'] = ($this->is_personal ? $mod_strings['LBL_IS_PERSONAL'] : $mod_strings['LBL_IS_GROUP']); $temp_array['STATUS'] = ($this->status == 'Active') ? $mod_strings['LBL_STATUS_ACTIVE'] : $mod_strings['LBL_STATUS_INACTIVE']; @@ -6610,6 +6833,12 @@ class InboundEmail extends SugarBean */ public function fill_in_additional_detail_fields() { + $this->calculateType(); + $this->calculateDefault(); + $this->calculateSignature(); + + $this->expandStoreOptions(); + if (!empty($this->service)) { $exServ = explode('::', $this->service); $this->tls = $exServ[0]; @@ -6625,6 +6854,102 @@ class InboundEmail extends SugarBean } } + public function calculateType(): void { + + if (!empty($this->type)){ + return; + } + + if (isTrue($this->is_personal ?? false)) { + $this->type = 'personal'; + return; + } + + $mailboxType = $this->mailbox_type ?? ''; + if ($mailboxType === 'createcase') { + $this->type = 'group'; + return; + } + + if ($mailboxType === 'bounce') { + $this->type = 'bounce'; + return; + } + + if ($mailboxType === 'pick' ) { + $this->type = 'group'; + } + } + + public function calculateDefault(): void { + + global $current_user; + + if ($this->type === 'personal' && $this->getUsersDefaultOutboundServerId($current_user) === $this->id) { + $this->is_default = 1; + } + } + + public function calculateSignature(): void { + $inboundEmailId = $this->id ?? ''; + $createdBy = $this->created_by ?? ''; + + if ($inboundEmailId === '' || $createdBy === '') { + return; + } + + /** @var User $owner */ + $owner = BeanFactory::getBean('Users', $createdBy); + + $emailSignatures = $owner->getPreference('account_signatures', 'Emails'); + $emailSignatures = sugar_unserialize(base64_decode($emailSignatures)); + + $signatureId = $emailSignatures[$inboundEmailId] ?? ''; + + if ($signatureId !== '') { + $this->account_signature_id = $signatureId; + } + } + + /** + * Expand options + * @return void + */ + public function expandStoreOptions(): void { + + if (empty($this->stored_options)) { + return; + } + + // FROM NAME and Address + $storedOptions = unserialize(base64_decode($this->stored_options), ['allowed_classes' => false]); + + $this->from_name = ($storedOptions['from_name'] ?? ''); + $this->from_addr = ($storedOptions['from_addr'] ?? ''); + $this->reply_to_name = $storedOptions['reply_to_name'] ?? ''; + $this->reply_to_addr = $storedOptions['reply_to_addr'] ?? ''; + $this->only_since = isTrue($storedOptions['LBL_ONLY_SINCE_NO'] ?? false); + $this->filter_domain = $storedOptions['filter_domain'] ?? ''; + $this->trashFolder = $storedOptions['trashFolder'] ?? ''; + $this->sentFolder = $storedOptions['sentFolder'] ?? ''; + $this->mailbox = $storedOptions['mailbox'] ?? ''; + + $this->leave_messages_on_mail_server = isTrue($storedOptions['leaveMessagesOnMailServer'] ?? false); + $this->move_messages_to_trash_after_import = !isTrue($storedOptions['leaveMessagesOnMailServer'] ?? true); + + $this->distrib_method = $storedOptions['distrib_method'] ?? ''; + $this->distribution_user_id = $storedOptions['distribution_user_id'] ?? ''; + $this->distribution_options = $storedOptions['distribution_options'] ?? ''; + $this->create_case_template_id = $storedOptions['create_case_email_template'] ?? ''; + $this->email_num_autoreplies_24_hours = $storedOptions['email_num_autoreplies_24_hours'] ?? $this->defaultEmailNumAutoreplies24Hours; + + $this->is_auto_import = isTrue($storedOptions['isAutoImport'] ?? false); + $this->is_create_case = ($this->mailbox_type ?? '') === 'createcase'; + $this->allow_outbound_group_usage = isTrue($storedOptions['allow_outbound_group_usage'] ?? false); + + $this->outbound_email_id = $storedOptions['outbound_email'] ?? ''; + } + /** * Checks for $user's autoImport setting and returns the current value * @param object $user User in focus, defaults to $current_user @@ -6944,9 +7269,9 @@ class InboundEmail extends SugarBean } $uidsToMove = implode('::;::', $uids); if ($this->moveEmails($this->id, $this->mailbox, $this->id, $trashFolder, $uidsToMove)) { - $GLOBALS['log']->debug("INBOUNDEMAIL: MoveEmail to {$trashFolder} successful."); + $GLOBALS['log']->fatal("INBOUNDEMAIL: MoveEmail to {$trashFolder} successful."); } else { - $GLOBALS['log']->debug("INBOUNDEMAIL: MoveEmail to {$trashFolder} FAILED - trying hard delete for message: $uid"); + $GLOBALS['log']->fatal("INBOUNDEMAIL: MoveEmail to {$trashFolder} FAILED - trying hard delete for message: $uid"); $uidsToDelete = implode(',', $uids); $this->getImap()->delete($uidsToDelete, FT_UID); $return = true; @@ -6976,7 +7301,7 @@ class InboundEmail extends SugarBean */ public function deleteMessageOnMailServerForPop3($uid) { - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email connection is not a resource for deleting Message On Mail Server For Pop3'); return false; @@ -7038,6 +7363,30 @@ class InboundEmail extends SugarBean return $id; } + + public function isOnlyPersonalInbound() + { + $inboundAccount = $this->getUserPersonalAccountCount(); + if ($inboundAccount == 1) { + return true; + } + return false; + } + + /** + * @param $id + * @return bool + */ + public function isDefaultPersonalInbound($userId): bool + { + $user = BeanFactory::getBean('Users', $userId); + $isDefault = $user->getPreference($this->keyForUsersDefaultIEAccount, 'Emails'); + if ($isDefault == $userId){ + return true; + } + return false; + } + /** * Get the users default IE account id * @@ -7908,7 +8257,7 @@ eoq; // ids's count limit for batch processing $limit = 20; - if (!is_resource($this->conn)) { + if (!$this->getImap()->isValidStream($this->conn)) { LoggerManager::getLogger()->fatal('Inbound Email connection is not a resource for getting New Emails For Synced Mailbox'); return false; @@ -8087,4 +8436,255 @@ eoq; return $uid; } + + public function bean_implements($interface) + { + if ($interface === 'ACL') { + return true; + } + + return false; + } + + /** + * Check if its admin only action + * @param string $view + * @return bool + */ + protected function isAdminOnlyAction(string $view): bool + { + $adminOnlyAction = ['edit', 'delete', 'editview', 'save']; + return in_array(strtolower($view), $adminOnlyAction); + } + + /** + * Check if its a security based action + * @param string $view + * @return bool + */ + protected function isSecurityGroupBasedAction(string $view): bool + { + $securityBasedActions = ['detail', 'detailview', 'view']; + return in_array(strtolower($view), $securityBasedActions); + } + + /** + * Get not allowed action + * @param string $view + * @return bool + */ + protected function isNotAllowedAction(string $view): bool + { + $notAllowed = ['export', 'import', 'massupdate', 'duplicate']; + return in_array(strtolower($view), $notAllowed); + } + + + /** + * @param array $order + * @return array + */ + protected function getSortCriteria(array $order): array + { + // handle sorting + // Default: to sort the date in descending order + $sortCriteria = SORTARRIVAL; + $sortCRM = 'udate'; + $sortOrder = 1; + + return [$sortCriteria, $sortCRM, $sortOrder]; + } + + /** + * @param array $filter + * @return string|null + */ + protected function getFilterCriteria(array $filter): ?string + { +// handle filtering + $filterCriteria = null; + + + if (!empty($filter)) { + foreach ($filter as $filterField => $filterFieldValue) { + if (empty($filterFieldValue)) { + continue; + } + + // Convert to a blank string as NULL will break the IMAP request + if ($filterCriteria == null) { + $filterCriteria = ''; + } + + $filterCriteria .= ' ' . $filterField . ' "' . $filterFieldValue . '" '; + } + } + + return $filterCriteria; + } + + /** + * @param array $returnService + * @param array $serviceArr + * @param $tmpMailbox + * @return void + */ + protected function overrideConnectionConfigs(array &$returnService, array &$serviceArr, $tmpMailbox): void + { + $connectionString = (string) str_replace('//', '', $this->connection_string ?? ''); + + $parts = explode('/', $connectionString) ?? []; + array_shift($parts); + $servicesString = implode('/', $parts); + $serviceKey = implode('-', $parts); + + $returnService[$serviceKey] = 'foo' . $servicesString; + $serviceArr[$serviceKey] = '{' . $this->connection_string . '}' . $tmpMailbox; + } + + /** + * @param $emailHeaders + * @param $sortCRM + * @param $sortOrder + * @return mixed + */ + protected function sortMessageList($emailHeaders, $sortCRM, $sortOrder) + { + // TODO: parameter 1 could be a bool but it should be an array! + usort( + $emailHeaders, + function ($a, $b) use ($sortCRM) { // defaults to DESC order + if ($a[$sortCRM] === $b[$sortCRM]) { + return 0; + } elseif ($a[$sortCRM] < $b[$sortCRM]) { + return 1; + } + + return -1; + } + ); + + // Make it ASC order + if (!$sortOrder) { + array_reverse($emailHeaders); + }; + + return $emailHeaders; + } + + /** + * @param $password + * @param int $imapConnectionOptions + * @return array + */ + protected function getOAuthCredentials($password, int $imapConnectionOptions): array + { + if ($this->isOAuth()) { + /** @var ExternalOAuthConnection $oAuthConnection */ + $oAuthConnection = BeanFactory::getBean('ExternalOAuthConnection', $this->external_oauth_connection_id); + $password = $oAuthConnection->access_token; + $imapConnectionOptions = OP_XOAUTH2; + } + + return [$password, $imapConnectionOptions]; + } + + /** + * Get Imap handler type + * @return string + */ + protected function getImapHandlerType(): string + { + global $log; + $handlerType = 'native'; + + if (!empty($this->auth_type) && $this->auth_type === 'oauth') { + $handlerType = 'imap2'; + } + + $log->debug('Using imap handler type: ' . $handlerType); + + return $handlerType; + } + + /** + * Get refersh token error messages + * @param $reLogin + * @param ExternalOAuthConnection $oauthConnection + * @param string $oAuthConnectionId + * @return string + */ + protected function getOAuthRefreshTokenErrorMessage( + $reLogin, + ExternalOAuthConnection $oauthConnection, + string $oAuthConnectionId + ): string { + $message = translate('ERR_IMAP_OAUTH_CONNECTION_ERROR', 'InboundEmail'); + $linkAction = 'DetailView'; + + if ($reLogin === true) { + $linkAction = 'EditView'; + $message = translate('WARN_OAUTH_TOKEN_SESSION_EXPIRED', 'InboundEmail'); + } + + $oauthConnectionName = $oauthConnection->name; + + $hasAccess = $oauthConnection->ACLAccess('edit') ?? false; + if ($hasAccess === true) { + $message .= " $oauthConnectionName."; + } else { + $message .= $oauthConnectionName . '.'; + } + + return $message; + } + + /** + * Get OAuthToken. Refresh if needed + * @param string $oAuthConnectionId + * @return string|null + */ + protected function getOAuthToken(string $oAuthConnectionId): ?string + { + require_once __DIR__ . '/../ExternalOAuthConnection/services/OAuthAuthorizationService.php'; + $oAuth = new OAuthAuthorizationService(); + + /** @var ExternalOAuthConnection $oauthConnection */ + $oauthConnection = BeanFactory::getBean('ExternalOAuthConnection', $oAuthConnectionId); + $password = $oauthConnection->access_token; + + $hasExpiredFeedback = $oAuth->hasConnectionTokenExpired($oauthConnection); + $refreshToken = $hasExpiredFeedback['refreshToken'] ?? false; + if ($refreshToken === true) { + $refreshTokenFeedback = $oAuth->refreshConnectionToken($oauthConnection); + + if ($refreshTokenFeedback['success'] === false) { + $message = $this->getOAuthRefreshTokenErrorMessage( + $refreshTokenFeedback['reLogin'], + $oauthConnection, + $oAuthConnectionId + ); + displayAdminError($message); + return null; + } + + return $oauthConnection->access_token; + } + + return $password; + } + + /** + * Check if is using oauth authentication + * @return bool + */ + protected function isOAuth(): bool + { + $authType = $this->auth_type ?? ''; + $oAuthConnectionId = $this->external_oauth_connection_id ?? ''; + + return $authType === 'oauth' && $oAuthConnectionId !== ''; + } + + } // end class definition diff --git a/modules/InboundEmail/ListView.html b/modules/InboundEmail/ListView.html deleted file mode 100755 index 76c1d0465..000000000 --- a/modules/InboundEmail/ListView.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - diff --git a/modules/InboundEmail/Menu.php b/modules/InboundEmail/Menu.php index 3c5904f47..cc09625a9 100755 --- a/modules/InboundEmail/Menu.php +++ b/modules/InboundEmail/Menu.php @@ -44,9 +44,14 @@ if (!defined('sugarEntry') || !sugarEntry) { global $mod_strings; $module_menu = array(); -$module_menu[]= array("index.php?module=InboundEmail&action=EditView", $mod_strings['LNK_LIST_CREATE_NEW_GROUP'],"Setup_Email"); -$module_menu[]= array("index.php?module=InboundEmail&action=EditView&mailbox_type=bounce", $mod_strings['LNK_LIST_CREATE_NEW_BOUNCE'],"List"); +$module_menu[]= array("index.php?module=InboundEmail&action=EditView&is_personal=1&type=personal", $mod_strings['LNK_LIST_CREATE_NEW_PERSONAL'],"Create"); +if (is_admin($GLOBALS['current_user'])) { + $module_menu[]= array("index.php?module=InboundEmail&action=EditView&type=group", $mod_strings['LNK_LIST_CREATE_NEW_GROUP'],"Create"); + $module_menu[]= array("index.php?module=InboundEmail&action=EditView&mailbox_type=bounce&type=bounce", $mod_strings['LNK_LIST_CREATE_NEW_BOUNCE'],"Create"); +} $module_menu[]= array("index.php?module=InboundEmail&action=index", $mod_strings['LNK_LIST_MAILBOXES'],"List"); +$module_menu[]= array("index.php?module=OutboundEmailAccounts&action=index", $mod_strings['LNK_LIST_OUTBOUND_EMAILS'],"List"); +$module_menu[]= array("index.php?module=ExternalOAuthConnection&action=index", $mod_strings['LNK_EXTERNAL_OAUTH_CONNECTIONS'],"List"); if (is_admin($GLOBALS['current_user'])) { $module_menu[]= array("index.php?module=Schedulers&action=index", $mod_strings['LNK_LIST_SCHEDULER'],"Schedulers"); diff --git a/modules/InboundEmail/Popup.php b/modules/InboundEmail/Popup.php index 5d9c92194..b7338f9fb 100755 --- a/modules/InboundEmail/Popup.php +++ b/modules/InboundEmail/Popup.php @@ -104,7 +104,7 @@ if (isset($_REQUEST['ssl']) && ($_REQUEST['ssl'] == "true" || $_REQUEST['ssl'] = $msg .= $mod_strings['LBL_FIND_SSL_WARN']; $useSsl = true; } - + $ie = BeanFactory::newBean('InboundEmail'); if (!empty($_REQUEST['ie_id'])) { $ie->retrieve($_REQUEST['ie_id']); @@ -120,6 +120,10 @@ if (!empty($_REQUEST['email_password'])) { } $ie->mailbox = 'INBOX'; +if (!empty($_REQUEST['connection_string'])) { + $ie->connection_string = urldecode($_REQUEST['connection_string'] ?? ''); +} + if ($popupBoolean) { $msg = $ie->connectMailserver(true); } diff --git a/modules/InboundEmail/PostSave.php b/modules/InboundEmail/PostSave.php new file mode 100644 index 000000000..b68bbcf4a --- /dev/null +++ b/modules/InboundEmail/PostSave.php @@ -0,0 +1,61 @@ +created_by ?? ''; + +if (empty($ownerId)) { + $ownerId = $current_user->id; +} +$onlyInbound = $focus->isOnlyPersonalInbound() ?? false; + +$isDefault = $focus->isDefaultPersonalInbound($ownerId) ?? false; + +if ($onlyInbound && !$isDefault) { + $owner = BeanFactory::getBean('Users', $ownerId); + + if ($ownerId === $current_user->id || is_admin($current_user)) { + $focus->setUsersDefaultOutboundServerId($owner, $focus->id); + } +} diff --git a/modules/InboundEmail/Save.php b/modules/InboundEmail/Save.php index af03e4cd1..d09671b8b 100755 --- a/modules/InboundEmail/Save.php +++ b/modules/InboundEmail/Save.php @@ -43,7 +43,7 @@ if (!defined('sugarEntry') || !sugarEntry) { require_once('include/SugarFolders/SugarFolders.php'); -global $current_user, $mod_strings; +global $current_user, $mod_strings, $app_strings, $log; $focus = BeanFactory::newBean('InboundEmail'); if (!empty($_REQUEST['record'])) { @@ -53,12 +53,40 @@ if (!empty($_REQUEST['record'])) { unset($focus->id); unset($focus->groupfolder_id); } + +$isNewRecord = (empty($focus->id) || $focus->new_with_id); + +if (!empty($_REQUEST['created_by']) && is_admin($current_user)) { + $focus->created_by = $_REQUEST['created_by']; + $focus->set_created_by = false; +} + +if ($isNewRecord && !empty($_REQUEST['created_by']) && !is_admin($current_user)) { + $_REQUEST['created_by'] = ''; + $focus->created_by = ''; +} + +if (!$isNewRecord && !empty($_REQUEST['created_by']) && !is_admin($current_user)) { + unset($_REQUEST['created_by']); +} + +if ($isNewRecord && empty($focus->created_by)) { + $focus->created_by = $current_user->id; +} + +$ownerId = $current_user->id; +if (!empty($focus->created_by)) { + $ownerId = $focus->created_by; +} + +$owner = BeanFactory::getBean('Users', $ownerId); + foreach ($focus->column_fields as $field) { - if ($field == 'email_password' && empty($_REQUEST['email_password']) && !empty($_REQUEST['email_user'])) { + if ($field === 'email_password' && empty($_REQUEST['email_password']) && !empty($_REQUEST['email_user'])) { continue; } if (isset($_REQUEST[$field])) { - if ($field != "group_id") { + if ($field !== "group_id") { $focus->$field = trim($_REQUEST[$field]); } } @@ -76,23 +104,49 @@ foreach ($focus->required_fields as $field) { } } +$type = $_REQUEST['type'] ?? ''; + if (!empty($_REQUEST['email_password'])) { $focus->email_password = $_REQUEST['email_password']; } $focus->protocol = $_REQUEST['protocol']; -if (isset($_REQUEST['is_create_case']) && $_REQUEST['is_create_case'] == 'on') { +if (isTrue($_REQUEST['is_create_case'] ?? false)) { $focus->mailbox_type = 'createcase'; -} else { - if (empty($focus->mailbox_type) || $focus->mailbox_type == 'createcase') { - $focus->mailbox_type = 'pick'; +} elseif (empty($focus->mailbox_type) || $focus->mailbox_type === 'createcase') { + $focus->mailbox_type = 'pick'; +} + +if ($type === 'personal') { + $_REQUEST['is_personal'] = 1; +} + +if (!empty($_REQUEST['is_personal'])) { + $focus->is_personal = isTrue($_REQUEST['is_personal']) ? 1 : 0 ; +} + +if ((empty($focus->is_personal) || isFalse($focus->is_personal)) && !is_admin($current_user)){ + sugar_die($app_strings['LBL_NO_ACCESS']); +} + +if (isTrue($focus->is_personal)) { + $focus->mailbox_type = 'pick'; + + if (empty($focus->group_id) ) { + $focus->group_id = $owner->id; } } +if ($type === 'bounce') { + $focus->mailbox_type = 'bounce'; +} + + + ///////////////////////////////////////////////////////// //// SERVICE STRING CONCATENATION -$useSsl = (isset($_REQUEST['ssl']) && $_REQUEST['ssl'] == 1) ? true : false; +$useSsl = isTrue($_REQUEST['is_ssl'] ?? false); $optimum = $focus->getSessionConnectionString($focus->server_url, $focus->email_user, $focus->port, $focus->protocol); if (empty($optimum)) { $optimum = $focus->findOptimumSettings($useSsl, $focus->email_user, $focus->email_password, $focus->server_url, $focus->port, $focus->protocol, $focus->mailbox); @@ -111,37 +165,35 @@ if (is_array($optimum) && (count($optimum) > 0) && !empty($optimum['serial'])) { //// END SERVICE STRING CONCAT ///////////////////////////////////////////////////////// -if (isset($_REQUEST['mark_read']) && $_REQUEST['mark_read'] == 1) { +if (isTrue($_REQUEST['mark_read'] ?? false)) { $focus->delete_seen = 0; } else { $focus->delete_seen = 0; } // handle stored_options serialization -if (isset($_REQUEST['only_since']) && $_REQUEST['only_since'] == 1) { - $onlySince = true; -} else { - $onlySince = false; -} +$onlySince = isTrue($_REQUEST['only_since'] ?? false); + $stored_options = array(); -$stored_options['from_name'] = trim($_REQUEST['from_name']); -$stored_options['from_addr'] = trim($_REQUEST['from_addr']); +$stored_options['from_name'] = trim($_REQUEST['from_name'] ?? ''); +$stored_options['from_addr'] = trim($_REQUEST['from_addr'] ?? ''); isValidEmailAddress($stored_options['from_addr']); -$stored_options['reply_to_name'] = trim($_REQUEST['reply_to_name']); -$stored_options['reply_to_addr'] = trim($_REQUEST['reply_to_addr']); +$stored_options['reply_to_name'] = trim($_REQUEST['reply_to_name'] ?? ''); +$stored_options['reply_to_addr'] = trim($_REQUEST['reply_to_addr'] ?? ''); $stored_options['only_since'] = $onlySince; -$stored_options['filter_domain'] = $_REQUEST['filter_domain']; -$stored_options['email_num_autoreplies_24_hours'] = $_REQUEST['email_num_autoreplies_24_hours']; -$stored_options['allow_outbound_group_usage'] = isset($_REQUEST['allow_outbound_group_usage']) ? true : false; +$stored_options['filter_domain'] = $_REQUEST['filter_domain'] ?? ''; +$stored_options['email_num_autoreplies_24_hours'] = $_REQUEST['email_num_autoreplies_24_hours'] ?? ''; +$stored_options['allow_outbound_group_usage'] = isTrue($_REQUEST['allow_outbound_group_usage'] ?? false); +$stored_options['outbound_email'] = $_REQUEST['outbound_email_id'] ?? null; if (!$focus->isPop3Protocol()) { $stored_options['mailbox'] = (isset($_REQUEST['mailbox']) ? trim($_REQUEST['mailbox']) : ""); $stored_options['trashFolder'] = (isset($_REQUEST['trashFolder']) ? trim($_REQUEST['trashFolder']) : ""); $stored_options['sentFolder'] = (isset($_REQUEST['sentFolder']) ? trim($_REQUEST['sentFolder']) : ""); } // if -if ($focus->isMailBoxTypeCreateCase() || ($focus->mailbox_type == 'createcase' && empty($_REQUEST['id']))) { - $stored_options['distrib_method'] = (isset($_REQUEST['distrib_method'])) ? $_REQUEST['distrib_method'] : ""; - $stored_options['create_case_email_template'] = (isset($_REQUEST['create_case_template_id'])) ? $_REQUEST['create_case_template_id'] : ""; +if ($focus->isMailBoxTypeCreateCase() || ($focus->mailbox_type === 'createcase' && empty($_REQUEST['id']))) { + $stored_options['distrib_method'] = $_REQUEST['distrib_method'] ?? ''; + $stored_options['create_case_email_template'] = $_REQUEST['create_case_template_id'] ?? ''; switch ($stored_options['distrib_method']) { case 'singleUser': $stored_options['distribution_user_name'] = !empty($_REQUEST['distribution_user_name']) ? $_REQUEST['distribution_user_name'] : ''; @@ -161,47 +213,50 @@ $storedOptions['folderDelimiter'] = $delimiter; //////////////////////////////////////////////////////////////////////////////// //// CREATE MAILBOX QUEUE //////////////////////////////////////////////////////////////////////////////// -if (!isset($focus->id)) { - $groupId = ""; - if (isset($_REQUEST['group_id']) && empty($_REQUEST['group_id'])) { - $groupId = $_REQUEST['group_id']; + +if (!empty($type) && $type !== 'personal') { + if (!isset($focus->id)) { + $groupId = ""; + if (isset($_REQUEST['group_id']) && empty($_REQUEST['group_id'])) { + $groupId = $_REQUEST['group_id']; + } else { + $groupId = create_guid(); + } + $focus->group_id = $groupId; + } + + + if (isTrue($_REQUEST['is_auto_import'] ?? false)) { + if (empty($focus->groupfolder_id)) { + $groupFolderId = $focus->createAutoImportSugarFolder(); + $focus->groupfolder_id = $groupFolderId; + } + $stored_options['isAutoImport'] = true; } else { - $groupId = create_guid(); + $focus->groupfolder_id = ""; + //If the user is turning the auto-import feature off then remove all previous subscriptions. + if (!empty($focus->fetched_row['groupfolder_id'])) { + $log->debug("Clearing all subscriptions to folder id: {$focus->fetched_row['groupfolder_id']}"); + $f = new SugarFolder(); + $f->clearSubscriptionsForFolder($focus->fetched_row['groupfolder_id']); + //Now delete the old group folder. + $f->retrieve($focus->fetched_row['groupfolder_id']); + $f->delete(); + } + $stored_options['isAutoImport'] = false; } - $focus->group_id = $groupId; -} - - -if (isset($_REQUEST['is_auto_import']) && $_REQUEST['is_auto_import'] == 'on') { - if (empty($focus->groupfolder_id)) { - $groupFolderId = $focus->createAutoImportSugarFolder(); - $focus->groupfolder_id = $groupFolderId; - } - $stored_options['isAutoImport'] = true; -} else { - $focus->groupfolder_id = ""; - //If the user is turning the auto-import feature off then remove all previous subscriptions. - if (!empty($focus->fetched_row['groupfolder_id'])) { - $GLOBALS['log']->debug("Clearining all subscriptions to folder id: {$focus->fetched_row['groupfolder_id']}"); - $f = new SugarFolder(); - $f->clearSubscriptionsForFolder($focus->fetched_row['groupfolder_id']); - //Now delete the old group folder. - $f->retrieve($focus->fetched_row['groupfolder_id']); - $f->delete(); - } - $stored_options['isAutoImport'] = false; } if (!empty($focus->groupfolder_id)) { - if ($_REQUEST['leaveMessagesOnMailServer'] == "1") { - $stored_options['leaveMessagesOnMailServer'] = 1; - } else { + if (isTrue($_REQUEST['move_messages_to_trash_after_import'] ?? false)) { $stored_options['leaveMessagesOnMailServer'] = 0; + } else { + $stored_options['leaveMessagesOnMailServer'] = 1; } } $focus->stored_options = base64_encode(serialize($stored_options)); -$GLOBALS['log']->info('----->InboundEmail now saving self'); +$log->info('----->InboundEmail now saving self'); //////////////////////////////////////////////////////////////////////////////// @@ -215,7 +270,28 @@ $GLOBALS['sugar_config']['disable_team_access_check'] = true; $focus->save(); +$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails'))); +if (!is_array($showFolders)) { + $showFolders = []; +} +if (!in_array($focus->id, $showFolders)) { + $showFolders[] = $focus->id; + $showStore = base64_encode(serialize($showFolders)); + $current_user->setPreference('showFolders', $showStore, 0, 'Emails'); +} +$idValidator = new \SuiteCRM\Utility\SuiteValidator(); + +if ($type === 'personal' && isset($_REQUEST['account_signature_id']) && $idValidator->isValidId($_REQUEST['account_signature_id'])) { + $email_signatures = $owner->getPreference('account_signatures', 'Emails'); + $email_signatures = sugar_unserialize(base64_decode($email_signatures)); + if (empty($email_signatures)) { + $email_signatures = array(); + } + + $email_signatures[$focus->id] = $_REQUEST['account_signature_id']; + $owner->setPreference('account_signatures', base64_encode(serialize($email_signatures)), 0, 'Emails'); +} // Folders @@ -224,7 +300,7 @@ $foldersFoundRow = $focus->db->fetchRow($foldersFound); $sf = new SugarFolder(); if (empty($foldersFoundRow)) { // Create Folders - $focusUser = $current_user; + $focusUser = $owner; $params = array( // Inbox "inbound" => array( @@ -381,7 +457,7 @@ if ($_REQUEST['module'] == 'Campaigns') { $edit='&edit=true'; } - $GLOBALS['log']->debug("Saved record with id of ".$return_id); + $log->debug("Saved record with id of ".$return_id); $redirectUrl = "Location: index.php?module=$return_module&action=$return_action&record=$return_id$edit"; @@ -391,6 +467,8 @@ if ($_REQUEST['module'] == 'Campaigns') { header($redirectUrl); } +require('modules/InboundEmail/PostSave.php'); + /** * Certain updates to the IE account need to be reflected in the related SugarFolder since they are diff --git a/modules/InboundEmail/ShowInboundFoldersList.php b/modules/InboundEmail/ShowInboundFoldersList.php index d3db17ccc..b5aba87e8 100755 --- a/modules/InboundEmail/ShowInboundFoldersList.php +++ b/modules/InboundEmail/ShowInboundFoldersList.php @@ -111,8 +111,8 @@ if (!empty($searchField)) { } // else } // else - -$ie = BeanFactory::newBean('InboundEmail'); +/** @var InboundEmail $ie */ +$ie = BeanFactory::newBean('InboundEmail'); if (!empty($_REQUEST['ie_id'])) { $ie->retrieve($_REQUEST['ie_id']); } @@ -127,6 +127,18 @@ if (!empty($_REQUEST['email_password'])) { } //$ie->mailbox = $_REQUEST['mailbox']; +if (!empty($_REQUEST['external_oauth_connection_id'])) { + $ie->external_oauth_connection_id = $_REQUEST['external_oauth_connection_id']; +} + +if (!empty($_REQUEST['auth_type'])) { + $ie->auth_type = $_REQUEST['auth_type']; +} + +if (!empty($_REQUEST['connection_string'])) { + $ie->connection_string = $_REQUEST['connection_string']; +} + $ie->mailbox = 'INBOX'; if ($popupBoolean) { diff --git a/modules/InboundEmail/controller.php b/modules/InboundEmail/controller.php new file mode 100644 index 000000000..5730a2500 --- /dev/null +++ b/modules/InboundEmail/controller.php @@ -0,0 +1,86 @@ +view = 'edit'; + if (!empty($this->bean) && !empty($_REQUEST['is_personal'])) { + $this->bean->is_personal = isTrue($_REQUEST['is_personal'] ?? false); + } + + if (empty($_REQUEST['record']) && isTrue($_REQUEST['is_personal'] ?? false)) { + $this->hasAccess = true; + return; + } + + if (!empty($this->bean) && isTrue($this->bean->is_personal) && $this->bean->checkPersonalAccountAccess()) { + $this->hasAccess = true; + } + } + + public function action_SetDefault() + { + global $current_user; + $outbound_id = empty($_REQUEST['record']) ? "" : $_REQUEST['record']; + $ie = BeanFactory::newBean('InboundEmail'); + + $ownerId = $this->bean->created_by ?? ''; + if (empty($ownerId)) { + $ownerId = $current_user->id; + } + + $owner = BeanFactory::getBean('Users', $ownerId); + + if($ownerId === $current_user->id || is_admin($current_user)){ + $ie->setUsersDefaultOutboundServerId($owner, $outbound_id); + } + + $module = (!empty($this->return_module) ? $this->return_module : $this->module); + $action = (!empty($this->return_action) ? $this->return_action : 'DetailView'); + $id = (!empty($this->return_id) ? $this->return_id : $outbound_id); + + $url = "index.php?module=" . $module . "&action=" . $action . "&record=" . $id; + $this->set_redirect($url); + } +} diff --git a/modules/InboundEmail/field_arrays.php b/modules/InboundEmail/field_arrays.php index 1d32aadf8..c22f023ba 100755 --- a/modules/InboundEmail/field_arrays.php +++ b/modules/InboundEmail/field_arrays.php @@ -60,6 +60,7 @@ $fields_array['InboundEmail'] = array( 'delete_seen', 'mailbox_type', 'template_id', + 'is_personal', ), 'list_fields' => array( 'id', diff --git a/modules/InboundEmail/js/auth_type_fields_toggle.js b/modules/InboundEmail/js/auth_type_fields_toggle.js new file mode 100644 index 000000000..988121384 --- /dev/null +++ b/modules/InboundEmail/js/auth_type_fields_toggle.js @@ -0,0 +1,90 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function authTypetoggleFields(type) { + + var fieldsPerType = { + 'basic': { + 'email_password': true, + 'external_oauth_connection_name': false, + }, + 'oauth': { + 'email_password': false, + 'external_oauth_connection_name': true, + }, + }; + + var fieldType = { + 'email_password': 'password', + 'external_oauth_connection_name': 'relate', + }; + + var fieldDisplay = fieldsPerType[type] || fieldsPerType.personal; + + Object.keys(fieldDisplay).forEach(function (fieldKey) { + var display = fieldDisplay[fieldKey]; + var method = 'show'; + var required = true; + + if(!display) { + method = 'hide'; + inboundEmailFields.setValue(fieldKey, ''); + required = false; + } + + var isValue = inboundEmailFields.getData(fieldKey, 'is-value-set'); + if(isValue === true) { + required = false; + } + + inboundEmailFields.setRequired(fieldKey, fieldType[fieldKey], 'EditView', required ); + inboundEmailFields[method](fieldKey); + }); +} + + +$(document).ready(function () { + var type = inboundEmailFields.getValue('auth_type'); + authTypetoggleFields(type); + + inboundEmailFields.getField$('auth_type').change(function () { + type = inboundEmailFields.getValue('auth_type'); + authTypetoggleFields(type); + }); +}); diff --git a/modules/InboundEmail/js/case_create_toggle.js b/modules/InboundEmail/js/case_create_toggle.js new file mode 100644 index 000000000..931ae15b9 --- /dev/null +++ b/modules/InboundEmail/js/case_create_toggle.js @@ -0,0 +1,69 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function displayCaseFields(display) { + var method = 'show'; + if (!display) { + method = 'hide'; + } + + var fields = [ + 'create_case_email_template_name', + 'distrib_method', + 'inbound_email_case_macro', + ]; + + fields.forEach(function (value) { + $('[data-field="' + value + '"]')[method](); + if (method === 'hide') { + var $elInput = $('#' + value); + $elInput && $elInput.val(''); + $elInput && $elInput.change(); + } + }); +} + +$(document).ready(function () { + var isCreateCaseOn = inboundEmailFields.getValue('is_create_case'); + displayCaseFields(isCreateCaseOn); + $('#is_create_case').change(function () { + isCreateCaseOn = inboundEmailFields.getValue('is_create_case'); + displayCaseFields(isCreateCaseOn); + }); +}); diff --git a/modules/InboundEmail/js/distribution_toggle.js b/modules/InboundEmail/js/distribution_toggle.js new file mode 100644 index 000000000..efc85d9f1 --- /dev/null +++ b/modules/InboundEmail/js/distribution_toggle.js @@ -0,0 +1,114 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function hideElem(id) { + if (document.getElementById(id)) { + document.getElementById(id).style.display = "none"; + } +} + +function showElem(id) { + if (document.getElementById(id)) { + document.getElementById(id).style.display = ""; + } +} + +function assign_field_change(field) { + hideElem(field + '[1]'); + hideElem(field + '[2]'); + + if (document.getElementById(field + '[0]').value == 'role') { + showElem(field + '[2]'); + } else if (document.getElementById(field + '[0]').value == 'security_group') { + showElem(field + '[1]'); + showElem(field + '[2]'); + } +} + +function displayDistributionOptions(display) { + if (display) { + $('[data-field="distribution_options"]').show(); + $('#distribution_options\\[0\\]').show(); + $('#distribution_options\\[1\\]').show(); + $('#distribution_options\\[2\\]').show(); + assign_field_change('distribution_options'); + } else { + $('[data-field="distribution_options"]').hide(); + $('#distribution_options\\[0\\]').hide(); + $('#distribution_options\\[1\\]').hide(); + $('#distribution_options\\[2\\]').hide(); + } +} + +function displayDistributionUser(display) { + if (display) { + $('[data-field="distribution_user_name"]').show(); + } else { + $('[data-field="distribution_user_name"]').hide(); + $('#distribution_user_name').val(''); + $('#distribution_user_name').change(); + $('#distribution_user_id').val(''); + $('#distribution_user_id').change(); + } +} + +$(document).ready(function () { + displayDistributionOptions(false); + $('#distrib_method').change(function () { + var val = $('#distrib_method').val(); + switch (val) { + case 'roundRobin': + case 'leastBusy': + case 'random': + displayDistributionOptions(true); + displayDistributionUser(false); + break; + case 'singleUser': + displayDistributionOptions(false); + displayDistributionUser(true); + break; + case 'AOPDefault': + default: + displayDistributionOptions(false); + displayDistributionUser(false); + break; + } + }); + $('#distrib_method').change(); +}); diff --git a/modules/InboundEmail/js/fields.js b/modules/InboundEmail/js/fields.js new file mode 100644 index 000000000..e2c2b8231 --- /dev/null +++ b/modules/InboundEmail/js/fields.js @@ -0,0 +1,312 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +var inboundEmailFields = function () { + + var requiredLabelTemplate = '*'; + var validationMessageTemplate = '
Missing required field: $FIELD_NAME
'; + + var getValidationDefinition = function (formName, field) { + if (validate[formName]) { + for (i = 0; i < validate[formName].length; i++) { + if (validate[formName][i][nameIndex] == field) { + return validate[formName][i]; + } + } + } + return null; + }; + + var configureValidation = function (formName, field, required) { + + var definition = getValidationDefinition(formName, field); + + if(!definition){ + return; + } + var isRequired = true; + + if(!required){ + isRequired = false; + } + + definition[requiredIndex] = isRequired; + }; + + var addRequiredIndicator = function ($label) { + var $indicator = $label.find('.required'); + + if ($indicator.length < 1) { + $label.append($(requiredLabelTemplate)); + } + }; + + var removeRequiredIndicator = function ($label) { + var $indicator = $label.find('.required'); + + if ($indicator.length > 0) { + $indicator.remove(); + } + }; + + var getDefaultFieldGetter = function () { + return function (field$) { + return (field$ && field$.val()) || ''; + }; + }; + + var getDefaultFieldSetter = function () { + return function (field$, value) { + if (!field$) { + return; + } + + field$.val(value); + field$.change(); + }; + }; + + return { + fields: { + 'record': { + type: 'varchar', + getField$: function (field) { + return $('input[name=' + field + ']') || null; + } + }, + 'origin_id': { + type: 'varchar' + }, + 'server_url': { + type: 'varchar' + }, + 'protocol': { + type: 'varchar' + }, + 'port': { + type: 'varchar' + }, + 'email_user': { + type: 'varchar' + }, + 'email_password': { + type: 'varchar' + }, + 'sentFolder': { + type: 'varchar' + }, + 'trashFolder': { + type: 'varchar' + }, + 'mailbox': { + type: 'varchar' + }, + 'is_ssl': { + type: 'checkbox' + }, + 'type': { + type: 'varchar' + }, + 'is_create_case': { + type: 'checkbox' + }, + 'searchField': { + type: 'varchar' + }, + 'auth_type': { + type: 'varchar' + }, + 'external_oauth_connection_name': { + type: 'varchar', + getField$: function (field) { + return $('input[name=' + field + ']') || null; + } + }, + 'external_oauth_connection_id': { + type: 'varchar', + getField$: function (field) { + return $('input[name=' + field + ']') || null; + } + }, + }, + + getters: { + default: getDefaultFieldGetter(), + varchar: getDefaultFieldGetter(), + checkbox: function (field$) { + return (field$ && field$.prop('checked')) || false; + } + }, + + setters: { + default: getDefaultFieldSetter(), + varchar: getDefaultFieldSetter(), + checkbox: function (field$, value) { + if (!field$) { + return; + } + + field$.prop('checked', !!value); + } + }, + + setValue: function (field, value) { + var field$ = this.getField$(field); + if (!field$) { + return null; + } + + var setter = this.getValueSetter(field); + if (!setter) { + return null; + } + + return setter(field$, value); + }, + + getValue: function (field) { + var field$ = this.getField$(field); + if (!field$) { + return null; + } + + var getter = this.getValueGetter(field); + if (!getter) { + return null; + } + + return getter(field$); + }, + + getData: function (field, dataKey) { + var field$ = this.getField$(field); + if (!field$) { + return null; + } + + return field$.data(dataKey); + }, + + hide: function (field) { + var field$ = this.getFieldCell$(field); + + if (!field$ || !field$.length) { + return; + } + + field$.hide(); + }, + + show: function (field) { + var field$ = this.getFieldCell$(field); + + if (!field$ || !field$.length) { + return; + } + + field$.show(); + }, + + + getField$: function (field) { + var handler = (this.fields[field] && this.fields[field].getField$) || null; + + if (handler) { + return handler(field); + } + + return $('#' + field) || null; + }, + + getFieldCell$: function (field) { + return $('[data-field="' + field + '"]') || null; + }, + + getFieldType: function (field) { + return (this.fields[field] && this.fields[field].type) || 'varchar'; + }, + + getValueGetter: function (field) { + var handler = (this.fields[field] && this.fields[field].getter) || null; + + if (handler) { + return handler; + } + + var type = this.getFieldType(field); + return this.getters[type] || this.getters['default']; + }, + + getValueSetter: function (field) { + var handler = (this.fields[field] && this.fields[field].setter) || null; + + if (handler) { + return handler; + } + + var type = this.getFieldType(field); + return this.setters[type] || this.setters['default']; + }, + + setRequired: function (field, fieldType, formName, required) { + configureValidation(this.formName, this.name, required); + + this.setRequiredIndicator(field, required); + + if (required) { + addToValidate(formName, field, fieldType, true, SUGAR.language.get('InboundEmail',"LBL_" + field.toUpperCase())); + } else { + removeFromValidate(formName, field); + } + + }, + + setRequiredIndicator: function (field, required) { + var $label = this.getFieldCell$(field).find('.label'); + if (required) { + addRequiredIndicator($label); + } else { + removeRequiredIndicator($label); + } + }, + + }; +}(); + + diff --git a/modules/InboundEmail/js/fields_toggle.js b/modules/InboundEmail/js/fields_toggle.js new file mode 100644 index 000000000..eaf3cf1cd --- /dev/null +++ b/modules/InboundEmail/js/fields_toggle.js @@ -0,0 +1,90 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function toggleFields(type) { + + var fieldsPerType = { + 'personal': { + 'outbound_email_name': true, + 'allow_outbound_group_usage': false, + 'is_default': true, + 'account_signature_id': true, + 'move_messages_to_trash_after_import': false + }, + 'group': { + 'outbound_email_name': false, + 'allow_outbound_group_usage': true, + 'is_default': false, + 'account_signature_id': false, + 'move_messages_to_trash_after_import': true + }, + 'cases': { + 'outbound_email_name': false, + 'allow_outbound_group_usage': true, + 'is_default': false, + 'account_signature_id': false, + 'move_messages_to_trash_after_import': true + }, + 'bounce': { + 'outbound_email_name': false, + 'allow_outbound_group_usage': false, + 'is_default': false, + 'account_signature_id': false, + 'move_messages_to_trash_after_import': true + } + }; + + var fieldDisplay = fieldsPerType[type] || fieldsPerType.personal; + + Object.keys(fieldDisplay).forEach(function (fieldKey) { + var display = fieldDisplay[fieldKey]; + var method = 'show'; + if(!display) { + method = 'hide'; + } + + inboundEmailFields[method](fieldKey); + }); +} + + +$(document).ready(function () { + var type = inboundEmailFields.getValue('type'); + toggleFields(type); +}); diff --git a/modules/InboundEmail/js/mail_folders.js b/modules/InboundEmail/js/mail_folders.js new file mode 100644 index 000000000..3eed072ff --- /dev/null +++ b/modules/InboundEmail/js/mail_folders.js @@ -0,0 +1,205 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function showMissingMailboxCredentialsDialog() { + var $modal = $('
'); + var $modalText = $('

'); + $modalText.append(SUGAR.language.get('app_strings',"LBL_EMAIL_WARNING_MISSING_CREDS")); + $modal.append($modalText); + $modal.dialog(); +} + +function validateMailFolderRequiredFields() { + var password = Rot13.write(inboundEmailFields.getValue('email_password')); + var isPasswordSet = inboundEmailFields.getData('email_password', 'is-value-set'); + var authType = inboundEmailFields.getValue('auth_type'); + var externalOAuthConnectionName = inboundEmailFields.getValue('external_oauth_connection_name'); + + if (authType === 'basic' && !password && isPasswordSet === false) { + return false; + } + + if (authType === 'oauth' && !externalOAuthConnectionName) { + return false; + } + + return true; +} + +function getExtraMailboxListParams() { + var authType = inboundEmailFields.getValue('auth_type'); + var recordId = inboundEmailFields.getValue('record'); + var oauthConnectionId = inboundEmailFields.getValue('external_oauth_connection_id'); + var connectionString = inboundEmailFields.getValue('connection_string'); + + var extraParams = {}; + + if (oauthConnectionId) { + extraParams.external_oauth_connection_id = oauthConnectionId; + } + + if (authType) { + extraParams.auth_type = authType; + } + + if (recordId) { + extraParams.ie_id = recordId; + } + + if (connectionString) { + extraParams.connection_string = connectionString; + } + + return extraParams; +} + +function openTrashMailboxPopup() { + var serverUrl = inboundEmailFields.getValue('server_url'); + var protocol = inboundEmailFields.getValue('protocol'); + var port = inboundEmailFields.getValue('port'); + var emailUser = inboundEmailFields.getValue('email_user'); + var password = Rot13.write(inboundEmailFields.getValue('email_password')); + var trashFolder = inboundEmailFields.getValue('trashFolder'); + var useSSL = inboundEmailFields.getValue('is_ssl'); + var isPersonal = inboundEmailFields.getValue('type') === 'personal'; + + + if (!validateMailFolderRequiredFields()) { + showMissingMailboxCredentialsDialog(); + return; + } + + var extraParams = getExtraMailboxListParams(); + + getFoldersListForInboundAccount( + "InboundEmail", + "ShowInboundFoldersList", + "Popup", + 400, + 300, + serverUrl, + protocol, + port, + emailUser, + password, + trashFolder, + useSSL, + isPersonal, + "trash", + "EditView", + extraParams + ); +} + +function openMailboxPopup() { + var serverUrl = inboundEmailFields.getValue('server_url'); + var protocol = inboundEmailFields.getValue('protocol'); + var port = inboundEmailFields.getValue('port'); + var emailUser = inboundEmailFields.getValue('email_user'); + var password = Rot13.write(inboundEmailFields.getValue('email_password')); + var mailbox = inboundEmailFields.getValue('mailbox'); + var useSSL = inboundEmailFields.getValue('is_ssl'); + var isPersonal = inboundEmailFields.getValue('type') === 'personal'; + var searchField = inboundEmailFields.getValue('searchField'); + + if (!validateMailFolderRequiredFields()) { + showMissingMailboxCredentialsDialog(); + return; + } + + var extraParams = getExtraMailboxListParams(); + + getFoldersListForInboundAccount( + "InboundEmail", + "ShowInboundFoldersList", + "Popup", + 400, + 300, + serverUrl, + protocol, + port, + emailUser, + password, + mailbox, + useSSL, + isPersonal, + searchField, + "EditView", + extraParams + ); +} + +function openSentMailboxPopup() { + var serverUrl = inboundEmailFields.getValue('server_url'); + var protocol = inboundEmailFields.getValue('protocol'); + var port = inboundEmailFields.getValue('port'); + var emailUser = inboundEmailFields.getValue('email_user'); + var password = Rot13.write(inboundEmailFields.getValue('email_password')); + var useSSL = inboundEmailFields.getValue('is_ssl'); + var isPersonal = inboundEmailFields.getValue('type') === 'personal'; + var sentFolder = inboundEmailFields.getValue('sentFolder'); + + if (!validateMailFolderRequiredFields()) { + showMissingMailboxCredentialsDialog(); + return; + } + + var extraParams = getExtraMailboxListParams(); + + getFoldersListForInboundAccount( + "InboundEmail", + "ShowInboundFoldersList", + "Popup", + 400, + 300, + serverUrl, + protocol, + port, + emailUser, + password, + sentFolder, + useSSL, + isPersonal, + "sent", + "EditView", + extraParams + ); + +} + diff --git a/modules/InboundEmail/js/owner_toggle.js b/modules/InboundEmail/js/owner_toggle.js new file mode 100644 index 000000000..3d8e7b5bf --- /dev/null +++ b/modules/InboundEmail/js/owner_toggle.js @@ -0,0 +1,76 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2022 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2018 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +function toggleOwnerField(type, isAdmin) { + var status = 'non-admin'; + if (isAdmin) { + status = 'admin'; + } + + var fieldsPerStatus = { + 'admin': { + 'owner_name': true, + }, + 'non-admin': { + 'owner_name': false, + }, + }; + + var fieldDisplay = fieldsPerStatus[status] || fieldsPerStatus.disabled; + + Object.keys(fieldDisplay).forEach(function (fieldKey) { + var display = fieldDisplay[fieldKey]; + var method = 'show'; + if(!display) { + method = 'hide'; + } + + if(type !== 'personal') { + method = 'hide'; + } + + inboundEmailFields[method](fieldKey); + }); +} + +$(document).ready(function () { + var isAdmin = userService.isAdmin(); + var type = inboundEmailFields.getValue('type'); + toggleOwnerField(type, isAdmin); +}); + diff --git a/modules/InboundEmail/js/panel_toggle.js b/modules/InboundEmail/js/panel_toggle.js new file mode 100644 index 000000000..d70160d1c --- /dev/null +++ b/modules/InboundEmail/js/panel_toggle.js @@ -0,0 +1,82 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function togglePanels(type) { + + var panelsPerType = { + 'personal': { + 'LBL_CONNECTION_CONFIGURATION': true, + 'LBL_OUTBOUND_CONFIGURATION': true, + 'LBL_AUTO_REPLY_CONFIGURATION': false, + 'LBL_GROUP_CONFIGURATION': false, + 'LBL_CASE_CONFIGURATION': false + }, + 'group': { + 'LBL_CONNECTION_CONFIGURATION': true, + 'LBL_OUTBOUND_CONFIGURATION': true, + 'LBL_AUTO_REPLY_CONFIGURATION': true, + 'LBL_GROUP_CONFIGURATION': true, + 'LBL_CASE_CONFIGURATION': true + }, + 'bounce': { + 'LBL_CONNECTION_CONFIGURATION': true, + 'LBL_OUTBOUND_CONFIGURATION': false, + 'LBL_AUTO_REPLY_CONFIGURATION': false, + 'LBL_GROUP_CONFIGURATION': false, + 'LBL_CASE_CONFIGURATION': false + } + }; + + var panelDisplay = panelsPerType[type] || panelsPerType.personal; + + Object.keys(panelDisplay).forEach(function (panelKey) { + var display = panelDisplay[panelKey]; + var method = 'show'; + if(!display) { + method = 'hide'; + } + $('[data-id="' + panelKey + '"]').closest('.panel')[method](); + }); +} + + +$(document).ready(function () { + var type = inboundEmailFields.getValue('type'); + togglePanels(type); +}); diff --git a/modules/InboundEmail/js/ssl_port_set.js b/modules/InboundEmail/js/ssl_port_set.js new file mode 100644 index 000000000..87372c526 --- /dev/null +++ b/modules/InboundEmail/js/ssl_port_set.js @@ -0,0 +1,51 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +$(document).ready(function () { + $('#is_ssl').change(function () { + var isSSL = inboundEmailFields.getValue('is_ssl'); + + var port = 143; + if (isSSL) { + port = 993; + } + + inboundEmailFields.setValue('port', port); + }); +}); diff --git a/modules/InboundEmail/js/test_configuration.js b/modules/InboundEmail/js/test_configuration.js new file mode 100644 index 000000000..12cebe93a --- /dev/null +++ b/modules/InboundEmail/js/test_configuration.js @@ -0,0 +1,71 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ + +function testInboundConfiguration() { + var serverUrl = inboundEmailFields.getValue('server_url'); + var protocol = inboundEmailFields.getValue('protocol'); + var port = inboundEmailFields.getValue('port'); + var emailUser = inboundEmailFields.getValue('email_user'); + var password = Rot13.write(inboundEmailFields.getValue('email_password')); + var mailbox = inboundEmailFields.getValue('mailbox'); + var useSSL = inboundEmailFields.getValue('is_ssl'); + var isPersonal = inboundEmailFields.getValue('type') === 'personal'; + var originId = inboundEmailFields.getValue('origin_id'); + var record = inboundEmailFields.getValue('record'); + var connectionString = inboundEmailFields.getValue('connection_string'); + + ie_test_open_popup_with_submit( + "InboundEmail", + "Popup", + "Popup", + 400, + 300, + serverUrl, + protocol, + port, + emailUser, + password, + mailbox, + useSSL, + isPersonal, + "EditView", + originId ? originId : record, + connectionString || '' + ); +} diff --git a/modules/InboundEmail/language/en_us.lang.php b/modules/InboundEmail/language/en_us.lang.php index c6fbf9d48..cf3363eee 100755 --- a/modules/InboundEmail/language/en_us.lang.php +++ b/modules/InboundEmail/language/en_us.lang.php @@ -79,8 +79,10 @@ $mod_strings = array( 'LBL_LIST_NAME' => 'Name:', 'LBL_LIST_GLOBAL_PERSONAL' => 'Type', 'LBL_LIST_SERVER_URL' => 'Mail Server', + 'LBL_SERVER_ADDRESS' => 'Server Address', 'LBL_LIST_STATUS' => 'Status', 'LBL_LOGIN' => 'User Name', + 'LBL_USERNAME' => 'User Name', 'LBL_MAILBOX_DEFAULT' => 'INBOX', 'LBL_MAILBOX_SSL' => 'Use SSL', 'LBL_MAILBOX_TYPE' => 'Possible Actions', @@ -107,6 +109,7 @@ $mod_strings = array( 'LBL_ONLY_SINCE_NO' => 'No. Check against all emails on mail server.', 'LBL_ONLY_SINCE_YES' => 'Yes.', 'LBL_PASSWORD' => 'Password', + 'LBL_EMAIL_PASSWORD' => 'Password', 'LBL_POP3_SUCCESS' => 'Your POP3 test connection was successful.', 'LBL_POPUP_TITLE' => 'Test Settings', 'LBL_SELECT_SUBSCRIBED_FOLDERS' => 'Select Subscribed Folder(s)', @@ -119,6 +122,7 @@ $mod_strings = array( 'LBL_SAME_AS_ABOVE' => 'Using From Name/Address', 'LBL_SERVER_OPTIONS' => 'Advanced Setup', 'LBL_SERVER_TYPE' => 'Mail Server Protocol', + 'LBL_SERVER_PORT' => 'Mail Server Port', 'LBL_SERVER_URL' => 'Mail Server Address', 'LBL_SSL_DESC' => 'If your mail server supports secure socket connections, enabling this will force SSL connections when importing email.', 'LBL_ASSIGN_TO_TEAM_DESC' => 'The selected team has access to the mail account.', @@ -127,15 +131,19 @@ $mod_strings = array( 'LBL_SYSTEM_DEFAULT' => 'System Default', 'LBL_TEST_BUTTON_TITLE' => 'Test', 'LBL_TEST_SETTINGS' => 'Test Settings', + 'LBL_TEST_CONNECTION_SETTINGS' => 'Test Connection Settings', 'LBL_TEST_SUCCESSFUL' => 'Connection completed successfully.', 'LBL_TEST_WAIT_MESSAGE' => 'One moment please...', 'LBL_WARN_IMAP_TITLE' => 'Inbound Email Disabled', 'LBL_WARN_IMAP' => 'Warnings:', 'LBL_WARN_NO_IMAP' => 'Inbound Email cannot function without the IMAP c-client libraries enabled/compiled with the PHP module. Please contact your administrator to resolve this issue.', - 'LNK_LIST_CREATE_NEW_GROUP' => 'New Group Mail Account', - 'LNK_LIST_CREATE_NEW_BOUNCE' => 'New Bounce Handling Account', - 'LNK_LIST_MAILBOXES' => 'All Mail Accounts', + 'LNK_LIST_CREATE_NEW_PERSONAL' => 'New Personal Inbound Email Account', + 'LNK_LIST_CREATE_NEW_GROUP' => 'New Group Inbound Email Account', + 'LNK_LIST_CREATE_NEW_CASES_TYPE' => 'New Case Handling Email Account', + 'LNK_LIST_CREATE_NEW_BOUNCE' => 'New Bounce Handling Email Account', + 'LNK_LIST_MAILBOXES' => 'Inbound Email Accounts', + 'LNK_LIST_OUTBOUND_EMAILS' => 'Outbound Email Accounts', 'LNK_LIST_SCHEDULER' => 'Schedulers', 'LNK_SEED_QUEUES' => 'Seed Queues From Teams', 'LBL_GROUPFOLDER_ID' => 'Group Folder Id', @@ -164,4 +172,50 @@ $mod_strings = array( 'LBL_SERVICE' => 'Service', 'LBL_STORED_OPTIONS' => 'Stored Options', 'LBL_GROUP_ID' => 'Group ID', + + 'LBL_OUTBOUND_CONFIGURATION' => 'Outbound Configuration', + 'LBL_CONNECTION_CONFIGURATION' => 'Server Configuration', + 'LBL_AUTO_REPLY_CONFIGURATION' => 'Auto Reply Configuration', + 'LBL_CASE_CONFIGURATION' => 'Case Configuration', + 'LBL_GROUP_CONFIGURATION' => 'Group Configuration', + + 'LBL_SECURITYGROUPS_SUBPANEL_TITLE' => 'Security Groups', + + + 'LBL_OUTBOUND_EMAIL_ACCOUNT' => 'Outbound Email Account', + 'LBL_OUTBOUND_EMAIL_ACCOUNT_ID' => 'Outbound Email Account id', + 'LBL_OUTBOUND_EMAIL_ACCOUNT_NAME' => 'Outbound Email Account', + + 'LBL_AUTOREPLY_EMAIL_TEMPLATE' => 'Auto Reply Email Template', + 'LBL_AUTOREPLY_EMAIL_TEMPLATE_ID' => 'Auto Reply Email Template id', + 'LBL_AUTOREPLY_EMAIL_TEMPLATE_NAME' => 'Auto Reply Email Template', + + 'LBL_CASE_EMAIL_TEMPLATE' => 'Case Email Template', + 'LBL_CASE_EMAIL_TEMPLATE_ID' => 'Case Email Template id', + 'LBL_CASE_EMAIL_TEMPLATE_NAME' => 'Case Email Template', + + 'LBL_PROTOCOL' => 'Protocol', + 'LBL_CONNECTION_STRING' => 'Connection String', + 'LBL_DISTRIB_METHOD' => 'Distribution Method', + 'LBL_DISTRIB_OPTIONS' => 'Distribution Options', + + 'LBL_DISTRIBUTION_USER' => 'Distribution User', + 'LBL_DISTRIBUTION_USER_ID' => 'Distribution User id', + 'LBL_DISTRIBUTION_USER_NAME' => 'Distribution User', + + 'LBL_EXTERNAL_OAUTH_CONNECTION' => 'External OAuth Connection', + 'LBL_EXTERNAL_OAUTH_CONNECTION_ID' => 'External OAuth Connection id', + 'LBL_EXTERNAL_OAUTH_CONNECTION_NAME' => 'External OAuth Connection', + 'LNK_EXTERNAL_OAUTH_CONNECTIONS' => 'External OAuth Connections', + + 'LBL_TYPE' => 'Type', + 'LBL_AUTH_TYPE' => 'Auth Type', + 'LBL_IS_DEFAULT' => 'Default', + 'LBL_SIGNATURE' => 'Signature', + + 'LBL_OWNER_NAME' => 'Owner', + + 'LBL_SET_AS_DEFAULT_BUTTON' => 'Set as default', + + 'LBL_MOVE_MESSAGES_TO_TRASH_AFTER_IMPORT' => 'Move Messages To Trash After Import?', ); diff --git a/modules/InboundEmail/metadata/SearchFields.php b/modules/InboundEmail/metadata/SearchFields.php new file mode 100644 index 000000000..81e578fbe --- /dev/null +++ b/modules/InboundEmail/metadata/SearchFields.php @@ -0,0 +1,52 @@ + ['query_type' => 'default'], + 'type' => ['query_type' => 'default'], + 'status' => ['query_type' => 'default'], + 'server_url' => ['query_type' => 'default'], + 'is_personal' => ['query_type' => 'default'], + 'created_by' => ['query_type' => 'default'], +]; diff --git a/modules/InboundEmail/metadata/detailviewdefs.php b/modules/InboundEmail/metadata/detailviewdefs.php new file mode 100644 index 000000000..cff68508a --- /dev/null +++ b/modules/InboundEmail/metadata/detailviewdefs.php @@ -0,0 +1,209 @@ + [ + 'templateMeta' => [ + 'form' => [ + 'buttons' => [ + 'EDIT', + 'DELETE', + [ + 'customCode' => ' + {if $fields.type.value === "personal" && $fields.created_by.value === $current_user_id} + + {/if} + ' + ] + ], + ], + 'maxColumns' => '2', + 'widths' => [ + [ + 'label' => '10', + 'field' => '30', + ], + [ + 'label' => '10', + 'field' => '30', + ], + ], + 'useTabs' => false, + 'tabDefs' => [ + 'DEFAULT' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_CONNECTION_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_OUTBOUND_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_AUTO_REPLY_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_GROUP_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_CASE_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + ], + 'preForm' => ' + {sugar_getscript file="modules/InboundEmail/InboundEmail.js"} + + ' + ], + 'panels' => [ + 'default' => [ + [ + 'name', + 'is_default' + ], + [ + 'type', + 'status' + ], + [ + 'owner_name', + ], + ], + 'lbl_connection_configuration' => [ + [ + 'auth_type', + 'external_oauth_connection_name', + ], + [ + 'server_url', + 'email_user' + ], + [ + 'protocol', + '' + ], + [ + 'port', + 'mailbox' + ], + [ + 'is_ssl', + 'trashFolder', + ], + [ + 'connection_string', + 'sentFolder' + ], + + ], + 'lbl_outbound_configuration' => [ + [ + 'outbound_email_name', + 'account_signature_id' + ], + [ + 'allow_outbound_group_usage', + ], + [ + 'from_name', + 'reply_to_name', + ], + [ + 'from_addr', + 'reply_to_addr' + ], + ], + 'lbl_auto_reply_configuration' => [ + [ + 'filter_domain', + 'autoreply_email_template_name' + ], + [ + 'email_num_autoreplies_24_hours', + '' + ], + ], + 'lbl_group_configuration' => [ + [ + 'is_auto_import', + 'move_messages_to_trash_after_import', + ], + ], + 'lbl_case_configuration' => [ + [ + 'is_create_case', + ], + [ + 'create_case_email_template_name', + 'distrib_method', + ], + [ + '', + 'distribution_options' + ], + [ + '', + 'distribution_user_name' + ] + ] + ], + ], +]; diff --git a/modules/InboundEmail/metadata/editviewdefs.php b/modules/InboundEmail/metadata/editviewdefs.php new file mode 100644 index 000000000..12d7c126a --- /dev/null +++ b/modules/InboundEmail/metadata/editviewdefs.php @@ -0,0 +1,222 @@ + [ + 'templateMeta' => [ + 'form' => [ + 'hidden' => [ + '', + '', + ], + 'buttons' => [ + 'SAVE', + 'CANCEL', + [ + 'customCode' => ' + + ', + ] + ] + ], + 'maxColumns' => '2', + 'widths' => [ + [ + 'label' => '10', + 'field' => '30', + ], + [ + 'label' => '10', + 'field' => '30', + ], + ], + 'useTabs' => false, + 'tabDefs' => [ + 'DEFAULT' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_CONNECTION_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_OUTBOUND_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_AUTO_REPLY_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_GROUP_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_CASE_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + ], + 'javascript' => ' + {sugar_getscript file="modules/InboundEmail/InboundEmail.js"} + + ' + ], + 'panels' => [ + 'default' => [ + [ + 'type', + ], + [ + 'name', + 'status' + ], + [ + 'owner_name', + ], + ], + 'lbl_connection_configuration' => [ + [ + 'auth_type', + 'external_oauth_connection_name', + ], + [ + 'server_url', + 'email_user' + ], + [ + 'protocol', + 'email_password' + ], + [ + 'port', + [ + 'name' => 'mailbox', + 'vname' => 'LBL_MAILBOX', + 'customCode' => '

', + ] + ], + [ + 'is_ssl', + [ + 'name' => 'trashFolder', + 'customCode' => '
', + ] + ], + [ + 'connection_string', + [ + 'name' => 'sentFolder', + + 'customCode' => '
', + ] + ], + ], + 'lbl_outbound_configuration' => [ + [ + 'outbound_email_name', + 'account_signature_id' + ], + [ + 'allow_outbound_group_usage', + ], + [ + 'from_name', + 'reply_to_name', + ], + [ + 'from_addr', + 'reply_to_addr' + ], + ], + 'lbl_auto_reply_configuration' => [ + [ + 'filter_domain', + 'autoreply_email_template_name' + ], + [ + 'email_num_autoreplies_24_hours', + '' + ], + ], + 'lbl_group_configuration' => [ + [ + 'is_auto_import', + 'move_messages_to_trash_after_import' + ], + ], + 'lbl_case_configuration' => [ + [ + 'is_create_case', + ], + [ + 'create_case_email_template_name', + 'distrib_method', + ], + [ + '', + 'distribution_options' + ], + [ + '', + 'distribution_user_name' + ] + ], + ], + ], +]; diff --git a/modules/InboundEmail/metadata/listviewdefs.php b/modules/InboundEmail/metadata/listviewdefs.php new file mode 100644 index 000000000..03b051680 --- /dev/null +++ b/modules/InboundEmail/metadata/listviewdefs.php @@ -0,0 +1,79 @@ + [ + 'width' => '32%', + 'label' => 'LBL_NAME', + 'default' => true, + 'link' => true, + ], + 'EMAIL_USER' => [ + 'label' => 'LBL_USERNAME', + 'width' => '10%', + 'default' => true, + ], + 'TYPE' => [ + 'label' => 'LBL_TYPE', + 'width' => '10%', + 'default' => true, + ], + 'IS_PERSONAL' => [ + 'label' => 'LBL_IS_PERSONAL', + 'width' => '10%', + 'default' => true, + ], + 'IS_DEFAULT' => [ + 'label' => 'LBL_IS_DEFAULT', + 'width' => '10%', + 'default' => true, + ], + 'STATUS' => [ + 'label' => 'LBL_STATUS', + 'width' => '10%', + 'default' => true, + ], + 'SERVER_URL' => [ + 'label' => 'LBL_SERVER_ADDRESS', + 'width' => '10%', + 'default' => true, + ], +]; diff --git a/modules/InboundEmail/metadata/metafiles.php b/modules/InboundEmail/metadata/metafiles.php new file mode 100644 index 000000000..8fe6c1f31 --- /dev/null +++ b/modules/InboundEmail/metadata/metafiles.php @@ -0,0 +1,49 @@ + 'modules/' . $module_name . '/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/' . $module_name . '/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/' . $module_name . '/metadata/listviewdefs.php', + 'searchdefs' => 'modules/' . $module_name . '/metadata/searchdefs.php', + 'popupdefs' => 'modules/' . $module_name . '/metadata/popupdefs.php', + 'searchfields' => 'modules/' . $module_name . '/metadata/SearchFields.php', +); diff --git a/modules/InboundEmail/metadata/searchdefs.php b/modules/InboundEmail/metadata/searchdefs.php new file mode 100644 index 000000000..daba3d33d --- /dev/null +++ b/modules/InboundEmail/metadata/searchdefs.php @@ -0,0 +1,88 @@ + [ + 'basic_search' => [ + 'name' => [ + 'name' => 'name', + 'default' => true, + ], + 'type' => [ + 'default' => true, + 'name' => 'type', + ], + 'status' => [ + 'name' => 'status', + 'default' => true, + ], + 'server_url' => [ + 'name' => 'server_url', + 'default' => true, + ], + ], + 'advanced_search' => [ + 'name' => [ + 'name' => 'name', + 'default' => true, + ], + 'type' => [ + 'default' => true, + 'name' => 'type', + ], + 'status' => [ + 'name' => 'status', + 'default' => true, + ], + 'server_url' => [ + 'name' => 'server_url', + 'default' => true, + ], + ], + ], + 'templateMeta' => [ + 'maxColumns' => '3', + 'maxColumnsBasic' => '4', + 'widths' => [ + 'label' => '10', + 'field' => '30', + ], + ], +]; diff --git a/modules/InboundEmail/metadata/subpaneldefs.php b/modules/InboundEmail/metadata/subpaneldefs.php new file mode 100644 index 000000000..936f443c8 --- /dev/null +++ b/modules/InboundEmail/metadata/subpaneldefs.php @@ -0,0 +1,67 @@ + [ + 'securitygroups' => [ + 'top_buttons' => [ + [ + 'widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'SecurityGroups', + 'mode' => 'MultiSelect' + ], + ], + 'order' => 900, + 'sort_by' => 'name', + 'sort_order' => 'asc', + 'module' => 'SecurityGroups', + 'refresh_page' => 1, + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'SecurityGroups', + 'add_subpanel_data' => 'securitygroup_id', + 'title_key' => 'LBL_SECURITYGROUPS_SUBPANEL_TITLE', + ], + ], +]; diff --git a/modules/InboundEmail/utils.php b/modules/InboundEmail/utils.php new file mode 100644 index 000000000..7889195cb --- /dev/null +++ b/modules/InboundEmail/utils.php @@ -0,0 +1,160 @@ +distribution_options) ?? ''; +} + +/** + * @param InboundEmail|null $focus + * @param string $field + * @param string $value + * @param string $view + * @return string + */ +function getUserSignature( + ?InboundEmail $focus, + string $field = 'account_signature_id', + string $value = '', + string $view = 'DetailView' +): string { + + global $current_user, $app_strings; + + $createdBy = $focus->created_by ?? ''; + /** @var User $owner */ + $owner = $current_user; + + if ($createdBy !== '') { + $owner = BeanFactory::getBean('Users', $createdBy); + } + + $defaultSignatureId = $owner->getPreference('signature_default') ?? ''; + + $isEditView = $view === 'EditView' || $view === 'MassUpdate' || $view === 'QuickCreate' || $view === 'ConvertLead'; + + $inboundEmailId = $focus->id ?? ''; + + if ($isEditView === true) { + return getInboundEmailSignatures($owner, $defaultSignatureId, 'account_signature_id'); + } + + if ($inboundEmailId === '') { + return ''; + } + + $emailSignatures = $owner->getPreference('account_signatures', 'Emails'); + $emailSignatures = sugar_unserialize(base64_decode($emailSignatures)); + + $signatureId = $emailSignatures[$inboundEmailId] ?? ''; + + if ($signatureId !== '' && $isEditView === true) { + return getInboundEmailSignatures($owner, $defaultSignatureId, 'account_signature_id', $signatureId); + } + + $signatures = $owner->getSignaturesArray(false); + + $signature = $signatures[$signatureId] ?? null; + + if ($signature === null) { + return $app_strings['LBL_DEFAULT_EMAIL_SIGNATURES']; + } + + if (empty($signature)) { + return $app_strings['LBL_DEFAULT_EMAIL_SIGNATURES']; + } + + return $signature['name'] ?? ''; +} + +/** + * @param User $owner + * @param string $defaultSig + * @param string $elementId + * @param string $selected + * @return string + */ +function getInboundEmailSignatures( + User $owner, + string $defaultSig = '', + string $elementId = 'account_signature_id', + string $selected = '' +): string { + $sig = $owner->getSignaturesArray(); + $sigs = array(); + foreach ($sig as $key => $arr) { + $sigs[$key] = !empty($arr['name']) ? $arr['name'] : ''; + } + + $out = "'; + + return $out; +} diff --git a/modules/InboundEmail/vardefs.php b/modules/InboundEmail/vardefs.php index 3d716245d..3a5832b5e 100755 --- a/modules/InboundEmail/vardefs.php +++ b/modules/InboundEmail/vardefs.php @@ -41,42 +41,70 @@ if (!defined('sugarEntry') || !sugarEntry) { * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ -$dictionary['InboundEmail'] = array('table' => 'inbound_email', 'comment' => 'Inbound email parameters', - 'fields' => array( - 'id' => array( +$dictionary['InboundEmail'] = [ + 'table' => 'inbound_email', + 'inline_edit' => false, + 'massupdate' => false, + 'duplicate_merge' => false, + 'comment' => 'Inbound email parameters', + 'audited'=> false, + 'fields' => [ + 'id' => [ 'name' => 'id', 'vname' => 'LBL_ID', 'type' => 'id', 'dbType' => 'varchar', 'len' => 36, 'required' => true, - 'reportable'=>false, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Unique identifier' - ), - 'deleted' => array( + ], + 'deleted' => [ 'name' => 'deleted', 'vname' => 'LBL_DELETED', 'type' => 'bool', 'required' => false, 'default' => '0', - 'reportable'=>false, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Record deltion indicator' - ), - 'date_entered' => array( + ], + 'date_entered' => [ 'name' => 'date_entered', 'vname' => 'LBL_DATE_ENTERED', 'type' => 'datetime', 'required' => true, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Date record created' - ), - 'date_modified' => array( + ], + 'date_modified' => [ 'name' => 'date_modified', 'vname' => 'LBL_DATE_MODIFIED', 'type' => 'datetime', 'required' => true, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Date record last modified' - ), - 'modified_user_id' => array( + ], + 'modified_user_id' => [ 'name' => 'modified_user_id', 'rname' => 'user_name', 'id_name' => 'modified_user_id', @@ -85,10 +113,15 @@ $dictionary['InboundEmail'] = array('table' => 'inbound_email', 'comment' => 'In 'table' => 'users', 'isnull' => false, 'dbType' => 'id', - 'reportable'=>true, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'User who last modified record' - ), - 'modified_user_id_link' => array( + ], + 'modified_user_id_link' => [ 'name' => 'modified_user_id_link', 'type' => 'link', 'relationship' => 'inbound_email_modified_user_id', @@ -97,8 +130,14 @@ $dictionary['InboundEmail'] = array('table' => 'inbound_email', 'comment' => 'In 'module' => 'Users', 'bean_name' => 'User', 'source' => 'non-db', - ), - 'created_by' => array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'created_by' => [ 'name' => 'created_by', 'rname' => 'user_name', 'id_name' => 'modified_user_id', @@ -107,9 +146,36 @@ $dictionary['InboundEmail'] = array('table' => 'inbound_email', 'comment' => 'In 'table' => 'users', 'isnull' => false, 'dbType' => 'id', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'User who created record' - ), - 'created_by_link' => array( + ], + 'owner_name' => [ + 'name' => 'owner_name', + 'rname' => 'name', + 'id_name' => 'created_by', + 'vname' => 'LBL_OWNER_NAME', + 'join_name' => 'owner_user', + 'type' => 'relate', + 'link' => 'created_by_link', + 'table' => 'users', + 'isnull' => 'true', + 'module' => 'Users', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'created_by_link' => [ 'name' => 'created_by_link', 'type' => 'link', 'relationship' => 'inbound_email_created_by', @@ -118,171 +184,830 @@ $dictionary['InboundEmail'] = array('table' => 'inbound_email', 'comment' => 'In 'module' => 'Users', 'bean_name' => 'User', 'source' => 'non-db', - ), - 'name' => array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'name' => [ 'name' => 'name', 'vname' => 'LBL_NAME', 'type' => 'varchar', 'len' => '255', 'required' => false, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Name given to the inbound email mailbox' - ), - 'status' => array( + ], + 'status' => [ 'name' => 'status', 'vname' => 'LBL_STATUS', - 'type' => 'varchar', + 'type' => 'enum', + 'options' => 'dom_inbound_email_account_status', 'len' => 100, 'default' => 'Active', 'required' => true, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Status of the inbound email mailbox (ex: Active or Inactive)' - ), - 'server_url' => array( + ], + 'server_url' => [ 'name' => 'server_url', 'vname' => 'LBL_SERVER_URL', 'type' => 'varchar', 'len' => '100', 'required' => true, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Mail server URL', - 'importable' => 'required', - ), - 'email_user' => array( + ], + 'connection_string' => [ + 'name' => 'connection_string', + 'vname' => 'LBL_CONNECTION_STRING', + 'type' => 'varchar', + 'placeholder' => 'LBL_OPTIONAL_CONNECTION_STRING', + 'required' => false, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'comment' => 'Mail server Connection string', + ], + 'email_user' => [ 'name' => 'email_user', 'vname' => 'LBL_LOGIN', 'type' => 'varchar', 'len' => '100', 'required' => true, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'User name allowed access to mail server' - ), - 'email_password' => array( + ], + 'email_password' => [ 'name' => 'email_password', 'vname' => 'LBL_PASSWORD', - 'type' => 'varchar', + 'type' => 'password', + 'dbType' => 'varchar', + 'display' => 'writeonly', 'len' => '100', - 'required' => true, + 'required' => false, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'sensitive' => true, + 'api-visible' => false, 'comment' => 'Password of user identified by email_user' - ), - 'port' => array( + ], + 'port' => [ 'name' => 'port', - 'vname' => 'LBL_SERVER_TYPE', + 'vname' => 'LBL_SERVER_PORT', 'type' => 'int', 'len' => '5', + 'default' => '143', 'required' => true, 'reportable' => false, - 'validation' => array('type' => 'range', 'min' => '110', 'max' => '65535'), + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'validation' => ['type' => 'range', 'min' => '110', 'max' => '65535'], 'comment' => 'Port used to access mail server' - ), - 'service' => array( + ], + 'service' => [ 'name' => 'service', 'vname' => 'LBL_SERVICE', 'type' => 'varchar', 'len' => '50', 'required' => true, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => '', - 'importable' => 'required', - ), - 'mailbox' => array( + ], + 'mailbox' => [ 'name' => 'mailbox', 'vname' => 'LBL_MAILBOX', 'type' => 'text', 'required' => true, 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => '' - ), - 'delete_seen' => array( + ], + 'sentFolder' => [ + 'name' => 'sentFolder', + 'vname' => 'LBL_SENT_FOLDER', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'trashFolder' => [ + 'name' => 'trashFolder', + 'vname' => 'LBL_TRASH_FOLDER', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'delete_seen' => [ 'name' => 'delete_seen', 'vname' => 'LBL_DELETE_SEEN', 'type' => 'bool', 'default' => '0', 'reportable' => false, - 'massupdate' => '', + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Delete email from server once read (seen)' - ), - 'mailbox_type' => array( + ], + 'move_messages_to_trash_after_import' => [ + 'name' => 'move_messages_to_trash_after_import', + 'vname' => 'LBL_MOVE_MESSAGES_TO_TRASH_AFTER_IMPORT', + 'type' => 'bool', + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mailbox_type' => [ 'name' => 'mailbox_type', 'vname' => 'LBL_MAILBOX_TYPE', 'type' => 'varchar', 'len' => '10', 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => '' - ), - 'template_id' => array( + ], + 'template_id' => [ 'name' => 'template_id', 'vname' => 'LBL_AUTOREPLY', 'type' => 'id', 'len' => '36', 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Template used for auto-reply' - ), - 'stored_options' => array( + ], + 'stored_options' => [ 'name' => 'stored_options', 'vname' => 'LBL_STORED_OPTIONS', 'type' => 'text', 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => '' - ), - 'group_id' => array( + ], + 'group_id' => [ 'name' => 'group_id', 'vname' => 'LBL_GROUP_ID', 'type' => 'id', 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Group ID (unused)' - ), - 'is_personal' => array( + ], + 'is_personal' => [ 'name' => 'is_personal', 'vname' => 'LBL_IS_PERSONAL', 'type' => 'bool', 'required' => true, 'default' => '0', - 'reportable'=>false, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'massupdate' => '', 'comment' => 'Personal account flag' - ), - 'groupfolder_id' => array( + ], + 'groupfolder_id' => [ 'name' => 'groupfolder_id', 'vname' => 'LBL_GROUPFOLDER_ID', 'type' => 'id', 'required' => false, - 'reportable'=>false, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Unique identifier' - ), - ), /* end fields() */ - 'indices' => array( - array( - 'name' =>'inbound_emailpk', - 'type' =>'primary', - 'fields' => array( + ], + 'type' => [ + 'name' => 'type', + 'vname' => 'LBL_TYPE', + 'type' => 'enum', + 'options' => 'dom_inbound_email_account_types', + 'display' => 'readonly', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'auth_type' => [ + 'name' => 'auth_type', + 'vname' => 'LBL_AUTH_TYPE', + 'type' => 'enum', + 'options' => 'dom_inbound_email_auth_types', + 'default' => 'basic', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'protocol' => [ + 'name' => 'protocol', + 'vname' => 'LBL_PROTOCOL', + 'type' => 'enum', + 'options' => 'dom_email_server_type', + 'function' => 'getInboundEmailProtocols', + 'default' => 'imap', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'is_ssl' => [ + 'name' => 'is_ssl', + 'vname' => 'LBL_SSL', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'is_default' => [ + 'name' => 'is_default', + 'vname' => 'LBL_IS_DEFAULT', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'from_name' => [ + 'name' => 'from_name', + 'vname' => 'LBL_FROM_NAME', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'from_addr' => [ + 'name' => 'from_addr', + 'vname' => 'LBL_FROM_ADDR', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'reply_to_name' => [ + 'name' => 'reply_to_name', + 'vname' => 'LBL_REPLY_TO_NAME', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'reply_to_addr' => [ + 'name' => 'reply_to_addr', + 'vname' => 'LBL_REPLY_TO_ADDR', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'account_signature_id' => [ + 'name' => 'account_signature_id', + 'vname' => 'LBL_SIGNATURE', + 'function' => [ + 'name' => 'getUserSignature', + 'returns' => 'html', + 'include' => 'modules/InboundEmail/utils.php', + ], + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'filter_domain' => [ + 'name' => 'filter_domain', + 'vname' => 'LBL_FILTER_DOMAIN', + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'email_num_autoreplies_24_hours' => [ + 'name' => 'email_num_autoreplies_24_hours', + 'vname' => 'LBL_MAX_AUTO_REPLIES', + 'type' => 'int', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'is_auto_import' => [ + 'name' => 'is_auto_import', + 'vname' => 'LBL_ENABLE_AUTO_IMPORT', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'is_create_case' => [ + 'name' => 'is_create_case', + 'vname' => 'LBL_CREATE_CASE', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'allow_outbound_group_usage' => [ + 'name' => 'allow_outbound_group_usage', + 'vname' => 'LBL_ALLOW_OUTBOUND_GROUP_USAGE', + 'type' => 'bool', + 'required' => false, + 'default' => '0', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'distrib_method' => [ + 'name' => 'distrib_method', + 'vname' => 'LBL_DISTRIB_METHOD', + 'type' => 'enum', + 'options' => 'dom_email_distribution_for_auto_create', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'distribution_options' => [ + 'name' => 'distribution_options', + 'vname' => 'LBL_DISTRIB_OPTIONS', + 'function' => [ + 'name' => 'getInboundEmailDistributionOptions', + 'returns' => 'html', + 'include' => 'modules/InboundEmail/utils.php', + ], + 'type' => 'varchar', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'source' => 'non-db', + ], + 'distribution_user' => [ + 'name' => 'distribution_user', + 'type' => 'link', + 'relationship' => 'inbound_emails_distribution_user', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_DISTRIBUTION_USER', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'distribution_user_id' => [ + 'name' => 'distribution_user_id', + 'rname' => 'id', + 'id_name' => 'distribution_user_id', + 'vname' => 'LBL_DISTRIBUTION_USER_ID', + 'type' => 'relate', + 'table' => 'users', + 'isnull' => 'true', + 'module' => 'Users', + 'dbType' => 'id', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'duplicate_merge' => 'disabled', + 'hideacl' => true, + ], + 'distribution_user_name' => [ + 'name' => 'distribution_user_name', + 'rname' => 'name', + 'id_name' => 'distribution_user_id', + 'vname' => 'LBL_DISTRIBUTION_USER_NAME', + 'join_name' => 'distribution_user', + 'type' => 'relate', + 'link' => 'distribution_user', + 'table' => 'users', + 'isnull' => 'true', + 'module' => 'Users', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'outbound_email' => [ + 'name' => 'outbound_email', + 'type' => 'link', + 'relationship' => 'inbound_outbound_email_accounts', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_OUTBOUND_EMAIL_ACCOUNT', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'outbound_email_id' => [ + 'name' => 'outbound_email_id', + 'rname' => 'id', + 'id_name' => 'outbound_email_id', + 'vname' => 'LBL_OUTBOUND_EMAIL_ACCOUNT_ID', + 'type' => 'relate', + 'table' => 'outbound_email', + 'isnull' => 'true', + 'module' => 'OutboundEmailAccounts', + 'dbType' => 'id', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + 'duplicate_merge' => 'disabled', + 'hideacl' => true, + ], + 'outbound_email_name' => [ + 'name' => 'outbound_email_name', + 'rname' => 'name', + 'id_name' => 'outbound_email_id', + 'vname' => 'LBL_OUTBOUND_EMAIL_ACCOUNT_NAME', + 'join_name' => 'outbound_email', + 'type' => 'relate', + 'link' => 'outbound_email', + 'table' => 'outbound_email', + 'isnull' => 'true', + 'module' => 'OutboundEmailAccounts', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'autoreply_email_template' => [ + 'name' => 'autoreply_email_template', + 'type' => 'link', + 'relationship' => 'inbound_emails_autoreply_email_templates', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_AUTOREPLY_EMAIL_TEMPLATE', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'autoreply_email_template_name' => [ + 'name' => 'autoreply_email_template_name', + 'rname' => 'name', + 'id_name' => 'template_id', + 'vname' => 'LBL_AUTOREPLY_EMAIL_TEMPLATE_NAME', + 'join_name' => 'email_templates', + 'type' => 'relate', + 'link' => 'autoreply_email_template', + 'table' => 'email_templates', + 'isnull' => 'true', + 'module' => 'EmailTemplates', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'create_case_email_template' => [ + 'name' => 'create_case_email_template', + 'type' => 'link', + 'relationship' => 'inbound_emails_case_email_templates', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_CASE_EMAIL_TEMPLATE', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'create_case_template_id' => [ + 'name' => 'create_case_template_id', + 'rname' => 'id', + 'id_name' => 'create_case_template_id', + 'vname' => 'LBL_CASE_EMAIL_TEMPLATE_ID', + 'type' => 'relate', + 'table' => 'email_templates', + 'isnull' => 'true', + 'module' => 'EmailTemplates', + 'dbType' => 'id', + 'duplicate_merge' => 'disabled', + 'hideacl' => true, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'create_case_email_template_name' => [ + 'name' => 'create_case_email_template_name', + 'rname' => 'name', + 'id_name' => 'create_case_template_id', + 'vname' => 'LBL_CASE_EMAIL_TEMPLATE_NAME', + 'join_name' => 'email_templates', + 'type' => 'relate', + 'link' => 'create_case_email_template', + 'table' => 'email_templates', + 'isnull' => 'true', + 'module' => 'EmailTemplates', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'external_oauth_connection' => [ + 'name' => 'external_oauth_connection', + 'type' => 'link', + 'relationship' => 'inbound_emails_external_oauth_connections', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_EXTERNAL_OAUTH_CONNECTION', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'external_oauth_connection_id' => [ + 'name' => 'external_oauth_connection_id', + 'rname' => 'id', + 'id_name' => 'external_oauth_connection_id', + 'vname' => 'LBL_EXTERNAL_OAUTH_CONNECTION_ID', + 'type' => 'relate', + 'table' => 'external_oauth_connections', + 'isnull' => 'true', + 'module' => 'ExternalOAuthConnection', + 'dbType' => 'id', + 'duplicate_merge' => 'disabled', + 'hideacl' => true, + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'external_oauth_connection_name' => [ + 'name' => 'external_oauth_connection_name', + 'rname' => 'name', + 'id_name' => 'external_oauth_connection_id', + 'vname' => 'LBL_EXTERNAL_OAUTH_CONNECTION_NAME', + 'join_name' => 'external_oauth_connections', + 'type' => 'relate', + 'link' => 'external_oauth_connection', + 'table' => 'external_oauth_connections', + 'isnull' => 'true', + 'module' => 'ExternalOAuthConnection', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + ], /* end fields() */ + 'indices' => [ + [ + 'name' => 'inbound_emailpk', + 'type' => 'primary', + 'fields' => [ 'id' - ) - ), - ), /* end indices */ - 'relationships' => array( - 'inbound_email_created_by' => array( - 'lhs_module'=> 'Users', - 'lhs_table' => 'users', - 'lhs_key' => 'id', - 'rhs_module'=> 'InboundEmail', - 'rhs_table'=> 'inbound_email', - 'rhs_key' => 'created_by', - 'relationship_type' => 'one-to-one' - ), - 'inbound_email_modified_user_id' => array( + ] + ], + ], /* end indices */ + 'relationships' => [ + 'inbound_emails_distribution_user' => [ 'lhs_module' => 'Users', 'lhs_table' => 'users', 'lhs_key' => 'id', - 'rhs_module'=> 'InboundEmail', - 'rhs_table'=> 'inbound_email', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'distribution_user_id', + 'relationship_type' => 'one-to-many' + ], + 'inbound_emails_autoreply_email_templates' => [ + 'lhs_module' => 'EmailTemplates', + 'lhs_table' => 'email_templates', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'template_id', + 'relationship_type' => 'one-to-many' + ], + 'inbound_emails_case_email_templates' => [ + 'lhs_module' => 'EmailTemplates', + 'lhs_table' => 'email_templates', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'create_case_template_id', + 'relationship_type' => 'one-to-many' + ], + 'inbound_emails_external_oauth_connections' => [ + 'lhs_module' => 'ExternalOAuthConnection', + 'lhs_table' => 'external_oauth_connections', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'external_oauth_connection_id', + 'relationship_type' => 'one-to-many' + ], + 'inbound_outbound_email_accounts' => [ + 'lhs_module' => 'OutboundEmailAccounts', + 'lhs_table' => 'outbound_email', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'outbound_email_id', + 'relationship_type' => 'one-to-many' + ], + 'inbound_email_created_by' => [ + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', + 'rhs_key' => 'created_by', + 'relationship_type' => 'one-to-one' + ], + 'inbound_email_modified_user_id' => [ + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'InboundEmail', + 'rhs_table' => 'inbound_email', 'rhs_key' => 'modified_user_id', 'relationship_type' => 'one-to-one' - ), - ), /* end relationships */ -); + ], + ], /* end relationships */ +]; - -VardefManager::createVardef('InboundEmail', 'InboundEmail', array( -)); +VardefManager::createVardef('InboundEmail', 'InboundEmail', ['security_groups']); diff --git a/modules/InboundEmail/views/view.detail.php b/modules/InboundEmail/views/view.detail.php new file mode 100644 index 000000000..b3a6b4460 --- /dev/null +++ b/modules/InboundEmail/views/view.detail.php @@ -0,0 +1,57 @@ +dv->ss->assign('is_admin', is_admin($current_user)); + $this->dv->ss->assign('current_user_id', $current_user->id); + parent::display(); + } +} diff --git a/modules/InboundEmail/views/view.edit.php b/modules/InboundEmail/views/view.edit.php new file mode 100644 index 000000000..1badaece6 --- /dev/null +++ b/modules/InboundEmail/views/view.edit.php @@ -0,0 +1,58 @@ +ev->ss->assign('is_admin', is_admin($current_user)); + parent::display(); + } +} diff --git a/modules/InboundEmail/views/view.list.php b/modules/InboundEmail/views/view.list.php new file mode 100644 index 000000000..1d5a9fbf8 --- /dev/null +++ b/modules/InboundEmail/views/view.list.php @@ -0,0 +1,57 @@ +params['export'] = false; + $this->lv->displayEmptyDataMessages = false; + } +} diff --git a/modules/MergeRecords/MergeRecord.php b/modules/MergeRecords/MergeRecord.php index ddd24ec0e..8e7fadff7 100755 --- a/modules/MergeRecords/MergeRecord.php +++ b/modules/MergeRecords/MergeRecord.php @@ -383,9 +383,9 @@ class MergeRecord extends SugarBean } } // Add ACL Check - if ($this->merge_bean->bean_implements('ACL') && ACLController::requireOwner($this->merge_bean->module_dir, 'delete')) { - global $current_user; - $where_clauses[] = $this->merge_bean->getOwnerWhere($current_user->id); + $accessWhere = $this->merge_bean->buildAccessWhere('delete'); + if (!empty($accessWhere)) { + $where_clauses[] = $accessWhere; } array_push($where_clauses, $this->merge_bean->table_name.".id !='".DBManagerFactory::getInstance()->quote($this->merge_bean->id)."'"); diff --git a/modules/OutboundEmailAccounts/Menu.php b/modules/OutboundEmailAccounts/Menu.php new file mode 100644 index 000000000..de5d72c90 --- /dev/null +++ b/modules/OutboundEmailAccounts/Menu.php @@ -0,0 +1,54 @@ +checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied('save'); + throw new RuntimeException('Access Denied'); + } + + $this->keepWriteOnlyFieldValues(); + if (!$this->mail_smtppass && $this->id) { $bean = BeanFactory::newBean('OutboundEmailAccounts'); $bean->retrieve($this->id); @@ -79,13 +91,188 @@ class OutboundEmailAccounts extends OutboundEmailAccounts_sugar return $results; } + /** + * @inheritDoc + */ public function retrieve($id = -1, $encode = true, $deleted = true) { $results = parent::retrieve($id, $encode, $deleted); + + if (!empty($results) && !$this->checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied('retrieve'); + return null; + } + $this->mail_smtppass = $this->mail_smtppass ? blowfishDecode(blowfishGetKey('OutBoundEmail'), $this->mail_smtppass) : null; return $results; } + /** + * @inheritDoc + */ + public function create_new_list_query( + $order_by, + $where, + $filter = array(), + $params = array(), + $show_deleted = 0, + $join_type = '', + $return_array = false, + $parentbean = null, + $singleSelect = false, + $ifListForExport = false + ) { + global $current_user, $db; + + $ret_array = parent::create_new_list_query( + $order_by, + $where, + $filter, + $params , + $show_deleted, + $join_type, + true, + $parentbean, + $singleSelect, + $ifListForExport + ); + + if(is_admin($current_user)) { + if ($return_array) { + return $ret_array; + } + + return $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by']; + } + + if (is_array($ret_array) && !empty($ret_array['where'])){ + $tableName = $db->quote($this->table_name); + $currentUserId = $db->quote($current_user->id); + + $showGroupRecords = "($tableName.type IS NULL) OR ($tableName.type != 'user' ) OR "; + + $hasActionAclsDefined = has_group_action_acls_defined('OutboundEmailAccounts', 'list'); + + if($hasActionAclsDefined === false) { + $showGroupRecords = ''; + } + + $ret_array['where'] = $ret_array['where'] . " AND ( $showGroupRecords ($tableName.type = 'user' AND $tableName.user_id = '$currentUserId') )"; + } + + if ($return_array) { + return $ret_array; + } + + return $ret_array['select'] . $ret_array['from'] . $ret_array['where'] . $ret_array['order_by']; + } + + /** + * Check if user has access to personal account + * @return bool + */ + public function checkPersonalAccountAccess() : bool { + global $current_user; + + if (is_admin($current_user)) { + return true; + } + + if (empty($this->type)) { + return true; + } + + if ($this->type !== 'user') { + return true; + } + + if (empty($this->user_id)) { + return true; + } + + if ($this->user_id === $current_user->id) { + return true; + } + + return false; + } + + /** + * Log personal account access denied + * @param string $action + * @return void + */ + public function logPersonalAccountAccessDenied(string $action) : void { + global $log, $current_user; + + $log->fatal("OutBoundEmailAccount | Access denied. Non-admin trying to access personal account. Action: '" . $action . "' | Current user id: '" . $current_user->id . "' | record: '" . $this->id . "'" ); + } + + /** + * @inheritDoc + */ + public function ACLAccess($view, $is_owner = 'not_set', $in_group = 'not_set') + { + global $current_user; + + $isNotAllowAction = $this->isNotAllowedAction($view); + if ($isNotAllowAction === true) { + return false; + } + + if (!$this->checkPersonalAccountAccess()) { + $this->logPersonalAccountAccessDenied("ACLAccess-$view"); + return false; + } + + $isPersonal = $this->type === 'user'; + $isAdmin = is_admin($current_user); + + if ($isPersonal === true && $this->checkPersonalAccountAccess()) { + return true; + } + + $isAdminOnlyAction = $this->isAdminOnlyAction($view); + if (!$isPersonal && !$isAdmin && $isAdminOnlyAction === true) { + return false; + } + + $hasActionAclsDefined = has_group_action_acls_defined('OutboundEmailAccounts', 'view'); + $isSecurityGroupBasedAction = $this->isSecurityGroupBasedAction($view); + + if (!$isPersonal && !$isAdmin && !$hasActionAclsDefined && $isSecurityGroupBasedAction === true) { + return false; + } + + return parent::ACLAccess($view, $is_owner, $in_group); + } + + /** + * @return void + */ + protected function keepWriteOnlyFieldValues(): void + { + if (empty($this->fetched_row)) { + return; + } + + foreach ($this->field_defs as $field => $field_def) { + if (empty($field_def['display']) || $field_def['display'] !== 'writeonly') { + continue; + } + + if (empty($this->fetched_row[$field])) { + continue; + } + + if (!empty($this->$field)) { + continue; + } + + $this->$field = $this->fetched_row[$field]; + } + } + public static function getPasswordChange() { global $mod_strings; @@ -168,7 +355,7 @@ HTML; EmailMan.testOutboundDialog.render(); EmailMan.testOutboundDialog.show(); } - + function showFullSmtpLogDialog(headerText, bodyHtml, dialogType) { var config = { }; @@ -179,11 +366,11 @@ HTML; config.width = 600; YAHOO.SUGAR.MessageBox.show(config); } - + function sendTestEmail() { var toAddress = document.getElementById("outboundtest_to_address").value; - - if (trim(toAddress) == "") + + if (trim(toAddress) == "") { overlay("{$APP['ERR_MISSING_REQUIRED_FIELDS']}", "{$APP['LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR']}", 'alert'); //return; @@ -192,11 +379,11 @@ HTML; overlay("{$APP['ERR_INVALID_REQUIRED_FIELDS']}", "{$APP['LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR']}", 'alert'); return; } - + //Hide the email address window and show a message notifying the user that the test email is being sent. EmailMan.testOutboundDialog.hide(); overlay("{$APP['LBL_EMAIL_PERFORMING_TASK']}", "{$APP['LBL_EMAIL_ONE_MOMENT']}", 'alert'); - + var callbackOutboundTest = { success : function(o) { hideOverlay(); @@ -204,17 +391,17 @@ HTML; if (responseObject.status) overlay("{$APP['LBL_EMAIL_TEST_OUTBOUND_SETTINGS']}", "{$APP['LBL_EMAIL_TEST_NOTIFICATION_SENT']}", 'alert'); else { - - var dialogBody = + + var dialogBody = "
" + "
" + responseObject.errorMessage + "
" + "
" + - "" + "
" + "
" +
-                                                                           responseObject.fullSmtpLog + 
+                                                                           responseObject.fullSmtpLog +
                                                                        "
" + "
" + "
" + @@ -228,7 +415,7 @@ HTML; var smtpPort = document.getElementById('mail_smtpport').value; var smtpssl = document.getElementById('mail_smtpssl').value; var mailsmtpauthreq = document.getElementById('mail_smtpauth_req'); - var mail_sendtype = 'SMTP'; + var mail_sendtype = 'SMTP'; var adminNotifyFromAddress = document.getElementById('smtp_from_addr').value ? document.getElementById('smtp_from_addr').value :'$adminNotifyFromName'; var adminNotifyFromName = document.getElementById('smtp_from_name').value ? document.getElementById('smtp_from_name').value : '$adminNotifyFromAddress'; var postDataString = @@ -275,4 +462,37 @@ HTML; HTML; return $html; } + + /** + * Check if its admin only action + * @param string $view + * @return bool + */ + protected function isAdminOnlyAction(string $view): bool + { + $adminOnlyAction = ['edit', 'delete', 'editview', 'save']; + return in_array(strtolower($view), $adminOnlyAction); + } + + /** + * Check if its a security based action + * @param string $view + * @return bool + */ + protected function isSecurityGroupBasedAction(string $view): bool + { + $securityBasedActions = ['detail', 'detailview', 'view']; + return in_array(strtolower($view), $securityBasedActions); + } + + /** + * Get not allowed action + * @param string $view + * @return bool + */ + protected function isNotAllowedAction(string $view): bool + { + $notAllowed = ['export', 'import', 'massupdate', 'duplicate']; + return in_array(strtolower($view), $notAllowed); + } } diff --git a/modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php b/modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php index 0a8edbe37..c57ad2b24 100644 --- a/modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php +++ b/modules/OutboundEmailAccounts/OutboundEmailAccounts_sugar.php @@ -75,16 +75,16 @@ class OutboundEmailAccounts_sugar extends Basic // var $smtp_auth; // var $smtp_port; // var $smtp_protocol; - + public function __construct() { parent::__construct(); } - + public function bean_implements($interface) { - switch ($interface) { - case 'ACL': return true; + if ($interface === 'ACL') { + return true; } return false; } diff --git a/modules/OutboundEmailAccounts/controller.php b/modules/OutboundEmailAccounts/controller.php new file mode 100644 index 000000000..a5cecd03d --- /dev/null +++ b/modules/OutboundEmailAccounts/controller.php @@ -0,0 +1,97 @@ +view = 'edit'; + $type = $_REQUEST['type'] ?? ''; + if (!empty($this->bean) && $type !== '') { + $this->bean->type = $type; + } + + if (empty($_REQUEST['record']) && $type === 'user') { + $this->hasAccess = true; + return; + } + + if (!empty($this->bean) && $type === 'user' && $this->bean->checkPersonalAccountAccess()) { + $this->hasAccess = true; + } + } + + public function action_save() { + global $current_user; + $isNewRecord = (empty($this->bean->id) || $this->bean->new_with_id); + + $this->bean->mail_sendtype = 'SMTP'; + + if (!empty($_REQUEST['user_id']) && is_admin($current_user)) { + $this->bean->assigned_user_id = $_REQUEST['user_id']; + $this->bean->user_id = $_REQUEST['user_id']; + } + + if ($isNewRecord && !empty($_REQUEST['user_id']) && !is_admin($current_user)) { + $_REQUEST['user_id'] = ''; + $this->bean->user_id = ''; + } + + if (!$isNewRecord && !empty($_REQUEST['user_id']) && !is_admin($current_user)) { + $_REQUEST['user_id'] = ''; + if (!empty($this->bean->fetched_row['user_id'])) { + $this->bean->user_id = $this->bean->fetched_row['user_id']; + } + } + + if ($isNewRecord && empty($this->bean->user_id)) { + $this->bean->user_id = $current_user->id; + $this->bean->assigned_user_id = $current_user->id; + } + + if (!$isNewRecord && !empty($this->bean->user_id) && empty($this->bean->assigned_user_id)) { + $this->bean->assigned_user_id = $this->bean->user_id; + } + + parent::action_save(); + } +} diff --git a/modules/OutboundEmailAccounts/js/fields.js b/modules/OutboundEmailAccounts/js/fields.js new file mode 100644 index 000000000..5bc3160a8 --- /dev/null +++ b/modules/OutboundEmailAccounts/js/fields.js @@ -0,0 +1,181 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +var outboundEmailFields = function () { + + var getDefaultFieldGetter = function () { + return function (field$) { + return (field$ && field$.val()) || ''; + }; + }; + + var getDefaultFieldSetter = function () { + return function (field$, value) { + if (!field$) { + return; + } + + field$.val(value); + field$.change(); + }; + }; + + return { + fields: { + 'record': { + type: 'varchar', + getField$: function (field) { + return $('input[name=' + field + ']') || null; + } + }, + 'mail_smtpssl': { + type: 'varchar' + }, + 'owner_name': { + type: 'varchar' + }, + 'type': { + type: 'varchar' + }, + 'mail_smtpport': { + type: 'varchar' + }, + 'mail_smtpauth_req': { + type: 'checkbox' + }, + }, + + getters: { + default: getDefaultFieldGetter(), + varchar: getDefaultFieldGetter(), + checkbox: function (field$) { + return (field$ && field$.prop('checked')) || false; + } + }, + + setters: { + default: getDefaultFieldSetter(), + varchar: getDefaultFieldSetter(), + checkbox: function (field$, value) { + if (!field$) { + return; + } + + field$.prop('checked', !!value); + } + }, + + setValue: function (field, value) { + var field$ = this.getField$(field); + if (!field$) { + return null; + } + + var setter = this.getValueSetter(field); + if (!setter) { + return null; + } + + return setter(field$, value); + }, + + getValue: function (field) { + var field$ = this.getField$(field); + if (!field$) { + return null; + } + + var getter = this.getValueGetter(field); + if (!getter) { + return null; + } + + return getter(field$); + }, + + hide: function (field) { + var field$ = this.getFieldCell$(field); + + if (!field$ || !field$.length) { + return; + } + + field$.hide(); + }, + + show: function (field) { + var field$ = this.getFieldCell$(field); + + if (!field$ || !field$.length) { + return; + } + + field$.show(); + }, + + + getField$: function (field) { + var handler = (this.fields[field] && this.fields[field].getField$) || null; + + if (handler) { + return handler(field); + } + + return $('#' + field) || null; + }, + + getFieldCell$: function (field) { + return $('[data-field="' + field + '"]') || null; + }, + + getFieldType: function (field) { + return (this.fields[field] && this.fields[field].type) || 'varchar'; + }, + + getValueGetter: function (field) { + var type = this.getFieldType(field); + return this.getters[type] || this.getters['default']; + }, + + getValueSetter: function (field) { + var type = this.getFieldType(field); + return this.setters[type] || this.setters['default']; + } + + }; +}(); diff --git a/modules/OutboundEmailAccounts/js/owner_toggle.js b/modules/OutboundEmailAccounts/js/owner_toggle.js new file mode 100644 index 000000000..eda8f0219 --- /dev/null +++ b/modules/OutboundEmailAccounts/js/owner_toggle.js @@ -0,0 +1,76 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +function toggleOwnerField(type, isAdmin) { + var status = 'non-admin'; + if (isAdmin) { + status = 'admin'; + } + + var fieldsPerStatus = { + 'admin': { + 'owner_name': true, + }, + 'non-admin': { + 'owner_name': false, + }, + }; + + var fieldDisplay = fieldsPerStatus[status] || fieldsPerStatus.disabled; + + Object.keys(fieldDisplay).forEach(function (fieldKey) { + var display = fieldDisplay[fieldKey]; + var method = 'show'; + if(!display) { + method = 'hide'; + } + + if(type !== 'user') { + method = 'hide'; + } + + outboundEmailFields[method](fieldKey); + }); +} + +$(document).ready(function () { + var isAdmin = userService.isAdmin(); + var type = outboundEmailFields.getValue('type'); + toggleOwnerField(type, isAdmin); +}); + diff --git a/modules/OutboundEmailAccounts/js/smtp_auth_toggle.js b/modules/OutboundEmailAccounts/js/smtp_auth_toggle.js new file mode 100644 index 000000000..a05673c3e --- /dev/null +++ b/modules/OutboundEmailAccounts/js/smtp_auth_toggle.js @@ -0,0 +1,76 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +function toggleAuthFields(authEnabled) { + var status = 'disabled'; + if (authEnabled) { + status = 'enabled'; + } + + var fieldsPerStatus = { + 'enabled': { + 'mail_smtppass': true, + }, + 'disabled': { + 'mail_smtppass': false, + }, + }; + + var fieldDisplay = fieldsPerStatus[status] || fieldsPerStatus.disabled; + + Object.keys(fieldDisplay).forEach(function (fieldKey) { + var display = fieldDisplay[fieldKey]; + var method = 'show'; + if(!display) { + method = 'hide'; + } + + outboundEmailFields[method](fieldKey); + }); +} + +$(document).ready(function () { + var authEnabled = outboundEmailFields.getValue('mail_smtpauth_req'); + toggleAuthFields(authEnabled); + + $('#mail_smtpauth_req').change(function () { + var authEnabled = outboundEmailFields.getValue('mail_smtpauth_req'); + toggleAuthFields(authEnabled); + }); +}); + diff --git a/modules/OutboundEmailAccounts/js/ssl_port_set.js b/modules/OutboundEmailAccounts/js/ssl_port_set.js new file mode 100644 index 000000000..79f840f73 --- /dev/null +++ b/modules/OutboundEmailAccounts/js/ssl_port_set.js @@ -0,0 +1,54 @@ +/** + * + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. + * + * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. + * Copyright (C) 2011 - 2022 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not + * reasonably feasible for technical reasons, the Appropriate Legal Notices must + * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". + */ +$(document).ready(function () { + $('#mail_smtpssl').change(function () { + var protocol = outboundEmailFields.getValue('mail_smtpssl'); + + var port = 25; + if (protocol === '1') { + port = 465; + } + + if (protocol === '2') { + port = 587; + } + + outboundEmailFields.setValue('mail_smtpport', port); + }); +}); diff --git a/modules/OutboundEmailAccounts/language/en_us.lang.php b/modules/OutboundEmailAccounts/language/en_us.lang.php index 8dcbaeb46..ac094aec8 100644 --- a/modules/OutboundEmailAccounts/language/en_us.lang.php +++ b/modules/OutboundEmailAccounts/language/en_us.lang.php @@ -64,7 +64,13 @@ $mod_strings = array( 'LBL_MODULE_TITLE' => 'Outbound Email Accounts', 'LBL_HOMEPAGE_TITLE' => 'My Outbound Email Accounts', 'LNK_NEW_RECORD' => 'Create Outbound Email Accounts', - 'LNK_LIST' => 'View Outbound Email Accounts', + + 'LNK_LIST_CREATE_NEW_PERSONAL' => 'New Personal Outbound Email Account', + 'LNK_LIST_CREATE_NEW_GROUP' => 'New Group Outbound Email Account', + 'LNK_LIST_CREATE_SYSTEM_OVERRIDE_GROUP' => 'New System Override Outbound Email Account', + + 'LNK_LIST' => 'Outbound Email Accounts', + 'LNK_LIST_INBOUND_EMAIL_ACCOUNTS' => 'Inbound Email Accounts', 'LBL_SEARCH_FORM_TITLE' => 'Search Outbound Email Accounts', 'LBL_HISTORY_SUBPANEL_TITLE' => 'View History', 'LBL_ACTIVITIES_SUBPANEL_TITLE' => 'Activities', @@ -76,16 +82,18 @@ $mod_strings = array( 'LBL_SMTP_PORT' => 'SMTP Port', 'LBL_SMTP_PROTOCOL' => 'SMTP Protocol', 'LBL_EDITVIEW_PANEL1' => 'Account settings', + 'LBL_OUTBOUND_CONFIGURATION' => 'Outbound Configuration', + 'LBL_CONNECTION_CONFIGURATION' => 'Server Configuration', 'LBL_CHANGE_PASSWORD' => 'Change password', 'LBL_SEND_TEST_EMAIL' => 'Send Test Email', // for outbound email dialog 'LBL_MISSING_DEFAULT_OUTBOUND_SMTP_SETTINGS' => 'The administrator has not yet configured the default outbound account. Unable to send test email.', 'LBL_MAIL_SMTPAUTH_REQ' => 'Use SMTP Authentication?', - 'LBL_MAIL_SMTPPASS' => 'SMTP Password:', - 'LBL_MAIL_SMTPPORT' => 'SMTP Port:', - 'LBL_MAIL_SMTPSERVER' => 'SMTP Server:', - 'LBL_MAIL_SMTPUSER' => 'SMTP Username:', + 'LBL_MAIL_SMTPPASS' => 'Password', + 'LBL_MAIL_SMTPPORT' => 'Port', + 'LBL_MAIL_SMTPSERVER' => 'Server', + 'LBL_MAIL_SMTPUSER' => 'Username', 'LBL_MAIL_SMTP_SETTINGS' => 'SMTP Server Specification', 'LBL_CHOOSE_EMAIL_PROVIDER' => 'Choose your Email provider:', 'LBL_YAHOOMAIL_SMTPPASS' => 'Yahoo! Mail Password:', @@ -102,4 +110,11 @@ $mod_strings = array( 'LBL_MAIL_SMTPSSL' => 'Mail SMTP/SSL', 'LBL_SMTP_FROM_NAME' => '"From" name', 'LBL_SMTP_FROM_ADDR' => '"From" address', + + 'LBL_SECURITYGROUPS_SUBPANEL_TITLE' => 'Security Groups', + + 'LBL_OWNER' => 'Owner', + 'LBL_OWNER_NAME' => 'Owner', + + 'LNK_EXTERNAL_OAUTH_CONNECTIONS' => 'External OAuth Connections' ); diff --git a/modules/OutboundEmailAccounts/metadata/SearchFields.php b/modules/OutboundEmailAccounts/metadata/SearchFields.php index 3c082a3e6..5ecc12229 100644 --- a/modules/OutboundEmailAccounts/metadata/SearchFields.php +++ b/modules/OutboundEmailAccounts/metadata/SearchFields.php @@ -47,7 +47,9 @@ $searchFields[$module_name] = 'name' => array( 'query_type'=>'default'), 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), 'assigned_user_id'=> array('query_type'=>'default'), - + 'user_id'=> array('query_type'=>'default'), + 'type'=> array('query_type'=>'default'), + //Range Search Support 'range_date_entered' => array('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), 'start_range_date_entered' => array('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), diff --git a/modules/OutboundEmailAccounts/metadata/detailviewdefs.php b/modules/OutboundEmailAccounts/metadata/detailviewdefs.php index 0f7a469c1..f3902b90c 100644 --- a/modules/OutboundEmailAccounts/metadata/detailviewdefs.php +++ b/modules/OutboundEmailAccounts/metadata/detailviewdefs.php @@ -1,97 +1,81 @@ - array( - 'templateMeta' => - array( - 'form' => - array( - 'buttons' => - array( - 0 => 'EDIT', - 1 => 'DUPLICATE', - 2 => 'DELETE', - 3 => 'FIND_DUPLICATES', - ), - ), - 'maxColumns' => '2', - 'widths' => - array( - 0 => - array( - 'label' => '10', - 'field' => '30', - ), - 1 => - array( - 'label' => '10', - 'field' => '30', - ), - ), - 'useTabs' => false, - 'tabDefs' => - array( - 'DEFAULT' => - array( - 'newTab' => false, - 'panelDefault' => 'expanded', - ), - 'LBL_EDITVIEW_PANEL1' => - array( - 'newTab' => false, - 'panelDefault' => 'expanded', - ), - ), - 'syncDetailEditViews' => true, - ), - 'panels' => - array( - 'default' => - array( - 0 => - array( - 0 => 'name', - ), - ), - 'lbl_editview_panel1' => - array( - 0 => - array( - 0 => - array( - 'name' => 'mail_smtpuser', - 'label' => 'LBL_USERNAME', - ), - ), - 1 => - array( - 0 => - array( - 'name' => 'mail_smtpserver', - 'label' => 'LBL_SMTP_SERVERNAME', - ), - 1 => - array( - 'name' => 'mail_smtpport', - 'label' => 'LBL_SMTP_PORT', - ), - ), - 2 => - array( - 0 => - array( - 'name' => 'mail_smtpauth_req', - 'label' => 'LBL_SMTP_AUTH', - ), - 1 => - array( - 'name' => 'mail_smtpssl', - 'studio' => 'visible', - 'label' => 'LBL_SMTP_PROTOCOL', - ), - ), - ), - ), - ), -); +$viewdefs ['OutboundEmailAccounts'] = [ + 'DetailView' => [ + 'templateMeta' => [ + 'form' => [ + 'buttons' => [ + 'EDIT', + 'DELETE', + ], + ], + 'maxColumns' => '2', + 'widths' => [ + [ + 'label' => '10', + 'field' => '30', + ], + [ + 'label' => '10', + 'field' => '30', + ], + ], + 'useTabs' => false, + 'tabDefs' => [ + 'DEFAULT' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_EDITVIEW_PANEL1' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + ], + 'preForm' => ' + + ', + ], + 'panels' => [ + 'default' => [ + [ + 'name', + '' + ], + [ + 'type', + '' + ], + [ + 'owner_name', + ], + ], + 'lbl_connection_configuration' => [ + [ + 'mail_smtpserver', + 'mail_smtpauth_req', + ], + [ + 'mail_smtpssl', + 'mail_smtpuser', + ], + [ + 'mail_smtpport', + '', + ], + ], + 'lbl_outbound_configuration' => [ + [ + 'smtp_from_name', + ], + [ + 'smtp_from_addr', + ], + ], + ], + ], +]; diff --git a/modules/OutboundEmailAccounts/metadata/editviewdefs.php b/modules/OutboundEmailAccounts/metadata/editviewdefs.php index 98496797f..5ed2ecd38 100644 --- a/modules/OutboundEmailAccounts/metadata/editviewdefs.php +++ b/modules/OutboundEmailAccounts/metadata/editviewdefs.php @@ -1,116 +1,90 @@ - array( - 'templateMeta' => - array( - 'maxColumns' => '2', - 'widths' => - array( - 0 => - array( - 'label' => '10', - 'field' => '30', - ), - 1 => - array( - 'label' => '10', - 'field' => '30', - ), - ), - 'useTabs' => false, - 'tabDefs' => - array( - 'DEFAULT' => - array( - 'newTab' => false, - 'panelDefault' => 'expanded', - ), - 'LBL_EDITVIEW_PANEL1' => - array( - 'newTab' => false, - 'panelDefault' => 'expanded', - ), - ), - 'syncDetailEditViews' => true, - ), - 'panels' => - array( - 'default' => - array( - 0 => - array( - 0 => 'name', - ), - ), - 'lbl_editview_panel1' => - array( - array( - 0 => - array( - 'name' => 'smtp_from_name', - 'label' => 'LBL_SMTP_FROM_NAME', - ), - ), - array( - 0 => - array( - 'name' => 'smtp_from_addr', - 'label' => 'LBL_SMTP_FROM_ADDR', - ), - ), - array( - 0 => - array( - 'name' => 'email_provider_chooser', - 'label' => 'LBL_CHOOSE_EMAIL_PROVIDER', - ), - ), - array( - 0 => - array( - 'name' => 'mail_smtpserver', - 'label' => 'LBL_SMTP_SERVERNAME', - ), - 1 => - array( - 'name' => 'mail_smtpport', - 'label' => 'LBL_SMTP_PORT', - ), - ), - array( - 0 => - array( - 'name' => 'mail_smtpauth_req', - 'label' => 'LBL_SMTP_AUTH', - ), - 1 => - array( - 'name' => 'mail_smtpssl', - 'studio' => 'visible', - 'label' => 'LBL_SMTP_PROTOCOL', - ), - ), - array( - array( - 'name' => 'mail_smtpuser', - 'label' => 'LBL_USERNAME', - ), - ), - array( - array( - 'name' => 'password_change', - 'label' => 'LBL_PASSWORD', - ), - ), - array( - array( - 'name' => 'sent_test_email_btn', - 'label' => 'LBL_SEND_TEST_EMAIL', - ), - ), - ), - ), - ), -); +$viewdefs ['OutboundEmailAccounts'] = [ + 'EditView' => [ + 'templateMeta' => [ + 'maxColumns' => '2', + 'widths' => [ + [ + 'label' => '10', + 'field' => '30', + ], + [ + 'label' => '10', + 'field' => '30', + ], + ], + 'useTabs' => false, + 'tabDefs' => [ + 'DEFAULT' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_CONNECTION_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + 'LBL_OUTBOUND_CONFIGURATION' => [ + 'newTab' => false, + 'panelDefault' => 'expanded', + ], + ], + 'form' => [ + 'hidden' => [ + ], + ], + 'javascript' => ' + + ', + ], + 'panels' => [ + 'default' => [ + [ + 'name', + '' + ], + [ + 'type', + '' + ], + [ + 'owner_name', + ], + ], + 'lbl_connection_configuration' => [ + [ + 'mail_smtpserver', + 'mail_smtpauth_req', + ], + [ + 'mail_smtpssl', + 'mail_smtpuser', + ], + [ + 'mail_smtpport', + 'mail_smtppass', + ], + [ + [ + 'name' => 'sent_test_email_btn', + 'label' => 'LBL_SEND_TEST_EMAIL', + ], + ], + ], + 'lbl_outbound_configuration' => [ + [ + 'smtp_from_name', + ], + [ + 'smtp_from_addr', + ], + ], + ], + ], +]; diff --git a/modules/OutboundEmailAccounts/metadata/listviewdefs.php b/modules/OutboundEmailAccounts/metadata/listviewdefs.php index 03d7effdb..b797b5448 100644 --- a/modules/OutboundEmailAccounts/metadata/listviewdefs.php +++ b/modules/OutboundEmailAccounts/metadata/listviewdefs.php @@ -1,26 +1,27 @@ - array( - 'width' => '32%', - 'label' => 'LBL_NAME', - 'default' => true, - 'link' => true, - ), - 'MAIL_SMTPUSER' => - array( - 'type' => 'varchar', - 'label' => 'LBL_USERNAME', - 'width' => '10%', - 'default' => true, - ), - 'MAIL_SMTPSERVER' => - array( - 'type' => 'varchar', - 'label' => 'LBL_SMTP_SERVERNAME', - 'width' => '10%', - 'default' => true, - ), -); +$listViewDefs [$module_name] = [ + 'NAME' => [ + 'width' => '32%', + 'label' => 'LBL_NAME', + 'default' => true, + 'link' => true, + ], + 'MAIL_SMTPUSER' => [ + 'type' => 'varchar', + 'label' => 'LBL_USERNAME', + 'width' => '10%', + 'default' => true, + ], + 'TYPE' => [ + 'label' => 'LBL_TYPE', + 'width' => '10%', + 'default' => true, + ], + 'MAIL_SMTPSERVER' => [ + 'type' => 'varchar', + 'label' => 'LBL_SMTP_SERVERNAME', + 'width' => '10%', + 'default' => true, + ], +]; diff --git a/modules/OutboundEmailAccounts/metadata/popupdefs.php b/modules/OutboundEmailAccounts/metadata/popupdefs.php index ef926e9c3..d8979efd5 100644 --- a/modules/OutboundEmailAccounts/metadata/popupdefs.php +++ b/modules/OutboundEmailAccounts/metadata/popupdefs.php @@ -1,46 +1,51 @@ 'OutboundEmailAccount', 'varName' => 'OutboundEmailAccount', 'orderBy' => 'outboundemailaccount.name', - 'whereClauses' => array( - 'mail_smtpuser' => 'outbound_email.mail_smtpuser', - 'mail_smtpserver' => 'outbound_email.mail_smtpserver', -), - 'searchInputs' => array( - 4 => 'mail_smtpuser', - 5 => 'mail_smtpserver', -), - 'searchdefs' => array( - 'mail_smtpuser' => - array( - 'type' => 'varchar', - 'label' => 'LBL_USERNAME', - 'width' => '10%', - 'name' => 'mail_smtpuser', - ), - 'mail_smtpserver' => - array( - 'type' => 'varchar', - 'label' => 'LBL_SMTP_SERVERNAME', - 'width' => '10%', - 'name' => 'mail_smtpserver', - ), -), - 'listviewdefs' => array( - 'mail_smtpuser' => - array( - 'type' => 'varchar', - 'label' => 'LBL_USERNAME', - 'width' => '10%', - 'default' => true, - ), - 'mail_smtpserver' => - array( - 'type' => 'varchar', - 'label' => 'LBL_SMTP_SERVERNAME', - 'width' => '10%', - 'default' => true, - ), -), -); + 'whereClauses' => [ + 'mail_smtpuser' => 'outbound_email.mail_smtpuser', + 'mail_smtpserver' => 'outbound_email.mail_smtpserver', + ], + 'searchInputs' => [ + 4 => 'mail_smtpuser', + 5 => 'mail_smtpserver', + ], + 'searchdefs' => [ + 'mail_smtpuser' => [ + 'type' => 'varchar', + 'label' => 'LBL_USERNAME', + 'width' => '10%', + 'name' => 'mail_smtpuser', + ], + 'mail_smtpserver' => [ + 'type' => 'varchar', + 'label' => 'LBL_SMTP_SERVERNAME', + 'width' => '10%', + 'name' => 'mail_smtpserver', + ], + ], + 'listviewdefs' => [ + 'NAME' => [ + 'width' => '40%', + 'label' => 'LBL_LIST_ACCOUNT_NAME', + 'link' => true, + 'default' => true, + 'name' => 'name', + ], + 'MAIL_SMTPUSER' => [ + 'type' => 'varchar', + 'label' => 'LBL_USERNAME', + 'width' => '10%', + 'default' => true, + 'link' => true, + 'name' => 'mail_smtpuser', + ], + 'MAIL_SMTPSERVER' => [ + 'type' => 'varchar', + 'label' => 'LBL_SMTP_SERVERNAME', + 'width' => '10%', + 'default' => true, + ], + ], +]; diff --git a/modules/InboundEmail/ListView.php b/modules/OutboundEmailAccounts/metadata/subpaneldefs.php old mode 100755 new mode 100644 similarity index 56% rename from modules/InboundEmail/ListView.php rename to modules/OutboundEmailAccounts/metadata/subpaneldefs.php index b5c64ab2b..962490cd7 --- a/modules/InboundEmail/ListView.php +++ b/modules/OutboundEmailAccounts/metadata/subpaneldefs.php @@ -41,39 +41,27 @@ if (!defined('sugarEntry') || !sugarEntry) { * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ -global $theme; -global $mod_strings; -global $app_list_strings; -global $current_user; -$focus = BeanFactory::newBean('InboundEmail'); -$focus->checkImap(); - -/////////////////////////////////////////////////////////////////////////////// -//// I-E SYSTEM SETTINGS -//// handle saving settings -if (isset($_REQUEST['save']) && $_REQUEST['save'] == 'true') { - $focus->saveInboundEmailSystemSettings('Case', $_REQUEST['inbound_email_case_macro']); -} -//// END I-E SYSTEM SETTINGS -/////////////////////////////////////////////////////////////////////////////// - -if (is_admin($current_user) && $_REQUEST['module'] != 'DynamicLayout' && !empty($_SESSION['editinplace'])) { - $ListView->setHeaderText("".SugarThemeRegistry::current()->getImage("EditLayout", "border='0' align='bottom'", null, null, '.gif', $mod_strings['LBL_EDIT_LAYOUT']).""); -} - -$where = ''; -$limit = '0'; -$orderBy = 'date_entered'; -$varName = $focus->object_name; -$allowByOverride = true; - -$listView = new ListView(); -$listView->initNewXTemplate('modules/InboundEmail/ListView.html', $mod_strings); - -echo $focus->getSystemSettingsForm(); -$listView->show_export_button = false; -$listView->ignorePopulateOnly = true; //Always show all records, ignore save_query performance setting. -$listView->setQuery($where, $limit, $orderBy, 'InboundEmail', $allowByOverride); -$listView->xTemplateAssign("EDIT_INLINE_IMG", SugarThemeRegistry::current()->getImage('edit_inline', 'align="absmiddle" border="0"', null, null, '.gif', $app_strings['LNK_EDIT'])); -$listView->processListView($focus, "main", "InboundEmail"); +$layout_defs['OutboundEmailAccounts'] = [ + // list of what Subpanels to show in the DetailView + 'subpanel_setup' => [ + 'securitygroups' => [ + 'top_buttons' => [ + [ + 'widget_class' => 'SubPanelTopSelectButton', + 'popup_module' => 'SecurityGroups', + 'mode' => 'MultiSelect' + ], + ], + 'order' => 900, + 'sort_by' => 'name', + 'sort_order' => 'asc', + 'module' => 'SecurityGroups', + 'refresh_page' => 1, + 'subpanel_name' => 'default', + 'get_subpanel_data' => 'SecurityGroups', + 'add_subpanel_data' => 'securitygroup_id', + 'title_key' => 'LBL_SECURITYGROUPS_SUBPANEL_TITLE', + ], + ], +]; diff --git a/modules/OutboundEmailAccounts/vardefs.php b/modules/OutboundEmailAccounts/vardefs.php index 196924972..796fa65e9 100644 --- a/modules/OutboundEmailAccounts/vardefs.php +++ b/modules/OutboundEmailAccounts/vardefs.php @@ -38,25 +38,27 @@ * reasonably feasible for technical reasons, the Appropriate Legal Notices must * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ -$dictionary["OutboundEmailAccounts"] = array( +$dictionary["OutboundEmailAccounts"] = [ 'table' => 'outbound_email', 'audited' => true, - 'inline_edit' => true, - 'duplicate_merge' => true, - 'fields' => - array( - 'id' => - array( + 'inline_edit' => false, + 'massupdate' => false, + 'duplicate_merge' => false, + 'fields' => [ + 'id' => [ 'name' => 'id', 'vname' => 'LBL_ID', 'type' => 'id', 'required' => true, - 'reportable' => true, 'comment' => 'Unique identifier', + 'reportable' => false, + 'massupdate' => false, 'inline_edit' => false, - ), - 'name' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'name' => [ 'name' => 'name', 'vname' => 'LBL_NAME', 'type' => 'name', @@ -65,52 +67,121 @@ $dictionary["OutboundEmailAccounts"] = array( 'len' => 255, 'unified_search' => true, 'full_text_search' => - array( - 'boost' => 3, - ), + [ + 'boost' => 3, + ], 'required' => true, 'importable' => 'required', 'duplicate_merge' => 'enabled', 'merge_filter' => 'selected', - ), - 'type' => array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'type' => [ 'name' => 'type', 'vname' => 'LBL_TYPE', - 'type' => 'varchar', + 'type' => 'enum', 'len' => 15, + 'display' => 'readonly', + 'options' => 'dom_outbound_email_account_types', 'required' => true, 'default' => 'user', 'reportable' => false, - ), - 'user_id' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'user_id' => [ 'name' => 'user_id', 'vname' => 'LBL_USER_ID', 'type' => 'id', - 'required' => true, + 'required' => false, 'reportable' => false, - ), - 'smtp_from_name' => - array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'owner' => [ + 'name' => 'owner', + 'type' => 'link', + 'relationship' => 'outbound_email_owner_user', + 'link_type' => 'one', + 'source' => 'non-db', + 'vname' => 'LBL_OWNER', + 'duplicate_merge' => 'disabled', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'owner_name' => [ + 'name' => 'owner_name', + 'rname' => 'name', + 'id_name' => 'user_id', + 'vname' => 'LBL_OWNER_NAME', + 'join_name' => 'owner', + 'type' => 'relate', + 'link' => 'owner', + 'table' => 'users', + 'isnull' => 'true', + 'module' => 'Users', + 'dbType' => 'varchar', + 'len' => '255', + 'source' => 'non-db', + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'smtp_from_name' => [ 'name' => 'smtp_from_name', 'vname' => 'LBL_SMTP_FROM_NAME', 'type' => 'varchar', - ), - 'smtp_from_addr' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'smtp_from_addr' => [ 'name' => 'smtp_from_addr', 'vname' => 'LBL_SMTP_FROM_ADDR', 'type' => 'varchar', - ), - 'mail_sendtype' => array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_sendtype' => [ 'name' => 'mail_sendtype', 'vname' => 'LBL_MAIL_SENDTYPE', 'type' => 'varchar', 'len' => 8, 'required' => true, - 'default' => 'smtp', + 'default' => 'SMTP', 'reportable' => false, - ), - 'mail_smtptype' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtptype' => [ 'name' => 'mail_smtptype', 'vname' => 'LBL_MAIL_SENDTYPE', 'type' => 'varchar', @@ -118,45 +189,80 @@ $dictionary["OutboundEmailAccounts"] = array( 'required' => true, 'default' => 'other', 'reportable' => false, - ), - 'mail_smtpserver' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtpserver' => [ 'name' => 'mail_smtpserver', 'vname' => 'LBL_MAIL_SMTPSERVER', 'type' => 'varchar', 'len' => 100, 'required' => false, 'reportable' => false, - ), - 'mail_smtpport' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtpport' => [ 'name' => 'mail_smtpport', 'vname' => 'LBL_MAIL_SMTPPORT', 'type' => 'varchar', 'len' => 5, - 'default' => 0, + 'default' => 25, 'reportable' => false, - ), - 'mail_smtpuser' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtpuser' => [ 'name' => 'mail_smtpuser', 'vname' => 'LBL_MAIL_SMTPUSER', 'type' => 'varchar', 'len' => 100, 'reportable' => false, - ), - 'mail_smtppass' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtppass' => [ 'name' => 'mail_smtppass', 'vname' => 'LBL_MAIL_SMTPPASS', - 'type' => 'varchar', + 'type' => 'password', + 'dbType' => 'varchar', 'len' => 100, + 'display' => 'writeonly', + 'required' => false, + 'sensitive' => true, + 'api-visible' => false, 'reportable' => false, - ), - 'mail_smtpauth_req' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtpauth_req' => [ 'name' => 'mail_smtpauth_req', 'vname' => 'LBL_MAIL_SMTPAUTH_REQ', 'type' => 'bool', 'default' => 0, 'reportable' => false, - ), - 'mail_smtpssl' => array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'mail_smtpssl' => [ 'name' => 'mail_smtpssl', 'vname' => 'LBL_MAIL_SMTPSSL', 'type' => 'enum', @@ -164,9 +270,13 @@ $dictionary["OutboundEmailAccounts"] = array( 'len' => 1, 'default' => 0, 'reportable' => false, - ), - 'date_entered' => - array( + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'date_entered' => [ 'name' => 'date_entered', 'vname' => 'LBL_DATE_ENTERED', 'type' => 'datetime', @@ -174,10 +284,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'comment' => 'Date record created', 'enable_range_search' => true, 'options' => 'date_range_search_dom', + 'reportable' => false, + 'massupdate' => false, 'inline_edit' => false, - ), - 'date_modified' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'date_modified' => [ 'name' => 'date_modified', 'vname' => 'LBL_DATE_MODIFIED', 'type' => 'datetime', @@ -185,10 +299,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'comment' => 'Date record last modified', 'enable_range_search' => true, 'options' => 'date_range_search_dom', + 'reportable' => false, + 'massupdate' => false, 'inline_edit' => false, - ), - 'modified_user_id' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'modified_user_id' => [ 'name' => 'modified_user_id', 'rname' => 'user_name', 'id_name' => 'modified_user_id', @@ -200,11 +318,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'dbType' => 'id', 'reportable' => true, 'comment' => 'User who last modified record', + 'reportable' => false, 'massupdate' => false, 'inline_edit' => false, - ), - 'modified_by_name' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'modified_by_name' => [ 'name' => 'modified_by_name', 'vname' => 'LBL_MODIFIED_NAME', 'type' => 'relate', @@ -218,9 +339,11 @@ $dictionary["OutboundEmailAccounts"] = array( 'duplicate_merge' => 'disabled', 'massupdate' => false, 'inline_edit' => false, - ), - 'created_by' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'created_by' => [ 'name' => 'created_by', 'rname' => 'user_name', 'id_name' => 'modified_user_id', @@ -231,11 +354,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'dbType' => 'id', 'group' => 'created_by_name', 'comment' => 'User who created record', + 'reportable' => false, 'massupdate' => false, 'inline_edit' => false, - ), - 'created_by_name' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'created_by_name' => [ 'name' => 'created_by_name', 'vname' => 'LBL_CREATED', 'type' => 'relate', @@ -250,18 +376,24 @@ $dictionary["OutboundEmailAccounts"] = array( 'importable' => 'false', 'massupdate' => false, 'inline_edit' => false, - ), - 'deleted' => - array( + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'deleted' => [ 'name' => 'deleted', 'vname' => 'LBL_DELETED', 'type' => 'bool', 'default' => '0', 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, 'comment' => 'Record deletion indicator', - ), - 'created_by_link' => - array( + ], + 'created_by_link' => [ 'name' => 'created_by_link', 'type' => 'link', 'relationship' => 'outbound_email_created_by', @@ -270,9 +402,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'module' => 'Users', 'bean_name' => 'User', 'source' => 'non-db', - ), - 'modified_user_link' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'modified_user_link' => [ 'name' => 'modified_user_link', 'type' => 'link', 'relationship' => 'outbound_email_modified_user', @@ -281,9 +418,14 @@ $dictionary["OutboundEmailAccounts"] = array( 'module' => 'Users', 'bean_name' => 'User', 'source' => 'non-db', - ), - 'assigned_user_id' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'assigned_user_id' => [ 'name' => 'assigned_user_id', 'rname' => 'user_name', 'id_name' => 'assigned_user_id', @@ -292,29 +434,36 @@ $dictionary["OutboundEmailAccounts"] = array( 'type' => 'relate', 'table' => 'users', 'module' => 'Users', - 'reportable' => true, 'isnull' => 'false', 'dbType' => 'id', - 'audited' => true, 'comment' => 'User ID assigned to record', 'duplicate_merge' => 'disabled', - ), - 'assigned_user_name' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'assigned_user_name' => [ 'name' => 'assigned_user_name', 'link' => 'assigned_user_link', 'vname' => 'LBL_ASSIGNED_TO_NAME', 'rname' => 'user_name', 'type' => 'relate', - 'reportable' => false, 'source' => 'non-db', 'table' => 'users', 'id_name' => 'assigned_user_id', 'module' => 'Users', 'duplicate_merge' => 'disabled', - ), - 'assigned_user_link' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'assigned_user_link' => [ 'name' => 'assigned_user_link', 'type' => 'link', 'relationship' => 'outbound_email_assigned_user', @@ -327,91 +476,79 @@ $dictionary["OutboundEmailAccounts"] = array( 'rname' => 'user_name', 'id_name' => 'assigned_user_id', 'table' => 'users', - ), - 'password_change' => - array( + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + 'password_change' => [ 'required' => false, 'name' => 'password_change', 'vname' => 'LBL_PASSWORD', 'type' => 'function', 'source' => 'non-db', - 'massupdate' => 0, 'no_default' => false, 'comments' => '', 'help' => '', - 'importable' => 'true', 'duplicate_merge' => 'disabled', 'duplicate_merge_dom_value' => '0', 'audited' => false, - 'inline_edit' => true, - 'reportable' => true, - 'unified_search' => false, 'merge_filter' => 'disabled', 'len' => '255', 'size' => '20', - 'function' => array( + 'function' => [ 'name' => 'OutboundEmailAccounts::getPasswordChange', 'returns' => 'html', 'include' => 'modules/OutboundEmailAccounts/OutboundEmailAccounts.php' - ), - ), - 'email_provider_chooser' => array( - 'required' => false, - 'name' => 'email_provider_chooser', - 'vname' => 'LBL_CHOOSE_EMAIL_PROVIDER', - 'type' => 'function', - 'source' => 'non-db', - 'massupdate' => 0, - 'no_default' => false, - 'comments' => '', - 'help' => '', - 'importable' => 'true', - 'duplicate_merge' => 'disabled', - 'duplicate_merge_dom_value' => '0', - 'audited' => false, - 'inline_edit' => true, - 'reportable' => true, + ], + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, 'unified_search' => false, - 'merge_filter' => 'disabled', - 'len' => '255', - 'size' => '20', - 'function' => array( - 'name' => 'OutboundEmailAccounts::getEmailProviderChooser', - 'returns' => 'html', - 'include' => 'modules/OutboundEmailAccounts/OutboundEmailAccounts.php' - ), - ), - 'sent_test_email_btn' => array( + ], + 'sent_test_email_btn' => [ 'required' => false, 'name' => 'sent_test_email_btn', 'vname' => 'LBL_SEND_TEST_EMAIL', 'type' => 'function', 'source' => 'non-db', - 'massupdate' => 0, 'no_default' => false, 'comments' => '', 'help' => '', - 'importable' => 'true', 'duplicate_merge' => 'disabled', 'duplicate_merge_dom_value' => '0', 'audited' => false, - 'inline_edit' => true, - 'reportable' => true, - 'unified_search' => false, 'merge_filter' => 'disabled', 'len' => '255', 'size' => '20', - 'function' => array( + 'function' => [ 'name' => 'OutboundEmailAccounts::getSendTestEmailBtn', 'returns' => 'html', 'include' => 'modules/OutboundEmailAccounts/OutboundEmailAccounts.php' - ), - ), - ), - 'relationships' => - array( - 'outbound_email_modified_user' => - array( + ], + 'reportable' => false, + 'massupdate' => false, + 'inline_edit' => false, + 'importable' => false, + 'exportable' => false, + 'unified_search' => false, + ], + ], + 'relationships' => [ + 'outbound_email_owner_user' => [ + 'lhs_module' => 'Users', + 'lhs_table' => 'users', + 'lhs_key' => 'id', + 'rhs_module' => 'OutboundEmailAccounts', + 'rhs_table' => 'outbound_email', + 'rhs_key' => 'user_id', + 'relationship_type' => 'one-to-many' + ], + 'outbound_email_modified_user' => [ 'lhs_module' => 'Users', 'lhs_table' => 'users', 'lhs_key' => 'id', @@ -419,9 +556,8 @@ $dictionary["OutboundEmailAccounts"] = array( 'rhs_table' => 'outbound_email', 'rhs_key' => 'modified_user_id', 'relationship_type' => 'one-to-many', - ), - 'outbound_email_created_by' => - array( + ], + 'outbound_email_created_by' => [ 'lhs_module' => 'Users', 'lhs_table' => 'users', 'lhs_key' => 'id', @@ -429,9 +565,8 @@ $dictionary["OutboundEmailAccounts"] = array( 'rhs_table' => 'outbound_email', 'rhs_key' => 'created_by', 'relationship_type' => 'one-to-many', - ), - 'outbound_email_assigned_user' => - array( + ], + 'outbound_email_assigned_user' => [ 'lhs_module' => 'Users', 'lhs_table' => 'users', 'lhs_key' => 'id', @@ -439,21 +574,20 @@ $dictionary["OutboundEmailAccounts"] = array( 'rhs_table' => 'outbound_email', 'rhs_key' => 'assigned_user_id', 'relationship_type' => 'one-to-many', - ), - ), + ], + ], 'optimistic_locking' => true, - 'unified_search' => true, - 'indices' => - array( - 'id' => - array( + 'unified_search' => false, + 'indices' => [ + 'id' => [ 'name' => 'outbound_email_pk', 'type' => 'primary', - 'fields' => - array( + 'fields' => [ 0 => 'id', - ), - ), - ), + ], + ], + ], 'custom_fields' => false, -); +]; + +VardefManager::createVardef('OutboundEmailAccounts', 'OutboundEmailAccounts', ['security_groups']); diff --git a/modules/OutboundEmailAccounts/views/view.detail.php b/modules/OutboundEmailAccounts/views/view.detail.php new file mode 100644 index 000000000..389daaf2e --- /dev/null +++ b/modules/OutboundEmailAccounts/views/view.detail.php @@ -0,0 +1,56 @@ +dv->ss->assign('is_admin', is_admin($current_user)); + parent::display(); + } +} diff --git a/modules/OutboundEmailAccounts/views/view.edit.php b/modules/OutboundEmailAccounts/views/view.edit.php new file mode 100644 index 000000000..f90ee51f3 --- /dev/null +++ b/modules/OutboundEmailAccounts/views/view.edit.php @@ -0,0 +1,57 @@ +ev->ss->assign('is_admin', is_admin($current_user)); + parent::display(); + } +} diff --git a/modules/OutboundEmailAccounts/views/view.list.php b/modules/OutboundEmailAccounts/views/view.list.php new file mode 100644 index 000000000..a676431be --- /dev/null +++ b/modules/OutboundEmailAccounts/views/view.list.php @@ -0,0 +1,57 @@ +params['export'] = false; + $this->lv->displayEmptyDataMessages = false; + } +} diff --git a/modules/ProspectLists/TargetListUpdate.php b/modules/ProspectLists/TargetListUpdate.php index 17a90d8f0..4bae94f1a 100755 --- a/modules/ProspectLists/TargetListUpdate.php +++ b/modules/ProspectLists/TargetListUpdate.php @@ -63,24 +63,12 @@ if ($_REQUEST['select_entire_list'] == '1') { $mass = new MassUpdate(); $mass->generateSearchWhere($_REQUEST['module'], $_REQUEST['current_query_by_page']); $ret_array = create_export_query_relate_link_patch($_REQUEST['module'], $mass->searchFields, $mass->where_clauses); - /* BEGIN - SECURITY GROUPS */ - //need to hijack the $ret_array['where'] of securitygroup required - if ($focus->bean_implements('ACL') && ACLController::requireSecurityGroup($focus->module_dir, 'list')) { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $owner_where = $focus->getOwnerWhere($current_user->id); - $group_where = SecurityGroup::getGroupWhere($focus->table_name, $focus->module_dir, $current_user->id); - if (!empty($owner_where)) { - if (empty($ret_array['where'])) { - $ret_array['where'] = " (". $owner_where." or ".$group_where.") "; - } else { - $ret_array['where'] .= " AND (". $owner_where." or ".$group_where.") "; - } - } else { - $ret_array['where'] .= ' AND '. $group_where; - } + + $accessWhere = $focus->buildAccessWhere('list'); + if (!empty($accessWhere)) { + $ret_array['where'] .= empty($ret_array['where']) ? $accessWhere : ' AND ' . $accessWhere; } - /* END - SECURITY GROUPS */ + $query = $focus->create_export_query($order_by, $ret_array['where'], $ret_array['join']); $result = DBManagerFactory::getInstance()->query($query, true); $uids = array(); diff --git a/modules/Studio/parsers/StudioParser.php b/modules/Studio/parsers/StudioParser.php index 40ccc9f15..ccf59255d 100755 --- a/modules/Studio/parsers/StudioParser.php +++ b/modules/Studio/parsers/StudioParser.php @@ -161,7 +161,7 @@ class StudioParser EOQ; } - public function buildImageButtons($buttons, $horizontal=true) + public static function buildImageButtons($buttons, $horizontal=true) { $text = ''; foreach ($buttons as $button) { @@ -214,7 +214,7 @@ EOQ; public function getFormButtons() { $buttons = $this->generateButtons(); - return $this->buildImageButtons($buttons); + return self::buildImageButtons($buttons); } public function getForm() { diff --git a/modules/Studio/wizards/EditDropDownWizard.php b/modules/Studio/wizards/EditDropDownWizard.php index 1db6f7be3..c81b9370c 100755 --- a/modules/Studio/wizards/EditDropDownWizard.php +++ b/modules/Studio/wizards/EditDropDownWizard.php @@ -66,7 +66,7 @@ class EditDropDownWizard extends StudioWizard { // return array('EditDropdown'=>$GLOBALS['mod_strings']['LBL_SW_EDIT_DROPDOWNS'], 'CreateDropdown'=>$GLOBALS['mod_strings']['LBL_ED_CREATE_DROPDOWN'] ); } - + public function process($option) { switch ($option) { @@ -75,14 +75,14 @@ class EditDropDownWizard extends StudioWizard require_once('modules/Studio/DropDowns/EditView.php'); break; case 'SaveDropDown': - DropDownHelper::saveDropDown($_REQUEST); + (new DropDownHelper())->saveDropDown($_REQUEST); require_once('modules/Studio/DropDowns/EditView.php'); break; default: parent::process($option); } } - + public function display() { // override the parent display - don't display any wizard stuff diff --git a/modules/Studio/wizards/RenameModules.php b/modules/Studio/wizards/RenameModules.php index 4aa83f482..c6bff0a18 100755 --- a/modules/Studio/wizards/RenameModules.php +++ b/modules/Studio/wizards/RenameModules.php @@ -781,7 +781,7 @@ class RenameModules $search = call_user_func($modifier, $search); $replace = call_user_func($modifier, $replace); } - + // Bug 47957 // If nothing was replaced - try to replace original string $result = ''; @@ -805,25 +805,25 @@ class RenameModules { $GLOBALS['log']->debug('Begining to save app string entries'); //Save changes to the moduleList app string entry - DropDownHelper::saveDropDown($_REQUEST); + (new DropDownHelper())->saveDropDown($_REQUEST); //Save changes to the moduleListSingular app string entry $newParams = array(); $newParams['dropdown_name'] = 'moduleListSingular'; $newParams['dropdown_lang'] = isset($_REQUEST['dropdown_lang']) ? $_REQUEST['dropdown_lang'] : ''; $newParams['use_push'] = true; - DropDownHelper::saveDropDown($this->createModuleListSingularPackage($newParams, $this->changedModules)); + (new DropDownHelper())->saveDropDown($this->createModuleListSingularPackage($newParams, $this->changedModules)); //Save changes to the "*type_display*" app_list_strings entry. global $app_list_strings; - + $typeDisplayList = getTypeDisplayList(); - + foreach (array_keys($this->changedModules)as $moduleName) { foreach ($typeDisplayList as $typeDisplay) { if (isset($app_list_strings[$typeDisplay]) && isset($app_list_strings[$typeDisplay][$moduleName])) { $newParams['dropdown_name'] = $typeDisplay; - DropDownHelper::saveDropDown($this->createModuleListSingularPackage($newParams, array($moduleName => $this->changedModules[$moduleName]))); + (new DropDownHelper())->saveDropDown($this->createModuleListSingularPackage($newParams, array($moduleName => $this->changedModules[$moduleName]))); } } } diff --git a/modules/Surveys/Menu.php b/modules/Surveys/Menu.php index a09f36c6e..22aec8478 100644 --- a/modules/Surveys/Menu.php +++ b/modules/Surveys/Menu.php @@ -61,3 +61,12 @@ if (ACLController::checkAccess('Surveys', 'list', true)) { 'Surveys' ); } +if (ACLController::checkAccess('SurveyResponses', 'list', true)) { + $module_menu[] = + array( + "index.php?module=SurveyResponses&action=index&return_module=Surveys&return_action=index", + translate('LNK_LIST', 'SurveyResponses'), + "List", + 'SurveyResponses' + ); +} diff --git a/modules/Users/Menu.php b/modules/Users/Menu.php index 4f7adcfea..c6ce03c50 100755 --- a/modules/Users/Menu.php +++ b/modules/Users/Menu.php @@ -66,3 +66,7 @@ if (is_admin($current_user)) { $module_menu[] = array("index.php?module=ACLRoles&action=index&return_module=SecurityGroups&return_action=ListView", $admin_mod_strings['LBL_MANAGE_ROLES_TITLE'], "Role_Management"); $module_menu[] = array("index.php?module=SecurityGroups&action=config&return_module=SecurityGroups&return_action=ListView", $admin_mod_strings['LBL_CONFIG_SECURITYGROUPS_TITLE'], "Security_Suite_Settings"); } + +$module_menu[]= array("index.php?module=InboundEmail&action=index", $mod_strings['LNK_LIST_INBOUND_EMAIL_ACCOUNTS'],"List"); +$module_menu[]= array("index.php?module=OutboundEmailAccounts&action=index", $mod_strings['LNK_LIST_OUTBOUND_EMAIL_ACCOUNTS'],"List"); +$module_menu[]= array("index.php?module=ExternalOAuthConnection&action=index", $mod_strings['LNK_EXTERNAL_OAUTH_CONNECTIONS'],"List"); diff --git a/modules/Users/language/en_us.lang.php b/modules/Users/language/en_us.lang.php index 89450ebb5..c23aa8df8 100755 --- a/modules/Users/language/en_us.lang.php +++ b/modules/Users/language/en_us.lang.php @@ -691,4 +691,8 @@ $mod_strings = array( 'LBL_GSYNC_CAL' => 'Enable Calendar Sync', // END Google Token/Synchronization settings + 'LNK_LIST_OUTBOUND_EMAIL_ACCOUNTS' => 'Outbound Email Accounts', + 'LNK_LIST_INBOUND_EMAIL_ACCOUNTS' => 'Inbound Email Accounts', + 'LNK_EXTERNAL_OAUTH_CONNECTIONS' => 'External OAuth Connections', + ); // END STRINGS DEFS diff --git a/modules/Users/tpls/EditViewFooter.tpl b/modules/Users/tpls/EditViewFooter.tpl index 936fff79f..eb48183c5 100755 --- a/modules/Users/tpls/EditViewFooter.tpl +++ b/modules/Users/tpls/EditViewFooter.tpl @@ -235,8 +235,10 @@  {sugar_help text=$MOD.LBL_RECEIVE_NOTIFICATIONS_TEXT} diff --git a/php_version.php b/php_version.php index 976a687ae..7c64b5be3 100644 --- a/php_version.php +++ b/php_version.php @@ -4,7 +4,7 @@ if (!defined('sugarEntry') || !sugarEntry) { } // The absolute minimum version on which to install SuiteCRM -define('SUITECRM_PHP_MIN_VERSION', '7.2.9'); +define('SUITECRM_PHP_MIN_VERSION', '7.4.0'); // The minimum recommended version on which to install SuiteCRM -define('SUITECRM_PHP_REC_VERSION', '7.3.0'); +define('SUITECRM_PHP_REC_VERSION', '7.4.0'); diff --git a/service/v3_1/SugarWebServiceUtilv3_1.php b/service/v3_1/SugarWebServiceUtilv3_1.php index 01f3dd866..d20427688 100755 --- a/service/v3_1/SugarWebServiceUtilv3_1.php +++ b/service/v3_1/SugarWebServiceUtilv3_1.php @@ -401,18 +401,7 @@ class SugarWebServiceUtilv3_1 extends SugarWebServiceUtilv3 $show_deleted = 1; } $order_by=$seed->process_order_by($order_by, null); - - if ($seed->bean_implements('ACL') && ACLController::requireOwner($seed->module_dir, 'list')) { - global $current_user; - $owner_where = $seed->getOwnerWhere($current_user->id); - if (!empty($owner_where)) { - if (empty($where)) { - $where = $owner_where; - } else { - $where .= ' AND '. $owner_where; - } - } - } + $params = array(); if ($favorites) { $params['favorites'] = true; diff --git a/soap/SoapSugarUsers.php b/soap/SoapSugarUsers.php index 1feb9fd3f..05e045f07 100755 --- a/soap/SoapSugarUsers.php +++ b/soap/SoapSugarUsers.php @@ -1358,22 +1358,11 @@ function get_relationships($session, $module_name, $module_id, $related_module, $sql .= " AND ( {$related_module_query} )"; } - /* BEGIN - SECURITY GROUPS */ - global $current_user; - if($mod->bean_implements('ACL') && ACLController::requireSecurityGroup($mod->module_dir, 'list') ) - { - require_once('modules/SecurityGroups/SecurityGroup.php'); - global $current_user; - $owner_where = $mod->getOwnerWhere($current_user->id); - $group_where = SecurityGroup::getGroupWhere($mod->table_name,$mod->module_dir,$current_user->id); - if(!empty($owner_where)){ - $sql .= " AND (". $owner_where." or ".$group_where.") "; - } else { - $sql .= ' AND '. $group_where; - } - } - /* END - SECURITY GROUPS */ - + $accessWhere = $mod->buildAccessWhere('list'); + if (!empty($accessWhere)) { + $sql .= ' AND ' . $accessWhere; + } + $result = $related_mod->db->query($sql); while ($row = $related_mod->db->fetchByAssoc($result)) { $list[] = $row['id']; diff --git a/suitecrm_version.php b/suitecrm_version.php index a83319416..6be55da11 100755 --- a/suitecrm_version.php +++ b/suitecrm_version.php @@ -3,5 +3,5 @@ if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } -$suitecrm_version = '7.12.8'; -$suitecrm_timestamp = '2022-08-10 12:00:00'; +$suitecrm_version = '7.13.0'; +$suitecrm_timestamp = '2022-12-20 12:00:00'; diff --git a/tests/unit/phpunit/includes/utils/file_utilsTest.php b/tests/unit/phpunit/includes/utils/file_utilsTest.php index 5d7630eb3..a633fd336 100644 --- a/tests/unit/phpunit/includes/utils/file_utilsTest.php +++ b/tests/unit/phpunit/includes/utils/file_utilsTest.php @@ -174,6 +174,7 @@ class file_utilsTest extends SuitePHPUnitFrameworkTestCase 'EmailTemplates' => 'EmailTemplates', 'EmailText' => 'EmailText', 'Employees' => 'Employees', + 'ExternalOAuthConnection' => 'ExternalOAuthConnection', 'Favorites' => 'Favorites', 'FP_events' => 'FP_events', 'FP_Event_Locations' => 'FP_Event_Locations', diff --git a/tests/unit/phpunit/modules/ACLRoles/ACLRoleTest.php b/tests/unit/phpunit/modules/ACLRoles/ACLRoleTest.php index 20da0694a..6b243bce5 100644 --- a/tests/unit/phpunit/modules/ACLRoles/ACLRoleTest.php +++ b/tests/unit/phpunit/modules/ACLRoles/ACLRoleTest.php @@ -78,14 +78,12 @@ class ACLRoleTest extends SuitePHPUnitFrameworkTestCase public function testgetUserRoleNames(): void { - $aclRole = BeanFactory::newBean('ACLRoles'); - //test with empty value - $result = $aclRole->getUserRoleNames(''); + $result = ACLRole::getUserRoleNames(''); self::assertIsArray($result); //test with non empty but non existing role id value - $result = $aclRole->getUserRoleNames('1'); + $result = ACLRole::getUserRoleNames('1'); self::assertIsArray($result); } diff --git a/tests/unit/phpunit/modules/Emails/EmailTest.php b/tests/unit/phpunit/modules/Emails/EmailTest.php index eff56598d..9a4b007ed 100644 --- a/tests/unit/phpunit/modules/Emails/EmailTest.php +++ b/tests/unit/phpunit/modules/Emails/EmailTest.php @@ -65,7 +65,8 @@ class EmailTest extends SuitePHPUnitFrameworkTestCase // handle non-gmail sent folder (mailbox is set) $mailer = new SugarPHPMailerMock(); $ie = BeanFactory::newBean('InboundEmail'); - $ieId = $ie->save(); + $ie->save(); + $ieId = $ie->id; self::assertTrue((bool)$ieId); $_REQUEST['inbound_email_id'] = $ieId; $email = new EmailMock(); diff --git a/tests/unit/phpunit/modules/InboundEmail/InboundEmailTest.php b/tests/unit/phpunit/modules/InboundEmail/InboundEmailTest.php index 8ea4605fb..a9714de72 100644 --- a/tests/unit/phpunit/modules/InboundEmail/InboundEmailTest.php +++ b/tests/unit/phpunit/modules/InboundEmail/InboundEmailTest.php @@ -136,7 +136,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('setTimeout', [1, 15], [true]); $fake->add('setTimeout', [2, 15], [true]); $fake->add('setTimeout', [3, 15], [true]); - $fake->add('open', ["{:/service=/ssl/tls/validate-cert/secure}", null, null, 0, 0, []], [function () { + $fake->add('open', ["{:143/service=imap/ssl/tls/validate-cert/secure}", null, null, 0, 0, []], [function () { return tempFileWithMode('wb+'); }]); $fake->add('getLastError', null, ['Too many login failures']); @@ -194,7 +194,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('setTimeout', [2, 60], [true]); $fake->add('setTimeout', [3, 60], [true]); $fake->add('getErrors', null, [false]); - $fake->add('open', ["{:/service=/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { + $fake->add('open', ["{:143/service=imap/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { return tempFileWithMode('wb+'); }]); $fake->add('getLastError', null, ["SECURITY PROBLEM: insecure server advertised AUTH=PLAIN"]); @@ -230,7 +230,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('setTimeout', [2, 60], [true]); $fake->add('setTimeout', [3, 60], [true]); $fake->add('getErrors', null, [false]); - $fake->add('open', ["{:/service=/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { + $fake->add('open', ["{:143/service=imap/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { return tempFileWithMode('wb+'); }]); $fake->add('getLastError', null, ['Too many login failures']); @@ -238,12 +238,12 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('getConnection', null, [function () { return tempFileWithMode('wb+'); }]); - $fake->add('getMailboxes', ['{:/service=/notls/novalidate-cert/secure}', '*'], [[]]); + $fake->add('getMailboxes', ['{:143/service=imap/notls/novalidate-cert/secure}', '*'], [[]]); $fake->add('close', null, [null]); $exp = [ 'good' => [], - 'bad' => ['both-secure' => '{:/service=/notls/novalidate-cert/secure}'], + 'bad' => ['both-secure' => '{:143/service=imap/notls/novalidate-cert/secure}'], 'err' => ['both-secure' => 'Login or Password Incorrect'], ]; @@ -275,7 +275,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('setTimeout', [2, 60], [true]); $fake->add('setTimeout', [3, 60], [true]); $fake->add('getErrors', null, [false]); - $fake->add('open', ["{:/service=/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { + $fake->add('open', ["{:143/service=imap/notls/novalidate-cert/secure}", null, null, 0, 0, []], [function () { return tempFileWithMode('wb+'); }]); $fake->add('getLastError', null, [false]); @@ -316,7 +316,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $fake->add('setTimeout', [2, 60], [true]); $fake->add('setTimeout', [3, 60], [true]); $fake->add('getErrors', null, [false]); - $fake->add('open', ["{:/service=/ssl/tls/validate-cert/secure}", null, null, 0, 0, []], [function () { + $fake->add('open', ["{:143/service=imap/ssl/tls/validate-cert/secure}", null, null, 0, 0, []], [function () { return tempFileWithMode('wb+'); }]); $fake->add('getLastError', null, [false]); @@ -2185,9 +2185,9 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase { $inboundEmail = BeanFactory::newBean('InboundEmail'); - self::assertEquals('{:/service=}', $inboundEmail->getConnectString()); //test with default options - self::assertEquals('{:/service=mail.google.com}INBOX', $inboundEmail->getConnectString('mail.google.com', 'INBOX'));//test with includeMbox true - self::assertEquals('{:/service=mail.google.com}', $inboundEmail->getConnectString('mail.google.com', 'INBOX', false));//test with includeMbox false + self::assertEquals('{:143/service=imap}', $inboundEmail->getConnectString()); //test with default options + self::assertEquals('{:143/service=imapmail.google.com}INBOX', $inboundEmail->getConnectString('mail.google.com', 'INBOX'));//test with includeMbox true + self::assertEquals('{:143/service=imapmail.google.com}', $inboundEmail->getConnectString('mail.google.com', 'INBOX', false));//test with includeMbox false } public function testdisconnectMailserver(): void @@ -2213,7 +2213,7 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase //test with test and force true $result = $inboundEmail->connectMailserver(true, true); - self::assertEquals("Can't open mailbox {:/service=}: invalid remote specification

Please check your settings and try again.", $result); + self::assertEquals("Can't open mailbox {:143/service=imap}: invalid remote specification

Please check your settings and try again.", $result); } public function testcheckImap(): void @@ -2266,14 +2266,22 @@ class InboundEmailTest extends SuitePHPUnitFrameworkTestCase $result = $inboundEmail->get_list_view_data(); $expected = array( - 'DELETED' => '0', - 'STATUS' => 'Active', - 'DELETE_SEEN' => '0', - 'MAILBOX_TYPE' => 'INBOX', - 'IS_PERSONAL' => '0', - 'MAILBOX_TYPE_NAME' => null, - 'GLOBAL_PERSONAL_STRING' => 'group', - ); + 'DELETED' => '0', + 'STATUS' => 'Active', + 'DELETE_SEEN' => '0', + 'MAILBOX_TYPE' => 'INBOX', + 'IS_PERSONAL' => '0', + 'MAILBOX_TYPE_NAME' => null, + 'GLOBAL_PERSONAL_STRING' => 'group', + 'PORT' => '143', + 'AUTH_TYPE' => 'Basic Auth', + 'PROTOCOL' => 'imap', + 'IS_SSL' => '0', + 'IS_DEFAULT' => '0', + 'IS_AUTO_IMPORT' => '0', + 'IS_CREATE_CASE' => '0', + 'ALLOW_OUTBOUND_GROUP_USAGE' => '0', + ); self::assertIsArray($result); self::assertEquals($expected, $result); diff --git a/tests/unit/phpunit/modules/SecurityGroups/SecurityGroupTest.php b/tests/unit/phpunit/modules/SecurityGroups/SecurityGroupTest.php index 33624dc65..7784451df 100644 --- a/tests/unit/phpunit/modules/SecurityGroups/SecurityGroupTest.php +++ b/tests/unit/phpunit/modules/SecurityGroups/SecurityGroupTest.php @@ -274,6 +274,7 @@ class SecurityGroupTest extends SuitePHPUnitFrameworkTestCase 'Cases', 'AOS_Products', 'Opportunities', + 'OutboundEmailAccounts', 'FP_Event_Locations', 'Tasks', 'jjwg_Markers', @@ -295,8 +296,10 @@ class SecurityGroupTest extends SuitePHPUnitFrameworkTestCase 'AOS_PDF_Templates', 'Calls', 'Accounts', + 'InboundEmail', 'Leads', 'Emails', + 'ExternalOAuthConnection', 'ProjectTask', 'Project', 'FP_events', diff --git a/themes/suite8/include/ListView/ListViewGeneric.tpl b/themes/suite8/include/ListView/ListViewGeneric.tpl index 0095c0611..47de9d04c 100644 --- a/themes/suite8/include/ListView/ListViewGeneric.tpl +++ b/themes/suite8/include/ListView/ListViewGeneric.tpl @@ -192,7 +192,18 @@ {if isset($params.hide_header_label) && $params.hide_header_label == true} {else} {sugar_translate label=$params.label module=$pageData.bean.moduleDir} -    {/if} + {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy && $params.force_show_sort_direction} + {if $pageData.ordering.sortOrder == 'ASC'} + {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} + {capture assign="alt_sort"}{sugar_translate label='LBL_ALT_SORT_DESC'}{/capture} + + {else} + {capture assign="imageName"}arrow_up.{$arrowExt}{/capture} + {capture assign="alt_sort"}{sugar_translate label='LBL_ALT_SORT_ASC'}{/capture} + + {/if} + {/if} +    {/if} {/if} {/if} diff --git a/themes/suite8/modules/SavedSearch/SavedSearchForm.tpl b/themes/suite8/modules/SavedSearch/SavedSearchForm.tpl index 3424283a0..7fb54f5c4 100644 --- a/themes/suite8/modules/SavedSearch/SavedSearchForm.tpl +++ b/themes/suite8/modules/SavedSearch/SavedSearchForm.tpl @@ -46,20 +46,20 @@ {$columnChooser}
-

+
-
+
- + + + +