<?php
/**
 *
 * SugarCRM Community Edition is a customer relationship management program developed by
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
 *
 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
 * Copyright (C) 2011 - 2016 SalesAgility Ltd.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by the
 * Free Software Foundation with the addition of the following permission added
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along with
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 *
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
 */

if (!defined('sugarEntry') || !sugarEntry){
    die('Not A Valid Entry Point');
}

/*********************************************************************************

 * Description:
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
 * Reserved. Contributor(s): ______________________________________..
 *********************************************************************************/

require_once("include/ytree/Tree.php");
require_once("include/ytree/ExtNode.php");
require_once("include/SugarFolders/SugarFolders.php");



class EmailUI {
	var $db;
	var $folder; // place holder for SugarFolder object
	var $folderStates = array(); // array of folderPath names and their states (1/0)
	var $smarty;
	var $addressSeparators = array(";", ",");
	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";
	var $groupCss = "<span class='groupInbox'>";
	var $cacheTimeouts = array(
		'messages'		=> 86400,	// 24 hours
		'folders'		=> 300,		// 5 mins
		'attachments'	=> 86400,	// 24 hours
	);
	var $userCacheDir = '';
	var $coreDynamicFolderQuery = "SELECT emails.id polymorphic_id, 'Emails' polymorphic_module FROM emails
								   JOIN emails_text on emails.id = emails_text.email_id
                                   WHERE (type = '::TYPE::' OR status = '::STATUS::') AND assigned_user_id = '::USER_ID::' AND emails.deleted = '0'";

	/**
	 * Sole constructor
	 */
	function __construct() {
		global $sugar_config;
		global $current_user;

		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');

		if(!empty($folderStateSerial)) {
			$this->folderStates = sugar_unserialize($folderStateSerial);
		}

		$this->smarty = new Sugar_Smarty();
		$this->folder = new SugarFolder();
		$this->userCacheDir = sugar_cached("modules/Emails/{$current_user->id}");
		$this->db = DBManagerFactory::getInstance();
	}

	/**
	 * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
	 */
	function EmailUI(){
		$deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
		if(isset($GLOBALS['log'])) {
			$GLOBALS['log']->deprecated($deprecatedMessage);
		}
		else {
			trigger_error($deprecatedMessage, E_USER_DEPRECATED);
		}
		self::__construct();
	}

	///////////////////////////////////////////////////////////////////////////
	////	CORE
	/**
	 * Renders the frame for emails
	 */
	function displayEmailFrame() {
        require_once("include/OutboundEmail/OutboundEmail.php");

		global $app_strings, $app_list_strings;
		global $mod_strings;
		global $sugar_config;
		global $current_user;
		global $locale;
		global $timedate;
		global $theme;
		global $sugar_version;
		global $sugar_flavor;
		global $current_language;
		global $server_unique_key;

		$this->preflightUserCache();
		$ie = new InboundEmail();

		// focus listView
		$list = array(
			'mbox' => 'Home',
			'ieId' => '',
			'name' => 'Home',
			'unreadChecked' => 0,
			'out' => array(),
		);

		$this->_generateComposeConfigData('email_compose');


        //Check quick create module access
        $QCAvailableModules = $this->_loadQuickCreateModules();

        //Get the quickSearch js needed for assigned user id on Search Tab
        require_once('include/QuickSearchDefaults.php');
        $qsd = QuickSearchDefaults::getQuickSearchDefaults();
        $qsd->setFormName('advancedSearchForm');
        $quicksearchAssignedUser = "if(typeof sqs_objects == 'undefined'){var sqs_objects = new Array;}";
        $quicksearchAssignedUser .= "sqs_objects['advancedSearchForm_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
        $qsd->setFormName('Distribute');
        $quicksearchAssignedUser .= "sqs_objects['Distribute_assigned_user_name']=" . json_encode($qsd->getQSUser()) . ";";
        $this->smarty->assign('quickSearchForAssignedUser', $quicksearchAssignedUser);


		///////////////////////////////////////////////////////////////////////
		////	BASIC ASSIGNS
		$this->smarty->assign("currentUserId",$current_user->id);
		$this->smarty->assign("CURRENT_USER_EMAIL",$current_user->email1);
        $this->smarty->assign("currentUserName",$current_user->name);
		$this->smarty->assign('yuiPath', 'modules/Emails/javascript/yui-ext/');
		$this->smarty->assign('app_strings', $app_strings);
		$this->smarty->assign('mod_strings', $mod_strings);
		$this->smarty->assign('theme', $theme);
		$this->smarty->assign('sugar_config', $sugar_config);
		$this->smarty->assign('is_admin', $current_user->is_admin);
		$this->smarty->assign('sugar_version', $sugar_version);
		$this->smarty->assign('sugar_flavor', $sugar_flavor);
		$this->smarty->assign('current_language', $current_language);
		$this->smarty->assign('server_unique_key', $server_unique_key);
		$this->smarty->assign('qcModules', json_encode($QCAvailableModules));
		$extAllDebugValue = "ext-all.js";
		$this->smarty->assign('extFileName', $extAllDebugValue);

		// settings: general
		$e2UserPreferences = $this->getUserPrefsJS();
		$emailSettings = $e2UserPreferences['emailSettings'];

		///////////////////////////////////////////////////////////////////////
		////	USER SETTINGS
		// settings: accounts

		$cuDatePref = $current_user->getUserDateTimePreferences();
		$this->smarty->assign('dateFormat', $cuDatePref['date']);
		$this->smarty->assign('dateFormatExample', str_replace(array("Y", "m", "d"), array("yyyy", "mm", "dd"), $cuDatePref['date']));
		$this->smarty->assign('calFormat', $timedate->get_cal_date_format());
        $this->smarty->assign('TIME_FORMAT', $timedate->get_user_time_format());

		$ieAccounts = $ie->retrieveByGroupId($current_user->id);
		$ieAccountsOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";

		foreach($ieAccounts as $k => $v) {
			$disabled = (!$v->is_personal) ? "DISABLED" : "";
			$group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
			$ieAccountsOptions .= "<option value='{$v->id}' $disabled>{$group}{$v->name}</option>\n";
		}

		$this->smarty->assign('ieAccounts', $ieAccountsOptions);
		$this->smarty->assign('rollover', $this->rolloverStyle);

		$protocol = filterInboundEmailPopSelection($app_list_strings['dom_email_server_type']);
		$this->smarty->assign('PROTOCOL', get_select_options_with_id($protocol, ''));
		$this->smarty->assign('MAIL_SSL_OPTIONS', get_select_options_with_id($app_list_strings['email_settings_for_ssl'], ''));
		$this->smarty->assign('ie_mod_strings', return_module_language($current_language, 'InboundEmail'));

		$charsetSelectedValue = isset($emailSettings['defaultOutboundCharset']) ? $emailSettings['defaultOutboundCharset'] : false;
		if (!$charsetSelectedValue) {
			$charsetSelectedValue = $current_user->getPreference('default_export_charset', 'global');
			if (!$charsetSelectedValue) {
				$charsetSelectedValue = $locale->getPrecedentPreference('default_email_charset');
			}
		}
		$charset = array(
			'options' => $locale->getCharsetSelect(),
			'selected' => $charsetSelectedValue,
		);
		$this->smarty->assign('charset', $charset);

		$emailCheckInterval = array('options' => $app_strings['LBL_EMAIL_CHECK_INTERVAL_DOM'], 'selected' => $emailSettings['emailCheckInterval']);
		$this->smarty->assign('emailCheckInterval', $emailCheckInterval);
		$this->smarty->assign('attachmentsSearchOptions', $app_list_strings['checkbox_dom']);
		$this->smarty->assign('sendPlainTextChecked', ($emailSettings['sendPlainText'] == 1) ? 'CHECKED' : '');
		$this->smarty->assign('showNumInList', get_select_options_with_id($app_list_strings['email_settings_num_dom'], $emailSettings['showNumInList']));

		////	END USER SETTINGS
		///////////////////////////////////////////////////////////////////////

		///////////////////////////////////////////////////////////////////////
		////	SIGNATURES
		$prependSignature = ($current_user->getPreference('signature_prepend')) ? 'true' : 'false';
		$defsigID = $current_user->getPreference('signature_default');
		$this->smarty->assign('signatures', $current_user->getSignatures(false, $defsigID));
		$this->smarty->assign('signaturesSettings', $current_user->getSignatures(false, $defsigID, false));
		$signatureButtons = $current_user->getSignatureButtons('SUGAR.email2.settings.createSignature', !empty($defsigID));
		if (!empty($defsigID)) {
			$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;
					</span>';
		} else {
			$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;
					</span>';
		}
		$this->smarty->assign('signatureButtons', $signatureButtons);
		$this->smarty->assign('signaturePrepend', $prependSignature == 'true' ? 'CHECKED' : '');
		////	END SIGNATURES
		///////////////////////////////////////////////////////////////////////

		///////////////////////////////////////////////////////////////////////
		////	EMAIL TEMPLATES
		$email_templates_arr = $this->getEmailTemplatesArray();
		natcasesort($email_templates_arr);
		$this->smarty->assign('EMAIL_TEMPLATE_OPTIONS', get_select_options_with_id($email_templates_arr, ''));
		////	END EMAIL TEMPLATES
		///////////////////////////////////////////////////////////////////////

		///////////////////////////////////////////////////////////////////////
		////	FOLDERS & TreeView
		$this->smarty->assign('groupUserOptions', $ie->getGroupsWithSelectOptions(array('' => $app_strings['LBL_EMAIL_CREATE_NEW'])));

		$tree = $this->getMailboxNodes();

		// preloaded folder
		$preloadFolder = 'lazyLoadFolder = ';
		$focusFolderSerial = $current_user->getPreference('focusFolder', 'Emails');
		if(!empty($focusFolderSerial)) {
			$focusFolder = sugar_unserialize($focusFolderSerial);
			//$focusFolder['ieId'], $focusFolder['folder']
			$preloadFolder .= json_encode($focusFolder).";";
		} else {
			$preloadFolder .= "new Object();";
		}
		////	END FOLDERS
		///////////////////////////////////////////////////////////////////////

		$out = "";
		$out .= $this->smarty->fetch("modules/Emails/templates/_baseEmail.tpl");
		$out .= $tree->generate_header();
		$out .= $tree->generateNodesNoInit(true, 'email2treeinit');
		$out .=<<<eoq
			<script type="text/javascript" language="javascript">

				var loader = new YAHOO.util.YUILoader({
				    require : [
				    	"layout", "element", "tabview", "menu",
				    	"cookie", "sugarwidgets"
				    ],
				    loadOptional: true,
				    skin: { base: 'blank', defaultSkin: '' },
				    onSuccess: email2init,
				    allowRollup: true,
				    base: "include/javascript/yui/build/"
				});
				loader.addModule({
				    name :"sugarwidgets",
				    type : "js",
				    fullpath: "include/javascript/sugarwidgets/SugarYUIWidgets.js",
				    varName: "YAHOO.SUGAR",
				    requires: ["datatable", "dragdrop", "treeview", "tabview", "calendar"]
				});
				loader.insert();

				{$preloadFolder};

			</script>
eoq;


		return $out;
	}

	/**
	 * Generate the frame needed for the quick compose email UI.  This frame is loaded dynamically
	 * by an ajax call.
	 *
	 * @return JSON An object containing html markup and js script variables.
	 */
	function displayQuickComposeEmailFrame()
	{
        $this->preflightUserCache();

	    $this->_generateComposeConfigData('email_compose_light');
		$javascriptOut = $this->smarty->fetch("modules/Emails/templates/_baseConfigData.tpl");

        $divOut = $this->smarty->fetch("modules/Emails/templates/overlay.tpl");
        $divOut .= $this->smarty->fetch("modules/Emails/templates/addressSearchContent.tpl");

        $outData = array('jsData' => $javascriptOut,'divData'=> $divOut);
        $out = json_encode($outData);
        return $out;
    }

    /**
     * Load the modules from the metadata file and include in a custom one if it exists
     *
     * @return array
     */
    protected function _loadQuickCreateModules()
    {
        $QCAvailableModules = array();
        $QCModules = array();

        include('modules/Emails/metadata/qcmodulesdefs.php');
        if (file_exists('custom/modules/Emails/metadata/qcmodulesdefs.php')) {
            include('custom/modules/Emails/metadata/qcmodulesdefs.php');
        }

        foreach($QCModules as $module) {
            $seed = SugarModule::get($module)->loadBean();
            if ( ( $seed instanceOf SugarBean ) && $seed->ACLAccess('edit') ) {
                $QCAvailableModules[] = $module;
            }
        }

        return $QCAvailableModules;
    }

