Test Failed
Push — CI ( 0f01dd...c95a04 )
by Adam
55:13
created

EmailUI   F

Complexity

Total Complexity 417

Size/Duplication

Total Lines 3021
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 18
Metric Value
wmc 417
lcom 3
cbo 18
dl 0
loc 3021
rs 0.6314

72 Methods

Rating   Name   Duplication   Size   Complexity  
A EmailUI() 0 15 2
F displayEmailFrame() 0 198 12
A displayQuickComposeEmailFrame() 0 14 1
B _loadQuickCreateModules() 0 19 5
A generateComposePackageForQuickCreateFromComposeUrl() 0 12 2
B generateComposePackageForQuickCreate() 0 27 4
D _generateComposeConfigData() 0 92 10
A getContacts() 0 17 2
A setContacts() 0 12 3
A removeContacts() 0 15 3
B saveContactEdit() 0 27 3
B getEditContact() 0 40 3
C getUserContacts() 0 59 10
B getUserPrefsJS() 0 73 6
A saveNewFolder() 0 20 2
A saveListViewSortOrder() 0 15 2
A saveFolderOpenState() 0 14 2
A saveListView() 0 9 1
B preflightEmailCache() 0 17 5
A deleteEmailCacheForFolders() 0 6 2
A emptyTrash() 0 14 4
D getMailboxNodes() 0 109 15
A getMailBoxesFromCacheValue() 0 8 1
C buildTreeNode() 0 57 10
A getUnreadCount() 0 7 1
A getDraftAttachments() 0 18 2
B createCopyOfInboundAttachment() 0 39 6
A parseAttachmentInfo() 0 10 2
F getQuickCreateForm() 0 130 16
C getImportForm() 0 47 10
F getDetailViewForEmail2() 0 117 13
A setReadFlag() 0 3 1
D markEmails() 0 104 19
C doAssignment() 0 43 7
A getTeams() 0 2 1
B doDistributionWithMethod() 0 17 5
A distRoundRobin() 0 23 3
A distLeastBusy() 0 18 3
A distDirect() 0 11 2
A getAssignedEmailsCountForUsers() 0 9 2
A getLastRobin() 0 7 2
A setLastRobin() 0 8 2
F getSingleMessage() 0 84 15
A getListEmails() 0 10 1
F displayComposeEmail() 0 77 18
C handleReplyType() 0 56 12
D _getPeopleUnionQuery() 0 77 13
C getRelatedEmail() 0 63 15
F findEmailFromBeanIds() 0 71 14
B _cleanUIDList() 0 26 4
A createFolder() 0 11 2
C preflightUser() 0 89 8
A generateDynamicFolderQuery() 0 22 3
A preflightUserCache() 0 11 3
A clearInboundAccountCache() 0 12 3
A getEmailTemplatesArray() 0 17 4
F getFromAccountsArray() 0 72 13
F getFromAllAccountsArray() 0 98 25
A arrayToXML() 0 20 4
C getShowAccountsOptions() 0 52 12
A getShowAccountsOptionsForSearch() 0 20 4
A displaySuccessMessage() 0 17 2
A validCacheFileExists() 0 14 3
A getCacheValue() 0 23 3
A getCacheTimestamp() 0 17 3
A setCacheTimestamp() 0 16 3
A writeCacheFile() 0 14 1
A _writeCacheFile() 0 20 2
B jsonOuput() 0 17 7
C xmlOutput() 0 29 7
A generateExpandableAddrs() 0 20 3
A unifyEmailString() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like EmailUI often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EmailUI, and based on these observations, apply Extract Interface, too.

1
<?php
2
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
/*********************************************************************************
4
 * SugarCRM Community Edition is a customer relationship management program developed by
5
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
/*********************************************************************************
42
43
 * Description:
44
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
45
 * Reserved. Contributor(s): ______________________________________..
46
 *********************************************************************************/
47
48
require_once("include/ytree/Tree.php");
49
require_once("include/ytree/ExtNode.php");
50
require_once("include/SugarFolders/SugarFolders.php");
51
52
53
54
class EmailUI {
55
	var $db;
56
	var $folder; // place holder for SugarFolder object
57
	var $folderStates = array(); // array of folderPath names and their states (1/0)
58
	var $smarty;
59
	var $addressSeparators = array(";", ",");
60
	var $rolloverStyle = "<style>div#rollover {position: relative;float: left;margin: none;text-decoration: none;}div#rollover a:hover {padding: 0;}div#rollover a span {display: none;}div#rollover a:hover span {text-decoration: none;display: block;width: 250px;margin-top: 5px;margin-left: 5px;position: absolute;padding: 10px;color: #333;	border: 1px solid #ccc;	background-color: #fff;	font-size: 12px;z-index: 1000;}</style>\n";
61
	var $groupCss = "<span class='groupInbox'>";
62
	var $cacheTimeouts = array(
63
		'messages'		=> 86400,	// 24 hours
64
		'folders'		=> 300,		// 5 mins
65
		'attachments'	=> 86400,	// 24 hours
66
	);
67
	var $userCacheDir = '';
68
	var $coreDynamicFolderQuery = "SELECT emails.id polymorphic_id, 'Emails' polymorphic_module FROM emails
69
								   JOIN emails_text on emails.id = emails_text.email_id
70
                                   WHERE (type = '::TYPE::' OR status = '::STATUS::') AND assigned_user_id = '::USER_ID::' AND emails.deleted = '0'";
71
72
	/**
73
	 * Sole constructor
74
	 */
75
	function EmailUI() {
76
		global $sugar_config;
77
		global $current_user;
78
79
		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
80
81
		if(!empty($folderStateSerial)) {
82
			$this->folderStates = unserialize($folderStateSerial);
83
		}
84
85
		$this->smarty = new Sugar_Smarty();
86
		$this->folder = new SugarFolder();
87
		$this->userCacheDir = sugar_cached("modules/Emails/{$current_user->id}");
88
		$this->db = DBManagerFactory::getInstance();
89
	}
90
91
92
	///////////////////////////////////////////////////////////////////////////
93
	////	CORE
94
	/**
95
	 * Renders the frame for emails
96
	 */
97
	function displayEmailFrame() {
98
99
		require_once("include/OutboundEmail/OutboundEmail.php");
100
101
		global $app_strings, $app_list_strings;
102
		global $mod_strings;
103
		global $sugar_config;
104
		global $current_user;
105
		global $locale;
106
		global $timedate;
107
		global $theme;
108
		global $sugar_version;
109
		global $sugar_flavor;
110
		global $current_language;
111
		global $server_unique_key;
112
113
		$this->preflightUserCache();
114
		$ie = new InboundEmail();
115
116
		// focus listView
117
		$list = array(
118
			'mbox' => 'Home',
119
			'ieId' => '',
120
			'name' => 'Home',
121
			'unreadChecked' => 0,
122
			'out' => array(),
123
		);
124
125
		$this->_generateComposeConfigData('email_compose');
126
127
128
        //Check quick create module access
129
        $QCAvailableModules = $this->_loadQuickCreateModules();
130
131
        //Get the quickSearch js needed for assigned user id on Search Tab
132
        require_once('include/QuickSearchDefaults.php');
133
        $qsd = QuickSearchDefaults::getQuickSearchDefaults();
134
        $qsd->setFormName('advancedSearchForm');
135
        $quicksearchAssignedUser = "if(typeof sqs_objects == 'undefined'){var sqs_objects = new Array;}";
136
        $quicksearchAssignedUser .= "sqs_objects['advancedSearchForm_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
137
        $qsd->setFormName('Distribute');
138
        $quicksearchAssignedUser .= "sqs_objects['Distribute_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
139
        $this->smarty->assign('quickSearchForAssignedUser', $quicksearchAssignedUser);
140
141
142
		///////////////////////////////////////////////////////////////////////
143
		////	BASIC ASSIGNS
144
		$this->smarty->assign("currentUserId",$current_user->id);
145
		$this->smarty->assign("CURRENT_USER_EMAIL",$current_user->email1);
146
        $this->smarty->assign("currentUserName",$current_user->name);
147
		$this->smarty->assign('yuiPath', 'modules/Emails/javascript/yui-ext/');
148
		$this->smarty->assign('app_strings', $app_strings);
149
		$this->smarty->assign('mod_strings', $mod_strings);
150
		$this->smarty->assign('theme', $theme);
151
		$this->smarty->assign('sugar_config', $sugar_config);
152
		$this->smarty->assign('is_admin', $current_user->is_admin);
153
		$this->smarty->assign('sugar_version', $sugar_version);
154
		$this->smarty->assign('sugar_flavor', $sugar_flavor);
155
		$this->smarty->assign('current_language', $current_language);
156
		$this->smarty->assign('server_unique_key', $server_unique_key);
157
		$this->smarty->assign('qcModules', json_encode($QCAvailableModules));
158
		$extAllDebugValue = "ext-all.js";
159
		$this->smarty->assign('extFileName', $extAllDebugValue);
160
161
		// settings: general
162
		$e2UserPreferences = $this->getUserPrefsJS();
163
		$emailSettings = $e2UserPreferences['emailSettings'];
164
165
		///////////////////////////////////////////////////////////////////////
166
		////	USER SETTINGS
167
		// settings: accounts
168
169
		$cuDatePref = $current_user->getUserDateTimePreferences();
170
		$this->smarty->assign('dateFormat', $cuDatePref['date']);
171
		$this->smarty->assign('dateFormatExample', str_replace(array("Y", "m", "d"), array("yyyy", "mm", "dd"), $cuDatePref['date']));
172
		$this->smarty->assign('calFormat', $timedate->get_cal_date_format());
173
        $this->smarty->assign('TIME_FORMAT', $timedate->get_user_time_format());
174
175
		$ieAccounts = $ie->retrieveByGroupId($current_user->id);
176
		$ieAccountsOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
177
178
		foreach($ieAccounts as $k => $v) {
179
			$disabled = (!$v->is_personal) ? "DISABLED" : "";
180
			$group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
181
			$ieAccountsOptions .= "<option value='{$v->id}' $disabled>{$group}{$v->name}</option>\n";
182
		}
183
184
		$this->smarty->assign('ieAccounts', $ieAccountsOptions);
185
		$this->smarty->assign('rollover', $this->rolloverStyle);
186
187
		$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']);
188
		$this->smarty->assign('PROTOCOL', get_select_options_with_id($protocol, ''));
189
		$this->smarty->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], ''));
190
		$this->smarty->assign('ie_mod_strings', return_module_language($current_language, 'InboundEmail'));
191
192
		$charsetSelectedValue = isset($emailSettings['defaultOutboundCharset']) ? $emailSettings['defaultOutboundCharset'] : false;
193
		if (!$charsetSelectedValue) {
194
			$charsetSelectedValue = $current_user->getPreference('default_export_charset', 'global');
195
			if (!$charsetSelectedValue) {
196
				$charsetSelectedValue = $locale->getPrecedentPreference('default_email_charset');
197
			}
198
		}
199
		$charset = array(
200
			'options' => $locale->getCharsetSelect(),
201
			'selected' => $charsetSelectedValue,
202
		);
203
		$this->smarty->assign('charset', $charset);
204
205
		$emailCheckInterval = array('options' => $app_strings['LBL_EMAIL_CHECK_INTERVAL_DOM'], 'selected' => $emailSettings['emailCheckInterval']);
206
		$this->smarty->assign('emailCheckInterval', $emailCheckInterval);
207
		$this->smarty->assign('attachmentsSearchOptions', $app_list_strings['checkbox_dom']);
208
		$this->smarty->assign('sendPlainTextChecked', ($emailSettings['sendPlainText'] == 1) ? 'CHECKED' : '');
209
		$this->smarty->assign('showNumInList', get_select_options_with_id($app_list_strings['email_settings_num_dom'], $emailSettings['showNumInList']));
210
211
		////	END USER SETTINGS
212
		///////////////////////////////////////////////////////////////////////
213
214
		///////////////////////////////////////////////////////////////////////
215
		////	SIGNATURES
216
		$prependSignature = ($current_user->getPreference('signature_prepend')) ? 'true' : 'false';
217
		$defsigID = $current_user->getPreference('signature_default');
218
		$this->smarty->assign('signatures', $current_user->getSignatures(false, $defsigID));
219
		$this->smarty->assign('signaturesSettings', $current_user->getSignatures(false, $defsigID, false));
220
		$signatureButtons = $current_user->getSignatureButtons('SUGAR.email2.settings.createSignature', !empty($defsigID));
221
		if (!empty($defsigID)) {
222
			$signatureButtons = $signatureButtons . '<span name="delete_sig" id="delete_sig" style="visibility:inherit;"><input class="button" onclick="javascript:SUGAR.email2.settings.deleteSignature();" value="'.$app_strings['LBL_EMAIL_DELETE'].'" type="button" tabindex="392">&nbsp;
223
					</span>';
224
		} else {
225
			$signatureButtons = $signatureButtons . '<span name="delete_sig" id="delete_sig" style="visibility:hidden;"><input class="button" onclick="javascript:SUGAR.email2.settings.deleteSignature();" value="'.$app_strings['LBL_EMAIL_DELETE'].'" type="button" tabindex="392">&nbsp;
226
					</span>';
227
		}
228
		$this->smarty->assign('signatureButtons', $signatureButtons);
229
		$this->smarty->assign('signaturePrepend', $prependSignature == 'true' ? 'CHECKED' : '');
230
		////	END SIGNATURES
231
		///////////////////////////////////////////////////////////////////////
232
233
		///////////////////////////////////////////////////////////////////////
234
		////	EMAIL TEMPLATES
235
		$email_templates_arr = $this->getEmailTemplatesArray();
236
		natcasesort($email_templates_arr);
237
		$this->smarty->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, ''));
238
		////	END EMAIL TEMPLATES
239
		///////////////////////////////////////////////////////////////////////
240
241
		///////////////////////////////////////////////////////////////////////
242
		////	FOLDERS & TreeView
243
		$this->smarty->assign('groupUserOptions', $ie->getGroupsWithSelectOptions(array('' => $app_strings['LBL_EMAIL_CREATE_NEW'])));
244
245
		$tree = $this->getMailboxNodes();
246
247
		// preloaded folder
248
		$preloadFolder = 'lazyLoadFolder = ';
249
		$focusFolderSerial = $current_user->getPreference('focusFolder', 'Emails');
250
		if(!empty($focusFolderSerial)) {
251
			$focusFolder = unserialize($focusFolderSerial);
252
			//$focusFolder['ieId'], $focusFolder['folder']
253
			$preloadFolder .= json_encode($focusFolder).";";
254
		} else {
255
			$preloadFolder .= "new Object();";
256
		}
257
		////	END FOLDERS
258
		///////////////////////////////////////////////////////////////////////
259
260
		$out = "";
261
		$out .= $this->smarty->fetch("modules/Emails/templates/_baseEmail.tpl");
262
		$out .= $tree->generate_header();
263
		$out .= $tree->generateNodesNoInit(true, 'email2treeinit');
264
		$out .=<<<eoq
265
			<script type="text/javascript" language="javascript">
266
267
				var loader = new YAHOO.util.YUILoader({
268
				    require : [
269
				    	"layout", "element", "tabview", "menu",
270
				    	"cookie", "sugarwidgets"
271
				    ],
272
				    loadOptional: true,
273
				    skin: { base: 'blank', defaultSkin: '' },
274
				    onSuccess: email2init,
275
				    allowRollup: true,
276
				    base: "include/javascript/yui/build/"
277
				});
278
				loader.addModule({
279
				    name :"sugarwidgets",
280
				    type : "js",
281
				    fullpath: "include/javascript/sugarwidgets/SugarYUIWidgets.js",
282
				    varName: "YAHOO.SUGAR",
283
				    requires: ["datatable", "dragdrop", "treeview", "tabview", "calendar"]
284
				});
285
				loader.insert();
286
287
				{$preloadFolder};
288
289
			</script>
290
eoq;
291
292
293
		return $out;
294
	}
295
296
	/**
297
	 * Generate the frame needed for the quick compose email UI.  This frame is loaded dynamically
298
	 * by an ajax call.
299
	 *
300
	 * @return JSON An object containing html markup and js script variables.
301
	 */
