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