    /**
     * Given an email link url (eg. index.php?action=Compose&parent_type=Contacts...) break up the
     * request components and create a compose package that can be used by the quick compose UI. The
     * result is typically passed into the js call SUGAR.quickCompose.init which initalizes the quick compose
     * UI.
     *
     * @param String $emailLinkUrl
     * @return JSON Object containing the composePackage and full link url
     */
    function generateComposePackageForQuickCreateFromComposeUrl($emailLinkUrl, $lazyLoad=false)
    {
        $composeData = explode("&",$emailLinkUrl);
        $a_composeData = array();
    	foreach ($composeData as $singleRequest)
    	{
    		$tmp = explode("=",$singleRequest);
    		$a_composeData[$tmp[0]] = urldecode($tmp[1]);
    	}

    	return $this->generateComposePackageForQuickCreate($a_composeData,$emailLinkUrl, $lazyLoad);
    }
    /**
     * Generate the composePackage for the quick compose email UI.  The package contains
     * key/value pairs generated by the Compose.php file which are then set into the
     * quick compose email UI (eg. to addr, parent id, parent type, etc)
     *
     * @param Array $composeData Associative array read and processed by generateComposeDataPackage.
     * @param String $fullLinkUrl A link that contains all pertinant information so the user can be
     *                              directed to the full compose screen if needed
     * @param SugarBean $bean Optional - the parent object bean with data
     * @return JSON Object containg composePackage and fullLinkUrl
     */
    function generateComposePackageForQuickCreate($composeData,$fullLinkUrl, $lazyLoad=false, $bean = null)
    {
        $_REQUEST['forQuickCreate'] = true;

        if(!$lazyLoad){
    	    require_once('modules/Emails/Compose.php');
    	    $composePackage = generateComposeDataPackage($composeData,FALSE, $bean);
        }else{
            $composePackage = $composeData;
        }

    	// JSON object is passed into the function defined within the a href onclick event
    	// which is delimeted by '.  Need to escape all single quotes and &, <, >
    	// but not double quotes since json would escape them
    	foreach ($composePackage as $key => $singleCompose)
    	{
    	   if (is_string($singleCompose))
    	       $composePackage[$key] = str_replace("&nbsp;", " ", from_html($singleCompose));
    	}

    	$quickComposeOptions = array('fullComposeUrl' => $fullLinkUrl,'composePackage' => $composePackage);

    	$j_quickComposeOptions = JSON::encode($quickComposeOptions, false ,true);


    	return $j_quickComposeOptions;
    }

    /**
     * Generate the config data needed for the Full Compose UI and the Quick Compose UI.  The set of config data
     * returned is the minimum set needed by the quick compose UI.
     *
     * @param String $type Drives which tinyMCE options will be included.
     */
	function _generateComposeConfigData($type = "email_compose_light" )
	{
		global $app_list_strings,$current_user, $app_strings, $mod_strings,$current_language,$locale;

		//Link drop-downs
		$parent_types = $app_list_strings['record_type_display'];
		$disabled_parent_types = ACLController::disabledModuleList($parent_types, false, 'list');

		foreach($disabled_parent_types as $disabled_parent_type) {
		  unset($parent_types[$disabled_parent_type]);
		}
		asort($parent_types);
		$linkBeans = json_encode(get_select_options_with_id($parent_types, ''));

		//TinyMCE Config
		require_once("include/SugarTinyMCE.php");
        $tiny = new SugarTinyMCE();
        $tinyConf = $tiny->getConfig($type);

        //Generate Language Packs
		$lang = "var app_strings = new Object();\n";
		foreach($app_strings as $k => $v) {
			if(strpos($k, 'LBL_EMAIL_') !== false) {
				$v = str_replace("'", "\'", $v);
				$lang .= "app_strings.{$k} = '{$v}';\n";
			}
		}
		//Get the email mod strings but don't use the global variable as this may be overridden by
		//other modules when the quick create is rendered.
		$email_mod_strings = return_module_language($current_language,'Emails');
		$modStrings = "var mod_strings = new Object();\n";
		foreach($email_mod_strings as $k => $v) {
			$v = str_replace("'", "\'", $v);
			$modStrings .= "mod_strings.{$k} = '{$v}';\n";
		}
		$lang .= "\n\n{$modStrings}\n";

		//Grab the Inboundemail language pack
		$ieModStrings = "var ie_mod_strings = new Object();\n";
		$ie_mod_strings = return_module_language($current_language,'InboundEmail');
		foreach($ie_mod_strings as $k => $v) {
			$v = str_replace("'", "\'", $v);
			$ieModStrings .= "ie_mod_strings.{$k} = '{$v}';\n";
		}
		$lang .= "\n\n{$ieModStrings}\n";

		$this->smarty->assign('linkBeans', $linkBeans);
        $this->smarty->assign('linkBeansOptions', $parent_types);
        $this->smarty->assign('tinyMCE', $tinyConf);
        $this->smarty->assign('lang', $lang);
        $this->smarty->assign('app_strings', $app_strings);
		$this->smarty->assign('mod_strings', $email_mod_strings);
        $ie1 = new InboundEmail();

        //Signatures
        $defsigID = $current_user->getPreference('signature_default');
		$defaultSignature = $current_user->getDefaultSignature();
		$sigJson = !empty($defaultSignature) ? json_encode(array($defaultSignature['id'] => from_html($defaultSignature['signature_html']))) : "new Object()";
		$this->smarty->assign('defaultSignature', $sigJson);
		$this->smarty->assign('signatureDefaultId', (isset($defaultSignature['id'])) ? $defaultSignature['id'] : "");
		//User Preferences
		$this->smarty->assign('userPrefs', json_encode($this->getUserPrefsJS()));

		//Get the users default outbound id
		$defaultOutID = $ie1->getUsersDefaultOutboundServerId($current_user);
		$this->smarty->assign('defaultOutID', $defaultOutID);

		//Character Set
		$charsets = json_encode($locale->getCharsetSelect());
		$this->smarty->assign('emailCharsets', $charsets);

		//Relateable List of People for address book search
		//#20776 jchi
		$peopleTables = array("users",
		                      "contacts",
		                      "leads",
		                      "prospects",
		                      "accounts");
		$filterPeopleTables = array();
		global $app_list_strings, $app_strings;
		$filterPeopleTables['LBL_DROPDOWN_LIST_ALL'] = $app_strings['LBL_DROPDOWN_LIST_ALL'];
		foreach($peopleTables as $table) {
			$module = ucfirst($table);
            $class = substr($module, 0, strlen($module) - 1);
            require_once("modules/{$module}/{$class}.php");
            $person = new $class();

            if (!$person->ACLAccess('list')) continue;
            $filterPeopleTables[$person->table_name] = $app_list_strings['moduleList'][$person->module_dir];
		}
		$this->smarty->assign('listOfPersons' , get_select_options_with_id($filterPeopleTables,''));

	}



	////	END CORE
	///////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	////	ADDRESS BOOK
	/**
	 * Retrieves all relationship metadata for a user's address book
	 * @return array
	 */
	function getContacts() {
		global $current_user;

		$q = "SELECT * FROM address_book WHERE assigned_user_id = '{$current_user->id}' ORDER BY bean DESC";
		$r = $this->db->query($q);

		$ret = array();

		while($a = $this->db->fetchByAssoc($r)) {
			$ret[$a['bean_id']] = array(
				'id'		=> $a['bean_id'],
				'module'	=> $a['bean'],
			);
		}

		return $ret;
	}

	/**
	 * Saves changes to a user's address book
	 * @param array contacts
	 */
	function setContacts($contacts) {
		global $current_user;

		$oldContacts = $this->getContacts();

		foreach($contacts as $cid => $contact) {
			if(!in_array($contact['id'], $oldContacts)) {
				$q = "INSERT INTO address_book (assigned_user_id, bean, bean_id) VALUES ('{$current_user->id}', '{$contact['module']}', '{$contact['id']}')";
				$r = $this->db->query($q, true);
			}
		}
	}

	/**
	 * Removes contacts from the user's address book
	 * @param array ids
	 */
	function removeContacts($ids) {
		global $current_user;

		$concat = "";

		foreach($ids as $id) {
			if(!empty($concat))
				$concat .= ", ";

			$concat .= "'{$id}'";
		}

		$q = "DELETE FROM address_book WHERE assigned_user_id = '{$current_user->id}' AND bean_id IN ({$concat})";
		$r = $this->db->query($q);
	}

	/**
	 * saves editted Contact info
	 * @param string $str JSON serialized object
	 */
	function saveContactEdit($str) {

		$json = getJSONobj();

		$str = from_html($str);
		$obj = $json->decode($str);

		$contact = new Contact();
		$contact->retrieve($obj['contact_id']);
		$contact->first_name = $obj['contact_first_name'];
		$contact->last_name = $obj['contact_last_name'];
		$contact->save();

		// handle email address changes
		$addresses = array();

		foreach($obj as $k => $req) {
			if(strpos($k, 'emailAddress') !== false) {
				$addresses[$k] = $req;
			}
		}

		// prefill some REQUEST vars for emailAddress save
		$_REQUEST['emailAddressOptOutFlag'] = $obj['optOut'];
		$_REQUEST['emailAddressInvalidFlag'] = $obj['invalid'];
		$contact->emailAddress->saveEmail($obj['contact_id'], 'Contacts', $addresses, $obj['primary'], '');
	}

	/**
	 * Prepares the Edit Contact mini-form via template assignment
	 * @param string id ID of contact in question
	 * @param string module Module in focus
	 * @return array
	 */
	function getEditContact($id, $module) {
		global $app_strings;


		if(!class_exists("Contact")) {

		}

		$contact = new Contact();
		$contact->retrieve($_REQUEST['id']);
		$ret = array();

		if($contact->ACLAccess('edit')) {
			$contactMeta = array();
			$contactMeta['id'] = $contact->id;
			$contactMeta['module'] = $contact->module_dir;
			$contactMeta['first_name'] = $contact->first_name;
			$contactMeta['last_name'] = $contact->last_name;

			$this->smarty->assign("app_strings", $app_strings);
			$this->smarty->assign("contact_strings", return_module_language($_SESSION['authenticated_user_language'], 'Contacts'));
			$this->smarty->assign("contact", $contactMeta);

			$ea = new SugarEmailAddress();
			$newEmail = $ea->getEmailAddressWidgetEditView($id, $module, true);
			$this->smarty->assign("emailWidget", $newEmail['html']);

			$ret['form'] = $this->smarty->fetch("modules/Emails/templates/editContact.tpl");
			$ret['prefillData'] = $newEmail['prefillData'];
		} else {
			$id = "";
			$ret['form'] = $app_strings['LBL_EMAIL_ERROR_NO_ACCESS'];
			$ret['prefillData'] = '{}';
		}

		$ret['id'] = $id;
		$ret['contactName'] = $contact->full_name;

		return $ret;
	}


	/**
	 * Retrieves a concatenated list of contacts, those with assigned_user_id = user's id and those in the address_book
	 * table
	 * @param array $contacts Array of contact types -> IDs
	 * @param object $user User in focus
	 * @return array
	 */
	function getUserContacts($contacts, $user=null) {

		global $current_user;
		global $locale;

		if(empty($user)) {
			$user = $current_user;
		}

		$emailAddress = new SugarEmailAddress();
		$ret = array();

		$union = '';

		$modules = array();
		foreach($contacts as $contact) {
			if(!isset($modules[$contact['module']])) {
				$modules[$contact['module']] = array();
			}
			$modules[$contact['module']][] = $contact;
		}

		foreach($modules as $module => $contacts) {
			if(!empty($union)) {
				$union .= " UNION ALL ";
			}

			$table = strtolower($module);
			$idsSerial = '';

			foreach($contacts as $contact) {
				if(!empty($idsSerial)) {
					$idsSerial .= ",";
				}
				$idsSerial .= "'{$contact['id']}'";
			}

			$union .= "(SELECT id, first_name, last_name, title, '{$module}' module FROM {$table} WHERE id IN({$idsSerial}) AND deleted = 0 )";
		}
		if(!empty($union)) {
			$union .= " ORDER BY last_name";
		}

		$r = $user->db->query($union);

		//_pp($union);

		while($a = $user->db->fetchByAssoc($r)) {
			$c = array();

			$c['name'] = $locale->getLocaleFormattedName($a['first_name'], "<b>{$a['last_name']}</b>", '', $a['title'], '', $user);
			$c['id'] = $a['id'];
			$c['module'] = $a['module'];
			$c['email'] = $emailAddress->getAddressesByGUID($a['id'], $a['module']);
			$ret[$a['id']] = $c;
		}

		return $ret;
	}
	////	END ADDRESS BOOK
	///////////////////////////////////////////////////////////////////////////