302
	function displayQuickComposeEmailFrame()
303
	{
304
        $this->preflightUserCache();
305
306
	    $this->_generateComposeConfigData('email_compose_light');
307
		$javascriptOut = $this->smarty->fetch("modules/Emails/templates/_baseConfigData.tpl");
308
309
        $divOut = $this->smarty->fetch("modules/Emails/templates/overlay.tpl");
310
        $divOut .= $this->smarty->fetch("modules/Emails/templates/addressSearchContent.tpl");
311
312
        $outData = array('jsData' => $javascriptOut,'divData'=> $divOut);
313
        $out = json_encode($outData);
314
        return $out;
315
    }
316
317
    /**
318
     * Load the modules from the metadata file and include in a custom one if it exists
319
     *
320
     * @return array
321
     */
322
    protected function _loadQuickCreateModules()
323
    {
324
        $QCAvailableModules = array();
325
        $QCModules = array();
326
327
        include('modules/Emails/metadata/qcmodulesdefs.php');
328
        if (file_exists('custom/modules/Emails/metadata/qcmodulesdefs.php')) {
329
            include('custom/modules/Emails/metadata/qcmodulesdefs.php');
330
        }
331
332
        foreach($QCModules as $module) {
333
            $seed = SugarModule::get($module)->loadBean();
334
            if ( ( $seed instanceOf SugarBean ) && $seed->ACLAccess('edit') ) {
335
                $QCAvailableModules[] = $module;
336
            }
337
        }
338
339
        return $QCAvailableModules;
340
    }
341
342
    /**
343
     * Given an email link url (eg. index.php?action=Compose&parent_type=Contacts...) break up the
344
     * request components and create a compose package that can be used by the quick compose UI. The
345
     * result is typically passed into the js call SUGAR.quickCompose.init which initalizes the quick compose
346
     * UI.
347
     *
348
     * @param String $emailLinkUrl
349
     * @return JSON Object containing the composePackage and full link url
350
     */
351
    function generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, $lazyLoad=false)
352
    {
353
        $composeData = explode("&",$emailLinkUrl);
354
        $a_composeData = array();
355
    	foreach ($composeData as $singleRequest)
356
    	{
357
    		$tmp = explode("=",$singleRequest);
358
    		$a_composeData[$tmp[0]] = urldecode($tmp[1]);
359
    	}
360
361
    	return $this->generateComposePackageForQuickCreate($a_composeData,$emailLinkUrl, $lazyLoad);
362
    }
363
    /**
364
     * Generate the composePackage for the quick compose email UI.  The package contains
365
     * key/value pairs generated by the Compose.php file which are then set into the
366
     * quick compose email UI (eg. to addr, parent id, parent type, etc)
367
     *
368
     * @param Array $composeData Associative array read and processed by generateComposeDataPackage.
369
     * @param String $fullLinkUrl A link that contains all pertinant information so the user can be
370
     *                              directed to the full compose screen if needed
371
     * @param SugarBean $bean Optional - the parent object bean with data
372
     * @return JSON Object containg composePackage and fullLinkUrl
373
     */
374
    function generateComposePackageForQuickCreate($composeData,$fullLinkUrl, $lazyLoad=false, $bean = null)
375
    {
376
        $_REQUEST['forQuickCreate'] = true;
377
378
        if(!$lazyLoad){
379
    	    require_once('modules/Emails/Compose.php');
380
    	    $composePackage = generateComposeDataPackage($composeData,FALSE, $bean);
0 ignored issues
show
Unused Code introduced by
The call to generateComposeDataPackage() has too many arguments starting with $bean.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
381
        }else{
382
            $composePackage = $composeData;
383
        }
384
385
    	// JSON object is passed into the function defined within the a href onclick event
386
    	// which is delimeted by '.  Need to escape all single quotes and &, <, >
387
    	// but not double quotes since json would escape them
388
    	foreach ($composePackage as $key => $singleCompose)
0 ignored issues
show
Bug introduced by
The expression $composePackage of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
389
    	{
390
    	   if (is_string($singleCompose))
391
    	       $composePackage[$key] = str_replace("&nbsp;", " ", from_html($singleCompose));
392
    	}
393
394
    	$quickComposeOptions = array('fullComposeUrl' => $fullLinkUrl,'composePackage' => $composePackage);
395
396
    	$j_quickComposeOptions = JSON::encode($quickComposeOptions, false ,true);
397
398
399
    	return $j_quickComposeOptions;
400
    }
401
402
    /**
403
     * Generate the config data needed for the Full Compose UI and the Quick Compose UI.  The set of config data
404
     * returned is the minimum set needed by the quick compose UI.
405
     *
406
     * @param String $type Drives which tinyMCE options will be included.
407
     */
408
	function _generateComposeConfigData($type = "email_compose_light" )
409
	{
410
		global $app_list_strings,$current_user, $app_strings, $mod_strings,$current_language,$locale;
411
412
		//Link drop-downs
413
		$parent_types = $app_list_strings['record_type_display'];
414
		$disabled_parent_types = ACLController::disabledModuleList($parent_types, false, 'list');
415
416
		foreach($disabled_parent_types as $disabled_parent_type) {
417
		  unset($parent_types[$disabled_parent_type]);
418
		}
419
		asort($parent_types);
420
		$linkBeans = json_encode(get_select_options_with_id($parent_types, ''));
421
422
		//TinyMCE Config
423
		require_once("include/SugarTinyMCE.php");
424
        $tiny = new SugarTinyMCE();
425
        $tinyConf = $tiny->getConfig($type);
426
427
        //Generate Language Packs
428
		$lang = "var app_strings = new Object();\n";
429
		foreach($app_strings as $k => $v) {
430
			if(strpos($k, 'LBL_EMAIL_') !== false) {
431
				$lang .= "app_strings.{$k} = '{$v}';\n";
432
			}
433
		}
434
		//Get the email mod strings but don't use the global variable as this may be overridden by
435
		//other modules when the quick create is rendered.
436
		$email_mod_strings = return_module_language($current_language,'Emails');
437
		$modStrings = "var mod_strings = new Object();\n";
438
		foreach($email_mod_strings as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $email_mod_strings of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
439
			$v = str_replace("'", "\'", $v);
440
			$modStrings .= "mod_strings.{$k} = '{$v}';\n";
441
		}
442
		$lang .= "\n\n{$modStrings}\n";
443
444
		//Grab the Inboundemail language pack
445
		$ieModStrings = "var ie_mod_strings = new Object();\n";
446
		$ie_mod_strings = return_module_language($current_language,'InboundEmail');
447
		foreach($ie_mod_strings as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $ie_mod_strings of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
448
			$v = str_replace("'", "\'", $v);
449
			$ieModStrings .= "ie_mod_strings.{$k} = '{$v}';\n";
450
		}
451
		$lang .= "\n\n{$ieModStrings}\n";
452
453
		$this->smarty->assign('linkBeans', $linkBeans);
454
        $this->smarty->assign('linkBeansOptions', $parent_types);
455
        $this->smarty->assign('tinyMCE', $tinyConf);
456
        $this->smarty->assign('lang', $lang);
457
        $this->smarty->assign('app_strings', $app_strings);
458
		$this->smarty->assign('mod_strings', $email_mod_strings);
459
        $ie1 = new InboundEmail();
460
461
        //Signatures
462
        $defsigID = $current_user->getPreference('signature_default');
463
		$defaultSignature = $current_user->getDefaultSignature();
464
		$sigJson = !empty($defaultSignature) ? json_encode(array($defaultSignature['id'] => from_html($defaultSignature['signature_html']))) : "new Object()";
465
		$this->smarty->assign('defaultSignature', $sigJson);
466
		$this->smarty->assign('signatureDefaultId', (isset($defaultSignature['id'])) ? $defaultSignature['id'] : "");
467
		//User Preferences
468
		$this->smarty->assign('userPrefs', json_encode($this->getUserPrefsJS()));
469
470
		//Get the users default outbound id
471
		$defaultOutID = $ie1->getUsersDefaultOutboundServerId($current_user);
472
		$this->smarty->assign('defaultOutID', $defaultOutID);
473
474
		//Character Set
475
		$charsets = json_encode($locale->getCharsetSelect());
476
		$this->smarty->assign('emailCharsets', $charsets);
477
478
		//Relateable List of People for address book search
479
		//#20776 jchi
480
		$peopleTables = array("users",
481
		                      "contacts",
482
		                      "leads",
483
		                      "prospects",
484
		                      "accounts");
485
		$filterPeopleTables = array();
486
		global $app_list_strings, $app_strings;
487
		$filterPeopleTables['LBL_DROPDOWN_LIST_ALL'] = $app_strings['LBL_DROPDOWN_LIST_ALL'];
488
		foreach($peopleTables as $table) {
489
			$module = ucfirst($table);
490
            $class = substr($module, 0, strlen($module) - 1);
491
            require_once("modules/{$module}/{$class}.php");
492
            $person = new $class();
493
494
            if (!$person->ACLAccess('list')) continue;
495
            $filterPeopleTables[$person->table_name] = $app_list_strings['moduleList'][$person->module_dir];
496
		}
497
		$this->smarty->assign('listOfPersons' , get_select_options_with_id($filterPeopleTables,''));
498
499
	}
500
501
502
503
	////	END CORE
504
	///////////////////////////////////////////////////////////////////////////
505
506
	///////////////////////////////////////////////////////////////////////////
507
	////	ADDRESS BOOK
508
	/**
509
	 * Retrieves all relationship metadata for a user's address book
510
	 * @return array
511
	 */
512
	function getContacts() {
513
		global $current_user;
514
515
		$q = "SELECT * FROM address_book WHERE assigned_user_id = '{$current_user->id}' ORDER BY bean DESC";
516
		$r = $this->db->query($q);
517
518
		$ret = array();
519
520
		while($a = $this->db->fetchByAssoc($r)) {
521
			$ret[$a['bean_id']] = array(
522
				'id'		=> $a['bean_id'],
523
				'module'	=> $a['bean'],
524
			);
525
		}
526
527
		return $ret;
528
	}
529
530
	/**
531
	 * Saves changes to a user's address book
532
	 * @param array contacts
533
	 */
534
	function setContacts($contacts) {
535
		global $current_user;
536
537
		$oldContacts = $this->getContacts();
538
539
		foreach($contacts as $cid => $contact) {
540
			if(!in_array($contact['id'], $oldContacts)) {
541
				$q = "INSERT INTO address_book (assigned_user_id, bean, bean_id) VALUES ('{$current_user->id}', '{$contact['module']}', '{$contact['id']}')";
542
				$r = $this->db->query($q, true);
543
			}
544
		}
545
	}
546
547
	/**
548
	 * Removes contacts from the user's address book
549
	 * @param array ids
550
	 */
551
	function removeContacts($ids) {
552
		global $current_user;
553
554
		$concat = "";
555
556
		foreach($ids as $id) {
557
			if(!empty($concat))
558
				$concat .= ", ";
559
560
			$concat .= "'{$id}'";
561
		}
562
563
		$q = "DELETE FROM address_book WHERE assigned_user_id = '{$current_user->id}' AND bean_id IN ({$concat})";
564
		$r = $this->db->query($q);
565
	}
566
567
	/**
568
	 * saves editted Contact info
569
	 * @param string $str JSON serialized object
570
	 */
571
	function saveContactEdit($str) {
572
573
		$json = getJSONobj();
574
575
		$str = from_html($str);
576
		$obj = $json->decode($str);
577
578
		$contact = new Contact();
579
		$contact->retrieve($obj['contact_id']);
580
		$contact->first_name = $obj['contact_first_name'];
581
		$contact->last_name = $obj['contact_last_name'];
582
		$contact->save();
583
584
		// handle email address changes
585
		$addresses = array();
586
587
		foreach($obj as $k => $req) {
0 ignored issues
show
Bug introduced by
The expression $obj of type string is not traversable.
Loading history...
588
			if(strpos($k, 'emailAddress') !== false) {
589
				$addresses[$k] = $req;
590
			}
591
		}
592
593
		// prefill some REQUEST vars for emailAddress save
594
		$_REQUEST['emailAddressOptOutFlag'] = $obj['optOut'];
595
		$_REQUEST['emailAddressInvalidFlag'] = $obj['invalid'];
596
		$contact->emailAddress->save($obj['contact_id'], 'Contacts', $addresses, $obj['primary'], '');
597
	}
598
599
	/**
600
	 * Prepares the Edit Contact mini-form via template assignment
601
	 * @param string id ID of contact in question
602
	 * @param string module Module in focus
603
	 * @return array
604
	 */
605
	function getEditContact($id, $module) {
606
		global $app_strings;
607
608
609
		if(!class_exists("Contact")) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
610
611
		}
612
613
		$contact = new Contact();
614
		$contact->retrieve($_REQUEST['id']);
615
		$ret = array();
616
617
		if($contact->ACLAccess('edit')) {
618
			$contactMeta = array();
619
			$contactMeta['id'] = $contact->id;
620
			$contactMeta['module'] = $contact->module_dir;
621
			$contactMeta['first_name'] = $contact->first_name;
622
			$contactMeta['last_name'] = $contact->last_name;
623
624
			$this->smarty->assign("app_strings", $app_strings);
625
			$this->smarty->assign("contact_strings", return_module_language($_SESSION['authenticated_user_language'], 'Contacts'));
626
			$this->smarty->assign("contact", $contactMeta);
627
628
			$ea = new SugarEmailAddress();
629
			$newEmail = $ea->getEmailAddressWidgetEditView($id, $module, true);
630
			$this->smarty->assign("emailWidget", $newEmail['html']);
631
632
			$ret['form'] = $this->smarty->fetch("modules/Emails/templates/editContact.tpl");
633
			$ret['prefillData'] = $newEmail['prefillData'];
634
		} else {
635
			$id = "";
636
			$ret['form'] = $app_strings['LBL_EMAIL_ERROR_NO_ACCESS'];
637
			$ret['prefillData'] = '{}';
638
		}
639
640
		$ret['id'] = $id;
641
		$ret['contactName'] = $contact->full_name;
642
643
		return $ret;
644
	}
645
646
647
	/**
648
	 * Retrieves a concatenated list of contacts, those with assigned_user_id = user's id and those in the address_book
649
	 * table
650
	 * @param array $contacts Array of contact types -> IDs
651
	 * @param object $user User in focus
652
	 * @return array
653
	 */
654
	function getUserContacts($contacts, $user=null) {
655
656
		global $current_user;
657
		global $locale;
658
659
		if(empty($user)) {
660
			$user = $current_user;
661
		}
662
663
		$emailAddress = new SugarEmailAddress();
664
		$ret = array();
665
666
		$union = '';
667
668
		$modules = array();
669
		foreach($contacts as $contact) {
670
			if(!isset($modules[$contact['module']])) {
671
				$modules[$contact['module']] = array();
672
			}
673
			$modules[$contact['module']][] = $contact;
674
		}
675
676
		foreach($modules as $module => $contacts) {
677
			if(!empty($union)) {
678
				$union .= " UNION ALL ";
679
			}
680
681
			$table = strtolower($module);
682
			$idsSerial = '';
683
684
			foreach($contacts as $contact) {
685
				if(!empty($idsSerial)) {
686
					$idsSerial .= ",";
687
				}
688
				$idsSerial .= "'{$contact['id']}'";
689
			}
690
691
			$union .= "(SELECT id, first_name, last_name, title, '{$module}' module FROM {$table} WHERE id IN({$idsSerial}) AND deleted = 0 )";
692
		}
693
		if(!empty($union)) {
694
			$union .= " ORDER BY last_name";
695
		}
696
697
		$r = $user->db->query($union);
698
699
		//_pp($union);
700
701
		while($a = $user->db->fetchByAssoc($r)) {
702
			$c = array();
703
704
			$c['name'] = $locale->getLocaleFormattedName($a['first_name'], "<b>{$a['last_name']}</b>", '', $a['title'], '', $user);
705
			$c['id'] = $a['id'];
706
			$c['module'] = $a['module'];
707
			$c['email'] = $emailAddress->getAddressesByGUID($a['id'], $a['module']);
708
			$ret[$a['id']] = $c;
709
		}
710
711
		return $ret;
712
	}
