From 9d484f189aecef49b2928b042bf7945c355a2f14 Mon Sep 17 00:00:00 2001 From: Clemente Raposo Date: Wed, 21 Dec 2022 11:44:57 +0000 Subject: [PATCH] Squashed 'public/legacy/' changes from 60ccef0448..81ce7933fd 81ce7933fd SuiteCRM 7.13.0 Release 595d2bd92b Fix saveDropDown getting called statically a70c5d1b99 Fix message deletion after auto import f57b5ede02 Fix Inbound Email allow_outbound_group_usage filtering 9d38016f59 Remove external_oauth_providers config d5b4f0025c Remove provider field from ExternalOAuthConnection d457827c7d Change ExternalOAuthProvider to use open visibility by default for group records 3a51437d3a Add null check b49d6b79a0 Fix Inbound email tests 277f2c91cb Set default on inbound emails 261dae81c1 Add group to OutboundEmailAccounts menu 3e9dbdd5de Fix ExternalOAuthConnection list view pagination and checkboxes 36cbb6a90c Fix ExternalOAuthProvider list view pagination and checkboxes fe5f0a10d6 Fix OutboundEmailAccounts list view pagination and checkboxes b9217a36e2 Fix InboundEmail list view pagination and checkboxes 83bd0024a6 Allow selecting group InboundEmails in folder management f6a9111b25 Fix inbound email relationship definition 07b3110f8a Filter listview email displayed accounts according to preferences 6c49df527a Remove code that auto-selects a group email none is selected 243a0276af Fix preferences mail folder management dropdown e7838f0bd4 Fix owner field definition in OutboundEmailAccounts db9a52a27d Fix bounce mailbox type not being properly set 14d43e1efa Fix compose emails not sending f9e3677db8 Add optional connection string to InboundEmail module cef8b2bdb6 Allow setting placeholder for varchar on editview b2d669a022 Fix group_id not being saved properly on InboundEmail 8d25cc19d8 Fix: From not populating fae3d7b629 Fix folders not clearing subscription a8e9eba917 Fix signatures not being editable after being created 1762704a28 Fix menu label in ExternalOAuthConnections module e97ddb6af0 Fix inbound_emails_external_oauth_connections relationship 2cbebdd5a9 Replace External Oauth Provider sugar_config with module 89f2cee005 Add admin menu entry for ExternalOAuthProviders dbe91ffe26 Add External providers to ExternalOAuthConnector menu 63b944e033 Add ExternalOAuthProvider module 214f0d9008 Rename ExternalOAuthProvider to ExternalOAuthProviderConnector 972356fa90 Add stringmap field c701e4c6d5 Add json_decode smarty modifier 49024376be Update Travis build to remove php 7.3 test runs c23f0e57ac Update Minimum php version to php 7.4 b5914d782e Fix #9670 - Disabling the user profile option about notification of assignments does not work c2f260e477 Clear caches used by Inline Edition 89de5b620f Fix #99568: Ignore int length when comparing vardefs in newer MySQL versions fb50e2250e ElasticSearch Indexing batch error handling 32af678e4f Fix #9473 - Missing item "Survey" in campainglog_activity_type_dom a12f4f37be Fix #9638 - Elasticsearch issue with accented characters d85d72996d Fix #9499 - Add View Survey Responses Menu item dcd3ea1091 Fix #9574 - Update method to static for module renaming c56a5b2188 Fix #9646 - Display TinyMCE in step 4 of the campaigns form wizard d99439aca1 Fix #9717 - Security Suite Record Group selector doesn't appear when duplicating records ea0b42469a Add new ACL access logic hooks be0dec47dc Refactor module access query for extendability 8361cceb60 fix #9802 - Diagnostic checkboxes 44e4f47cca SuiteCRM 7.13.0-beta Release 0d6fef782e Fix #9839 - Make Inbound Email not auditable c0b93a5d2a Fix #9839 - Align Inbound and Outbound email menu labels 3883c2cb7e Fix #9839 - Inbound email assignment fields save and detail display 0a4fbfa2a9 Fix #9839 - Inbound email filters not displaying 6fefdd79a0 Fix #9839 - OutboundEmailAccounts list filtering 3dcab78053 Fix #9839 - Hide sort fields in search modal if none is sortable 95d099d3b4 Fix #9839 - Always sort emails by date received aff7965abd Fix #9839 - Add showing sort direction when field is not manually sortable e3f7d02a65 Fix #9839 - Use previously selected email mailbox when using the navigation links 01c96bf15c Fix #9839 - Add Imap2Handler to use imap2 lib d8dee51d94 Fix #9839 - Move email list retrieval from InboundEmail to ImapHandler f798b9af4a Fix #9839 - Update InboundEmail calls to mailparser to send 2nd argument 68a8fa97dd Fix #9839 - Move stream validity check to ImapHandlers fb4f1c81ec Fix #9839 - Fix InboundEmail pagination totals dc26951a35 Fix #9839 - Use previously selected email mailbox when using the navigation links cca80e945b Fix #9839 - Move case macro input to Case module settings admin menu 0fb1075aa2 Fix #9839 - Fix undefined error in listview displayEmptyDataMessages 990e98e4bc Fix #9839 - Add support to test oauth connection in InboundEmail 7259c9ce79 Fix #9839 - Allow refreshing ExternalOAuthConnection tokens 49c5c0ee09 Fix #9839 - Make ExternalOAuthConnection sensitive fields db_encrypted 17bbeb3683 Fix #9839 - Allow admins to list Group and personal ExternalOAuthConnection 0f559a6223 Fix #9839 - Allow encrypting fields on db by setting db_encrypted 471792d75f Fix #9839 - Apply acl and group check filtering to OutboundEmailAccounts 093f08f27b Fix #9839 - Apply acl and group check filtering to InboundEmail decdd27b23 Fix #9839 - Apply acl and group check filtering to ExternalOAuthConnection 584e40cfb3 Fix #9839 - Add user acl group action check 07c5b9f021 Fix #9839 - Show no-data message on empty OutboundEmailAccounts listview b857e4feab Fix #9839 - Show no-data message on empty ExternalOAuthConnection listview 9b6a7c4fcf Fix #9839 - Validate required fields on InboundEmail folder selection 0755e4bc7e Fix #9839 - Mark fields required when changing authType in InboundEmail 55123f4d70 Fix #9839 - Show no-data message on empty InboundEmail listview 059d112349 Fix #9839 - Fix InboundEmail save a656abd069 Fix #9839 - Make getUserRoleNames a static method ae49f130a9 Fix #9839 - Add is-value-set data to password field 2964fcbebc Fix #9839 - Add option to disable listview empty data messages a5794343cb Fix #9839 - Add ExternalOAuthConnection link to admin menu 215413931c Fix #9839 - Align mail related menu entries ee9e98741d Fix #9839 - Always keep write-only fields in OutboundEmailAccounts 4e0551e9f0 Fix #9839 - Disable massupdate and export in OutboundEmailAccounts bulk actions bbf351ee5e Fix #9839 - Disable massupdate and export in InboundEmail bulkactions 6871295c66 Fix #9839 - Allow selecting auth type in InboundEmail module 9befcd0ae6 Fix #9839 - Add ExternalOAuthConnection entrypoints 2cee6f1d67 Fix #9839 - Add ExternalOAuthConnection module 70025d5b66 Fix #9839 - Add write-only display option to text fields 25e2443850 Fix #9839 - Add write-only display option to varchar fields 6be8a334b1 Fix #9839 - Allow creating personal outbound email accounts 8bff1fb237 Fix #9839 - Align Outbound email accounts views with Inbound e396b7373c Fix #9839 - Allow admin to create personal inbound accounts for users 284d0eca76 Fix #9839 - Align inbound email and outbound email list views 186d8e41e4 Fix #9839 - Add Security Groups subpanel to Outbound email accounts c07f43decb Fix #9839 - Add Security Groups subpanel to Inbound email accounts 87c9eee413 Fix #9839 - Add access checks to personal outbound email accounts 2f76e6a5f5 Fix #9839 - Add access checks to personal inbound email accounts 88adc8135b Fix #9839 - Remove email account configuration from User Settings 33feb0b1c2 Fix #9839 - Allow setting personal InboundEmail signatures 4cb0fd99aa Fix #9839 - Allow setting personal InboundEmail as default b8cc31d8dd Fix #9839 - Add security groups to OutboundEmailAccounts 70a0daba51 Fix #9839 - Tidy OutboundEmailAccounts view definitions ca171a4460 Fix #9839 - Remove email_provider_chooser from OutboundEmailAccounts f8a6105618 Fix #9839 - Add menu definition to OutboundEmailAccounts 7d6cfd6c6c Fix #9839 - Load InboundEmail stored_options into fields on load f18ec84b47 Fix #9839 - Adjust InboundEmail save to use new fields 54bfb4f72c Fix #9839 - Remove InboundEmail legacy custom views 69d008671e Fix #9839 - Add new menu entries to InboundEmail d01a196f3b Fix #9839 - Add js code for inboundEmail 701498d007 Fix #9839 - Add standard view definitions to InboundEmail b5870531ba Fix #9839 - Add fields for stored_options in InboundEmail 8c57b07591 Fix #9839 - Add inbound and outbound email menu links to Users module a8bc647662 Fix #9839 - Add combinescripts smarty plugin e4db0fbfd4 Fix #9839 - Add writeonly display mode for password fields 1cc85c2dbf Fix #9839 - Add readonly display mode for enum fields git-subtree-dir: public/legacy git-subtree-split: 81ce7933fd9cecc378154ed4eac7eaab5ec1f139 --- .travis.yml | 5 +- ModuleInstall/extensions.php | 1 + README.md | 2 +- data/SugarBean.php | 174 +-- files.md5 | 290 ++-- include/DetailView/DetailView.php | 30 +- include/EditView/EditView2.php | 2 +- include/Imap/Imap2Handler.php | 1318 +++++++++++++++++ include/Imap/ImapHandler.php | 178 ++- include/Imap/ImapHandlerFactory.php | 73 +- include/Imap/ImapHandlerFake.php | 58 +- include/Imap/ImapHandlerFakeCalls.php | 36 +- include/Imap/ImapHandlerInterface.php | 103 +- include/ListView/ListViewSmarty.php | 7 +- .../MVC/Controller/entry_point_registry.php | 2 + include/OutboundEmail/OutboundEmail.php | 4 +- .../ScriptLoader/SuiteScriptLoader.php | 59 + .../plugins/function.suite_combinescripts.php | 77 + .../Smarty/plugins/modifier.json_decode.php | 50 + include/SugarFields/Fields/Base/EditView.tpl | 21 +- include/SugarFields/Fields/Enum/EditView.tpl | 31 +- .../SugarFields/Fields/Password/EditView.tpl | 13 +- .../Fields/Stringmap/DetailView.tpl | 79 + .../SugarFields/Fields/Stringmap/EditView.tpl | 121 ++ .../Fields/Stringmap/SugarFieldStringmap.php | 152 ++ .../Fields/Stringmap/js/stringmap-factory.js | 56 + .../Fields/Stringmap/js/stringmap.js | 136 ++ include/SugarFields/Fields/Text/EditView.tpl | 22 +- include/SugarFolders/SugarFolders.php | 144 +- include/SugarPHPMailer.php | 4 +- include/SugarTinyMCE.php | 14 +- include/database/MysqliManager.php | 17 + include/export_utils.php | 29 +- include/javascript/sugar_3.js | 4 +- include/language/en_us.lang.php | 50 +- include/modules.php | 8 + include/utils.php | 89 +- include/utils/LogicHook.php | 4 +- install/language/en_us.lang.php | 2 +- install/ready.php | 3 +- .../src_files/include/javascript/sugar_3.js | 22 +- .../modules/InboundEmail/InboundEmail.js | 14 +- .../ElasticSearch/ElasticSearchEngine.php | 2 +- .../ElasticSearch/ElasticSearchIndexer.php | 20 +- lib/Search/SearchQuery.php | 9 +- lib/Search/UI/SearchResultsController.php | 3 +- lib/Utility/ArrayMapper.php | 8 +- modules/ACLRoles/ACLRole.php | 2 +- modules/AOP_Case_Updates/util.php | 49 + modules/AOR_Reports/AOR_Report.php | 25 +- modules/Administration/AOPAdmin.php | 8 + modules/Administration/AOPAdmin.tpl | 11 + modules/Administration/Diagnostic.tpl | 24 +- modules/Administration/PasswordManager.php | 3 +- .../Administration/QuickRepairAndRebuild.php | 1 + .../SyncInboundEmailAccounts.php | 4 +- .../SyncInboundEmailAccountsPage.php | 5 +- ...ncInboundEmailAccountsSubActionHandler.php | 37 +- .../Administration/language/en_us.lang.php | 11 + .../metadata/adminpaneldefs.php | 14 + modules/Campaigns/CampaignDiagnostic.php | 14 +- modules/Campaigns/WizardEmailSetup.php | 95 +- modules/Campaigns/utils.php | 15 +- modules/EmailMan/EmailManDelivery.php | 8 +- modules/Emails/Email.php | 4 +- modules/Emails/EmailUI.php | 98 +- modules/Emails/EmailsController.php | 2 +- modules/Emails/EmailsDataAddressCollector.php | 8 +- modules/Emails/Folder.php | 63 +- .../include/ListView/ListViewDataEmails.php | 40 +- .../ListViewDataEmailsSearchOnIMap.php | 34 +- modules/Emails/javascript/EmailUI.js | 9 - modules/Emails/metadata/listviewdefs.php | 23 +- modules/Emails/views/view.list.php | 7 + .../ExternalOAuthConnection.php | 304 ++++ modules/ExternalOAuthConnection/Menu.php | 54 + .../ExternalOAuthConnection/controller.php | 61 + .../entrypoint/redirectToExternalOAuth.php | 64 + .../entrypoint/setExternalOAuthToken.php | 86 ++ .../js/authenticate.js | 60 + modules/ExternalOAuthConnection/js/fields.js | 188 +++ .../language/en_us.lang.php | 100 ++ .../metadata/SearchFields.php | 48 + .../metadata/detailviewdefs.php | 98 ++ .../metadata/editviewdefs.php | 103 ++ .../metadata/listviewdefs.php | 64 + .../metadata/metafiles.php | 49 + .../metadata/searchdefs.php | 57 + .../metadata/subpaneldefs.php | 65 + .../ExternalOAuthProviderConnector.php | 373 +++++ ...xternalOAuthProviderConnectorInterface.php | 145 ++ .../Generic/GenericOAuthProviderConnector.php | 82 + .../MicrosoftOAuthProviderConnector.php | 108 ++ .../services/OAuthAuthorizationService.php | 378 +++++ .../ExternalOAuthConnection/tpl/setToken.tpl | 51 + modules/ExternalOAuthConnection/vardefs.php | 253 ++++ .../views/view.list.php} | 24 +- .../ExternalOAuthProvider.php | 508 +++++++ modules/ExternalOAuthProvider/Menu.php | 54 + modules/ExternalOAuthProvider/controller.php | 61 + .../language/en_us.lang.php | 109 ++ .../metadata/SearchFields.php | 48 + .../metadata/detailviewdefs.php | 148 ++ .../metadata/editviewdefs.php | 125 ++ .../metadata/listviewdefs.php | 64 + .../metadata/metafiles.php | 49 + .../metadata/searchdefs.php | 57 + .../metadata/subpaneldefs.php | 65 + modules/ExternalOAuthProvider/utils.php | 96 ++ modules/ExternalOAuthProvider/vardefs.php | 333 +++++ .../ExternalOAuthProvider/views/view.list.php | 57 + modules/InboundEmail/Delete.php | 2 + modules/InboundEmail/DetailView.html | 252 ---- modules/InboundEmail/DetailView.php | 309 ---- modules/InboundEmail/EditView.html | 624 -------- modules/InboundEmail/EditView.php | 503 ------- modules/InboundEmail/InboundEmail.js | 10 +- modules/InboundEmail/InboundEmail.php | 1092 +++++++++++--- modules/InboundEmail/ListView.html | 94 -- modules/InboundEmail/Menu.php | 9 +- modules/InboundEmail/Popup.php | 6 +- modules/InboundEmail/PostSave.php | 61 + modules/InboundEmail/Save.php | 192 ++- .../InboundEmail/ShowInboundFoldersList.php | 16 +- modules/InboundEmail/controller.php | 86 ++ modules/InboundEmail/field_arrays.php | 1 + .../js/auth_type_fields_toggle.js | 90 ++ modules/InboundEmail/js/case_create_toggle.js | 69 + .../InboundEmail/js/distribution_toggle.js | 114 ++ modules/InboundEmail/js/fields.js | 312 ++++ modules/InboundEmail/js/fields_toggle.js | 90 ++ modules/InboundEmail/js/mail_folders.js | 205 +++ modules/InboundEmail/js/owner_toggle.js | 76 + modules/InboundEmail/js/panel_toggle.js | 82 + modules/InboundEmail/js/ssl_port_set.js | 51 + modules/InboundEmail/js/test_configuration.js | 71 + modules/InboundEmail/language/en_us.lang.php | 60 +- .../InboundEmail/metadata/SearchFields.php | 52 + .../InboundEmail/metadata/detailviewdefs.php | 209 +++ .../InboundEmail/metadata/editviewdefs.php | 222 +++ .../InboundEmail/metadata/listviewdefs.php | 79 + modules/InboundEmail/metadata/metafiles.php | 49 + modules/InboundEmail/metadata/searchdefs.php | 88 ++ .../InboundEmail/metadata/subpaneldefs.php | 67 + modules/InboundEmail/utils.php | 160 ++ modules/InboundEmail/vardefs.php | 903 +++++++++-- modules/InboundEmail/views/view.detail.php | 57 + modules/InboundEmail/views/view.edit.php | 58 + modules/InboundEmail/views/view.list.php | 57 + modules/MergeRecords/MergeRecord.php | 6 +- modules/OutboundEmailAccounts/Menu.php | 54 + .../OutboundEmailAccounts.php | 242 ++- .../OutboundEmailAccounts_sugar.php | 8 +- modules/OutboundEmailAccounts/controller.php | 97 ++ modules/OutboundEmailAccounts/js/fields.js | 181 +++ .../OutboundEmailAccounts/js/owner_toggle.js | 76 + .../js/smtp_auth_toggle.js | 76 + .../OutboundEmailAccounts/js/ssl_port_set.js | 54 + .../language/en_us.lang.php | 25 +- .../metadata/SearchFields.php | 4 +- .../metadata/detailviewdefs.php | 176 +-- .../metadata/editviewdefs.php | 204 ++- .../metadata/listviewdefs.php | 49 +- .../metadata/popupdefs.php | 89 +- .../metadata/subpaneldefs.php} | 58 +- modules/OutboundEmailAccounts/vardefs.php | 440 ++++-- .../views/view.detail.php | 56 + .../OutboundEmailAccounts/views/view.edit.php | 57 + .../OutboundEmailAccounts/views/view.list.php | 57 + modules/ProspectLists/TargetListUpdate.php | 22 +- modules/Studio/parsers/StudioParser.php | 4 +- modules/Studio/wizards/EditDropDownWizard.php | 6 +- modules/Studio/wizards/RenameModules.php | 12 +- modules/Surveys/Menu.php | 9 + modules/Users/Menu.php | 4 + modules/Users/language/en_us.lang.php | 4 + modules/Users/tpls/EditViewFooter.tpl | 6 +- php_version.php | 4 +- service/v3_1/SugarWebServiceUtilv3_1.php | 13 +- soap/SoapSugarUsers.php | 21 +- suitecrm_version.php | 4 +- .../phpunit/includes/utils/file_utilsTest.php | 1 + .../phpunit/modules/ACLRoles/ACLRoleTest.php | 6 +- .../unit/phpunit/modules/Emails/EmailTest.php | 3 +- .../modules/InboundEmail/InboundEmailTest.php | 46 +- .../SecurityGroups/SecurityGroupTest.php | 3 + .../include/ListView/ListViewGeneric.tpl | 13 +- .../modules/SavedSearch/SavedSearchForm.tpl | 8 +- 188 files changed, 13961 insertions(+), 3464 deletions(-) create mode 100644 include/Imap/Imap2Handler.php create mode 100644 include/Services/ScriptLoader/SuiteScriptLoader.php create mode 100644 include/Smarty/plugins/function.suite_combinescripts.php create mode 100644 include/Smarty/plugins/modifier.json_decode.php create mode 100644 include/SugarFields/Fields/Stringmap/DetailView.tpl create mode 100644 include/SugarFields/Fields/Stringmap/EditView.tpl create mode 100644 include/SugarFields/Fields/Stringmap/SugarFieldStringmap.php create mode 100644 include/SugarFields/Fields/Stringmap/js/stringmap-factory.js create mode 100644 include/SugarFields/Fields/Stringmap/js/stringmap.js create mode 100644 modules/ExternalOAuthConnection/ExternalOAuthConnection.php create mode 100644 modules/ExternalOAuthConnection/Menu.php create mode 100644 modules/ExternalOAuthConnection/controller.php create mode 100644 modules/ExternalOAuthConnection/entrypoint/redirectToExternalOAuth.php create mode 100644 modules/ExternalOAuthConnection/entrypoint/setExternalOAuthToken.php create mode 100644 modules/ExternalOAuthConnection/js/authenticate.js create mode 100644 modules/ExternalOAuthConnection/js/fields.js create mode 100644 modules/ExternalOAuthConnection/language/en_us.lang.php create mode 100644 modules/ExternalOAuthConnection/metadata/SearchFields.php create mode 100644 modules/ExternalOAuthConnection/metadata/detailviewdefs.php create mode 100644 modules/ExternalOAuthConnection/metadata/editviewdefs.php create mode 100644 modules/ExternalOAuthConnection/metadata/listviewdefs.php create mode 100644 modules/ExternalOAuthConnection/metadata/metafiles.php create mode 100644 modules/ExternalOAuthConnection/metadata/searchdefs.php create mode 100644 modules/ExternalOAuthConnection/metadata/subpaneldefs.php create mode 100644 modules/ExternalOAuthConnection/provider/ExternalOAuthProviderConnector.php create mode 100644 modules/ExternalOAuthConnection/provider/ExternalOAuthProviderConnectorInterface.php create mode 100644 modules/ExternalOAuthConnection/provider/Generic/GenericOAuthProviderConnector.php create mode 100644 modules/ExternalOAuthConnection/provider/Microsoft/MicrosoftOAuthProviderConnector.php create mode 100644 modules/ExternalOAuthConnection/services/OAuthAuthorizationService.php create mode 100644 modules/ExternalOAuthConnection/tpl/setToken.tpl create mode 100644 modules/ExternalOAuthConnection/vardefs.php rename modules/{InboundEmail/index.php => ExternalOAuthConnection/views/view.list.php} (85%) mode change 100755 => 100644 create mode 100644 modules/ExternalOAuthProvider/ExternalOAuthProvider.php create mode 100644 modules/ExternalOAuthProvider/Menu.php create mode 100644 modules/ExternalOAuthProvider/controller.php create mode 100644 modules/ExternalOAuthProvider/language/en_us.lang.php create mode 100644 modules/ExternalOAuthProvider/metadata/SearchFields.php create mode 100644 modules/ExternalOAuthProvider/metadata/detailviewdefs.php create mode 100644 modules/ExternalOAuthProvider/metadata/editviewdefs.php create mode 100644 modules/ExternalOAuthProvider/metadata/listviewdefs.php create mode 100644 modules/ExternalOAuthProvider/metadata/metafiles.php create mode 100644 modules/ExternalOAuthProvider/metadata/searchdefs.php create mode 100644 modules/ExternalOAuthProvider/metadata/subpaneldefs.php create mode 100644 modules/ExternalOAuthProvider/utils.php create mode 100644 modules/ExternalOAuthProvider/vardefs.php create mode 100644 modules/ExternalOAuthProvider/views/view.list.php delete mode 100755 modules/InboundEmail/DetailView.html delete mode 100755 modules/InboundEmail/DetailView.php delete mode 100755 modules/InboundEmail/EditView.html delete mode 100755 modules/InboundEmail/EditView.php delete mode 100755 modules/InboundEmail/ListView.html create mode 100644 modules/InboundEmail/PostSave.php create mode 100644 modules/InboundEmail/controller.php create mode 100644 modules/InboundEmail/js/auth_type_fields_toggle.js create mode 100644 modules/InboundEmail/js/case_create_toggle.js create mode 100644 modules/InboundEmail/js/distribution_toggle.js create mode 100644 modules/InboundEmail/js/fields.js create mode 100644 modules/InboundEmail/js/fields_toggle.js create mode 100644 modules/InboundEmail/js/mail_folders.js create mode 100644 modules/InboundEmail/js/owner_toggle.js create mode 100644 modules/InboundEmail/js/panel_toggle.js create mode 100644 modules/InboundEmail/js/ssl_port_set.js create mode 100644 modules/InboundEmail/js/test_configuration.js create mode 100644 modules/InboundEmail/metadata/SearchFields.php create mode 100644 modules/InboundEmail/metadata/detailviewdefs.php create mode 100644 modules/InboundEmail/metadata/editviewdefs.php create mode 100644 modules/InboundEmail/metadata/listviewdefs.php create mode 100644 modules/InboundEmail/metadata/metafiles.php create mode 100644 modules/InboundEmail/metadata/searchdefs.php create mode 100644 modules/InboundEmail/metadata/subpaneldefs.php create mode 100644 modules/InboundEmail/utils.php create mode 100644 modules/InboundEmail/views/view.detail.php create mode 100644 modules/InboundEmail/views/view.edit.php create mode 100644 modules/InboundEmail/views/view.list.php create mode 100644 modules/OutboundEmailAccounts/Menu.php create mode 100644 modules/OutboundEmailAccounts/controller.php create mode 100644 modules/OutboundEmailAccounts/js/fields.js create mode 100644 modules/OutboundEmailAccounts/js/owner_toggle.js create mode 100644 modules/OutboundEmailAccounts/js/smtp_auth_toggle.js create mode 100644 modules/OutboundEmailAccounts/js/ssl_port_set.js rename modules/{InboundEmail/ListView.php => OutboundEmailAccounts/metadata/subpaneldefs.php} (56%) mode change 100755 => 100644 create mode 100644 modules/OutboundEmailAccounts/views/view.detail.php create mode 100644 modules/OutboundEmailAccounts/views/view.edit.php create mode 100644 modules/OutboundEmailAccounts/views/view.list.php 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}
-

+
-
+
- + + + +