	///////////////////////////////////////////////////////////////////////////
	////	EMAIL 2.0 Preferences
	function getUserPrefsJS() {
		global $current_user;
		global $locale;

		// sort order per mailbox view
		$sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
		$sortArray = array();
		if(!empty($sortSerial)) {
			$sortArray = sugar_unserialize($sortSerial);
		}

		// treeview collapsed/open states
		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
		$folderStates = array();
		if(!empty($folderStateSerial)) {
			$folderStates = sugar_unserialize($folderStateSerial);
		}

		// subscribed accounts
		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));

		// general settings
		$emailSettings = $current_user->getPreference('emailSettings', 'Emails');

		if(empty($emailSettings)) {
			$emailSettings = array();
			$emailSettings['emailCheckInterval'] = -1;
			$emailSettings['autoImport'] = '';
			$emailSettings['alwaysSaveOutbound'] = '1';
			$emailSettings['sendPlainText'] = '';
			$emailSettings['defaultOutboundCharset'] = $GLOBALS['sugar_config']['default_email_charset'];
			$emailSettings['showNumInList'] = 20;
		}

		// focus folder
		$focusFolder = $current_user->getPreference('focusFolder', 'Emails');
		$focusFolder = !empty($focusFolder) ? sugar_unserialize($focusFolder) : array();

		// unread only flag
		$showUnreadOnly = $current_user->getPreference('showUnreadOnly', 'Emails');

		$listViewSort = array(
			"sortBy" => 'date',
			"sortDirection" => 'DESC',
		);

		// signature prefs
		$signaturePrepend = $current_user->getPreference('signature_prepend') ? 'true' : 'false';
		$signatureDefault = $current_user->getPreference('signature_default');
		$signatures = array(
			'signature_prepend' => $signaturePrepend,
			'signature_default' => $signatureDefault
		);


		// current_user
		$user = array(
			'emailAddresses' => $current_user->emailAddress->getAddressesByGUID($current_user->id, 'Users'),
			'full_name' => from_html($current_user->full_name),
		);

		$userPreferences = array();
		$userPreferences['sort'] = $sortArray;
		$userPreferences['folderStates'] = $folderStates;
		$userPreferences['showFolders'] = $showFolders;
		$userPreferences['emailSettings'] = $emailSettings;
		$userPreferences['focusFolder'] = $focusFolder;
		$userPreferences['showUnreadOnly'] = $showUnreadOnly;
		$userPreferences['listViewSort'] = $listViewSort;
		$userPreferences['signatures'] = $signatures;
		$userPreferences['current_user'] = $user;
		return $userPreferences;
	}



	///////////////////////////////////////////////////////////////////////////
	////	FOLDER FUNCTIONS

	/**
	 * Creates a new Sugar folder
	 * @param string $nodeLabel New sugar folder name
	 * @param string $parentLabel Parent folder name
	 */
	function saveNewFolder($nodeLabel, $parentId, $isGroup=0) {
		global $current_user;

		$this->folder->name = $nodeLabel;
		$this->folder->is_group = $isGroup;
		$this->folder->parent_folder = ($parentId == 'Home') ? "" : $parentId;
		$this->folder->has_child = 0;
		$this->folder->created_by = $current_user->id;
		$this->folder->modified_by = $current_user->id;
		$this->folder->date_modified = $this->folder->date_created = TimeDate::getInstance()->nowDb();

		$this->folder->save();
		return array(
			'action' => 'newFolderSave',
			'id' => $this->folder->id,
			'name' => $this->folder->name,
			'is_group' => $this->folder->is_group,
			'is_dynamic' => $this->folder->is_dynamic
		);
	}

	/**
	 * Saves user sort prefernces
	 */
	function saveListViewSortOrder($ieId, $focusFolder, $sortBy, $sortDir) {
		global $current_user;

		$sortArray = array();

		$sortSerial = $current_user->getPreference('folderSortOrder', 'Emails');
		if(!empty($sortSerial)) {
			$sortArray = sugar_unserialize($sortSerial);
		}

		$sortArray[$ieId][$focusFolder]['current']['sort'] = $sortBy;
		$sortArray[$ieId][$focusFolder]['current']['direction'] = $sortDir;
		$sortSerial = serialize($sortArray);
		$current_user->setPreference('folderSortOrder', $sortSerial, '', 'Emails');
	}

	/**
	 * Stickies folder collapse/open state
	 */
	function saveFolderOpenState($focusFolder, $focusFolderOpen) {
		global $current_user;

		$folderStateSerial = $current_user->getPreference('folderOpenState', 'Emails');
		$folderStates = array();

		if(!empty($folderStateSerial)) {
			$folderStates = sugar_unserialize($folderStateSerial);
		}

		$folderStates[$focusFolder] = $focusFolderOpen;
		$newFolderStateSerial = serialize($folderStates);
		$current_user->setPreference('folderOpenState', $newFolderStateSerial, '', 'Emails');
	}

	/**
	 * saves a folder's view state
	 */
	function saveListView($ieId, $folder) {
		global $current_user;

		$saveState = array();
		$saveState['ieId'] = $ieId;
		$saveState['folder'] = $folder;
		$saveStateSerial = serialize($saveState);
		$current_user->setPreference('focusFolder', $saveStateSerial, '', 'Emails');
	}

	/**
	 * Generates cache folder structure
	 */
	function preflightEmailCache($cacheRoot) {
		// base
		if(!file_exists($cacheRoot))
			mkdir_recursive(clean_path($cacheRoot));

		// folders
		if(!file_exists($cacheRoot."/folders"))
			mkdir_recursive(clean_path("{$cacheRoot}/folders"));

		// messages
		if(!file_exists($cacheRoot."/messages"))
			mkdir_recursive(clean_path("{$cacheRoot}/messages"));

		// attachments
		if(!file_exists($cacheRoot."/attachments"))
			mkdir_recursive(clean_path("{$cacheRoot}/attachments"));
	}

	function deleteEmailCacheForFolders($cacheRoot) {
		$filePath = $cacheRoot."/folders/folders.php";
		if (file_exists($filePath)) {
			unlink($filePath);
		}
	}
	///////////////////////////////////////////////////////////////////////////
	////	IMAP FUNCTIONS
	/**
	 * Identifies subscribed mailboxes and empties the trash
	 * @param object $ie InboundEmail
	 */
	function emptyTrash(&$ie) {
		global $current_user;

		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));

		if(is_array($showFolders)) {
			foreach($showFolders as $ieId) {
				if(!empty($ieId)) {
					$ie->retrieve($ieId);
					$ie->emptyTrash();
				}
			}
		}
	}

	/**
	 * returns an array of nodes that correspond to IMAP mailboxes.
	 * @param bool $forceRefresh
	 * @return object TreeView object
	 */
	function getMailboxNodes() {
		global $sugar_config;
		global $current_user;
		global $app_strings;

		$tree = new Tree("frameFolders");
		$tree->tree_style= 'include/ytree/TreeView/css/check/tree.css';

		$nodes = array();
		$ie = new InboundEmail();
		$refreshOffset = $this->cacheTimeouts['folders']; // 5 mins.  this will be set via user prefs

		$rootNode = new ExtNode($app_strings['LBL_EMAIL_HOME_FOLDER'], $app_strings['LBL_EMAIL_HOME_FOLDER']);
		$rootNode->dynamicloadfunction = '';
		$rootNode->expanded = true;
		$rootNode->dynamic_load = true;
		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));

		if(empty($showFolders)) {
			$showFolders = array();
		}

		// INBOX NODES
		if($current_user->hasPersonalEmail()) {
			$personals = $ie->retrieveByGroupId($current_user->id);

			foreach($personals as $k => $personalAccount) {
				if(in_array($personalAccount->id, $showFolders)) {
					// check for cache value
					$cacheRoot = sugar_cached("modules/Emails/{$personalAccount->id}");
					$this->preflightEmailCache($cacheRoot);

					if($this->validCacheFileExists($personalAccount->id, 'folders', "folders.php")) {
						$mailboxes = $this->getMailBoxesFromCacheValue($personalAccount);
					} else {
						$mailboxes = $personalAccount->getMailboxes();
					}

					$acctNode = new ExtNode('Home::' . $personalAccount->name, $personalAccount->name);
					$acctNode->dynamicloadfunction = '';
					$acctNode->expanded = false;
					$acctNode->set_property('cls', 'ieFolder');
					$acctNode->set_property('ieId', $personalAccount->id);
		        	$acctNode->set_property('protocol', $personalAccount->protocol);

					if(array_key_exists('Home::'.$personalAccount->name, $this->folderStates)) {
						if($this->folderStates['Home::'.$personalAccount->name] == 'open') {
							$acctNode->expanded = true;
						}
					}
					$acctNode->dynamic_load = true;

					$nodePath = $acctNode->_properties['id'];

					foreach($mailboxes as $k => $mbox) {
						$acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $personalAccount->id,
						    $nodePath, false, $personalAccount));
					}

					$rootNode->add_node($acctNode);
				}
			}
		}

		// GROUP INBOX NODES
		$beans = $ie->retrieveAllByGroupId($current_user->id, false);
		foreach($beans as $k => $groupAccount) {
			if(in_array($groupAccount->id, $showFolders)) {
				// check for cache value
				$cacheRoot = sugar_cached("modules/Emails/{$groupAccount->id}");
				$this->preflightEmailCache($cacheRoot);
				//$groupAccount->connectMailserver();

				if($this->validCacheFileExists($groupAccount->id, 'folders', "folders.php")) {
					$mailboxes = $this->getMailBoxesFromCacheValue($groupAccount);
				} else {
					$mailboxes = $groupAccount->getMailBoxesForGroupAccount();
				}

				$acctNode = new ExtNode($groupAccount->name, "group.{$groupAccount->name}");
				$acctNode->dynamicloadfunction = '';
				$acctNode->expanded = false;
		        $acctNode->set_property('isGroup', 'true');
		        $acctNode->set_property('ieId', $groupAccount->id);
		        $acctNode->set_property('protocol', $groupAccount->protocol);

				if(array_key_exists('Home::'.$groupAccount->name, $this->folderStates)) {
					if($this->folderStates['Home::'.$groupAccount->name] == 'open') {
						$acctNode->expanded = true;
					}
				}
				$acctNode->dynamic_load = true;
				$nodePath = $rootNode->_properties['id']."::".$acctNode->_properties['id'];

				foreach($mailboxes as $k => $mbox) {
					$acctNode->add_node($this->buildTreeNode($k, $k, $mbox, $groupAccount->id,
					   $nodePath, true, $groupAccount));
				}

				$rootNode->add_node($acctNode);
			}
		}

		// SugarFolder nodes
		/* SugarFolders are built at onload when the UI renders */

		$tree->add_node($rootNode);
		return $tree;
	}

	function getMailBoxesFromCacheValue($mailAccount) {
		$foldersCache = $this->getCacheValue($mailAccount->id, 'folders', "folders.php", 'foldersCache');
		$mailboxes = $foldersCache['mailboxes'];
		$mailboxesArray = $mailAccount->generateFlatArrayFromMultiDimArray($mailboxes, $mailAccount->retrieveDelimiter());
		$mailAccount->saveMailBoxFolders($mailboxesArray);
		$this->deleteEmailCacheForFolders($cacheRoot);
		return $mailboxes;
	} // fn

	/**
	 * Builds up a TreeView Node object
	 * @param mixed
	 * @param mixed
	 * @param string
	 * @param string ID of InboundEmail instance
	 * @param string nodePath Serialized path from root node to current node
	 * @param bool isGroup
	 * @param bool forceRefresh
	 * @return mixed
	 */
	function buildTreeNode($key, $label, $mbox, $ieId, $nodePath, $isGroup, $ie) {
		global $sugar_config;

		// get unread counts
		$exMbox = explode("::", $nodePath);
		$unseen = 0;
		$GLOBALS['log']->debug("$key --- $nodePath::$label");

		if(count($exMbox) >= 2) {
			$mailbox = "";
			for($i=2; $i<count($exMbox); $i++) {
				if($mailbox != "") {
					$mailbox .= ".";
				}
				$mailbox .= "{$exMbox[$i]}";
			}

		    $mailbox = substr($key, strpos($key, '.'));

			$unseen = $this->getUnreadCount($ie, $mailbox);

			if($unseen > 0) {
				//$label = " <span id='span{$ie->id}{$ie->mailbox}' style='font-weight:bold'>{$label} (<span id='span{$ie->id}{$ie->mailbox}nums'>{$unseen}</span>)</span>";
			}
		}

		$nodePath = $nodePath."::".$label;
        $node = new ExtNode($nodePath, $label);
        $node->dynamicloadfunction = '';
        $node->expanded = false;
        $node->set_property('labelStyle', "remoteFolder");


        if(array_key_exists($nodePath, $this->folderStates)) {
        	if($this->folderStates[$nodePath] == 'open') {
        		$node->expanded = true;
        	}
        }

		$group = ($isGroup) ? 'true' : 'false';
        $node->dynamic_load = true;
        //$node->set_property('href', " SUGAR.email2.listView.populateListFrame(YAHOO.namespace('frameFolders').selectednode, '{$ieId}', 'false');");
        $node->set_property('isGroup', $group);
        $node->set_property('isDynamic', 'false');
        $node->set_property('ieId', $ieId);
        $node->set_property('mbox', $key);
        $node->set_property('unseen', $unseen);
        $node->set_property('cls', 'ieFolder');

        if(is_array($mbox)) {
        	foreach($mbox as $k => $v) {
        		$node->add_node($this->buildTreeNode("$key.$k", $k, $v, $ieId, $nodePath, $isGroup, $ie));
        	}
        }

        return $node;
	}

	/**
	 * Totals the unread emails
	 */
	function getUnreadCount(&$ie, $mailbox) {
		global $sugar_config;
		$unseen = 0;

		// use cache
		return $ie->getCacheUnreadCount($mailbox);
	}

	///////////////////////////////////////////////////////////////////////////
	////	DISPLAY CODE
	/**
	 * Used exclusively by draft code.  Returns Notes and Documents as attachments.
	 * @param array $ret
	 * @return array
	 */
	function getDraftAttachments($ret) {
		global $db;

		// $ret['uid'] is the draft Email object's GUID
		$ret['attachments'] = array();

		$q = "SELECT id, filename FROM notes WHERE parent_id = '{$ret['uid']}' AND deleted = 0";
		$r = $db->query($q);

		while($a = $db->fetchByAssoc($r)) {
			$ret['attachments'][$a['id']] = array(
				'id'		=> $a['id'],
				'filename'	=> $a['filename'],
			);
		}

		return $ret;
	}

	function createCopyOfInboundAttachment($ie, $ret, $uid) {
		global $sugar_config;
		if ($ie->isPop3Protocol()) {
			// get the UIDL from database;
			$cachedUIDL = md5($uid);
			$cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$cachedUIDL}.php");
		} else {
			$cache = sugar_cached("modules/Emails/{$ie->id}/messages/{$ie->mailbox}{$uid}.php");
		}
		if(file_exists($cache)) {
			include($cache); // profides $cacheFile
			$metaOut = unserialize($cacheFile['out']);
			$meta = $metaOut['meta']['email'];
			if (isset($meta['attachments'])) {
				$attachmentHtmlData = $meta['attachments'];
				$actualAttachmentInfo = array();
				$this->parseAttachmentInfo($actualAttachmentInfo, $attachmentHtmlData);
				if (sizeof($actualAttachmentInfo) > 0) {
					foreach($actualAttachmentInfo as $key => $value) {
					    $info_vars = array();
					    parse_str($value, $info_vars);
					    $fileName = $info_vars['tempName'];
					    $attachmentid = $info_vars['id'];
						$guid = create_guid();
						$destination = clean_path("{$this->userCacheDir}/{$guid}");

						$attachmentFilePath = sugar_cached("modules/Emails/{$ie->id}/attachments/{$attachmentid}");
						copy($attachmentFilePath, $destination);
						$ret['attachments'][$guid] = array();
						$ret['attachments'][$guid]['id'] = $guid . $fileName;
						$ret['attachments'][$guid]['filename'] = $fileName;
					} // for
				} // if
			} // if

		} // if
		return $ret;

	} // fn

	function parseAttachmentInfo(&$actualAttachmentInfo, $attachmentHtmlData) {
	 	$downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
		while ($downLoadPHP) {
		 	$attachmentHtmlData = substr($attachmentHtmlData, $downLoadPHP+30);
		 	$final = strpos($attachmentHtmlData, "\">");
		 	$actualAttachmentInfo[] = substr($attachmentHtmlData, 0, $final);
		 	$attachmentHtmlData = substr($attachmentHtmlData, $final);
		 	$downLoadPHP = strpos($attachmentHtmlData, "index.php?entryPoint=download&");
		} // while
	}
	/**
	 * Renders the QuickCreate form from Smarty and returns HTML
	 * @param array $vars request variable global
	 * @param object $email Fetched email object
	 * @param bool $addToAddressBook
	 * @return array
	 */
	function getQuickCreateForm($vars, $email, $addToAddressBookButton=false) {
		require_once("include/EditView/EditView2.php");
		global $app_strings;
		global $mod_strings;
		global $current_user;
		global $beanList;
		global $beanFiles;
		global $current_language;

		//Setup the current module languge
		$mod_strings = return_module_language($current_language, $_REQUEST['qc_module']);

		$bean = $beanList[$_REQUEST['qc_module']];
		$class = $beanFiles[$bean];
		require_once($class);

		$focus = new $bean();

		$people = array(
		'Contact'
		,'Lead'
		);
		$emailAddress = array();

		// people
		if(in_array($bean, $people)) {
			// lead specific
			$focus->lead_source = 'Email';
			$focus->lead_source_description = trim($email->name);

			$from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr;

            if(isset($_REQUEST['sugarEmail']) && !empty($_REQUEST['sugarEmail']))
            {
                if($email->status == "sent")
                {
                    $from = (isset($email->to_addrs_names) && !empty($email->to_addrs_names)) ? $email->to_addrs_names : $email->to_addrs;
                }else{
                    $from = (isset($email->from_name) && !empty($email->from_name)) ? $email->from_name : $email->from_addr_name;
                }
            }

			$name = explode(" ", trim($from));

			$address = trim(array_pop($name));
			$address = str_replace(array("<",">","&lt;","&gt;"), "", $address);

			$emailAddress[] = array(
				'email_address'		=> $address,
				'primary_address'	=> 1,
				'invalid_email'		=> 0,
				'opt_out'			=> 0,
				'reply_to_address'	=> 1
			);

			$focus->email1 = $address;

			if(!empty($name)) {
				$focus->last_name = trim(array_pop($name));

				foreach($name as $first) {
					if(!empty($focus->first_name)) {
						$focus->first_name .= " ";
					}
					$focus->first_name .= trim($first);
				}
			}
		} else {
			// bugs, cases, tasks
			$focus->name = trim($email->name);
		}

		$focus->description = trim(strip_tags($email->description));
		$focus->assigned_user_id = $current_user->id;


		$EditView = new EditView();
		$EditView->ss = new Sugar_Smarty();
		//MFH BUG#20283 - checks for custom quickcreate fields
		$EditView->setup($_REQUEST['qc_module'], $focus, 'custom/modules/'.$focus->module_dir.'/metadata/editviewdefs.php', 'include/EditView/EditView.tpl');
		$EditView->process();
		$EditView->render();

		$EditView->defs['templateMeta']['form']['buttons'] = array(
			'email2save' => array(
				'id' => 'e2AjaxSave',
				'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_SAVE_BUTTON_LABEL']
				              . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(false);" />'
			),
			'email2saveandreply' => array(
			    'id' => 'e2SaveAndReply',
			    'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_SAVE_AND_REPLY']
			                  . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(\'reply\');" />'
			),
			'email2cancel' => array(
			     'id' => 'e2cancel',
			     'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_CANCEL']
                              . '   " onclick="SUGAR.email2.detailView.quickCreateDialog.hide();" />'
			)
		);


		if($addToAddressBookButton) {
			$EditView->defs['templateMeta']['form']['buttons']['email2saveAddToAddressBook'] = array(
				'id' => 'e2addToAddressBook',
				'customCode' => '<input type="button" class="button" value="   '.$app_strings['LBL_EMAIL_ADDRESS_BOOK_SAVE_AND_ADD']
				              . '   " onclick="SUGAR.email2.detailView.saveQuickCreate(true);" />'
			);
		}

		//Get the module language for javascript
	    if(!is_file(sugar_cached('jsLanguage/') . $_REQUEST['qc_module'] . '/' . $GLOBALS['current_language'] . '.js')) {
            require_once('include/language/jsLanguage.php');
            jsLanguage::createModuleStringsCache($_REQUEST['qc_module'], $GLOBALS['current_language']);
        }
		$jsLanguage = getVersionedScript("cache/jsLanguage/{$_REQUEST['qc_module']}/{$GLOBALS['current_language']}.js", $GLOBALS['sugar_config']['js_lang_version']);


		$EditView->view = 'EmailQCView';
		$EditView->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl';
		$EditView->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl';
		$meta = array();
		$meta['html'] = $jsLanguage . $EditView->display(false, true);
		$meta['html'] = str_replace("src='".getVersionedPath('include/SugarEmailAddress/SugarEmailAddress.js')."'", '', $meta['html']);
		$meta['emailAddress'] = $emailAddress;

		$mod_strings = return_module_language($current_language, 'Emails');

		return $meta;
	}

	/**
     * Renders the Import form from Smarty and returns HTML
     * @param array $vars request variable global
     * @param object $email Fetched email object
     * @param bool $addToAddressBook
     * @return array
     */
    function getImportForm($vars, $email, $formName = 'ImportEditView') {
		require_once("include/EditView/EditView2.php");
        require_once("include/TemplateHandler/TemplateHandler.php");
		require_once('include/QuickSearchDefaults.php');
        $qsd = QuickSearchDefaults::getQuickSearchDefaults();
		$qsd->setFormName($formName);

        global $app_strings;
        global $current_user;
        global $app_list_strings;
		$sqs_objects = array(
		                     "{$formName}_parent_name" => $qsd->getQSParent(),
		);
        $smarty = new Sugar_Smarty();
        $smarty->assign("APP",$app_strings);
        $smarty->assign('formName',$formName);
        $showAssignTo = false;
        if (!isset($vars['showAssignTo']) || $vars['showAssignTo'] == true) {
        	$showAssignTo = true;
		} // if
		if ($showAssignTo) {
	        if(empty($email->assigned_user_id) && empty($email->id))
	            $email->assigned_user_id = $current_user->id;
	        if(empty($email->assigned_name) && empty($email->id))
	            $email->assigned_user_name = $current_user->user_name;
	        $sqs_objects["{$formName}_assigned_user_name"] = $qsd->getQSUser();
		}
		$smarty->assign("showAssignedTo",$showAssignTo);

        $showDelete = false;
        if (!isset($vars['showDelete']) || $vars['showDelete'] == true) {
            $showDelete = true;
        }
        $smarty->assign("showDelete",$showDelete);

        $smarty->assign("userId",$email->assigned_user_id);
        $smarty->assign("userName",$email->assigned_user_name);
        $parent_types = $app_list_strings['record_type_display'];
        $smarty->assign('parentOptions', get_select_options_with_id($parent_types, $email->parent_type));

		$quicksearch_js = '<script type="text/javascript" language="javascript">sqs_objects = ' . json_encode($sqs_objects) . '</script>';
        $smarty->assign('SQS', $quicksearch_js);

        $meta = array();
        $meta['html'] = $smarty->fetch("modules/Emails/templates/importRelate.tpl");
        return $meta;
    }

    /**
     * This function returns the detail view for email in new 2.0 interface
     *
     */
    function getDetailViewForEmail2($emailId) {

		require_once('include/DetailView/DetailView.php');
		global $app_strings, $app_list_strings;
		global $mod_strings;

        $smarty = new Sugar_Smarty();

		// SETTING DEFAULTS
		$focus		= new Email();
		$focus->retrieve($emailId);
		$detailView->ss = new Sugar_Smarty();
		$detailView	= new DetailView();
		$title = "";
		$offset		= 0;
		if($focus->type == 'out') {
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_SENT_MODULE_NAME'],$focus->name), true);
		} elseif ($focus->type == 'draft') {
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_LIST_FORM_DRAFTS_TITLE'],$focus->name), true);
		} elseif($focus->type == 'inbound') {
			$title = getClassicModuleTitle('Emails', array($mod_strings['LBL_INBOUND_TITLE'],$focus->name), true);
		}
		$smarty->assign("emailTitle", $title);

		// DEFAULT TO TEXT IF NO HTML CONTENT:
		$html = trim(from_html($focus->description_html));
		if(empty($html)) {
			$smarty->assign('SHOW_PLAINTEXT', 'true');
		} else {
			$smarty->assign('SHOW_PLAINTEXT', 'false');
		}

		//if not empty or set to test (from test campaigns)
		if (!empty($focus->parent_type) && $focus->parent_type !='test') {
			$smarty->assign('PARENT_MODULE', $focus->parent_type);
			$smarty->assign('PARENT_TYPE', $app_list_strings['record_type_display'][$focus->parent_type] . ":");
		}

        global $gridline;
		$smarty->assign('MOD', $mod_strings);
		$smarty->assign('APP', $app_strings);
		$smarty->assign('GRIDLINE', $gridline);
		$smarty->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']);
		$smarty->assign('ID', $focus->id);
		$smarty->assign('TYPE', $focus->type);
		$smarty->assign('PARENT_NAME', $focus->parent_name);
		$smarty->assign('PARENT_ID', $focus->parent_id);
		$smarty->assign('NAME', $focus->name);
		$smarty->assign('ASSIGNED_TO', $focus->assigned_user_name);
		$smarty->assign('DATE_MODIFIED', $focus->date_modified);
		$smarty->assign('DATE_ENTERED', $focus->date_entered);
		$smarty->assign('DATE_START', $focus->date_start);
		$smarty->assign('TIME_START', $focus->time_start);
		$smarty->assign('FROM', $focus->from_addr);
		$smarty->assign('TO', nl2br($focus->to_addrs));
		$smarty->assign('CC', nl2br($focus->cc_addrs));
		$smarty->assign('BCC', nl2br($focus->bcc_addrs));
		$smarty->assign('CREATED_BY', $focus->created_by_name);
		$smarty->assign('MODIFIED_BY', $focus->modified_by_name);
		$smarty->assign('DATE_SENT', $focus->date_entered);
		$smarty->assign('EMAIL_NAME', 'RE: '.$focus->name);
		$smarty->assign("TAG", $focus->listviewACLHelper());
		$smarty->assign("SUGAR_VERSION", $GLOBALS['sugar_version']);
		$smarty->assign("JS_CUSTOM_VERSION", $GLOBALS['sugar_config']['js_custom_version']);
		if(!empty($focus->reply_to_email)) {
			$replyTo = "
				<tr>
		        <td class=\"tabDetailViewDL\"><slot>".$mod_strings['LBL_REPLY_TO_NAME']."</slot></td>
		        <td colspan=3 class=\"tabDetailViewDF\"><slot>".$focus->reply_to_addr."</slot></td>
		        </tr>";
		 	$smarty->assign("REPLY_TO", $replyTo);
		}
		///////////////////////////////////////////////////////////////////////////////
		////	JAVASCRIPT VARS
		$jsVars  = '';
		$jsVars .= "var showRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL']}';";
		$jsVars .= "var hideRaw = '{$mod_strings['LBL_BUTTON_RAW_LABEL_HIDE']}';";
		$smarty->assign("JS_VARS", $jsVars);
		///////////////////////////////////////////////////////////////////////////////
		////	NOTES (attachements, etc.)
		///////////////////////////////////////////////////////////////////////////////

		$note = new Note();
		$where = "notes.parent_id='{$focus->id}'";
		//take in account if this is from campaign and the template id is stored in the macros.

		if(isset($macro_values) && isset($macro_values['email_template_id'])){
		    $where = "notes.parent_id='{$macro_values['email_template_id']}'";
		}
		$notes_list = $note->get_full_list("notes.name", $where, true);

		if(! isset($notes_list)) {
			$notes_list = array();
		}

		$attachments = '';
		for($i=0; $i<count($notes_list); $i++) {
			$the_note = $notes_list[$i];
			$attachments .= "<a href=\"index.php?entryPoint=download&id={$the_note->id}&type=Notes\">".$the_note->name."</a><br />";
			$focus->cid2Link($the_note->id, $the_note->file_mime_type);
		}
		$smarty->assign('DESCRIPTION', nl2br($focus->description));
		$smarty->assign('DESCRIPTION_HTML', from_html($focus->description_html));
		$smarty->assign("ATTACHMENTS", $attachments);
		///////////////////////////////////////////////////////////////////////////////
		////    SUBPANELS
		///////////////////////////////////////////////////////////////////////////////
		$show_subpanels = true;
		if ($show_subpanels) {
		    require_once('include/SubPanel/SubPanelTiles.php');
		    $subpanel = new SubPanelTiles($focus, 'Emails');
		    $smarty->assign("SUBPANEL", $subpanel->display());
		}
        $meta['html'] = $smarty->fetch("modules/Emails/templates/emailDetailView.tpl");
        return $meta;

    } // fn

	/**
	 * Sets the "read" flag in the overview cache
	 */
	function setReadFlag($ieId, $mbox, $uid) {
		$this->markEmails('read', $ieId, $mbox, $uid);
	}

	/**
	 * Marks emails with the passed flag type.  This will be applied to local
	 * cache files as well as remote emails.
	 * @param string $type Flag type
	 * @param string $ieId
	 * @param string $folder IMAP folder structure or SugarFolder GUID
	 * @param string $uids Comma sep list of UIDs or GUIDs
	 */
	function markEmails($type, $ieId, $folder, $uids) {

		global $app_strings;
		$uids = $this->_cleanUIDList($uids);
		$exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);

		if(strpos($folder, 'sugar::') !== false) {
			// dealing with a sugar email object, uids are GUIDs
			foreach($exUids as $id) {
				$email = new Email();
				$email->retrieve($id);

                // BUG FIX BEGIN
                // Bug 50973 - marking unread in group inbox removes message
                if (empty($email->assigned_user_id))
                {
                    $email->setFieldNullable('assigned_user_id');
                }
                // BUG FIX END

				switch($type) {
					case "unread":
						$email->status = 'unread';
						$email->save();
					break;

					case "read":
						$email->status = 'read';
						$email->save();
					break;

					case "deleted":
						$email->delete();
					break;

					case "flagged":
						$email->flagged = 1;
						$email->save();
					break;

					case "unflagged":
						$email->flagged = 0;
						$email->save();
					break;

				}

                // BUG FIX BEGIN
                // Bug 50973 - reset assigned_user_id field defs
                if (empty($email->assigned_user_id))
                {
                    $email->revertFieldNullable('assigned_user_id');
                }
                // BUG FIX END
			}
		} else {
			/* dealing with IMAP email, uids are IMAP uids */
			global $ie; // provided by EmailUIAjax.php
			if(empty($ie)) {

				$ie = new InboundEmail();
			}
			$ie->retrieve($ieId);
			$ie->mailbox = $folder;
			$ie->connectMailserver();
			// mark cache files
			if($type == 'deleted') {
				$ie->deleteMessageOnMailServer($uids);
				$ie->deleteMessageFromCache($uids);
			} else {
				$overviews = $ie->getCacheValueForUIDs($ie->mailbox, $exUids);
				$manipulated = array();

				foreach($overviews['retArr'] as $k => $overview) {
					if(in_array($overview->uid, $exUids)) {
						switch($type) {
							case "unread":
								$overview->seen = 0;
							break;

							case "read":
								$overview->seen = 1;
							break;

							case "flagged":
								$overview->flagged = 1;
							break;

							case "unflagged":
								$overview->flagged = 0;
							break;
						}
						$manipulated[] = $overview;
					}
				}

				if(!empty($manipulated)) {
					$ie->setCacheValue($ie->mailbox, array(), $manipulated);
					/* now mark emails on email server */
					$ie->markEmails(implode(",", explode($app_strings['LBL_EMAIL_DELIMITER'], $uids)), $type);
				}
			} // end not type == deleted
		}
	}