713
	////	END ADDRESS BOOK
714
	///////////////////////////////////////////////////////////////////////////
715
716
717
	///////////////////////////////////////////////////////////////////////////
718
	////	EMAIL 2.0 Preferences
719
	function getUserPrefsJS() {
720
		global $current_user;
721
		global $locale;
722
723
		// sort order per mailbox view
724
		$sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
725
		$sortArray = array();
726
		if(!empty($sortSerial)) {
727
			$sortArray = unserialize($sortSerial);
728
		}
729
730
		// treeview collapsed/open states
731
		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
732
		$folderStates = array();
733
		if(!empty($folderStateSerial)) {
734
			$folderStates = unserialize($folderStateSerial);
735
		}
736
737
		// subscribed accounts
738
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
739
740
		// general settings
741
		$emailSettings = $current_user->getPreference('emailSettings', 'Emails');
742
743
		if(empty($emailSettings)) {
744
			$emailSettings = array();
745
			$emailSettings['emailCheckInterval'] = -1;
746
			$emailSettings['autoImport'] = '';
747
			$emailSettings['alwaysSaveOutbound'] = '1';
748
			$emailSettings['sendPlainText'] = '';
749
			$emailSettings['defaultOutboundCharset'] = $GLOBALS['sugar_config']['default_email_charset'];
750
			$emailSettings['showNumInList'] = 20;
751
		}
752
753
		// focus folder
754
		$focusFolder = $current_user->getPreference('focusFolder', 'Emails');
755
		$focusFolder = !empty($focusFolder) ? unserialize($focusFolder) : array();
756
757
		// unread only flag
758
		$showUnreadOnly = $current_user->getPreference('showUnreadOnly', 'Emails');
759
760
		$listViewSort = array(
761
			"sortBy" => 'date',
762
			"sortDirection" => 'DESC',
763
		);
764
765
		// signature prefs
766
		$signaturePrepend = $current_user->getPreference('signature_prepend') ? 'true' : 'false';
767
		$signatureDefault = $current_user->getPreference('signature_default');
768
		$signatures = array(
769
			'signature_prepend' => $signaturePrepend,
770
			'signature_default' => $signatureDefault
771
		);
772
773
774
		// current_user
775
		$user = array(
776
			'emailAddresses' => $current_user->emailAddress->getAddressesByGUID($current_user->id, 'Users'),
777
			'full_name' => from_html($current_user->full_name),
778
		);
779
780
		$userPreferences = array();
781
		$userPreferences['sort'] = $sortArray;
782
		$userPreferences['folderStates'] = $folderStates;
783
		$userPreferences['showFolders'] = $showFolders;
784
		$userPreferences['emailSettings'] = $emailSettings;
785
		$userPreferences['focusFolder'] = $focusFolder;
786
		$userPreferences['showUnreadOnly'] = $showUnreadOnly;
787
		$userPreferences['listViewSort'] = $listViewSort;
788
		$userPreferences['signatures'] = $signatures;
789
		$userPreferences['current_user'] = $user;
790
		return $userPreferences;
791
	}
792
793
794
795
	///////////////////////////////////////////////////////////////////////////
796
	////	FOLDER FUNCTIONS
797
798
	/**
799
	 * Creates a new Sugar folder
800
	 * @param string $nodeLabel New sugar folder name
801
	 * @param string $parentLabel Parent folder name
0 ignored issues
show
Bug introduced by
There is no parameter named $parentLabel. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
802
	 */
803
	function saveNewFolder($nodeLabel, $parentId, $isGroup=0) {
804
		global $current_user;
805
806
		$this->folder->name = $nodeLabel;
807
		$this->folder->is_group = $isGroup;
808
		$this->folder->parent_folder = ($parentId == 'Home') ? "" : $parentId;
809
		$this->folder->has_child = 0;
810
		$this->folder->created_by = $current_user->id;
811
		$this->folder->modified_by = $current_user->id;
812
		$this->folder->date_modified = $this->folder->date_created = TimeDate::getInstance()->nowDb();
813
814
		$this->folder->save();
815
		return array(
816
			'action' => 'newFolderSave',
817
			'id' => $this->folder->id,
818
			'name' => $this->folder->name,
819
			'is_group' => $this->folder->is_group,
820
			'is_dynamic' => $this->folder->is_dynamic
821
		);
822
	}
823
824
	/**
825
	 * Saves user sort prefernces
826
	 */
827
	function saveListViewSortOrder($ieId, $focusFolder, $sortBy, $sortDir) {
828
		global $current_user;
829
830
		$sortArray = array();
831
832
		$sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
833
		if(!empty($sortSerial)) {
834
			$sortArray = unserialize($sortSerial);
835
		}
836
837
		$sortArray[$ieId][$focusFolder]['current']['sort'] = $sortBy;
838
		$sortArray[$ieId][$focusFolder]['current']['direction'] = $sortDir;
839
		$sortSerial = serialize($sortArray);
840
		$current_user->setPreference('folderSortOrder', $sortSerial, '', 'Emails');
841
	}
842
843
	/**
844
	 * Stickies folder collapse/open state
845
	 */
846
	function saveFolderOpenState($focusFolder, $focusFolderOpen) {
847
		global $current_user;
848
849
		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
850
		$folderStates = array();
851
852
		if(!empty($folderStateSerial)) {
853
			$folderStates = unserialize($folderStateSerial);
854
		}
855
856
		$folderStates[$focusFolder] = $focusFolderOpen;
857
		$newFolderStateSerial = serialize($folderStates);
858
		$current_user->setPreference('folderOpenState', $newFolderStateSerial, '', 'Emails');
859
	}
860
861
	/**
862
	 * saves a folder's view state
863
	 */
864
	function saveListView($ieId, $folder) {
865
		global $current_user;
866
867
		$saveState = array();
868
		$saveState['ieId'] = $ieId;
869
		$saveState['folder'] = $folder;
870
		$saveStateSerial = serialize($saveState);
871
		$current_user->setPreference('focusFolder', $saveStateSerial, '', 'Emails');
872
	}
873
874
	/**
875
	 * Generates cache folder structure
876
	 */
877
	function preflightEmailCache($cacheRoot) {
878
		// base
879
		if(!file_exists($cacheRoot))
880
			mkdir_recursive(clean_path($cacheRoot));
881
882
		// folders
883
		if(!file_exists($cacheRoot."/folders"))
884
			mkdir_recursive(clean_path("{$cacheRoot}/folders"));
885
886
		// messages
887
		if(!file_exists($cacheRoot."/messages"))
888
			mkdir_recursive(clean_path("{$cacheRoot}/messages"));
889
890
		// attachments
891
		if(!file_exists($cacheRoot."/attachments"))
892
			mkdir_recursive(clean_path("{$cacheRoot}/attachments"));
893
	}
894
895
	function deleteEmailCacheForFolders($cacheRoot) {
896
		$filePath = $cacheRoot."/folders/folders.php";
897
		if (file_exists($filePath)) {
898
			unlink($filePath);
899
		}
900
	}
901
	///////////////////////////////////////////////////////////////////////////
902
	////	IMAP FUNCTIONS
903
	/**
904
	 * Identifies subscribed mailboxes and empties the trash
905
	 * @param object $ie InboundEmail
906
	 */
907
	function emptyTrash(&$ie) {
908
		global $current_user;
909
910
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
911
912
		if(is_array($showFolders)) {
913
			foreach($showFolders as $ieId) {
914
				if(!empty($ieId)) {
915
					$ie->retrieve($ieId);
916
					$ie->emptyTrash();
917
				}
918
			}
919
		}
920
	}
921
922
	/**
923
	 * returns an array of nodes that correspond to IMAP mailboxes.
924
	 * @param bool $forceRefresh
0 ignored issues
show
Bug introduced by
There is no parameter named $forceRefresh. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
925
	 * @return object TreeView object
926
	 */
927
	function getMailboxNodes() {
928
		global $sugar_config;
929
		global $current_user;
930
		global $app_strings;
931
932
		$tree = new Tree("frameFolders");
933
		$tree->tree_style= 'include/ytree/TreeView/css/check/tree.css';
934
935
		$nodes = array();
936
		$ie = new InboundEmail();
937
		$refreshOffset = $this->cacheTimeouts['folders']; // 5 mins.  this will be set via user prefs
938
939
		$rootNode = new ExtNode($app_strings['LBL_EMAIL_HOME_FOLDER'], $app_strings['LBL_EMAIL_HOME_FOLDER']);
940
		$rootNode->dynamicloadfunction = '';
941
		$rootNode->expanded = true;
942
		$rootNode->dynamic_load = true;
943
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
944
945
		if(empty($showFolders)) {
946
			$showFolders = array();
947
		}
948
949
		// INBOX NODES
950
		if($current_user->hasPersonalEmail()) {
951
			$personals = $ie->retrieveByGroupId($current_user->id);
952
953
			foreach($personals as $k => $personalAccount) {
954
				if(in_array($personalAccount->id, $showFolders)) {
955
					// check for cache value
956
					$cacheRoot = sugar_cached("modules/Emails/{$personalAccount->id}");
957
					$this->preflightEmailCache($cacheRoot);
958
959
					if($this->validCacheFileExists($personalAccount->id, 'folders', "folders.php")) {
960
						$mailboxes = $this->getMailBoxesFromCacheValue($personalAccount);
961
					} else {
962
						$mailboxes = $personalAccount->getMailboxes();
963
					}
964
965
					$acctNode = new ExtNode('Home::' . $personalAccount->name, $personalAccount->name);
966
					$acctNode->dynamicloadfunction = '';
967
					$acctNode->expanded = false;
968
					$acctNode->set_property('cls', 'ieFolder');
969
					$acctNode->set_property('ieId', $personalAccount->id);
970
		        	$acctNode->set_property('protocol', $personalAccount->protocol);
971
972
					if(array_key_exists('Home::'.$personalAccount->name, $this->folderStates)) {
973
						if($this->folderStates['Home::'.$personalAccount->name] == 'open') {
974
							$acctNode->expanded = true;
975
						}
976
					}
977
					$acctNode->dynamic_load = true;
978
979
					$nodePath = $acctNode->_properties['id'];
980
981
					foreach($mailboxes as $k => $mbox) {
982
						$acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $personalAccount->id,
983
						    $nodePath, false, $personalAccount));
984
					}
985
986
					$rootNode->add_node($acctNode);
987
				}
988
			}
989
		}
990
991
		// GROUP INBOX NODES
992
		$beans = $ie->retrieveAllByGroupId($current_user->id, false);
993
		foreach($beans as $k => $groupAccount) {
994
			if(in_array($groupAccount->id, $showFolders)) {
995
				// check for cache value
996
				$cacheRoot = sugar_cached("modules/Emails/{$groupAccount->id}");
997
				$this->preflightEmailCache($cacheRoot);
998
				//$groupAccount->connectMailserver();
999
1000
				if($this->validCacheFileExists($groupAccount->id, 'folders', "folders.php")) {
1001
					$mailboxes = $this->getMailBoxesFromCacheValue($groupAccount);
1002
				} else {
1003
					$mailboxes = $groupAccount->getMailBoxesForGroupAccount();
1004
				}
1005
1006
				$acctNode = new ExtNode($groupAccount->name, "group.{$groupAccount->name}");
1007
				$acctNode->dynamicloadfunction = '';
1008
				$acctNode->expanded = false;
1009
		        $acctNode->set_property('isGroup', 'true');
1010
		        $acctNode->set_property('ieId', $groupAccount->id);
1011
		        $acctNode->set_property('protocol', $groupAccount->protocol);
1012
1013
				if(array_key_exists('Home::'.$groupAccount->name, $this->folderStates)) {
1014
					if($this->folderStates['Home::'.$groupAccount->name] == 'open') {
1015
						$acctNode->expanded = true;
1016
					}
1017
				}
1018
				$acctNode->dynamic_load = true;
1019
				$nodePath = $rootNode->_properties['id']."::".$acctNode->_properties['id'];
1020
1021
				foreach($mailboxes as $k => $mbox) {
1022
					$acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $groupAccount->id,
1023
					   $nodePath, true, $groupAccount));
1024
				}
1025
1026
				$rootNode->add_node($acctNode);
1027
			}
1028
		}
1029
1030
		// SugarFolder nodes
1031
		/* SugarFolders are built at onload when the UI renders */
1032
1033
		$tree->add_node($rootNode);
1034
		return $tree;
1035
	}
1036
1037
	function getMailBoxesFromCacheValue($mailAccount) {
1038
		$foldersCache = $this->getCacheValue($mailAccount->id, 'folders', "folders.php", 'foldersCache');
1039
		$mailboxes = $foldersCache['mailboxes'];
1040
		$mailboxesArray = $mailAccount->generateFlatArrayFromMultiDimArray($mailboxes, $mailAccount->retrieveDelimiter());
1041
		$mailAccount->saveMailBoxFolders($mailboxesArray);
1042
		$this->deleteEmailCacheForFolders($cacheRoot);
1043
		return $mailboxes;
1044
	} // fn
1045
1046
	/**
1047
	 * Builds up a TreeView Node object
1048
	 * @param mixed
1049
	 * @param mixed
1050
	 * @param string
1051
	 * @param string ID of InboundEmail instance
1052
	 * @param string nodePath Serialized path from root node to current node
1053
	 * @param bool isGroup
1054
	 * @param bool forceRefresh
1055
	 * @return mixed
1056
	 */
1057
	function buildTreeNode($key, $label, $mbox, $ieId, $nodePath, $isGroup, $ie) {
1058
		global $sugar_config;
1059
1060
		// get unread counts
1061
		$exMbox = explode("::", $nodePath);
1062
		$unseen = 0;
1063
		$GLOBALS['log']->debug("$key --- $nodePath::$label");
1064
1065
		if(count($exMbox) >= 2) {
1066
			$mailbox = "";
1067
			for($i=2; $i<count($exMbox); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1068
				if($mailbox != "") {
1069
					$mailbox .= ".";
1070
				}
1071
				$mailbox .= "{$exMbox[$i]}";
1072
			}
1073
1074
		    $mailbox = substr($key, strpos($key, '.'));
1075
1076
			$unseen = $this->getUnreadCount($ie, $mailbox);
1077
1078
			if($unseen > 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1079
				//$label = " <span id='span{$ie->id}{$ie->mailbox}' style='font-weight:bold'>{$label} (<span id='span{$ie->id}{$ie->mailbox}nums'>{$unseen}</span>)</span>";
1080
			}
1081
		}
1082
1083
		$nodePath = $nodePath."::".$label;
1084
        $node = new ExtNode($nodePath, $label);
1085
        $node->dynamicloadfunction = '';
1086
        $node->expanded = false;
1087
        $node->set_property('labelStyle', "remoteFolder");
1088
1089
1090
        if(array_key_exists($nodePath, $this->folderStates)) {
1091
        	if($this->folderStates[$nodePath] == 'open') {
1092
        		$node->expanded = true;
1093
        	}
1094
        }
1095
1096
		$group = ($isGroup) ? 'true' : 'false';
1097
        $node->dynamic_load = true;
1098
        //$node->set_property('href', " SUGAR.email2.listView.populateListFrame(YAHOO.namespace('frameFolders').selectednode, '{$ieId}', 'false');");
1099
        $node->set_property('isGroup', $group);
1100
        $node->set_property('isDynamic', 'false');
1101
        $node->set_property('ieId', $ieId);
1102
        $node->set_property('mbox', $key);
1103
        $node->set_property('unseen', $unseen);
1104
        $node->set_property('cls', 'ieFolder');
1105
1106
        if(is_array($mbox)) {
1107
        	foreach($mbox as $k => $v) {
1108
        		$node->add_node($this->buildTreeNode("$key.$k", $k, $v, $ieId, $nodePath, $isGroup, $ie));
1109
        	}
1110
        }
1111
1112
        return $node;
1113
	}
1114
1115
	/**
1116
	 * Totals the unread emails
1117
	 */
