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