function doAssignment($distributeMethod, $ieid, $folder, $uids, $users) {
	global $app_strings;
	$users = explode(",", $users);
	$emailIds = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
	$out = "";
	if($folder != 'sugar::Emails') {
		$emailIds = array();
		$uids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
		$ie = new InboundEmail();
		$ie->retrieve($ieid);
		$messageIndex = 1;
		// dealing with an inbound email data so we need to import an email and then
		foreach($uids as $uid) {
			$ie->mailbox = $folder;
			$ie->connectMailserver();
			$msgNo = $uid;
			if (!$ie->isPop3Protocol()) {
				$msgNo = imap_msgno($ie->conn, $uid);
			} else {
				$msgNo = $ie->getCorrectMessageNoForPop3($uid);
			}

			if(!empty($msgNo)) {
				if ($ie->importOneEmail($msgNo, $uid)) {
					$emailIds[] = $ie->email->id;
					$ie->deleteMessageOnMailServer($uid);
					//$ie->retrieve($ieid);
					//$ie->connectMailserver();
					$ie->mailbox = $folder;
					$ie->deleteMessageFromCache(($uids[] = $uid));
				} else {
					$out = $out . "Message No : " . $messageIndex . " failed. Reason : Message already imported \r\n";
				}
			}
			$messageIndex++;
		} // for
	} // if

	if (count($emailIds) > 0) {
		$this->doDistributionWithMethod($users, $emailIds, $distributeMethod);
	} // if
	return $out;
} // fn