1118
	function getUnreadCount(&$ie, $mailbox) {
1119
		global $sugar_config;
1120
		$unseen = 0;
1121
1122
		// use cache
1123
		return $ie->getCacheUnreadCount($mailbox);
1124
	}
1125
1126
	///////////////////////////////////////////////////////////////////////////
1127
	////	DISPLAY CODE
1128
	/**
1129
	 * Used exclusively by draft code.  Returns Notes and Documents as attachments.
1130
	 * @param array $ret
1131
	 * @return array
1132
	 */
1133
	function getDraftAttachments($ret) {
1134
		global $db;
1135
1136
		// $ret['uid'] is the draft Email object's GUID
1137
		$ret['attachments'] = array();
1138
1139
		$q = "SELECT id, filename FROM notes WHERE parent_id = '{$ret['uid']}' AND deleted = 0";
1140
		$r = $db->query($q);
1141
1142
		while($a = $db->fetchByAssoc($r)) {
1143
			$ret['attachments'][$a['id']] = array(
1144
				'id'		=> $a['id'],
1145
				'filename'	=> $a['filename'],
1146
			);
1147
		}
1148
1149
		return $ret;
1150
	}
1151
1152
	function createCopyOfInboundAttachment($ie, $ret, $uid) {
1153
		global $sugar_config;
1154
		if ($ie->isPop3Protocol()) {
1155
			// get the UIDL from database;
1156
			$cachedUIDL = md5($uid);
1157
			$cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$cachedUIDL}.php");
1158
		} else {
1159
			$cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$uid}.php");
1160
		}
1161
		if(file_exists($cache)) {
1162
			include($cache); // profides $cacheFile
1163
			$metaOut = unserialize($cacheFile['out']);
1164
			$meta = $metaOut['meta']['email'];
1165
			if (isset($meta['attachments'])) {
1166
				$attachmentHtmlData = $meta['attachments'];
1167
				$actualAttachmentInfo = array();
1168
				$this->parseAttachmentInfo($actualAttachmentInfo, $attachmentHtmlData);
1169
				if (sizeof($actualAttachmentInfo) > 0) {
1170
					foreach($actualAttachmentInfo as $key => $value) {
1171
					    $info_vars = array();
1172
					    parse_str($value, $info_vars);
1173
					    $fileName = $info_vars['tempName'];
1174
					    $attachmentid = $info_vars['id'];
1175
						$guid = create_guid();
1176
						$destination = clean_path("{$this->userCacheDir}/{$guid}");
1177
1178
						$attachmentFilePath = sugar_cached("modules/Emails/{$ie->id}/attachments/{$attachmentid}");
1179
						copy($attachmentFilePath, $destination);
1180
						$ret['attachments'][$guid] = array();
1181
						$ret['attachments'][$guid]['id'] = $guid . $fileName;
1182
						$ret['attachments'][$guid]['filename'] = $fileName;
1183
					} // for
1184
				} // if
1185
			} // if
1186
1187
		} // if
1188
		return $ret;
1189
1190
	} // fn
1191
1192
	function parseAttachmentInfo(&$actualAttachmentInfo, $attachmentHtmlData) {
1193
	 	$downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
1194
		while ($downLoadPHP) {
1195
		 	$attachmentHtmlData = substr($attachmentHtmlData, $downLoadPHP+30);
1196
		 	$final = strpos($attachmentHtmlData, "\">");
1197
		 	$actualAttachmentInfo[] = substr($attachmentHtmlData, 0, $final);
1198
		 	$attachmentHtmlData = substr($attachmentHtmlData, $final);
1199
		 	$downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
1200
		} // while
1201
	}
1202
	/**
1203
	 * Renders the QuickCreate form from Smarty and returns HTML
1204
	 * @param array $vars request variable global
1205
	 * @param object $email Fetched email object
1206
	 * @param bool $addToAddressBook
0 ignored issues
show
Documentation introduced by
There is no parameter named $addToAddressBook. Did you maybe mean $addToAddressBookButton?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1207
	 * @return array
1208
	 */
1209
	function getQuickCreateForm($vars, $email, $addToAddressBookButton=false) {
1210
		require_once("include/EditView/EditView2.php");
1211
		global $app_strings;
1212
		global $mod_strings;
1213
		global $current_user;
1214
		global $beanList;
1215
		global $beanFiles;
1216
		global $current_language;
1217
1218
		//Setup the current module languge
1219
		$mod_strings = return_module_language($current_language, $_REQUEST['qc_module']);
1220
1221
		$bean = $beanList[$_REQUEST['qc_module']];
1222
		$class = $beanFiles[$bean];
1223
		require_once($class);
1224
1225
		$focus = new $bean();
1226
1227
		$people = array(
1228
		'Contact'
1229
		,'Lead'
1230
		);
1231
		$emailAddress = array();
1232
1233
		// people
1234
		if(in_array($bean, $people)) {
1235
			// lead specific
1236
			$focus->lead_source = 'Email';
1237
			$focus->lead_source_description = trim($email->name);
1238
1239
			$from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr;
1240
1241
            if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail']))
1242
            {
1243
                if($email->status == "sent")
1244
                {
1245
                    $from = (isset($email->to_addrs_names) && !empty($email->to_addrs_names)) ? $email->to_addrs_names : $email->to_addrs;
1246
                }else{
1247
                    $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr_name;
1248
                }
1249
            }
1250
1251
			$name = explode(" ", trim($from));
1252
1253
			$address = trim(array_pop($name));
1254
			$address = str_replace(array("<",">","&lt;","&gt;"), "", $address);
1255
1256
			$emailAddress[] = array(
1257
				'email_address'		=> $address,
1258
				'primary_address'	=> 1,
1259
				'invalid_email'		=> 0,
1260
				'opt_out'			=> 0,
1261
				'reply_to_address'	=> 1
1262
			);
1263
1264
			$focus->email1 = $address;
1265
1266
			if(!empty($name)) {
1267
				$focus->last_name = trim(array_pop($name));
1268
1269
				foreach($name as $first) {
1270
					if(!empty($focus->first_name)) {
1271
						$focus->first_name .= " ";
1272
					}
1273
					$focus->first_name .= trim($first);
1274
				}
1275
			}
1276
		} else {
1277
			// bugs, cases, tasks
1278
			$focus->name = trim($email->name);
1279
		}
1280
1281
		$focus->description = trim(strip_tags($email->description));
1282
		$focus->assigned_user_id = $current_user->id;
1283
1284
1285
		$EditView = new EditView();
0 ignored issues
show
Bug introduced by
The call to EditView::EditView() misses some required arguments starting with $module.
Loading history...
Deprecated Code introduced by
The class EditView has been deprecated.

This class, trait or interface has been deprecated.

Loading history...
1286
		$EditView->ss = new Sugar_Smarty();
1287
		//MFH BUG#20283 - checks for custom quickcreate fields
1288
		$EditView->setup($_REQUEST['qc_module'], $focus, 'custom/modules/'.$focus->module_dir.'/metadata/editviewdefs.php', 'include/EditView/EditView.tpl');
1289
		$EditView->process();
1290
		$EditView->render();
0 ignored issues
show
Bug introduced by
The method render() does not seem to exist on object<EditView>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1291
1292
		$EditView->defs['templateMeta']['form']['buttons'] = array(
1293
			'email2save' => array(
1294
				'id' => 'e2AjaxSave',
1295
				'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_SAVE_BUTTON_LABEL']
1296
				              . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(false);" />'
1297
			),
1298
			'email2saveandreply' => array(
1299
			    'id' => 'e2SaveAndReply',
1300
			    'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_SAVE_AND_REPLY']
1301
			                  . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(\'reply\');" />'
1302
			),
1303
			'email2cancel' => array(
1304
			     'id' => 'e2cancel',
1305
			     'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_CANCEL']
1306
                              . '   " onclick="SUGAR.email2.detailView.quickCreateDialog.hide();" />'
1307
			)
1308
		);
1309
1310
1311
		if($addToAddressBookButton) {
1312
			$EditView->defs['templateMeta']['form']['buttons']['email2saveAddToAddressBook'] = array(
1313
				'id' => 'e2addToAddressBook',
1314
				'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_ADDRESS_BOOK_SAVE_AND_ADD']
1315
				              . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(true);" />'
1316
			);
1317
		}
1318
1319
		//Get the module language for javascript
1320
	    if(!is_file(sugar_cached('jsLanguage/') . $_REQUEST['qc_module'] . '/' . $GLOBALS['current_language'] . '.js')) {
1321
            require_once('include/language/jsLanguage.php');
1322
            jsLanguage::createModuleStringsCache($_REQUEST['qc_module'], $GLOBALS['current_language']);
1323
        }
1324
		$jsLanguage = getVersionedScript("cache/jsLanguage/{$_REQUEST['qc_module']}/{$GLOBALS['current_language']}.js", $GLOBALS['sugar_config']['js_lang_version']);
1325
1326
1327
		$EditView->view = 'EmailQCView';
1328
		$EditView->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl';
1329
		$EditView->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl';
1330
		$meta = array();
1331
		$meta['html'] = $jsLanguage . $EditView->display(false, true);
0 ignored issues
show
Unused Code introduced by
The call to EditView::display() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1332
		$meta['html'] = str_replace("src='".getVersionedPath('include/SugarEmailAddress/SugarEmailAddress.js')."'", '', $meta['html']);
1333
		$meta['emailAddress'] = $emailAddress;
1334
1335
		$mod_strings = return_module_language($current_language, 'Emails');
1336
1337
		return $meta;
1338
	}
1339
1340
	/**
1341
     * Renders the Import form from Smarty and returns HTML
1342
     * @param array $vars request variable global
1343
     * @param object $email Fetched email object
1344
     * @param bool $addToAddressBook
0 ignored issues
show
Bug introduced by
There is no parameter named $addToAddressBook. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1345
     * @return array
1346
     */
1347
    function getImportForm($vars, $email, $formName = 'ImportEditView') {
1348
		require_once("include/EditView/EditView2.php");
1349
        require_once("include/TemplateHandler/TemplateHandler.php");
1350
		require_once('include/QuickSearchDefaults.php');
1351
        $qsd = QuickSearchDefaults::getQuickSearchDefaults();
1352
		$qsd->setFormName($formName);
1353
1354
        global $app_strings;
1355
        global $current_user;
1356
        global $app_list_strings;
1357
		$sqs_objects = array(
1358
		                     "{$formName}_parent_name" => $qsd->getQSParent(),
1359
		);
1360
        $smarty = new Sugar_Smarty();
1361
        $smarty->assign("APP",$app_strings);
1362
        $smarty->assign('formName',$formName);
1363
        $showAssignTo = false;
1364
        if (!isset($vars['showAssignTo']) || $vars['showAssignTo'] == true) {
1365
        	$showAssignTo = true;
1366
		} // if
1367
		if ($showAssignTo) {
1368
	        if(empty($email->assigned_user_id) && empty($email->id))
1369
	            $email->assigned_user_id = $current_user->id;
1370
	        if(empty($email->assigned_name) && empty($email->id))
1371
	            $email->assigned_user_name = $current_user->user_name;
1372
	        $sqs_objects["{$formName}_assigned_user_name"] = $qsd->getQSUser();
1373
		}
1374
		$smarty->assign("showAssignedTo",$showAssignTo);
1375
1376
        $showDelete = false;
1377
        if (!isset($vars['showDelete']) || $vars['showDelete'] == true) {
1378
            $showDelete = true;
1379
        }
1380
        $smarty->assign("showDelete",$showDelete);
1381
1382
        $smarty->assign("userId",$email->assigned_user_id);
1383
        $smarty->assign("userName",$email->assigned_user_name);
1384
        $parent_types = $app_list_strings['record_type_display'];
1385
        $smarty->assign('parentOptions', get_select_options_with_id($parent_types, $email->parent_type));
1386
1387
		$quicksearch_js = '<script type="text/javascript" language="javascript">sqs_objects = ' . json_encode($sqs_objects) . '</script>';
1388
        $smarty->assign('SQS', $quicksearch_js);
1389
1390
        $meta = array();
1391
        $meta['html'] = $smarty->fetch("modules/Emails/templates/importRelate.tpl");
1392
        return $meta;
1393
    }
1394
1395
    /**
1396
     * This function returns the detail view for email in new 2.0 interface
1397
     *
1398
     */
1399
    function getDetailViewForEmail2($emailId) {
1400
1401
		require_once('include/DetailView/DetailView.php');
1402
		global $app_strings, $app_list_strings;
1403
		global $mod_strings;
1404
1405
        $smarty = new Sugar_Smarty();
1406
1407
		// SETTING DEFAULTS
1408
		$focus		= new Email();
1409
		$focus->retrieve($emailId);
1410
		$detailView->ss = new Sugar_Smarty();
0 ignored issues
show
Bug introduced by
The variable $detailView seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1411
		$detailView	= new DetailView();
1412
		$title = "";
1413
		$offset		= 0;
1414
		if($focus->type == 'out') {
1415
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true);
1416
		} elseif ($focus->type == 'draft') {
1417
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true);
1418
		} elseif($focus->type == 'inbound') {
1419
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true);
1420
		}
1421
		$smarty->assign("emailTitle", $title);
1422
1423
		// DEFAULT TO TEXT IF NO HTML CONTENT:
1424
		$html = trim(from_html($focus->description_html));
1425
		if(empty($html)) {
1426
			$smarty->assign('SHOW_PLAINTEXT', 'true');
1427
		} else {
1428
			$smarty->assign('SHOW_PLAINTEXT', 'false');
1429
		}
1430
1431
		//if not empty or set to test (from test campaigns)
1432
		if (!empty($focus->parent_type) && $focus->parent_type !='test') {
1433
			$smarty->assign('PARENT_MODULE', $focus->parent_type);
1434
			$smarty->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ":");
1435
		}
1436
1437
        global $gridline;
1438
		$smarty->assign('MOD', $mod_strings);
1439
		$smarty->assign('APP', $app_strings);
1440
		$smarty->assign('GRIDLINE', $gridline);
1441
		$smarty->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']);
1442
		$smarty->assign('ID', $focus->id);
1443
		$smarty->assign('TYPE', $focus->type);
1444
		$smarty->assign('PARENT_NAME', $focus->parent_name);
1445
		$smarty->assign('PARENT_ID', $focus->parent_id);
1446
		$smarty->assign('NAME', $focus->name);
1447
		$smarty->assign('ASSIGNED_TO', $focus->assigned_user_name);
1448
		$smarty->assign('DATE_MODIFIED', $focus->date_modified);
1449
		$smarty->assign('DATE_ENTERED', $focus->date_entered);
1450
		$smarty->assign('DATE_START', $focus->date_start);
1451
		$smarty->assign('TIME_START', $focus->time_start);
1452
		$smarty->assign('FROM', $focus->from_addr);
1453
		$smarty->assign('TO', nl2br($focus->to_addrs));
1454
		$smarty->assign('CC', nl2br($focus->cc_addrs));
1455
		$smarty->assign('BCC', nl2br($focus->bcc_addrs));
1456
		$smarty->assign('CREATED_BY', $focus->created_by_name);
1457
		$smarty->assign('MODIFIED_BY', $focus->modified_by_name);
1458
		$smarty->assign('DATE_SENT', $focus->date_entered);
1459
		$smarty->assign('EMAIL_NAME', 'RE: '.$focus->name);
1460
		$smarty->assign("TAG", $focus->listviewACLHelper());
1461
		$smarty->assign("SUGAR_VERSION", $GLOBALS['sugar_version']);
1462
		$smarty->assign("JS_CUSTOM_VERSION", $GLOBALS['sugar_config']['js_custom_version']);
1463
		if(!empty($focus->reply_to_email)) {
1464
			$replyTo = "
1465
				<tr>
1466
		        <td class=\"tabDetailViewDL\"><slot>".$mod_strings['LBL_REPLY_TO_NAME']."</slot></td>
1467
		        <td colspan=3 class=\"tabDetailViewDF\"><slot>".$focus->reply_to_addr."</slot></td>
1468
		        </tr>";
1469
		 	$smarty->assign("REPLY_TO", $replyTo);
1470
		}
1471
		///////////////////////////////////////////////////////////////////////////////
