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