/**
 * get team id and team set id from request
 * @return  array
 */
function getTeams() {
}

function doDistributionWithMethod($users, $emailIds, $distributionMethod) {
	// we have users and the items to distribute
	if($distributionMethod == 'roundRobin') {
		$this->distRoundRobin($users, $emailIds);
	} elseif($distributionMethod == 'leastBusy') {
		$this->distLeastBusy($users, $emailIds);
	} elseif($distributionMethod == 'direct') {
		if(count($users) > 1) {
			// only 1 user allowed in direct assignment
			$error = 1;
		} else {
			$user = $users[0];
			$this->distDirect($user, $emailIds);
		} // else
	} // elseif

} // fn

/**
 * distributes emails to users on Round Robin basis
 * @param	$userIds	array of users to dist to
 * @param	$mailIds	array of email ids to push on those users
 * @return  boolean		true on success
 */
function distRoundRobin($userIds, $mailIds) {
	// check if we have a 'lastRobin'
	$lastRobin = $userIds[0];
	foreach($mailIds as $k => $mailId) {
		$userIdsKeys = array_flip($userIds); // now keys are values
		$thisRobinKey = $userIdsKeys[$lastRobin] + 1;
		if(!empty($userIds[$thisRobinKey])) {
			$thisRobin = $userIds[$thisRobinKey];
			$lastRobin = $userIds[$thisRobinKey];
		} else {
			$thisRobin = $userIds[0];
			$lastRobin = $userIds[0];
		}

		$email = new Email();
		$email->retrieve($mailId);
		$email->assigned_user_id = $thisRobin;
		$email->status = 'unread';
		$email->save();
	}

	return true;
}

/**
 * distributes emails to users on Least Busy basis
 * @param	$userIds	array of users to dist to
 * @param	$mailIds	array of email ids to push on those users
 * @return  boolean		true on success
 */
function distLeastBusy($userIds, $mailIds) {
	foreach($mailIds as $k => $mailId) {
		$email = new Email();
		$email->retrieve($mailId);
		foreach($userIds as $k => $id) {
			$r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '.$id.' AND status = 'unread'");
			$a = $this->db->fetchByAssoc($r);
			$counts[$id] = $a['c'];
		}
		asort($counts); // lowest to highest
		$countsKeys = array_flip($counts); // keys now the 'count of items'
		$leastBusy = array_shift($countsKeys); // user id of lowest item count
		$email->assigned_user_id = $leastBusy;
		$email->status = 'unread';
		$email->save();
	}
	return true;
}

/**
 * distributes emails to 1 user
 * @param	$user		users to dist to
 * @param	$mailIds	array of email ids to push
 * @return  boolean		true on success
 */
function distDirect($user, $mailIds) {
	foreach($mailIds as $k => $mailId) {
		$email = new Email();
		$email->retrieve($mailId);
		$email->assigned_user_id = $user;
		$email->status = 'unread';

		$email->save();
	}
	return true;
}

function getAssignedEmailsCountForUsers($userIds) {
	$counts = array();
	foreach($userIds as $id) {
		$r = $this->db->query("SELECT count(*) AS c FROM emails WHERE assigned_user_id = '$id' AND status = 'unread'");
		$a = $this->db->fetchByAssoc($r);
		$counts[$id] = $a['c'];
	} // foreach
	return $counts;
} // fn

function getLastRobin($ie) {
	$lastRobin = "";
	if($this->validCacheFileExists($ie->id, 'folders', "robin.cache.php")) {
		$lastRobin = $this->getCacheValue($ie->id, 'folders', "robin.cache.php", 'robin');
	} // if
	return $lastRobin;
} // fn

function setLastRobin($ie, $lastRobin) {
    global $sugar_config;
    $cacheFolderPath = sugar_cached("modules/Emails/{$ie->id}/folders");
    if (!file_exists($cacheFolderPath)) {
    	mkdir_recursive($cacheFolderPath);
    }
	$this->writeCacheFile('robin', $lastRobin, $ie->id, 'folders', "robin.cache.php");
} // fn

	/**
	 * returns the metadata defining a single email message for display.  Uses cache file if it exists
	 * @return array
	 */