1472
		////	JAVASCRIPT VARS
1473
		$jsVars  = '';
1474
		$jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';";
1475
		$jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';";
1476
		$smarty->assign("JS_VARS", $jsVars);
1477
		///////////////////////////////////////////////////////////////////////////////
1478
		////	NOTES (attachements, etc.)
1479
		///////////////////////////////////////////////////////////////////////////////
1480
1481
		$note = new Note();
1482
		$where = "notes.parent_id='{$focus->id}'";
1483
		//take in account if this is from campaign and the template id is stored in the macros.
1484
1485
		if(isset($macro_values) && isset($macro_values['email_template_id'])){
0 ignored issues
show
Bug introduced by
The variable $macro_values seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1486
		    $where = "notes.parent_id='{$macro_values['email_template_id']}'";
1487
		}
1488
		$notes_list = $note->get_full_list("notes.name", $where, true);
1489
1490
		if(! isset($notes_list)) {
1491
			$notes_list = array();
1492
		}
1493
1494
		$attachments = '';
1495
		for($i=0; $i<count($notes_list); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1496
			$the_note = $notes_list[$i];
1497
			$attachments .= "<a href=\"index.php?entryPoint=download&id={$the_note->id}&type=Notes\">".$the_note->name."</a><br />";
1498
			$focus->cid2Link($the_note->id, $the_note->file_mime_type);
1499
		}
1500
		$smarty->assign('DESCRIPTION', nl2br($focus->description));
1501
		$smarty->assign('DESCRIPTION_HTML', from_html($focus->description_html));
1502
		$smarty->assign("ATTACHMENTS", $attachments);
1503
		///////////////////////////////////////////////////////////////////////////////
1504
		////    SUBPANELS
1505
		///////////////////////////////////////////////////////////////////////////////
1506
		$show_subpanels = true;
1507
		if ($show_subpanels) {
1508
		    require_once('include/SubPanel/SubPanelTiles.php');
1509
		    $subpanel = new SubPanelTiles($focus, 'Emails');
1510
		    $smarty->assign("SUBPANEL", $subpanel->display());
1511
		}
1512
        $meta['html'] = $smarty->fetch("modules/Emails/templates/emailDetailView.tpl");
1513
        return $meta;
1514
1515
    } // fn
1516
1517
	/**
1518
	 * Sets the "read" flag in the overview cache
1519
	 */
1520
	function setReadFlag($ieId, $mbox, $uid) {
1521
		$this->markEmails('read', $ieId, $mbox, $uid);
1522
	}
1523
1524
	/**
1525
	 * Marks emails with the passed flag type.  This will be applied to local
1526
	 * cache files as well as remote emails.
1527
	 * @param string $type Flag type
1528
	 * @param string $ieId
1529
	 * @param string $folder IMAP folder structure or SugarFolder GUID
1530
	 * @param string $uids Comma sep list of UIDs or GUIDs
1531
	 */
1532
	function markEmails($type, $ieId, $folder, $uids) {
1533
1534
		global $app_strings;
1535
		$uids = $this->_cleanUIDList($uids);
1536
		$exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1537
1538
		if(strpos($folder, 'sugar::') !== false) {
1539
			// dealing with a sugar email object, uids are GUIDs
1540
			foreach($exUids as $id) {
1541
				$email = new Email();
1542
				$email->retrieve($id);
1543
1544
                // BUG FIX BEGIN
1545
                // Bug 50973 - marking unread in group inbox removes message
1546
                if (empty($email->assigned_user_id))
1547
                {
1548
                    $email->setFieldNullable('assigned_user_id');
1549
                }
1550
                // BUG FIX END
1551
1552
				switch($type) {
1553
					case "unread":
1554
						$email->status = 'unread';
1555
						$email->save();
1556
					break;
1557
1558
					case "read":
1559
						$email->status = 'read';
1560
						$email->save();
1561
					break;
1562
1563
					case "deleted":
1564
						$email->delete();
1565
					break;
1566
1567
					case "flagged":
1568
						$email->flagged = 1;
1569
						$email->save();
1570
					break;
1571
1572
					case "unflagged":
1573
						$email->flagged = 0;
1574
						$email->save();
1575
					break;
1576
1577
				}
1578
1579
                // BUG FIX BEGIN
1580
                // Bug 50973 - reset assigned_user_id field defs
1581
                if (empty($email->assigned_user_id))
1582
                {
1583
                    $email->revertFieldNullable('assigned_user_id');
1584
                }
1585
                // BUG FIX END
1586
			}
1587
		} else {
1588
			/* dealing with IMAP email, uids are IMAP uids */
1589
			global $ie; // provided by EmailUIAjax.php
1590
			if(empty($ie)) {
1591
1592
				$ie = new InboundEmail();
1593
			}
1594
			$ie->retrieve($ieId);
1595
			$ie->mailbox = $folder;
1596
			$ie->connectMailserver();
1597
			// mark cache files
1598
			if($type == 'deleted') {
1599
				$ie->deleteMessageOnMailServer($uids);
0 ignored issues
show
Bug introduced by
It seems like $uids defined by $this->_cleanUIDList($uids) on line 1535 can also be of type array; however, InboundEmail::deleteMessageOnMailServer() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1600
				$ie->deleteMessageFromCache($uids);
1601
			} else {
1602
				$overviews = $ie->getCacheValueForUIDs($ie->mailbox, $exUids);
1603
				$manipulated = array();
1604
1605
				foreach($overviews['retArr'] as $k => $overview) {
1606
					if(in_array($overview->uid, $exUids)) {
1607
						switch($type) {
1608
							case "unread":
1609
								$overview->seen = 0;
1610
							break;
1611
1612
							case "read":
1613
								$overview->seen = 1;
1614
							break;
1615
1616
							case "flagged":
1617
								$overview->flagged = 1;
1618
							break;
1619
1620
							case "unflagged":
1621
								$overview->flagged = 0;
1622
							break;
1623
						}
1624
						$manipulated[] = $overview;
1625
					}
1626
				}
1627
1628
				if(!empty($manipulated)) {
1629
					$ie->setCacheValue($ie->mailbox, array(), $manipulated);
1630
					/* now mark emails on email server */
1631
					$ie->markEmails(implode(",", explode($app_strings['LBL_EMAIL_DELIMITER'], $uids)), $type);
1632
				}
1633
			} // end not type == deleted
1634
		}
1635
	}
1636
1637
function doAssignment($distributeMethod, $ieid, $folder, $uids, $users) {
1638
	global $app_strings;
1639
	$users = explode(",", $users);
1640
	$emailIds = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1641
	$out = "";
1642
	if($folder != 'sugar::Emails') {
1643
		$emailIds = array();
1644
		$uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
1645
		$ie = new InboundEmail();
1646
		$ie->retrieve($ieid);
1647
		$messageIndex = 1;
1648
		// dealing with an inbound email data so we need to import an email and then
1649
		foreach($uids as $uid) {
1650
			$ie->mailbox = $folder;
1651
			$ie->connectMailserver();
1652
			$msgNo = $uid;
1653
			if (!$ie->isPop3Protocol()) {
1654
				$msgNo = imap_msgno($ie->conn, $uid);
1655
			} else {
1656
				$msgNo = $ie->getCorrectMessageNoForPop3($uid);
1657
			}
1658
1659
			if(!empty($msgNo)) {
1660
				if ($ie->importOneEmail($msgNo, $uid)) {
1661
					$emailIds[] = $ie->email->id;
1662
					$ie->deleteMessageOnMailServer($uid);
1663
					//$ie->retrieve($ieid);
1664
					//$ie->connectMailserver();
1665
					$ie->mailbox = $folder;
1666
					$ie->deleteMessageFromCache(($uids[] = $uid));
1667
				} else {
1668
					$out = $out . "Message No : " . $messageIndex . " failed. Reason : Message already imported \r\n";
1669
				}
1670
			}
1671
			$messageIndex++;
1672
		} // for
1673
	} // if
1674
1675
	if (count($emailIds) > 0) {
1676
		$this->doDistributionWithMethod($users, $emailIds, $distributeMethod);
1677
	} // if
1678
	return $out;
1679
} // fn
1680
1681
/**
1682
 * get team id and team set id from request
1683
 * @return  array
1684
 */
1685
function getTeams() {
1686
}
1687
1688
function doDistributionWithMethod($users, $emailIds, $distributionMethod) {
1689
	// we have users and the items to distribute
1690
	if($distributionMethod == 'roundRobin') {
1691
		$this->distRoundRobin($users, $emailIds);
1692
	} elseif($distributionMethod == 'leastBusy') {
1693
		$this->distLeastBusy($users, $emailIds);
1694
	} elseif($distributionMethod == 'direct') {
1695
		if(count($users) > 1) {
1696
			// only 1 user allowed in direct assignment
1697
			$error = 1;
1698
		} else {
1699
			$user = $users[0];
1700
			$this->distDirect($user, $emailIds);
1701
		} // else
1702
	} // elseif
1703
1704
} // fn
1705
1706
/**
1707
 * distributes emails to users on Round Robin basis
1708
 * @param	$userIds	array of users to dist to
1709
 * @param	$mailIds	array of email ids to push on those users
1710
 * @return  boolean		true on success
1711
 */
1712
function distRoundRobin($userIds, $mailIds) {
1713
	// check if we have a 'lastRobin'
1714
	$lastRobin = $userIds[0];
1715
	foreach($mailIds as $k => $mailId) {
1716
		$userIdsKeys = array_flip($userIds); // now keys are values
1717
		$thisRobinKey = $userIdsKeys[$lastRobin] + 1;
1718
		if(!empty($userIds[$thisRobinKey])) {
1719
			$thisRobin = $userIds[$thisRobinKey];
1720
			$lastRobin = $userIds[$thisRobinKey];
1721
		} else {
1722
			$thisRobin = $userIds[0];
1723
			$lastRobin = $userIds[0];
1724
		}
1725
1726
		$email = new Email();
1727
		$email->retrieve($mailId);
1728
		$email->assigned_user_id = $thisRobin;
1729
		$email->status = 'unread';
1730
		$email->save();
1731
	}
1732
1733
	return true;
1734
}
1735
1736
/**
1737
 * distributes emails to users on Least Busy basis
1738
 * @param	$userIds	array of users to dist to
1739
 * @param	$mailIds	array of email ids to push on those users
1740
 * @return  boolean		true on success
1741
 */
1742
function distLeastBusy($userIds, $mailIds) {
1743
	foreach($mailIds as $k => $mailId) {
1744
		$email = new Email();
1745
		$email->retrieve($mailId);
1746
		foreach($userIds as $k => $id) {
1747
			$r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '.$id.' AND status = 'unread'");
1748
			$a = $this->db->fetchByAssoc($r);
1749
			$counts[$id] = $a['c'];
1750
		}
1751
		asort($counts); // lowest to highest
1752
		$countsKeys = array_flip($counts); // keys now the 'count of items'
1753
		$leastBusy = array_shift($countsKeys); // user id of lowest item count
1754
		$email->assigned_user_id = $leastBusy;
1755
		$email->status = 'unread';
1756
		$email->save();
1757
	}
1758
	return true;
1759
}
1760
1761
/**
1762
 * distributes emails to 1 user
1763
 * @param	$user		users to dist to
1764
 * @param	$mailIds	array of email ids to push
1765
 * @return  boolean		true on success
1766
 */
1767
function distDirect($user, $mailIds) {
1768
	foreach($mailIds as $k => $mailId) {
1769
		$email = new Email();
1770
		$email->retrieve($mailId);
1771
		$email->assigned_user_id = $user;
1772
		$email->status = 'unread';
1773
1774
		$email->save();
1775
	}
1776
	return true;
1777
}
1778
1779
function getAssignedEmailsCountForUsers($userIds) {
1780
	$counts = array();
1781
	foreach($userIds as $id) {
1782
		$r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '$id' AND status = 'unread'");
1783
		$a = $this->db->fetchByAssoc($r);
1784
		$counts[$id] = $a['c'];
1785
	} // foreach
1786
	return $counts;
1787
} // fn
1788
1789
function getLastRobin($ie) {
1790
	$lastRobin = "";
1791
	if($this->validCacheFileExists($ie->id, 'folders', "robin.cache.php")) {
1792
		$lastRobin = $this->getCacheValue($ie->id, 'folders', "robin.cache.php", 'robin');
1793
	} // if
1794
	return $lastRobin;
1795
} // fn
1796
1797
function setLastRobin($ie, $lastRobin) {
1798
    global $sugar_config;
1799
    $cacheFolderPath = sugar_cached("modules/Emails/{$ie->id}/folders");
1800
    if (!file_exists($cacheFolderPath)) {
1801
    	mkdir_recursive($cacheFolderPath);
1802
    }
1803
	$this->writeCacheFile('robin', $lastRobin, $ie->id, 'folders', "robin.cache.php");
1804
} // fn
1805
1806
	/**
1807
	 * returns the metadata defining a single email message for display.  Uses cache file if it exists
1808
	 * @return array
1809
	 */
1810
function getSingleMessage($ie) {
1811
1812
		global $timedate;
1813
		global $app_strings,$mod_strings;
1814
		$ie->retrieve($_REQUEST['ieId']);
1815
		$noCache = true;
1816
1817
		$ie->mailbox = $_REQUEST['mbox'];
1818
		$filename = $_REQUEST['mbox'].$_REQUEST['uid'].".php";
1819
		$md5uidl = "";
1820
		if ($ie->isPop3Protocol()) {
1821
			$md5uidl = md5($_REQUEST['uid']);
1822
			$filename = $_REQUEST['mbox'].$md5uidl.".php";
1823
		} // if
1824
1825
		if(isset($filename) && strpos($filename, "..") !== false){
1826
			die("Directory navigation attack denied.");
1827
		}
1828
1829
		if($this->validCacheFileExists($_REQUEST['ieId'], 'messages', $filename)) {
1830
			$out = $this->getCacheValue($_REQUEST['ieId'], 'messages', $filename, 'out');
1831
			$noCache = false;
1832
1833
			// something fubar'd the cache?
1834
			if(empty($out['meta']['email']['name']) && empty($out['meta']['email']['description'])) {
1835
				$noCache = true;
1836
			} else {
1837
				// When sending data from cache, convert date into users preffered format
1838
				$dateTimeInGMTFormat = $out['meta']['email']['date_start'];
1839
				$out['meta']['email']['date_start'] = $timedate->to_display_date_time($dateTimeInGMTFormat);
1840
			} // else
1841
		}
1842
1843
		if($noCache) {
1844
			$writeToCacheFile = true;
1845
			if ($ie->isPop3Protocol()) {
1846
				$status = $ie->setEmailForDisplay($_REQUEST['uid'], true, true, true);
1847
			} else {
1848
				$status = $ie->setEmailForDisplay($_REQUEST['uid'], false, true, true);
1849
			}
1850
			$out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']);
1851
			// modify the out object to store date in GMT format on the local cache file
1852
			$dateTimeInUserFormat = $out['meta']['email']['date_start'];
1853
			$out['meta']['email']['date_start'] = $timedate->to_db($dateTimeInUserFormat);
1854
			if ($status == 'error') {
1855
				$writeToCacheFile = false;
1856
			}
1857
			if ($writeToCacheFile) {
1858
				if ($ie->isPop3Protocol()) {
1859
					$this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$md5uidl}.php");
1860
				} else {
1861
					$this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$_REQUEST['uid']}.php");
1862
				} // else
1863
			// restore date in the users preferred format to be send on to UI for diaply
1864
			$out['meta']['email']['date_start'] = $dateTimeInUserFormat;
1865
			} // if
1866
		}
1867
		$out['meta']['email']['toaddrs'] = $this->generateExpandableAddrs($out['meta']['email']['toaddrs']);
1868
		if(!empty($out['meta']['email']['cc_addrs'])) {
1869
            $ccs = $this->generateExpandableAddrs($out['meta']['email']['cc_addrs']);
1870
		    $out['meta']['cc'] = <<<eoq
1871
				<tr>
1872
					<td NOWRAP valign="top" class="displayEmailLabel">
1873
						{$app_strings['LBL_EMAIL_CC']}:
1874
					</td>
1875
					<td class="displayEmailValue">
1876
						{$ccs}
1877
					</td>
1878
				</tr>
1879
eoq;
1880
		}
1881
1882
		 if(empty($out['meta']['email']['description']))
1883
                $out['meta']['email']['description'] = $mod_strings['LBL_EMPTY_EMAIL_BODY'];
1884
1885
		if($noCache) {
1886
			$GLOBALS['log']->debug("EMAILUI: getSingleMessage() NOT using cache file");
1887
		} else {
1888
			$GLOBALS['log']->debug("EMAILUI: getSingleMessage() using cache file [ ".$_REQUEST['mbox'].$_REQUEST['uid'].".php ]");
1889
		}
1890
1891
		$this->setReadFlag($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['uid']);
1892
		return $out;
1893
	}
1894
1895
1896
	/**
1897
	 * Returns the HTML for a list of emails in a given folder
1898
	 * @param GUID $ieId GUID to InboundEmail instance
1899
	 * @param string $mbox Mailbox path name in dot notation
1900
	 * @param int $folderListCacheOffset Seconds for valid cache file
1901
	 * @return string HTML render of list.
1902
	 */
1903
	function getListEmails($ieId, $mbox, $folderListCacheOffset, $forceRefresh='false') {
1904
		global $sugar_config;
1905
1906
1907
		$ie = new InboundEmail();
1908
		$ie->retrieve($ieId);
1909
		$list = $ie->displayFolderContents($mbox, $forceRefresh);
0 ignored issues
show
Bug introduced by
The call to displayFolderContents() misses a required argument $page.

This check looks for function calls that miss required arguments.

Loading history...
1910
1911
		return $list;
1912
	}
1913
1914
	/**
1915
	 * Returns the templatized compose screen.  Used by reply, forwards and draft status messages.
1916
	 * @param object email Email bean in focus
1917
	 */
1918
	function displayComposeEmail($email) {
1919
		global $locale;
1920
		global $current_user;
1921
1922
1923
		$ea = new SugarEmailAddress();
1924
1925
		if(!empty($email)) {
1926
		    $email->cids2Links();
1927
			$description = (empty($email->description_html)) ? $email->description : $email->description_html;
1928
		}
1929
1930
		//Get the most complete address list availible for this email
1931
		$addresses = array('toAddresses' => 'to', 'ccAddresses' => 'cc', 'bccAddresses' => 'bcc');
1932
		foreach($addresses as $var => $type)
1933
		{
1934
			$$var = "";
1935
			foreach (array("{$type}_addrs_names", "{$type}addrs", "{$type}_addrs") as $emailVar)
1936
			{
1937
				if (!empty($email->$emailVar)) {
1938
					$$var = $email->$emailVar;
1939
					break;
1940
				}
1941
			}
1942
		}
1943
1944
		$ret = array();
1945
		$ret['type'] = $email->type;
1946
		$ret['name'] = $email->name;
1947
		$ret['description'] = $description;
1948
		$ret['from'] = (isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'forward') ? "" : $email->from_addr;
1949
		$ret['to'] = from_html($toAddresses);
0 ignored issues
show
Bug introduced by
The variable $toAddresses seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1950
		$ret['uid'] = $email->id;
1951
		$ret['parent_name'] = $email->parent_name;
1952
		$ret['parent_type'] = $email->parent_type;
1953
		$ret['parent_id'] = $email->parent_id;
1954
1955
       if ($email->type == 'draft') {
1956
            $ret['cc'] = from_html($ccAddresses);
0 ignored issues
show
Bug introduced by
The variable $ccAddresses does not exist. Did you mean $addresses?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1957
            $ret['bcc'] = $bccAddresses;
0 ignored issues
show
Bug introduced by
The variable $bccAddresses does not exist. Did you mean $addresses?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1958
        }
1959
		// reply all
1960
		if(isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'replyAll') {
1961
		    $ret['cc'] = from_html($ccAddresses);
0 ignored issues
show
Bug introduced by
The variable $ccAddresses does not exist. Did you mean $addresses?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1962
		    $ret['bcc'] = $bccAddresses;
0 ignored issues
show
Bug introduced by
The variable $bccAddresses does not exist. Did you mean $addresses?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1963
1964
			$userEmails = array();
1965
			$userEmailsMeta = $ea->getAddressesByGUID($current_user->id, 'Users');
1966
			foreach($userEmailsMeta as $emailMeta) {
1967
				$userEmails[] = from_html(strtolower(trim($emailMeta['email_address'])));
1968
			}
1969
			$userEmails[] = from_html(strtolower(trim($email->from_addr)));
1970
1971
			$ret['cc'] = from_html($email->cc_addrs);
1972
			$toAddresses = from_html($toAddresses);
0 ignored issues
show
Bug introduced by
The variable $toAddresses seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1973
			$to = str_replace($this->addressSeparators, "::", $toAddresses);
1974
			$exTo = explode("::", $to);
1975
1976
			if(is_array($exTo)) {
1977
				foreach($exTo as $addr) {
1978
					$addr = strtolower(trim($addr));
1979
					if(!in_array($addr, $userEmails)) {
1980
						if(!empty($ret['cc'])) {
1981
							$ret['cc'] = $ret['cc'].", ";
1982
						}
1983
						$ret['cc'] = $ret['cc'].trim($addr);
1984
					}
1985
				}
1986
			} elseif(!empty($exTo)) {
1987
				$exTo = trim($exTo);
1988
				if(!in_array($exTo, $userEmails)) {
1989
					$ret['cc'] = $ret['cc'].", ".$exTo;
1990
				}
1991
			}
1992
		}
1993
		return $ret;
1994
	}
1995
	/**
1996
	 * Formats email body on reply/forward
1997
	 * @param object email Email object in focus
1998
	 * @param string type
1999
	 * @return object email
2000
	 */
2001
	function handleReplyType($email, $type) {
2002
		global $mod_strings;
2003
		 $GLOBALS['log']->debug("****At Handle Reply Type: $type");
2004
		switch($type) {
2005
			case "reply":
2006
			case "replyAll":
2007
				$header = $email->getReplyHeader();
2008
                if(!preg_match('/^(re:)+/i', $email->name)) {
2009
                    $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
2010
                }
2011
				if ($type == "reply") {
2012
					$email->cc_addrs = "";
2013
					if (!empty($email->reply_to_addr)) {
2014
						$email->from_addr = $email->reply_to_addr;
2015
					} // if
2016
				} else {
2017
					if (!empty($email->reply_to_addr)) {
2018
						$email->to_addrs = $email->to_addrs . "," . $email->reply_to_addr;
2019
					} // if
2020
				} // else
2021
			break;
2022
2023
			case "forward":
2024
				$header = $email->getForwardHeader();
2025
				if(!preg_match('/^(fw:)+/i', $email->name)) {
2026
                    $email->name = "{$mod_strings['LBL_FW']} {$email->name}";
2027
                }
2028
				$email->cc_addrs = "";
2029
			break;
2030
2031
			case "replyCase":
2032
				$GLOBALS['log']->debug("EMAILUI: At reply case");
2033
				$header = $email->getReplyHeader();
2034
2035
                $myCase = new aCase();
2036
                $myCase->retrieve($email->parent_id);
2037
                $myCaseMacro = $myCase->getEmailSubjectMacro();
2038
                $email->parent_name = $myCase->name;
2039
                $GLOBALS['log']->debug("****Case # : {$myCase->case_number} macro: $myCaseMacro");
2040
				if(!strpos($email->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) {
2041
		        	$GLOBALS['log']->debug("Replacing");
2042
		            $email->name = str_replace('%1',$myCase->case_number,$myCaseMacro) . ' '. $email->name;
2043
		        }
2044
                $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
2045
            break;
2046
		}
2047
2048
		$html = trim($email->description_html);
2049
		$plain = trim($email->description);
2050
2051
		$desc = (!empty($html)) ? $html : $plain;
2052
2053
		$email->description = $header.$email->quoteHtmlEmailForNewEmailUI($desc);
2054
		return $email;
2055
2056
	}
2057
2058
	///////////////////////////////////////////////////////////////////////////
2059
	////	PRIVATE HELPERS
2060
	/**
2061
	 * Generates a UNION query to get one list of users, contacts, leads, and
2062
	 * prospects; used specifically for the addressBook
2063
	 */
2064
	function _getPeopleUnionQuery($whereArr , $person) {
2065
		global $current_user , $app_strings;
2066
		global $db;
2067
		if(!isset($person) || $person === 'LBL_DROPDOWN_LIST_ALL'){
2068
			$peopleTables = array("users",
2069
			                      "contacts",
2070
			                      "leads",
2071
			                      "prospects",
2072
			                      "accounts"
2073
			                     );
2074
		}else{
2075
			$peopleTables = array($person);
2076
		}
2077
		$q = '';
2078
2079
		$whereAdd = "";
2080
2081
		foreach($whereArr as $column => $clause) {
2082
			if(!empty($whereAdd)) {
2083
				$whereAdd .= " AND ";
2084
			}
2085
			$clause = $current_user->db->quote($clause);
2086
			$whereAdd .= "{$column} LIKE '{$clause}%'";
2087
		}
2088
2089
2090
		foreach($peopleTables as $table) {
2091
			$module = ucfirst($table);
2092
            $class = substr($module, 0, strlen($module) - 1);
2093
            require_once("modules/{$module}/{$class}.php");
2094
            $person = new $class();
2095
			if (!$person->ACLAccess('list')) {
2096
				continue;
2097
			} // if
2098
			$where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id <> '{$current_user->id}')";
2099
2100
            if (ACLController::requireOwner($module, 'list')) {
2101
            	$where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
2102
            } // if
2103
			if(!empty($whereAdd)) {
2104
				$where .= " AND ({$whereAdd})";
2105
			}
2106
2107
			if ($person === 'accounts') {
2108
				$t = "SELECT {$table}.id, '' first_name, {$table}.name, eabr.primary_address, ea.email_address, '{$module}' module ";
2109
			} else {
2110
				$t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2111
			}
2112
			$t .= "FROM {$table} ";
2113
			$t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
2114
			$t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
2115
			$t .= " WHERE {$where}";
2116
2117
			/* BEGIN - SECURITY GROUPS */
2118
			//this function may not even be used anymore. Seems like findEmailFromBeanIds is preferred now
2119
			if($person->bean_implements('ACL') && ACLController::requireSecurityGroup($module, 'list') )
2120
			{
2121
				require_once('modules/SecurityGroups/SecurityGroup.php');
2122
				global $current_user;
2123
				$owner_where = $person->getOwnerWhere($current_user->id);
2124
				$group_where = SecurityGroup::getGroupWhere($table,$module,$current_user->id);
2125
				$t .= " AND (".  $owner_where." or ".$group_where.") ";
2126
			}
2127
			/* END - SECURITY GROUPS */
2128
    	
2129
2130
			if(!empty($q)) {
2131
				$q .= "\n UNION ALL \n";
2132
			}
2133
2134
			$q .= "({$t})";
2135
		}
2136
		$countq = "SELECT count(people.id) c from ($q) people";
2137
		$q .= "ORDER BY last_name";
2138
2139
		return array('query' => $q, 'countQuery' => $countq);
2140
    }
2141
2142
    /**
2143
     * get emails of related bean for a given bean id
2144
     * @param $beanType
2145
     * @param $condition array of conditions inclued bean id
2146
     * @return array('query' => $q, 'countQuery' => $countq);
0 ignored issues
show
Documentation introduced by
The doc-type array('query' could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2147
     */
2148
    function getRelatedEmail($beanType, $whereArr, $relatedBeanInfoArr = ''){
2149
    	global $beanList, $current_user, $app_strings, $db;
2150
    	$finalQuery = '';
2151
		$searchBeans = null;
2152
		if($beanType === 'LBL_DROPDOWN_LIST_ALL')
2153
			$searchBeans = array("users",
2154
			                     "contacts",
2155
			                     "leads",
2156
			                     "prospects",
2157
			                     "accounts"
2158
			                    );
2159
2160
    	if ($relatedBeanInfoArr == '' || empty($relatedBeanInfoArr['related_bean_type']) )
2161
    	{
2162
			if ($searchBeans != null)
2163
			{
2164
				$q = array();
2165
				foreach ($searchBeans as $searchBean)
2166
				{
2167
				    $searchq = $this->findEmailFromBeanIds('', $searchBean, $whereArr);
2168
				    if(!empty($searchq)) {
2169
					    $q[] = "($searchq)";
2170
				    }
2171
				}
2172
				if (!empty($q))
2173
    			    $finalQuery .= implode("\n UNION ALL \n", $q);
2174
			}
2175
			else
2176
				$finalQuery = $this->findEmailFromBeanIds('', $beanType, $whereArr);
2177
    	}
2178
    	else
2179
    	{
2180
    	    $class = $beanList[$relatedBeanInfoArr['related_bean_type']];
2181
    	    $focus = new $class();
2182
    	    $focus->retrieve($relatedBeanInfoArr['related_bean_id']);
2183
    	    if ($searchBeans != null)
2184
    	    {
2185
    	        $q = array();
2186
    	        foreach ($searchBeans as $searchBean)
2187
    	        {
2188
    	            if ($focus->load_relationship($searchBean))
2189
    	            {
2190
    	                $data = $focus->$searchBean->get();
2191
    	                if (count($data) != 0)
2192
    	                $q[] = '('.$this->findEmailFromBeanIds($data, $searchBean, $whereArr).')';
2193
    	            }
2194
    	        }
2195
    	        if (!empty($q))
2196
    	        $finalQuery .= implode("\n UNION ALL \n", $q);
2197
    	    }
2198
    	    else
2199
    	    {
2200
    	        if ($focus->load_relationship($beanType))
2201
    	        {
2202
    	            $data = $focus->$beanType->get();
2203
    	            if (count($data) != 0)
2204
    	            $finalQuery = $this->findEmailFromBeanIds($data, $beanType, $whereArr);
2205
    	        }
2206
    	    }
2207
    	}
2208
    	$countq = "SELECT count(people.id) c from ($finalQuery) people";
2209
	   	return array('query' => $finalQuery, 'countQuery' => $countq);
2210
    }
2211
2212
    function findEmailFromBeanIds($beanIds, $beanType, $whereArr) {
2213
    	global $current_user;
2214
		$q = '';
2215
		$whereAdd = "";
2216
		$relatedIDs = '';
2217
		if ($beanIds != '') {
2218
			foreach ($beanIds as $key => $value) {
2219
				$beanIds[$key] = '\''.$value.'\'';
2220
			}
2221
			$relatedIDs = implode(',', $beanIds);
2222
		}
2223
2224
		if ($beanType == 'accounts') {
2225
			if (isset($whereArr['first_name'])) {
2226
				$whereArr['name'] = $whereArr['first_name'];
2227
			}
2228
			unset($whereArr['last_name']);
2229
			unset($whereArr['first_name']);
2230
		}
2231
2232
		foreach($whereArr as $column => $clause) {
2233
			if(!empty($whereAdd)) {
2234
				$whereAdd .= " OR ";
2235
			}
2236
			$clause = $current_user->db->quote($clause);
2237
			$whereAdd .= "{$column} LIKE '{$clause}%'";
2238
		}
2239
		$table = $beanType;
2240
		$module = ucfirst($table);
2241
	    $class = substr($module, 0, strlen($module) - 1);
2242
	    require_once("modules/{$module}/{$class}.php");
2243
	    $person = new $class();
2244
		if ($person->ACLAccess('list')) {
2245
			if ($relatedIDs != '') {
2246
				$where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id in ($relatedIDs))";
2247
			} else {
2248
				$where = "({$table}.deleted = 0 AND eabr.primary_address = 1)";
2249
			}
2250
2251
			if (ACLController::requireOwner($module, 'list')) {
2252
				$where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
2253
			} // if
2254
			if(!empty($whereAdd)) {
2255
				$where .= " AND ({$whereAdd})";
2256
			}
2257
2258
			if ($beanType === 'accounts') {
2259
				$t = "SELECT {$table}.id, '' first_name, {$table}.name last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2260
			} else {
2261
				$t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
2262
			}
2263
2264
			$t .= "FROM {$table} ";
2265
			$t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
2266
			$t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
2267
			$t .= " WHERE {$where}";
2268
			/* BEGIN - SECURITY GROUPS */
2269
			//this function may not even be used anymore. Seems like findEmailFromBeanIds is preferred now
2270
			if($person->bean_implements('ACL') && ACLController::requireSecurityGroup($module, 'list') )
2271
			{
2272
				require_once('modules/SecurityGroups/SecurityGroup.php');
2273
				global $current_user;
2274
				$owner_where = $person->getOwnerWhere($current_user->id);
2275
				$group_where = SecurityGroup::getGroupWhere($table,$module,$current_user->id);
2276
				$t .= " AND (".  $owner_where." or ".$group_where.") ";
2277
			}
2278
			/* END - SECURITY GROUPS */
2279
2280
		} // if