function getSingleMessage($ie) {
		global $timedate;
		global $app_strings,$mod_strings;
		$ie->retrieve($_REQUEST['ieId']);
		$noCache = true;

		$ie->mailbox = $_REQUEST['mbox'];
		$filename = $_REQUEST['mbox'].$_REQUEST['uid'].".php";
		$md5uidl = "";
		if ($ie->isPop3Protocol()) {
			$md5uidl = md5($_REQUEST['uid']);
			$filename = $_REQUEST['mbox'].$md5uidl.".php";
		} // if

		if(isset($filename) && strpos($filename, "..") !== false){
			die("Directory navigation attack denied.");
		}

		if($this->validCacheFileExists($_REQUEST['ieId'], 'messages', $filename)) {
			$out = $this->getCacheValue($_REQUEST['ieId'], 'messages', $filename, 'out');
			$noCache = false;

			// something fubar'd the cache?
			if(empty($out['meta']['email']['name']) && empty($out['meta']['email']['description'])) {
				$noCache = true;
			} else {
				// When sending data from cache, convert date into users preffered format
				$dateTimeInGMTFormat = $out['meta']['email']['date_start'];
				$out['meta']['email']['date_start'] = $timedate->to_display_date_time($dateTimeInGMTFormat);
			} // else
		}

		if($noCache) {
			$writeToCacheFile = true;
			if ($ie->isPop3Protocol()) {
				$status = $ie->setEmailForDisplay($_REQUEST['uid'], true, true, true);
			} else {
				$status = $ie->setEmailForDisplay($_REQUEST['uid'], false, true, true);
			}
			$out = $ie->displayOneEmail($_REQUEST['uid'], $_REQUEST['mbox']);
			// modify the out object to store date in GMT format on the local cache file
			$dateTimeInUserFormat = $out['meta']['email']['date_start'];
			$out['meta']['email']['date_start'] = $timedate->to_db($dateTimeInUserFormat);
			if ($status == 'error') {
				$writeToCacheFile = false;
			}
			if ($writeToCacheFile) {
				if ($ie->isPop3Protocol()) {
					$this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$md5uidl}.php");
				} else {
					$this->writeCacheFile('out', $out, $_REQUEST['ieId'], 'messages', "{$_REQUEST['mbox']}{$_REQUEST['uid']}.php");
				} // else
			// restore date in the users preferred format to be send on to UI for diaply
			$out['meta']['email']['date_start'] = $dateTimeInUserFormat;
			} // if
		}
		$out['meta']['email']['toaddrs'] = $this->generateExpandableAddrs($out['meta']['email']['toaddrs']);
		if(!empty($out['meta']['email']['cc_addrs'])) {
            $ccs = $this->generateExpandableAddrs($out['meta']['email']['cc_addrs']);
		    $out['meta']['cc'] = <<<eoq
				<tr>
					<td NOWRAP valign="top" class="displayEmailLabel">
						{$app_strings['LBL_EMAIL_CC']}:
					</td>
					<td class="displayEmailValue">
						{$ccs}
					</td>
				</tr>
eoq;
		}

		 if(empty($out['meta']['email']['description'])) {
             $out['meta']['email']['description'] = $mod_strings['LBL_EMPTY_EMAIL_BODY'];
         } else {
             // clean html
             $sugarCleaner = new SugarCleaner();
             $out['meta']['email']['description'] = $sugarCleaner::cleanHtml($out['meta']['email']['description'], true);
         }

		if($noCache) {
			$GLOBALS['log']->debug("EMAILUI: getSingleMessage() NOT using cache file");
		} else {
			$GLOBALS['log']->debug("EMAILUI: getSingleMessage() using cache file [ ".$_REQUEST['mbox'].$_REQUEST['uid'].".php ]");
		}



		$this->setReadFlag($_REQUEST['ieId'], $_REQUEST['mbox'], $_REQUEST['uid']);
		return $out;
	}


	/**
	 * Returns the HTML for a list of emails in a given folder
	 * @param GUID $ieId GUID to InboundEmail instance
	 * @param string $mbox Mailbox path name in dot notation
	 * @param int $folderListCacheOffset Seconds for valid cache file
	 * @return string HTML render of list.
	 */
	function getListEmails($ieId, $mbox, $folderListCacheOffset, $forceRefresh='false') {
		global $sugar_config;


		$ie = new InboundEmail();
		$ie->retrieve($ieId);
		$list = $ie->displayFolderContents($mbox, $forceRefresh);

		return $list;
	}

	/**
	 * Returns the templatized compose screen.  Used by reply, forwards and draft status messages.
	 * @param object email Email bean in focus
	 */
	function displayComposeEmail($email) {
		global $locale;
		global $current_user;


		$ea = new SugarEmailAddress();

		if(!empty($email)) {
		    $email->cids2Links();
			$description = (empty($email->description_html)) ? $email->description : $email->description_html;
		}

		//Get the most complete address list availible for this email
		$addresses = array('toAddresses' => 'to', 'ccAddresses' => 'cc', 'bccAddresses' => 'bcc');
		foreach($addresses as $var => $type)
		{
			$$var = "";
			foreach (array("{$type}_addrs_names", "{$type}addrs", "{$type}_addrs") as $emailVar)
			{
				if (!empty($email->$emailVar)) {
					$$var = $email->$emailVar;
					break;
				}
			}
		}

		$ret = array();
		$ret['type'] = $email->type;
		$ret['name'] = $email->name;
		$ret['description'] = $description;
		$ret['from'] = (isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'forward') ? "" : $email->from_addr;
		$ret['to'] = from_html($toAddresses);
		$ret['uid'] = $email->id;
		$ret['parent_name'] = $email->parent_name;
		$ret['parent_type'] = $email->parent_type;
		$ret['parent_id'] = $email->parent_id;

       if ($email->type == 'draft') {
            $ret['cc'] = from_html($ccAddresses);
            $ret['bcc'] = $bccAddresses;
        }
		// reply all
		if(isset($_REQUEST['composeType']) && $_REQUEST['composeType'] == 'replyAll') {
		    $ret['cc'] = from_html($ccAddresses);
		    $ret['bcc'] = $bccAddresses;

			$userEmails = array();
			$userEmailsMeta = $ea->getAddressesByGUID($current_user->id, 'Users');
			foreach($userEmailsMeta as $emailMeta) {
				$userEmails[] = from_html(strtolower(trim($emailMeta['email_address'])));
			}
			$userEmails[] = from_html(strtolower(trim($email->from_addr)));

			$ret['cc'] = from_html($email->cc_addrs);
			$toAddresses = from_html($toAddresses);
			$to = str_replace($this->addressSeparators, "::", $toAddresses);
			$exTo = explode("::", $to);

			if(is_array($exTo)) {
				foreach($exTo as $addr) {
					$addr = strtolower(trim($addr));
					if(!in_array($addr, $userEmails)) {
						if(!empty($ret['cc'])) {
							$ret['cc'] = $ret['cc'].", ";
						}
						$ret['cc'] = $ret['cc'].trim($addr);
					}
				}
			} elseif(!empty($exTo)) {
				$exTo = trim($exTo);
				if(!in_array($exTo, $userEmails)) {
					$ret['cc'] = $ret['cc'].", ".$exTo;
				}
			}
		}
		return $ret;
	}
	/**
	 * Formats email body on reply/forward
	 * @param object email Email object in focus
	 * @param string type
	 * @return object email
	 */
	function handleReplyType($email, $type) {
		global $mod_strings;
		 $GLOBALS['log']->debug("****At Handle Reply Type: $type");
		switch($type) {
			case "reply":
			case "replyAll":
				$header = $email->getReplyHeader();
                if(!preg_match('/^(re:)+/i', $email->name)) {
                    $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
                }
				if ($type == "reply") {
					$email->cc_addrs = "";
					if (!empty($email->reply_to_addr)) {
						$email->from_addr = $email->reply_to_addr;
					} // if
				} else {
					if (!empty($email->reply_to_addr)) {
						$email->to_addrs = $email->to_addrs . "," . $email->reply_to_addr;
					} // if
				} // else
			break;

			case "forward":
				$header = $email->getForwardHeader();
				if(!preg_match('/^(fw:)+/i', $email->name)) {
                    $email->name = "{$mod_strings['LBL_FW']} {$email->name}";
                }
				$email->cc_addrs = "";
			break;

			case "replyCase":
				$GLOBALS['log']->debug("EMAILUI: At reply case");
				$header = $email->getReplyHeader();

                $myCase = new aCase();
                $myCase->retrieve($email->parent_id);
                $myCaseMacro = $myCase->getEmailSubjectMacro();
                $email->parent_name = $myCase->name;
                $GLOBALS['log']->debug("****Case # : {$myCase->case_number} macro: $myCaseMacro");
				if(!strpos($email->name, str_replace('%1',$myCase->case_number,$myCaseMacro))) {
		        	$GLOBALS['log']->debug("Replacing");
		            $email->name = str_replace('%1',$myCase->case_number,$myCaseMacro) . ' '. $email->name;
		        }
                $email->name = "{$mod_strings['LBL_RE']} {$email->name}";
            break;
		}

		$html = trim($email->description_html);
		$plain = trim($email->description);

		$desc = (!empty($html)) ? $html : $plain;

		$email->description = $header.$email->quoteHtmlEmailForNewEmailUI($desc);
		return $email;

	}

	///////////////////////////////////////////////////////////////////////////
	////	PRIVATE HELPERS
	/**
	 * Generates a UNION query to get one list of users, contacts, leads, and
	 * prospects; used specifically for the addressBook
	 */
	function _getPeopleUnionQuery($whereArr , $person) {
		global $current_user , $app_strings;
		global $db;
		if(!isset($person) || $person === 'LBL_DROPDOWN_LIST_ALL'){
			$peopleTables = array("users",
			                      "contacts",
			                      "leads",
			                      "prospects",
			                      "accounts"
			                     );
		}else{
			$peopleTables = array($person);
		}
		$q = '';

		$whereAdd = "";

		foreach($whereArr as $column => $clause) {
			if(!empty($whereAdd)) {
				$whereAdd .= " AND ";
			}
			$clause = $current_user->db->quote($clause);
			$whereAdd .= "{$column} LIKE '{$clause}%'";
		}


		foreach($peopleTables as $table) {
			$module = ucfirst($table);
            $class = substr($module, 0, strlen($module) - 1);
            require_once("modules/{$module}/{$class}.php");
            $person = new $class();
			if (!$person->ACLAccess('list')) {
				continue;
			} // if
			$where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id <> '{$current_user->id}')";

            if (ACLController::requireOwner($module, 'list')) {
            	$where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
            } // if
			if(!empty($whereAdd)) {
				$where .= " AND ({$whereAdd})";
			}

			if ($person === 'accounts') {
				$t = "SELECT {$table}.id, '' first_name, {$table}.name, eabr.primary_address, ea.email_address, '{$module}' module ";
			} else {
				$t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
			}
			$t .= "FROM {$table} ";
			$t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
			$t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
			$t .= " WHERE {$where}";

			/* BEGIN - SECURITY GROUPS */
			//this function may not even be used anymore. Seems like findEmailFromBeanIds is preferred now
			if($person->bean_implements('ACL') && ACLController::requireSecurityGroup($module, 'list') )
			{
				require_once('modules/SecurityGroups/SecurityGroup.php');
				global $current_user;
				$owner_where = $person->getOwnerWhere($current_user->id);
				$group_where = SecurityGroup::getGroupWhere($table,$module,$current_user->id);
				$t .= " AND (".  $owner_where." or ".$group_where.") ";
			}
			/* END - SECURITY GROUPS */


			if(!empty($q)) {
				$q .= "\n UNION ALL \n";
			}

			$q .= "({$t})";
		}
		$countq = "SELECT count(people.id) c from ($q) people";
		$q .= "ORDER BY last_name";

		return array('query' => $q, 'countQuery' => $countq);
    }

    /**
     * get emails of related bean for a given bean id
     * @param $beanType
     * @param $condition array of conditions inclued bean id
     * @return array('query' => $q, 'countQuery' => $countq);
     */
    function getRelatedEmail($beanType, $whereArr, $relatedBeanInfoArr = ''){
    	global $beanList, $current_user, $app_strings, $db;
    	$finalQuery = '';
		$searchBeans = null;
		if($beanType === 'LBL_DROPDOWN_LIST_ALL')
			$searchBeans = array("users",
			                     "contacts",
			                     "leads",
			                     "prospects",
			                     "accounts"
			                    );

    	if ($relatedBeanInfoArr == '' || empty($relatedBeanInfoArr['related_bean_type']) )
    	{
			if ($searchBeans != null)
			{
				$q = array();
				foreach ($searchBeans as $searchBean)
				{
				    $searchq = $this->findEmailFromBeanIds('', $searchBean, $whereArr);
				    if(!empty($searchq)) {
					    $q[] = "($searchq)";
				    }
				}
				if (!empty($q))
    			    $finalQuery .= implode("\n UNION ALL \n", $q);
			}
			else
				$finalQuery = $this->findEmailFromBeanIds('', $beanType, $whereArr);
    	}
    	else
    	{
    	    $class = $beanList[$relatedBeanInfoArr['related_bean_type']];
    	    $focus = new $class();
    	    $focus->retrieve($relatedBeanInfoArr['related_bean_id']);
    	    if ($searchBeans != null)
    	    {
    	        $q = array();
    	        foreach ($searchBeans as $searchBean)
    	        {
    	            if ($focus->load_relationship($searchBean))
    	            {
    	                $data = $focus->$searchBean->get();
    	                if (count($data) != 0)
    	                $q[] = '('.$this->findEmailFromBeanIds($data, $searchBean, $whereArr).')';
    	            }
    	        }
    	        if (!empty($q))
    	        $finalQuery .= implode("\n UNION ALL \n", $q);
    	    }
    	    else
    	    {
    	        if ($focus->load_relationship($beanType))
    	        {
    	            $data = $focus->$beanType->get();
    	            if (count($data) != 0)
    	            $finalQuery = $this->findEmailFromBeanIds($data, $beanType, $whereArr);
    	        }
    	    }
    	}
    	$countq = "SELECT count(people.id) c from ($finalQuery) people";
	   	return array('query' => $finalQuery, 'countQuery' => $countq);
    }

    function findEmailFromBeanIds($beanIds, $beanType, $whereArr) {
    	global $current_user;
		$q = '';
		$whereAdd = "";
		$relatedIDs = '';
		if ($beanIds != '') {
			foreach ($beanIds as $key => $value) {
				$beanIds[$key] = '\''.$value.'\'';
			}
			$relatedIDs = implode(',', $beanIds);
		}

		if ($beanType == 'accounts') {
			if (isset($whereArr['first_name'])) {
				$whereArr['name'] = $whereArr['first_name'];
			}
			unset($whereArr['last_name']);
			unset($whereArr['first_name']);
		}

		foreach($whereArr as $column => $clause) {
			if(!empty($whereAdd)) {
				$whereAdd .= " OR ";
			}
			$clause = $current_user->db->quote($clause);
			$whereAdd .= "{$column} LIKE '{$clause}%'";
		}
		$table = $beanType;
		$module = ucfirst($table);
	    $class = substr($module, 0, strlen($module) - 1);
	    require_once("modules/{$module}/{$class}.php");
	    $person = new $class();
		if ($person->ACLAccess('list')) {
			if ($relatedIDs != '') {
				$where = "({$table}.deleted = 0 AND eabr.primary_address = 1 AND {$table}.id in ($relatedIDs))";
			} else {
				$where = "({$table}.deleted = 0 AND eabr.primary_address = 1)";
			}

			if (ACLController::requireOwner($module, 'list')) {
				$where = $where . " AND ({$table}.assigned_user_id = '{$current_user->id}')";
			} // if
			if(!empty($whereAdd)) {
				$where .= " AND ({$whereAdd})";
			}

			if ($beanType === 'accounts') {
				$t = "SELECT {$table}.id, '' first_name, {$table}.name last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
			} else {
				$t = "SELECT {$table}.id, {$table}.first_name, {$table}.last_name, eabr.primary_address, ea.email_address, '{$module}' module ";
			}

			$t .= "FROM {$table} ";
			$t .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
			$t .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
			$t .= " WHERE {$where}";
			/* BEGIN - SECURITY GROUPS */
			//this function may not even be used anymore. Seems like findEmailFromBeanIds is preferred now
			if($person->bean_implements('ACL') && ACLController::requireSecurityGroup($module, 'list') )
			{
				require_once('modules/SecurityGroups/SecurityGroup.php');
				global $current_user;
				$owner_where = $person->getOwnerWhere($current_user->id);
				$group_where = SecurityGroup::getGroupWhere($table,$module,$current_user->id);
				$t .= " AND (".  $owner_where." or ".$group_where.") ";
			}
			/* END - SECURITY GROUPS */

		} // if
		return $t;
    }

	/**
	 * Cleans UID lists
	 * @param mixed $uids
	 * @param bool $returnString False will return an array
	 * @return mixed
	 */
	function _cleanUIDList($uids, $returnString=false) {
		global $app_strings;
		$GLOBALS['log']->debug("_cleanUIDList: before - [ {$uids} ]");

		if(!is_array($uids)) {
			$returnString = true;

			$exUids = explode($app_strings['LBL_EMAIL_DELIMITER'], $uids);
			$uids = $exUids;
		}

		$cleanUids = array();
		foreach($uids as $uid) {
			$cleanUids[$uid] = $uid;
		}

		sort($cleanUids);

		if($returnString) {
			$cleanImplode = implode($app_strings['LBL_EMAIL_DELIMITER'], $cleanUids);
			$GLOBALS['log']->debug("_cleanUIDList: after - [ {$cleanImplode} ]");
			return $cleanImplode;
		}

		return $cleanUids;
	}

    /**
     * Creates Mail folder
     *
     * @param object $user User in focus
     * @param array $folder_params Array of parameters for folder creation
     */
    protected function createFolder($user, $folder_params)
    {
        $folder = new SugarFolder();
        foreach ($folder_params as $key => $val) {
            $folder->$key = $val;
        }

        $folder->save();

        return $folder;
    }

	/**
	 * Creates defaults for the User
	 * @param object $user User in focus
	 */
    public function preflightUser(&$user)
    {
        global $mod_strings;
        $folder_types = array();

        $params = array(
            // My Emails
            "inbound" => array(
                'name' => $mod_strings['LNK_MY_INBOX'],
                'folder_type' => "inbound",
                'has_child' => 1,
                'dynamic_query' => $this->generateDynamicFolderQuery("inbound", $user->id),
                'is_dynamic' => 1,
                'created_by' => $user->id,
                'modified_by' => $user->id,
            ),
            // My Drafts
            "draft" => array(
                'name' => $mod_strings['LNK_MY_DRAFTS'],
                'folder_type' => "draft",
                'has_child' => 0,
                'dynamic_query' => $this->generateDynamicFolderQuery("draft", $user->id),
                'is_dynamic' => 1,
                'created_by' => $user->id,
                'modified_by' => $user->id,
            ),
            // Sent Emails
            "sent" => array(
                'name' => $mod_strings['LNK_SENT_EMAIL_LIST'],
                'folder_type' => "sent",
                'has_child' => 0,
                'dynamic_query' => $this->generateDynamicFolderQuery("sent", $user->id),
                'is_dynamic' => 1,
                'created_by' => $user->id,
                'modified_by' => $user->id,
            ),
            // Archived Emails
            "archived" => array(
                'name' => $mod_strings['LBL_LIST_TITLE_MY_ARCHIVES'],
                'folder_type' => "archived",
                'has_child' => 0,
                'dynamic_query' => '',
                'is_dynamic' => 1,
                'created_by' => $user->id,
                'modified_by' => $user->id,
            ),
        );

        $q = "SELECT * FROM folders f WHERE f.created_by = '{$user->id}' AND f.deleted = 0 AND coalesce(" . $user->db->convert("f.folder_type", "length") . ",0) > 0";
        $r = $user->db->query($q);

        while ($row = $GLOBALS['db']->fetchByAssoc($r)) {
            if ($row['folder_type'] == 'inbound') {
                $parent_id = $row['id'];
            }
            if (!in_array($row['folder_type'], $folder_types)) {
                array_push($folder_types, $row['folder_type']);
            }
            if (isset($params[$row['folder_type']])) {
                unset($params[$row['folder_type']]);
            }
        }

        require_once("include/SugarFolders/SugarFolders.php");

        foreach ($params as $type => $type_params) {
            if ($type == "inbound") {

                $folder = $this->createFolder($user, $params[$type]);

                $parent_id = $folder->id;

                // handle the case where inbound folder was deleted, but other folders exist
                if (count($folder_types) != 0) {
                    // This update query will exclude inbound parent, and any custom created folders.
                    // For others, it will update their parent_id for the current user.
                    $q = "UPDATE folders SET parent_folder = '".$parent_id.
                    "' WHERE folder_type IN ('draft', 'sent', 'archived') AND created_by = '".$user->id."'";
                    $q = "UPDATE folders SET parent_folder = '".$parent_id.
                    "' WHERE folder_type IN ('draft', 'sent', 'archived') AND created_by = '".$user->id."'";
                    $r = $user->db->query($q);
                }
            } else {
                $params[$type]['parent_folder'] = $parent_id;

                $this->createFolder($user, $params[$type]);
            }
        }
    }

	/**
	 * Parses the core dynamic folder query
	 * @param string $type 'inbound', 'draft', etc.
	 * @param string $userId
	 * @return string
	 */
	function generateDynamicFolderQuery($type, $userId) {
		$q = $this->coreDynamicFolderQuery;

		$status = $type;

		if($type == "sent") {
			$type = "out";
		}

		$replacee = array("::TYPE::", "::STATUS::", "::USER_ID::");
		$replacer = array($type, $status, $userId);

		$ret = str_replace($replacee, $replacer, $q);

		if($type == 'inbound') {
			$ret .= " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
		} else {
			$ret .= " AND status NOT IN ('archived') AND type NOT IN ('archived')";
		}

		return $ret;
	}

	/**
	 * Preps the User's cache dir
	 */
	function preflightUserCache() {
		$path = clean_path($this->userCacheDir);
		if(!file_exists($this->userCacheDir))
			mkdir_recursive($path);

		$files = findAllFiles($path, array());

		foreach($files as $file) {
			unlink($file);
		}
	}

	function clearInboundAccountCache($ieId) {
		global $sugar_config;
		$cacheRoot = sugar_cached("modules/Emails/{$ieId}");
		$files = findAllFiles($cacheRoot."/messages/", array());
		foreach($files as $file) {
			unlink($file);
		} // fn
		$files = findAllFiles($cacheRoot."/attachments/", array());
		foreach($files as $file) {
			unlink($file);
		} // for
	} // fn

	/**
	 * returns an array of EmailTemplates that the user has access to for the compose email screen
	 * @return array
	 */
	function getEmailTemplatesArray() {

		global $app_strings;

		if(ACLController::checkAccess('EmailTemplates', 'list', true) && ACLController::checkAccess('EmailTemplates', 'view', true)) {
			$et = new EmailTemplate();
            $etResult = $et->db->query($et->create_new_list_query('',"(email_templates.type IS NULL OR email_templates.type='' OR email_templates.type='email')",array(),array(),''));
			$email_templates_arr = array('' => $app_strings['LBL_NONE']);
			while($etA = $et->db->fetchByAssoc($etResult)) {
				$email_templates_arr[$etA['id']] = $etA['name'];
			}
		} else {
			$email_templates_arr = array('' => $app_strings['LBL_NONE']);
		}

		return $email_templates_arr;
	}

	function getFromAccountsArray($ie) {
        global $current_user;
        global $app_strings;

        $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
        $ieAccountsFrom= array();

        $oe = new OutboundEmail();
        $system = $oe->getSystemMailerSettings();
        $ret = $current_user->getUsersNameAndEmail();
		$ret['name'] = from_html($ret['name']);
		$useMyAccountString = true;

        if(empty($ret['email'])) {
        	$systemReturn = $current_user->getSystemDefaultNameAndEmail();
        	$ret['email'] = $systemReturn['email'];
        	$ret['name'] = from_html($systemReturn['name']);
        	$useMyAccountString = false;
		} // if

		$myAccountString = '';
		if ($useMyAccountString) {
			$myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
		} // if

		//Check to make sure that the user has set the associated inbound email account -> outbound account is active.
		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));
        $sf = new SugarFolder();
        $groupSubs = $sf->getSubscriptions($current_user);

        foreach($ieAccountsFull as $k => $v)
        {
            $personalSelected = (!empty($showFolders) && in_array($v->id, $showFolders));

            $allowOutboundGroupUsage = $v->get_stored_options('allow_outbound_group_usage',FALSE);
            $groupSelected = ( in_array($v->groupfolder_id, $groupSubs)  && $allowOutboundGroupUsage);
            $selected = ( $personalSelected || $groupSelected );

            if(!$selected)
            {
                $GLOBALS['log']->debug("Inbound Email {$v->name}, not selected and will not be available for selection within compose UI.");
                continue;
            }

        	$name = $v->get_stored_options('from_name');
        	$addr = $v->get_stored_options('from_addr');
        	if ($name != null && $addr != null) {
        		$name = from_html($name);
        		if (!$v->is_personal) {
                	$ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
        		} else {
                	$ieAccountsFrom[] = array("value" => $v->id, "text" => "{$name} ({$addr})");
        		} // else
        	} // if
        } // foreach


        $userSystemOverride = $oe->getUsersMailerForSystemOverride($current_user->id);
        //Substitute in the users system override if its available.
        if($userSystemOverride != null)
		    $system = $userSystemOverride;

        if( !empty($system->mail_smtpserver) )
        {
            $admin = new Administration();
            $admin->retrieveSettings(); //retrieve all admin settings.
            $ieAccountsFrom[] = array("value" => $system->id, "text" =>
                "{$ret['name']} ({$ret['email']}){$myAccountString}");
        }

        return $ieAccountsFrom;
    } // fn

    /**
     * This function will return all the accounts this user has access to based on the
     * match of the emailId passed in as a parameter
     *
     * @param unknown_type $ie
     * @return unknown
     */
	function getFromAllAccountsArray($ie, $ret) {
        global $current_user;
        global $app_strings;

        $ret['fromAccounts'] = array();
        if (!isset($ret['to']) && !empty($ret['from'])) {
	        $ret['fromAccounts']['status'] = false;
	        return $ret;
        }
        $ieAccountsFull = $ie->retrieveAllByGroupIdWithGroupAccounts($current_user->id);
		$foundInPersonalAccounts = false;
		$foundInGroupAccounts = false;
		$foundInSystemAccounts = false;

		//$toArray = array();
		if ($ret['type'] == "draft") {
			$toArray = explode(",", $ret['from']);
		} else {
			$toArray = $ie->email->email2ParseAddressesForAddressesOnly($ret['to']);
		} // else
        foreach($ieAccountsFull as $k => $v) {
        	$storedOptions = unserialize(base64_decode($v->stored_options));
			if (  array_search_insensitive($storedOptions['from_addr'], $toArray)) {
        		if ($v->is_personal) {
					$foundInPersonalAccounts = true;
					break;
				} else  {
					$foundInGroupAccounts = true;
				} // else
			} // if
        } // foreach

	    $oe = new OutboundEmail();
        $system = $oe->getSystemMailerSettings();

        $return = $current_user->getUsersNameAndEmail();
		$return['name'] = from_html($return['name']);
		$useMyAccountString = true;

        if(empty($return['email'])) {
        	$systemReturn = $current_user->getSystemDefaultNameAndEmail();
        	$return['email'] = $systemReturn['email'];
        	$return['name'] = from_html($systemReturn['name']);
        	$useMyAccountString = false;
		} // if

		$myAccountString = '';
		if ($useMyAccountString) {
			$myAccountString = " - {$app_strings['LBL_MY_ACCOUNT']}";
		} // if

        if(!empty($system->id)) {

            $admin = new Administration();
            $admin->retrieveSettings(); //retrieve all admin settings.
            if (in_array(trim($return['email']), $toArray)) {
            	$foundInSystemAccounts = true;
            } // if
        } // if

        if (!$foundInPersonalAccounts && !$foundInGroupAccounts && !$foundInSystemAccounts) {
	        $ret['fromAccounts']['status'] = false;
	        return $ret;
        } // if

        $ieAccountsFrom= array();
        foreach($ieAccountsFull as $k => $v) {
        	$storedOptions = unserialize(base64_decode($v->stored_options));
        	$storedOptionsName = from_html($storedOptions['from_name']);

        	$selected = false;
			if (array_search_insensitive($storedOptions['from_addr'], $toArray)) {
        	//if ($ret['to'] == $storedOptions['from_addr']) {
        		$selected = true;
			} // if
        	if ($foundInPersonalAccounts) {
        		if ($v->is_personal) {
            		$ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']})");
        		} // if
        	} else {
            	$ieAccountsFrom[] = array("value" => $v->id, "selected" => $selected, "text" => "{$storedOptionsName} ({$storedOptions['from_addr']}) - {$app_strings['LBL_EMAIL_UPPER_CASE_GROUP']}");
        	} // else
        } // foreach

        if(!empty($system->id)) {
            if (!$foundInPersonalAccounts && !$foundInGroupAccounts && $foundInSystemAccounts) {
            $ieAccountsFrom[] = array("value" => $system->id, "selected" => true, "text" =>
                "{$return['name']} ({$return['email']}){$myAccountString}");
            } else {
            $ieAccountsFrom[] = array("value" => $system->id, "text" =>
                "{$return['name']} ({$return['email']}){$myAccountString}");
            } // else
        } // if

        $ret['fromAccounts']['status'] = ($foundInPersonalAccounts || $foundInGroupAccounts || $foundInSystemAccounts) ? true : false;
		$ret['fromAccounts']['data'] = $ieAccountsFrom;
        return $ret;
    } // fn


	/**
	 * takes an array and creates XML
	 * @param array Array to convert
	 * @param string Name to wrap highest level items in array
	 * @return string XML
	 */
	function arrayToXML($a, $paramName) {
		if(!is_array($a))
			return '';

		$bad = array("<",">","'",'"',"&");
		$good = array("&lt;", "&gt;", "&#39;", "&quot;","&amp;");

		$ret = "";

		for($i=0; $i<count($a); $i++) {
			$email = $a[$i];
			$ret .= "\n<{$paramName}>";

			foreach($email as $k => $v) {
				$ret .= "\n\t<{$k}>".str_replace($bad, $good, $v)."</{$k}>";
			}
			$ret .= "\n</{$paramName}>";
		}
		return $ret;
	}

	/**
	 * Re-used option getter for Show Accounts multiselect pane
	 */
	function getShowAccountsOptions(&$ie) {
		global $current_user;
		global $app_strings;
		global $mod_strings;

		$ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
		$ieAccountsShowOptionsMeta = array();
		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));

		$defaultIEAccount = $ie->getUsersDefaultOutboundServerId($current_user);

		foreach($ieAccountsFull as $k => $v) {
			$selected = (!empty($showFolders) && in_array($v->id, $showFolders)) ? true : false;
			$default = ($defaultIEAccount == $v->id) ? TRUE : FALSE;
			$has_groupfolder = !empty($v->groupfolder_id) ? TRUE : FALSE;
			$type = ($v->is_personal) ? $mod_strings['LBL_MAILBOX_TYPE_PERSONAL'] : $mod_strings['LBL_MAILBOX_TYPE_GROUP'];

			$ieAccountsShowOptionsMeta[] = array("id" => $v->id, "name" => $v->name, 'is_active' => $selected,
													'server_url' => $v->server_url, 'is_group' => !$v->is_personal,'group_id' => $v->group_id,
													'is_default' => $default, 'has_groupfolder' => $has_groupfolder,'type' => $type );
		}

		//Retrieve the grou folders
		$f = new SugarFolder();
		$groupFolders = $f->getGroupFoldersForSettings($current_user);

		foreach ($groupFolders as $singleGroup)
		{
		    //Retrieve the related IE accounts.
            $relatedIEAccounts = $ie->retrieveByGroupFolderId($singleGroup['id']);

            if(count($relatedIEAccounts) == 0)
                $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS_EMPTY'];
            else if(count($relatedIEAccounts) == 1)
            {
                if($relatedIEAccounts[0]->status != 'Active' || $relatedIEAccounts[0]->mailbox_type == 'bounce')
                    continue;

                $server_url = $relatedIEAccounts[0]->server_url;
            }
            else
                $server_url = $app_strings['LBL_EMAIL_MULT_GROUP_FOLDER_ACCOUNTS'];

            $type = $mod_strings['LBL_MAILBOX_TYPE_GROUP_FOLDER'];
		    $ieAccountsShowOptionsMeta[] = array("id" => $singleGroup['id'], "name" => $singleGroup['origName'], 'is_active' => $singleGroup['selected'],
													'server_url' => $server_url, 'is_group' => true,'group_id' => $singleGroup['id'],
													'is_default' => FALSE, 'has_groupfolder' => true,'type' => $type);
		}


		return $ieAccountsShowOptionsMeta;
	}

	function getShowAccountsOptionsForSearch(&$ie) {
		global $current_user;
		global $app_strings;

		$ieAccountsFull = $ie->retrieveAllByGroupId($current_user->id);
		//$ieAccountsShowOptions = "<option value=''>{$app_strings['LBL_NONE']}</option>\n";
		$ieAccountsShowOptionsMeta = array();
		$ieAccountsShowOptionsMeta[] = array("value" => "", "text" => $app_strings['LBL_NONE'], 'selected' => '');
		$showFolders = sugar_unserialize(base64_decode($current_user->getPreference('showFolders', 'Emails')));

		foreach($ieAccountsFull as $k => $v) {
			if(!in_array($v->id, $showFolders)) {
				continue;
			}
			$group = (!$v->is_personal) ? $app_strings['LBL_EMAIL_GROUP']."." : "";
			$ieAccountsShowOptionsMeta[] = array("value" => $v->id, "text" => $group.$v->name, 'protocol' => $v->protocol);
		}

		return $ieAccountsShowOptionsMeta;
	}
	/**
	 * Formats a display message on successful async call
	 * @param string $type Type of message to display
	 */
	function displaySuccessMessage($type) {
		global $app_strings;

		switch($type) {
			case "delete":
				$message = $app_strings['LBL_EMAIL_DELETE_SUCCESS'];
			break;

			default:
				$message = "NOOP: invalid type";
			break;
		}

		$this->smarty->assign('app_strings', $app_strings);
		$this->smarty->assign('message', $message);
		echo $this->smarty->fetch("modules/Emails/templates/successMessage.tpl");
	}

	/**
	 * Validates existence and expiration of a cache file
	 * @param string $ieId
	 * @param string $type Type of cache file: folders, messages, etc.
	 * @param string $file The cachefile name
	 * @param int refreshOffset Refresh time in secs.
	 * @return mixed.
	 */
	function validCacheFileExists($ieId, $type, $file, $refreshOffset=-1) {
		global $sugar_config;

		if($refreshOffset == -1) {
			$refreshOffset = $this->cacheTimeouts[$type]; // use defaults
		}

		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
		if(file_exists($cacheFilePath)) {
			return true;
		}

		return false;
	}

	/**
	 * retrieves the cached value
	 * @param string $ieId
	 * @param string $type Type of cache file: folders, messages, etc.
	 * @param string $file The cachefile name
	 * @param string $key name of cache value
	 * @return mixed
	 */
	function getCacheValue($ieId, $type, $file, $key) {
		global $sugar_config;

		$cleanIeId = cleanDirName($ieId);
		$cleanType = cleanDirName($type);
		$cleanFile = cleanFileName($file);
		$cacheFilePath = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
		$cacheFile = array();

		if(file_exists($cacheFilePath)) {
			include($cacheFilePath); // provides $cacheFile

			if(isset($cacheFile[$key])) {
				$ret = unserialize($cacheFile[$key]);
				return $ret;
			}
		} else {
			$GLOBALS['log']->debug("EMAILUI: cache file not found [ {$cacheFilePath} ] - creating blank cache file");
			$this->writeCacheFile('retArr', array(), $ieId, $type, $file);
		}

		return null;
	}

	/**
	 * retrieves the cache file last touched time
	 * @param string $ieId
	 * @param string $type Type of cache file: folders, messages, etc.
	 * @param string $file The cachefile name
	 * @return string
	 */
	function getCacheTimestamp($ieId, $type, $file) {
		global $sugar_config;

		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
		$cacheFile = array();

		if(file_exists($cacheFilePath)) {
			include($cacheFilePath); // provides $cacheFile['timestamp']

			if(isset($cacheFile['timestamp'])) {
				$GLOBALS['log']->debug("EMAILUI: found timestamp [ {$cacheFile['timestamp']} ]");
				return $cacheFile['timestamp'];
			}
		}

		return '';
	}

	/**
	 * Updates the timestamp for a cache file - usually to mark a "check email"
	 * process
	 * @param string $ieId
	 * @param string $type Type of cache file: folders, messages, etc.
	 * @param string $file The cachefile name
	 */
	function setCacheTimestamp($ieId, $type, $file) {
		global $sugar_config;

		$cacheFilePath = sugar_cached("modules/Emails/{$ieId}/{$type}/{$file}");
		$cacheFile = array();

		if(file_exists($cacheFilePath)) {
			include($cacheFilePath); // provides $cacheFile['timestamp']

			if(isset($cacheFile['timestamp'])) {
				$cacheFile['timestamp'] = strtotime('now');
				$GLOBALS['log']->debug("EMAILUI: setting updated timestamp [ {$cacheFile['timestamp']} ]");
				return $this->_writeCacheFile($cacheFile, $cacheFilePath);
			}
		}
	}


	/**
	 * Writes caches to flat file in cache dir.
	 * @param string $key Key to the main cache entry (not timestamp)
	 * @param mixed $var Variable to be cached
	 * @param string $ieId I-E focus ID
	 * @param string $type Folder in cache
	 * @param string $file Cache file name
	 */
	function writeCacheFile($key, $var, $ieId, $type, $file) {
		global $sugar_config;

		$cleanIeId = cleanDirName($ieId);
		$cleanType = cleanDirName($type);
		$cleanFile = cleanFileName($file);
		$the_file = sugar_cached("modules/Emails/{$cleanIeId}/{$cleanType}/{$cleanFile}");
		$timestamp = strtotime('now');
		$array = array();
		$array['timestamp'] = $timestamp;
		$array[$key] = serialize($var); // serialized since varexport_helper() can't handle PHP objects

		return $this->_writeCacheFile($array, $the_file);
	}

	/**
	 * Performs the actual file write.  Abstracted from writeCacheFile() for
	 * flexibility
	 * @param array $array The array to write to the cache
	 * @param string $file Full path (relative) with cache file name
	 * @return bool
	 */
	function _writeCacheFile($array, $file) {
		global $sugar_config;

		$arrayString = var_export_helper($array);

		$date = date("r");
	    $the_string =<<<eoq
<?php // created: {$date}
	\$cacheFile = {$arrayString};
?>
eoq;
	    if($fh = @sugar_fopen($file, "w")) {
	        fputs($fh, $the_string);
	        fclose($fh);
	        return true;
	    } else {
	    	$GLOBALS['log']->debug("EMAILUI: Could not write cache file [ {$file} ]");
	        return false;
	    }
	}

	/**
	 * Generate JSON encoded data to be consumed by yui datatable.
	 *
	 * @param array $data
	 * @param string $resultsParam The resultsList name
	 * @return string
	 */
	function jsonOuput($data, $resultsParam, $count=0, $fromCache=true, $unread=-1) {
	    global $app_strings;

		$count = ($count > 0) ? $count : 0;

		if(isset($a['fromCache']))
			$cached = ($a['fromCache'] == 1) ? 1 : 0;
		else
			$cached = ($fromCache) ? 1 : 0;

		if($data['mbox'] == 'undefined' || empty($data['mbox']))
			$data['mbox'] = $app_strings['LBL_NONE'];

		$jsonOut = array('TotalCount' => $count, 'FromCache' => $cached, 'UnreadCount' => $unread, $resultsParam => $data['out']);

		return json_encode($jsonOut);
	}
	/**
	 * generates XML output from an array
	 * @param array
	 * @param string master list Item
	 * @return string
	 */
	function xmlOutput($a, $paramName, $count=0, $fromCache=true, $unread=-1) {
		global $app_strings;
		$count = ($count > 0) ? $count : 0;

		if(isset($a['fromCache'])) {
			$cached = ($a['fromCache'] == 1) ? 1 : 0;
		} else {
			$cached = ($fromCache) ? 1 : 0;
		}

		if($a['mbox'] == 'undefined' || empty($a['mbox'])) {
			$a['mbox'] = $app_strings['LBL_NONE'];
		}

		$xml = $this->arrayToXML($a['out'], $paramName);

		$ret =<<<eoq
<?xml version="1.0" encoding="UTF-8"?>
<EmailPage>
<TotalCount>{$count}</TotalCount>
<UnreadCount>{$unread}</UnreadCount>
<FromCache> {$cached} </FromCache>
<{$paramName}s>
{$xml}
</{$paramName}s>
</EmailPage>
eoq;
		return $ret;
	}

    /**
     * Generate to/cc addresses string in email detailview.
     *
     * @param string $str
     * @param string $target values: to, cc
     * @param int $defaultNum
     * @return string $str
     */
	function generateExpandableAddrs($str) {
	    global $mod_strings;
	    $tempStr = $str.',';
        $tempStr = html_entity_decode($tempStr);
	    $tempStr = $this->unifyEmailString($tempStr);
        $defaultNum = 2;
        $pattern = '/@.*,/U';
        preg_match_all($pattern, $tempStr, $matchs);
        $totalCount = count($matchs[0]);

        if(!empty($matchs[0]) && $totalCount > $defaultNum) {
            $position = strpos($tempStr, $matchs[0][$defaultNum]);
            $hiddenCount = $totalCount - $defaultNum;
            $frontStr = substr($tempStr, 0, $position);
            $backStr = substr($tempStr, $position, -1);
            $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>';
        }

        return $str;
    }

    /**
     * Unify the seperator as ,
     *
     * @param String $str email address string
     * @return String converted string
     */
    function unifyEmailString($str) {
        preg_match_all('/@.*;/U', $str, $matches);
        if(!empty($matches[0])) {
            foreach($matches[0] as $key => $value) {
                $new[] = str_replace(";",",",$value);
            }
            return str_replace($matches[0], $new, $str);
        }
        return $str;
    }
} // end class def