2281
		return $t;
2282
    }
2283
2284
	/**
2285
	 * Cleans UID lists
2286
	 * @param mixed $uids
2287
	 * @param bool $returnString False will return an array
2288
	 * @return mixed
2289
	 */
2290
	function _cleanUIDList($uids, $returnString=false) {
2291
		global $app_strings;
2292
		$GLOBALS['log']->debug("_cleanUIDList: before - [ {$uids} ]");
2293
2294
		if(!is_array($uids)) {
2295
			$returnString = true;
2296
2297
			$exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
2298
			$uids = $exUids;
2299
		}
2300
2301
		$cleanUids = array();
2302
		foreach($uids as $uid) {
2303
			$cleanUids[$uid] = $uid;
2304
		}
2305
2306
		sort($cleanUids);
2307
2308
		if($returnString) {
2309
			$cleanImplode = implode($app_strings['LBL_EMAIL_DELIMITER'], $cleanUids);
2310
			$GLOBALS['log']->debug("_cleanUIDList: after - [ {$cleanImplode} ]");
2311
			return $cleanImplode;
2312
		}
2313
2314
		return $cleanUids;
2315
	}
2316
2317
    /**
2318
     * Creates Mail folder
2319
     *
2320
     * @param object $user User in focus
2321
     * @param array $folder_params Array of parameters for folder creation
2322
     */
2323
    protected function createFolder($user, $folder_params)
2324
    {
2325
        $folder = new SugarFolder();
2326
        foreach ($folder_params as $key => $val) {
2327
            $folder->$key = $val;
2328
        }
2329
2330
        $folder->save();
2331
2332
        return $folder;
2333
    }
2334
2335
	/**
2336
	 * Creates defaults for the User
2337
	 * @param object $user User in focus
2338
	 */
2339
    public function preflightUser(&$user)
2340
    {
2341
        global $mod_strings;
2342
        $folder_types = array();
2343
2344
        $params = array(
2345
            // My Emails
2346
            "inbound" => array(
2347
                'name' => $mod_strings['LNK_MY_INBOX'],
2348
                'folder_type' => "inbound",
2349
                'has_child' => 1,
2350
                'dynamic_query' => $this->generateDynamicFolderQuery("inbound", $user->id),
2351
                'is_dynamic' => 1,
2352
                'created_by' => $user->id,
2353
                'modified_by' => $user->id,
2354
            ),
2355
            // My Drafts
2356
            "draft" => array(
2357
                'name' => $mod_strings['LNK_MY_DRAFTS'],
2358
                'folder_type' => "draft",
2359
                'has_child' => 0,
2360
                'dynamic_query' => $this->generateDynamicFolderQuery("draft", $user->id),
2361
                'is_dynamic' => 1,
2362
                'created_by' => $user->id,
2363
                'modified_by' => $user->id,
2364
            ),
2365
            // Sent Emails
2366
            "sent" => array(
2367
                'name' => $mod_strings['LNK_SENT_EMAIL_LIST'],
2368
                'folder_type' => "sent",
2369
                'has_child' => 0,
2370
                'dynamic_query' => $this->generateDynamicFolderQuery("sent", $user->id),
2371
                'is_dynamic' => 1,
2372
                'created_by' => $user->id,
2373
                'modified_by' => $user->id,
2374
            ),
2375
            // Archived Emails
2376
            "archived" => array(
2377
                'name' => $mod_strings['LBL_LIST_TITLE_MY_ARCHIVES'],
2378
                'folder_type' => "archived",
2379
                'has_child' => 0,
2380
                'dynamic_query' => '',
2381
                'is_dynamic' => 1,
2382
                'created_by' => $user->id,
2383
                'modified_by' => $user->id,
2384
            ),
2385
        );
2386
2387
        $q = "SELECT * FROM folders f WHERE f.created_by = '{$user->id}' AND f.deleted = 0 AND coalesce(" . $user->db->convert("f.folder_type", "length") . ",0) > 0";
2388
        $r = $user->db->query($q);
2389
2390
        while ($row = $GLOBALS['db']->fetchByAssoc($r)) {
2391
            if ($row['folder_type'] == 'inbound') {
2392
                $parent_id = $row['id'];
2393
            }
2394
            if (!in_array($row['folder_type'], $folder_types)) {
2395
                array_push($folder_types, $row['folder_type']);
2396
            }
2397
            if (isset($params[$row['folder_type']])) {
2398
                unset($params[$row['folder_type']]);
2399
            }
2400
        }
2401
2402
        require_once("include/SugarFolders/SugarFolders.php");
2403
2404
        foreach ($params as $type => $type_params) {
2405
            if ($type == "inbound") {
2406
2407
                $folder = $this->createFolder($user, $params[$type]);
2408
2409
                $parent_id = $folder->id;
2410
2411
                // handle the case where inbound folder was deleted, but other folders exist
2412
                if (count($folder_types) != 0) {
2413
                    // This update query will exclude inbound parent, and any custom created folders.
2414
                    // For others, it will update their parent_id for the current user.
2415
                    $q = "UPDATE folders SET parent_folder = '".$parent_id.
2416
                    "' WHERE folder_type IN ('draft', 'sent', 'archived') AND created_by = '".$user->id."'";
2417
                    $q = "UPDATE folders SET parent_folder = '".$parent_id.
2418
                    "' WHERE folder_type IN ('draft', 'sent', 'archived') AND created_by = '".$user->id."'";
2419
                    $r = $user->db->query($q);
2420
                }
2421
            } else {
2422
                $params[$type]['parent_folder'] = $parent_id;
2423
2424
                $this->createFolder($user, $params[$type]);
2425
            }
2426
        }
2427
    }
2428
2429
	/**
2430
	 * Parses the core dynamic folder query
2431
	 * @param string $type 'inbound', 'draft', etc.
2432
	 * @param string $userId
2433
	 * @return string
2434
	 */
2435
	function generateDynamicFolderQuery($type, $userId) {
2436
		$q = $this->coreDynamicFolderQuery;
2437
2438
		$status = $type;
2439
2440
		if($type == "sent") {
2441
			$type = "out";
2442
		}
2443
2444
		$replacee = array("::TYPE::", "::STATUS::", "::USER_ID::");
2445
		$replacer = array($type, $status, $userId);
2446
2447
		$ret = str_replace($replacee, $replacer, $q);
2448
2449
		if($type == 'inbound') {
2450
			$ret .= " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
2451
		} else {
2452
			$ret .= " AND status NOT IN ('archived') AND type NOT IN ('archived')";
2453
		}
2454
2455
		return $ret;
2456
	}
2457
2458
	/**
2459
	 * Preps the User's cache dir
2460
	 */
2461
	function preflightUserCache() {
2462
		$path = clean_path($this->userCacheDir);
2463
		if(!file_exists($this->userCacheDir))
2464
			mkdir_recursive($path);
2465
2466
		$files = findAllFiles($path, array());
2467
2468
		foreach($files as $file) {
2469
			unlink($file);
2470
		}
2471
	}
2472
2473
	function clearInboundAccountCache($ieId) {
2474
		global $sugar_config;
2475
		$cacheRoot = sugar_cached("modules/Emails/{$ieId}");
2476
		$files = findAllFiles($cacheRoot."/messages/", array());
2477
		foreach($files as $file) {
2478
			unlink($file);
2479
		} // fn
2480
		$files = findAllFiles($cacheRoot."/attachments/", array());
2481
		foreach($files as $file) {
2482
			unlink($file);
2483
		} // for
2484
	} // fn
2485
2486
	/**
2487
	 * returns an array of EmailTemplates that the user has access to for the compose email screen
2488
	 * @return array
2489
	 */
2490
	function getEmailTemplatesArray() {
2491
2492
		global $app_strings;
2493
2494
		if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) {
2495
			$et = new EmailTemplate();
2496
            $etResult = $et->db->query($et->create_new_list_query('',"(type IS NULL OR type='' OR type='email')",array(),array(),''));
0 ignored issues
show
Bug introduced by
It seems like $et->create_new_list_que..., array(), array(), '') targeting SugarBean::create_new_list_query() can also be of type array<string,?>; however, DBManager::query() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2497
			$email_templates_arr = array('' => $app_strings['LBL_NONE']);
2498
			while($etA = $et->db->fetchByAssoc($etResult)) {
2499
				$email_templates_arr[$etA['id']] = $etA['name'];
2500
			}
2501
		} else {
2502
			$email_templates_arr = array('' => $app_strings['LBL_NONE']);
2503
		}
2504
2505
		return $email_templates_arr;
2506
	}
2507
2508
	function getFromAccountsArray($ie) {
2509
        global $current_user;
2510
        global $app_strings;
2511
2512
        $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
2513
        $ieAccountsFrom= array();
2514
2515
        $oe = new OutboundEmail();
2516
        $system = $oe->getSystemMailerSettings();
2517
        $ret = $current_user->getUsersNameAndEmail();
2518
		$ret['name'] = from_html($ret['name']);
2519
		$useMyAccountString = true;
2520
2521
        if(empty($ret['email'])) {
2522
        	$systemReturn = $current_user->getSystemDefaultNameAndEmail();
2523
        	$ret['email'] = $systemReturn['email'];
2524
        	$ret['name'] = from_html($systemReturn['name']);
2525
        	$useMyAccountString = false;
2526
		} // if
2527
2528
		$myAccountString = '';
2529
		if ($useMyAccountString) {
2530
			$myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
2531
		} // if
2532
2533
		//Check to make sure that the user has set the associated inbound email account -> outbound account is active.
2534
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2535
        $sf = new SugarFolder();
2536
        $groupSubs = $sf->getSubscriptions($current_user);
2537
2538
        foreach($ieAccountsFull as $k => $v)
2539
        {
2540
            $personalSelected = (!empty($showFolders) && in_array($v->id, $showFolders));
2541
2542
            $allowOutboundGroupUsage = $v->get_stored_options('allow_outbound_group_usage',FALSE);
2543
            $groupSelected = ( in_array($v->groupfolder_id, $groupSubs)  && $allowOutboundGroupUsage);
2544
            $selected = ( $personalSelected || $groupSelected );
2545
2546
            if(!$selected)
2547
            {
2548
                $GLOBALS['log']->debug("Inbound Email {$v->name}, not selected and will not be available for selection within compose UI.");
2549
                continue;
2550
            }
2551
2552
        	$name = $v->get_stored_options('from_name');
2553
        	$addr = $v->get_stored_options('from_addr');
2554
        	if ($name != null && $addr != null) {
2555
        		$name = from_html($name);
2556
        		if (!$v->is_personal) {
2557
                	$ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
2558
        		} else {
2559
                	$ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr})");
2560
        		} // else
2561
        	} // if
2562
        } // foreach
2563
2564
2565
        $userSystemOverride = $oe->getUsersMailerForSystemOverride($current_user->id);
2566
        //Substitute in the users system override if its available.
2567
        if($userSystemOverride != null)
2568
		    $system = $userSystemOverride;
2569
2570
        if( !empty($system->mail_smtpserver) )
2571
        {
2572
            $admin = new Administration();
2573
            $admin->retrieveSettings(); //retrieve all admin settings.
2574
            $ieAccountsFrom[] = array("value" => $system->id, "text" =>
2575
                "{$ret['name']} ({$ret['email']}){$myAccountString}");
2576
        }
2577
2578
        return $ieAccountsFrom;
2579
    } // fn
2580
2581
    /**
2582
     * This function will return all the accounts this user has access to based on the
2583
     * match of the emailId passed in as a parameter
2584
     *
2585
     * @param unknown_type $ie
2586
     * @return unknown
2587
     */
2588
	function getFromAllAccountsArray($ie, $ret) {
2589
        global $current_user;
2590
        global $app_strings;
2591
2592
        $ret['fromAccounts'] = array();
2593
        if (!isset($ret['to']) && !empty($ret['from'])) {
2594
	        $ret['fromAccounts']['status'] = false;
2595
	        return $ret;
2596
        }
2597
        $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
2598
		$foundInPersonalAccounts = false;
2599
		$foundInGroupAccounts = false;
2600
		$foundInSystemAccounts = false;
2601
2602
		//$toArray = array();
2603
		if ($ret['type'] == "draft") {
2604
			$toArray = explode(",", $ret['from']);
2605
		} else {
2606
			$toArray = $ie->email->email2ParseAddressesForAddressesOnly($ret['to']);
2607
		} // else
2608
        foreach($ieAccountsFull as $k => $v) {
2609
        	$storedOptions = unserialize(base64_decode($v->stored_options));
2610
			if (  array_search_insensitive($storedOptions['from_addr'], $toArray)) {
2611
        		if ($v->is_personal) {
2612
					$foundInPersonalAccounts = true;
2613
					break;
2614
				} else  {
2615
					$foundInGroupAccounts = true;
2616
				} // else
2617
			} // if
2618
        } // foreach
2619
2620
	    $oe = new OutboundEmail();
2621
        $system = $oe->getSystemMailerSettings();
2622
2623
        $return = $current_user->getUsersNameAndEmail();
2624
		$return['name'] = from_html($return['name']);
2625
		$useMyAccountString = true;
2626
2627
        if(empty($return['email'])) {
2628
        	$systemReturn = $current_user->getSystemDefaultNameAndEmail();
2629
        	$return['email'] = $systemReturn['email'];
2630
        	$return['name'] = from_html($systemReturn['name']);
2631
        	$useMyAccountString = false;
2632
		} // if
2633
2634
		$myAccountString = '';
2635
		if ($useMyAccountString) {
2636
			$myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
2637
		} // if
2638
2639
        if(!empty($system->id)) {
2640
2641
            $admin = new Administration();
2642
            $admin->retrieveSettings(); //retrieve all admin settings.
2643
            if (in_array(trim($return['email']), $toArray)) {
2644
            	$foundInSystemAccounts = true;
2645
            } // if
2646
        } // if
2647
2648
        if (!$foundInPersonalAccounts && !$foundInGroupAccounts && !$foundInSystemAccounts) {
2649
	        $ret['fromAccounts']['status'] = false;
2650
	        return $ret;
2651
        } // if
2652
2653
        $ieAccountsFrom= array();
2654
        foreach($ieAccountsFull as $k => $v) {
2655
        	$storedOptions = unserialize(base64_decode($v->stored_options));
2656
        	$storedOptionsName = from_html($storedOptions['from_name']);
2657
2658
        	$selected = false;
2659
			if (array_search_insensitive($storedOptions['from_addr'], $toArray)) {
2660
        	//if ($ret['to'] == $storedOptions['from_addr']) {
2661
        		$selected = true;
2662
			} // if
2663
        	if ($foundInPersonalAccounts) {
2664
        		if ($v->is_personal) {
2665
            		$ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']})");
2666
        		} // if
2667
        	} else {
2668
            	$ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
2669
        	} // else
2670
        } // foreach
2671
2672
        if(!empty($system->id)) {
2673
            if (!$foundInPersonalAccounts && !$foundInGroupAccounts && $foundInSystemAccounts) {
2674
            $ieAccountsFrom[] = array("value" => $system->id, "selected" => true, "text" =>
2675
                "{$return['name']} ({$return['email']}){$myAccountString}");
2676
            } else {
2677
            $ieAccountsFrom[] = array("value" => $system->id, "text" =>
2678
                "{$return['name']} ({$return['email']}){$myAccountString}");
2679
            } // else
2680
        } // if
2681
2682
        $ret['fromAccounts']['status'] = ($foundInPersonalAccounts || $foundInGroupAccounts || $foundInSystemAccounts) ? true : false;
2683
		$ret['fromAccounts']['data'] = $ieAccountsFrom;
2684
        return $ret;
2685
    } // fn
2686
2687
2688
	/**
2689
	 * takes an array and creates XML
2690
	 * @param array Array to convert
2691
	 * @param string Name to wrap highest level items in array
2692
	 * @return string XML
2693
	 */
2694
	function arrayToXML($a, $paramName) {
2695
		if(!is_array($a))
2696
			return '';
2697
2698
		$bad = array("<",">","'",'"',"&");
2699
		$good = array("&lt;", "&gt;", "&#39;", "&quot;","&amp;");
2700
2701
		$ret = "";
2702
2703
		for($i=0; $i<count($a); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2704
			$email = $a[$i];
2705
			$ret .= "\n<{$paramName}>";
2706
2707
			foreach($email as $k => $v) {
2708
				$ret .= "\n\t<{$k}>".str_replace($bad, $good, $v)."</{$k}>";
2709
			}
2710
			$ret .= "\n</{$paramName}>";
2711
		}
2712
		return $ret;
2713
	}
2714
2715
	/**
2716
	 * Re-used option getter for Show Accounts multiselect pane
2717
	 */
2718
	function getShowAccountsOptions(&$ie) {
2719
		global $current_user;
2720
		global $app_strings;
2721
		global $mod_strings;
2722
2723
		$ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
2724
		$ieAccountsShowOptionsMeta = array();
2725
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2726
2727
		$defaultIEAccount = $ie->getUsersDefaultOutboundServerId($current_user);
2728
2729
		foreach($ieAccountsFull as $k => $v) {
2730
			$selected = (!empty($showFolders) && in_array($v->id, $showFolders)) ? true : false;
2731
			$default = ($defaultIEAccount == $v->id) ? TRUE : FALSE;
2732
			$has_groupfolder = !empty($v->groupfolder_id) ? TRUE : FALSE;
2733
			$type = ($v->is_personal) ? $mod_strings['LBL_MAILBOX_TYPE_PERSONAL'] : $mod_strings['LBL_MAILBOX_TYPE_GROUP'];
2734
2735
			$ieAccountsShowOptionsMeta[] = array("id" => $v->id, "name" => $v->name, 'is_active' => $selected,
2736
													'server_url' => $v->server_url, 'is_group' => !$v->is_personal,'group_id' => $v->group_id,
2737
													'is_default' => $default, 'has_groupfolder' => $has_groupfolder,'type' => $type );
2738
		}
2739
2740
		//Retrieve the grou folders
2741
		$f = new SugarFolder();
2742
		$groupFolders = $f->getGroupFoldersForSettings($current_user);
2743
2744
		foreach ($groupFolders as $singleGroup)
2745
		{
2746
		    //Retrieve the related IE accounts.
2747
            $relatedIEAccounts = $ie->retrieveByGroupFolderId($singleGroup['id']);
2748
2749
            if(count($relatedIEAccounts) == 0)
2750
                $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY'];
2751
            else if(count($relatedIEAccounts) == 1)
2752
            {
2753
                if($relatedIEAccounts[0]->status != 'Active' || $relatedIEAccounts[0]->mailbox_type == 'bounce')
2754
                    continue;
2755
2756
                $server_url = $relatedIEAccounts[0]->server_url;
2757
            }
2758
            else
2759
                $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS'];
2760
2761
            $type = $mod_strings['LBL_MAILBOX_TYPE_GROUP_FOLDER'];
2762
		    $ieAccountsShowOptionsMeta[] = array("id" => $singleGroup['id'], "name" => $singleGroup['origName'], 'is_active' => $singleGroup['selected'],
2763
													'server_url' => $server_url, 'is_group' => true,'group_id' => $singleGroup['id'],
2764
													'is_default' => FALSE, 'has_groupfolder' => true,'type' => $type);
2765
		}
2766
2767
2768
		return $ieAccountsShowOptionsMeta;
2769
	}
2770
2771
	function getShowAccountsOptionsForSearch(&$ie) {
2772
		global $current_user;
2773
		global $app_strings;
2774
2775
		$ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
2776
		//$ieAccountsShowOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
2777
		$ieAccountsShowOptionsMeta = array();
2778
		$ieAccountsShowOptionsMeta[] = array("value" => "", "text" => $app_strings['LBL_NONE'], 'selected' => '');
2779
		$showFolders = unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
2780
2781
		foreach($ieAccountsFull as $k => $v) {
2782
			if(!in_array($v->id, $showFolders)) {
2783
				continue;
2784
			}
2785
			$group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
2786
			$ieAccountsShowOptionsMeta[] = array("value" => $v->id, "text" => $group.$v->name, 'protocol' => $v->protocol);
2787
		}
2788
2789
		return $ieAccountsShowOptionsMeta;
2790
	}
2791
	/**
2792
	 * Formats a display message on successful async call
2793
	 * @param string $type Type of message to display
2794
	 */
2795
	function displaySuccessMessage($type) {
2796
		global $app_strings;
2797
2798
		switch($type) {
2799
			case "delete":
2800
				$message = $app_strings['LBL_EMAIL_DELETE_SUCCESS'];
2801
			break;
2802
2803
			default:
2804
				$message = "NOOP: invalid type";
2805
			break;
2806
		}
2807
2808
		$this->smarty->assign('app_strings', $app_strings);
2809
		$this->smarty->assign('message', $message);
2810
		echo $this->smarty->fetch("modules/Emails/templates/successMessage.tpl");
2811
	}
2812
2813
	/**
2814
	 * Validates existence and expiration of a cache file
2815
	 * @param string $ieId
2816
	 * @param string $type Type of cache file: folders, messages, etc.
2817
	 * @param string $file The cachefile name
2818
	 * @param int refreshOffset Refresh time in secs.
2819
	 * @return mixed.
0 ignored issues
show
Documentation introduced by
The doc-type mixed. could not be parsed: Unknown type name "mixed." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2820
	 */
2821
	function validCacheFileExists($ieId, $type, $file, $refreshOffset=-1) {
2822
		global $sugar_config;
2823
2824
		if($refreshOffset == -1) {
2825
			$refreshOffset = $this->cacheTimeouts[$type]; // use defaults
2826
		}
2827
2828
		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2829
		if(file_exists($cacheFilePath)) {
2830
			return true;
2831
		}
2832
2833
		return false;
2834
	}
2835
2836
	/**
2837
	 * retrieves the cached value
2838
	 * @param string $ieId
2839
	 * @param string $type Type of cache file: folders, messages, etc.
2840
	 * @param string $file The cachefile name
2841
	 * @param string $key name of cache value
2842
	 * @return mixed
2843
	 */
2844
	function getCacheValue($ieId, $type, $file, $key) {
2845
		global $sugar_config;
2846
2847
		$cleanIeId = cleanDirName($ieId);
2848
		$cleanType = cleanDirName($type);
2849
		$cleanFile = cleanFileName($file);
2850
		$cacheFilePath = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
2851
		$cacheFile = array();
2852
2853
		if(file_exists($cacheFilePath)) {
2854
			include($cacheFilePath); // provides $cacheFile
2855
2856
			if(isset($cacheFile[$key])) {
2857
				$ret = unserialize($cacheFile[$key]);
2858
				return $ret;
2859
			}
2860
		} else {
2861
			$GLOBALS['log']->debug("EMAILUI: cache file not found [ {$cacheFilePath} ] - creating blank cache file");
2862
			$this->writeCacheFile('retArr', array(), $ieId, $type, $file);
2863
		}
2864
2865
		return null;
2866
	}
2867
2868
	/**
2869
	 * retrieves the cache file last touched time
2870
	 * @param string $ieId
2871
	 * @param string $type Type of cache file: folders, messages, etc.
2872
	 * @param string $file The cachefile name
2873
	 * @return string
2874
	 */
2875
	function getCacheTimestamp($ieId, $type, $file) {
2876
		global $sugar_config;
2877
2878
		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2879
		$cacheFile = array();
2880
2881
		if(file_exists($cacheFilePath)) {
2882
			include($cacheFilePath); // provides $cacheFile['timestamp']
2883
2884
			if(isset($cacheFile['timestamp'])) {
2885
				$GLOBALS['log']->debug("EMAILUI: found timestamp [ {$cacheFile['timestamp']} ]");
2886
				return $cacheFile['timestamp'];
2887
			}
2888
		}
2889
2890
		return '';
2891
	}
2892
2893
	/**
2894
	 * Updates the timestamp for a cache file - usually to mark a "check email"
2895
	 * process
2896
	 * @param string $ieId
2897
	 * @param string $type Type of cache file: folders, messages, etc.
2898
	 * @param string $file The cachefile name
2899
	 */
2900
	function setCacheTimestamp($ieId, $type, $file) {
2901
		global $sugar_config;
2902
2903
		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
2904
		$cacheFile = array();
2905
2906
		if(file_exists($cacheFilePath)) {
2907
			include($cacheFilePath); // provides $cacheFile['timestamp']
2908
2909
			if(isset($cacheFile['timestamp'])) {
2910
				$cacheFile['timestamp'] = strtotime('now');
2911
				$GLOBALS['log']->debug("EMAILUI: setting updated timestamp [ {$cacheFile['timestamp']} ]");
2912
				return $this->_writeCacheFile($cacheFile, $cacheFilePath);
2913
			}
2914
		}
2915
	}
2916
2917
2918
	/**
2919
	 * Writes caches to flat file in cache dir.
2920
	 * @param string $key Key to the main cache entry (not timestamp)
2921
	 * @param mixed $var Variable to be cached
2922
	 * @param string $ieId I-E focus ID
2923
	 * @param string $type Folder in cache
2924
	 * @param string $file Cache file name
2925
	 */
2926
	function writeCacheFile($key, $var, $ieId, $type, $file) {
2927
		global $sugar_config;
2928
2929
		$cleanIeId = cleanDirName($ieId);
2930
		$cleanType = cleanDirName($type);
2931
		$cleanFile = cleanFileName($file);
2932
		$the_file = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
2933
		$timestamp = strtotime('now');
2934
		$array = array();
2935
		$array['timestamp'] = $timestamp;
2936
		$array[$key] = serialize($var); // serialized since varexport_helper() can't handle PHP objects
2937
2938
		return $this->_writeCacheFile($array, $the_file);
2939
	}
2940
2941
	/**
2942
	 * Performs the actual file write.  Abstracted from writeCacheFile() for
2943
	 * flexibility
2944
	 * @param array $array The array to write to the cache
2945
	 * @param string $file Full path (relative) with cache file name
2946
	 * @return bool
2947
	 */
2948
	function _writeCacheFile($array, $file) {
2949
		global $sugar_config;
2950
2951
		$arrayString = var_export_helper($array);
2952
2953
		$date = date("r");
2954
	    $the_string =<<<eoq
2955
<?php // created: {$date}
2956
	\$cacheFile = {$arrayString};
2957
?>
2958
eoq;
2959
	    if($fh = @sugar_fopen($file, "w")) {
2960
	        fputs($fh, $the_string);
2961
	        fclose($fh);
2962
	        return true;
2963
	    } else {
2964
	    	$GLOBALS['log']->debug("EMAILUI: Could not write cache file [ {$file} ]");
2965
	        return false;
2966
	    }
2967
	}
2968
2969
	/**
2970
	 * Generate JSON encoded data to be consumed by yui datatable.
2971
	 *
2972
	 * @param array $data
2973
	 * @param string $resultsParam The resultsList name
2974
	 * @return string
2975
	 */
2976
	function jsonOuput($data, $resultsParam, $count=0, $fromCache=true, $unread=-1) {
2977
	    global $app_strings;
2978
2979
		$count = ($count > 0) ? $count : 0;
2980
2981
		if(isset($a['fromCache']))
0 ignored issues
show
Bug introduced by
The variable $a seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
2982
			$cached = ($a['fromCache'] == 1) ? 1 : 0;
2983
		else
2984
			$cached = ($fromCache) ? 1 : 0;
2985
2986
		if($data['mbox'] == 'undefined' || empty($data['mbox']))
2987
			$data['mbox'] = $app_strings['LBL_NONE'];
2988
2989
		$jsonOut = array('TotalCount' => $count, 'FromCache' => $cached, 'UnreadCount' => $unread, $resultsParam => $data['out']);
2990
2991
		return json_encode($jsonOut);
2992
	}
2993
	/**
2994
	 * generates XML output from an array
2995
	 * @param array
2996
	 * @param string master list Item
2997
	 * @return string
2998
	 */
2999
	function xmlOutput($a, $paramName, $count=0, $fromCache=true, $unread=-1) {
3000
		global $app_strings;
3001
		$count = ($count > 0) ? $count : 0;
3002
3003
		if(isset($a['fromCache'])) {
3004
			$cached = ($a['fromCache'] == 1) ? 1 : 0;
3005
		} else {
3006
			$cached = ($fromCache) ? 1 : 0;
3007
		}
3008
3009
		if($a['mbox'] == 'undefined' || empty($a['mbox'])) {
3010
			$a['mbox'] = $app_strings['LBL_NONE'];
3011
		}
3012
3013
		$xml = $this->arrayToXML($a['out'], $paramName);
3014
3015
		$ret =<<<eoq
3016
<?xml version="1.0" encoding="UTF-8"?>
3017
<EmailPage>
3018
<TotalCount>{$count}</TotalCount>
3019
<UnreadCount>{$unread}</UnreadCount>
3020
<FromCache> {$cached} </FromCache>
3021
<{$paramName}s>
3022
{$xml}
3023
</{$paramName}s>
3024
</EmailPage>
3025
eoq;
3026
		return $ret;
3027
	}
3028
3029
    /**
3030
     * Generate to/cc addresses string in email detailview.
3031
     *
3032
     * @param string $str
3033
     * @param string $target values: to, cc
0 ignored issues
show
Bug introduced by
There is no parameter named $target. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3034
     * @param int $defaultNum
0 ignored issues
show
Bug introduced by
There is no parameter named $defaultNum. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
3035
     * @return string $str
3036
     */
3037
	function generateExpandableAddrs($str) {
3038
	    global $mod_strings;
3039
	    $tempStr = $str.',';
3040
        $tempStr = html_entity_decode($tempStr);
3041
	    $tempStr = $this->unifyEmailString($tempStr);
3042
        $defaultNum = 2;
3043
        $pattern = '/@.*,/U';
3044
        preg_match_all($pattern, $tempStr, $matchs);
3045
        $totalCount = count($matchs[0]);
3046
3047
        if(!empty($matchs[0]) && $totalCount > $defaultNum) {
3048
            $position = strpos($tempStr, $matchs[0][$defaultNum]);
3049
            $hiddenCount = $totalCount - $defaultNum;
3050
            $frontStr = substr($tempStr, 0, $position);
3051
            $backStr = substr($tempStr, $position, -1);
3052
            $str = htmlentities($frontStr) . '<a class="utilsLink" onclick="javascript: SUGAR.email2.detailView.displayAllAddrs(this);">...['.$mod_strings['LBL_EMAIL_DETAIL_VIEW_SHOW'].$hiddenCount.$mod_strings['LBL_EMAIL_DETAIL_VIEW_MORE'].']</a><span style="display: none;">' .htmlentities($backStr).'</span>';
3053
        }
3054
3055
        return $str;
3056
    }
3057
3058
    /**
3059
     * Unify the seperator as ,
3060
     *
3061
     * @param String $str email address string
3062
     * @return String converted string
3063
     */
3064
    function unifyEmailString($str) {
3065
        preg_match_all('/@.*;/U', $str, $matches);
3066
        if(!empty($matches[0])) {
3067
            foreach($matches[0] as $key => $value) {
3068
                $new[] = str_replace(";",",",$value);
3069
            }
3070
            return str_replace($matches[0], $new, $str);
3071
        }
3072
        return $str;
3073
    }
3074
} // end class def
3075