]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Emails/Email.php
Release 6.1.5
[Github/sugarcrm.git] / modules / Emails / Email.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42  * Reserved. Contributor(s): ______________________________________..
43  *********************************************************************************/
44 require_once('include/SugarPHPMailer.php');
45
46 require_once('include/Pear/HTML_Safe/Safe.php');
47
48 class Email extends SugarBean {
49         /* SugarBean schema */
50         var $id;
51         var $date_entered;
52         var $date_modified;
53         var $assigned_user_id;
54         var $assigned_user_name;
55         var $modified_user_id;
56         var $created_by;
57         var $deleted;
58         var $from_addr;
59         var $reply_to_addr;
60         var $to_addrs;
61     var $cc_addrs;
62     var $bcc_addrs;
63         var $message_id;
64
65         /* Bean Attributes */
66         var $name;
67     var $type = 'archived';
68     var $date_sent;
69         var $status;
70         var $intent;
71         var $mailbox_id;
72         var $from_name;
73
74         var $reply_to_status;
75         var $reply_to_name;
76         var $reply_to_email;
77         var $description;
78         var $description_html;
79         var $raw_source;
80         var $parent_id;
81         var $parent_type;
82
83         /* link attributes */
84         var $parent_name;
85
86
87         /* legacy */
88         var $date_start; // legacy
89         var $time_start; // legacy
90         var $from_addr_name;
91         var $to_addrs_arr;
92     var $cc_addrs_arr;
93     var $bcc_addrs_arr;
94         var $to_addrs_ids;
95         var $to_addrs_names;
96         var $to_addrs_emails;
97         var $cc_addrs_ids;
98         var $cc_addrs_names;
99         var $cc_addrs_emails;
100         var $bcc_addrs_ids;
101         var $bcc_addrs_names;
102         var $bcc_addrs_emails;
103         var $contact_id;
104         var $contact_name;
105
106         /* Archive Email attrs */
107         var $duration_hours;
108
109
110
111         var $new_schema = true;
112         var $table_name = 'emails';
113         var $module_dir = 'Emails';
114         var $object_name = 'Email';
115         var $db;
116
117         /* private attributes */
118         var $rolloverStyle              = "<style>div#rollover {position: relative;float: left;margin: none;text-decoration: none;}div#rollover a:hover {padding: 0;text-decoration: none;}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";
119         var $cachePath;
120         var $cacheFile                  = 'robin.cache.php';
121         var $replyDelimiter     = "> ";
122         var $emailDescription;
123         var $emailDescriptionHTML;
124         var $emailRawSource;
125         var $link_action;
126         var $emailAddress;
127         var $attachments = array();
128
129         /* to support Email 2.0 */
130         var $isDuplicate;
131         var $uid;
132         var $to;
133         var $flagged;
134         var $answered;
135         var $seen;
136         var $draft;
137         var $relationshipMap = array(
138                 'Contacts'      => 'emails_contacts_rel',
139                 'Accounts'      => 'emails_accounts_rel',
140                 'Leads'         => 'emails_leads_rel',
141                 'Users'         => 'emails_users_rel',
142                 'Prospects'     => 'emails_prospects_rel',
143         );
144
145         /* public */
146         var $et;                // EmailUI object
147
148
149
150         /**
151          * sole constructor
152          */
153         function Email() {
154             $this->cachePath = $GLOBALS['sugar_config']['cache_dir'].'modules/Emails';
155                 parent::SugarBean();
156
157                 $this->safe = new HTML_Safe();
158                 $this->safe->clear();
159                 $this->emailAddress = new SugarEmailAddress();
160         }
161
162         function email2init() {
163                 require_once('modules/Emails/EmailUI.php');
164                 $this->et = new EmailUI();
165         }
166         function bean_implements($interface){
167                 switch($interface){
168                         case 'ACL': return true;
169                         default: return false;
170                 }
171
172         }
173
174         /**
175          * Presaves one attachment for new email 2.0 spec
176          * DOES NOT CREATE A NOTE
177          * @return string ID of note associated with the attachment
178          */
179         function email2saveAttachment() {
180                 global $sugar_config;
181
182                 $filesError = array(
183                         0 => 'UPLOAD_ERR_OK - There is no error, the file uploaded with success.',
184                         1 => 'UPLOAD_ERR_INI_SIZE - The uploaded file exceeds the upload_max_filesize directive in php.ini.',
185                         2 => 'UPLOAD_ERR_FORM_SIZE - The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
186                         3 => 'UPLOAD_ERR_PARTIAL - The uploaded file was only partially uploaded.',
187                         4 => 'UPLOAD_ERR_NO_FILE - No file was uploaded.',
188                         5 => 'UNKNOWN ERROR',
189                         6 => 'UPLOAD_ERR_NO_TMP_DIR - Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.',
190                         7 => 'UPLOAD_ERR_CANT_WRITE - Failed to write file to disk. Introduced in PHP 5.1.0.',
191                 );
192
193                 // cn: Bug 5995 - rudimentary error checking
194                 if($_FILES['email_attachment']['error'] != 0 && $_FILES['email_attachment']['error'] != 4) {
195                         $GLOBALS['log']->debug('Email Attachment could not be attach due to error: '.$filesError[$_FILES['email_attachment']['error']]);
196                         return array();
197                 }
198
199                 if(isset($_FILES['email_attachment']) && is_uploaded_file($_FILES['email_attachment']['tmp_name'])) {
200                         $guid = create_guid();
201                         $cleanAttachmentFileName = from_html($_FILES['email_attachment']['name']);
202                         $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] ");
203                         $cleanAttachmentFileName = str_replace("\\", "", $cleanAttachmentFileName);
204                         $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] ");
205                         //$destination = clean_path("{$this->et->userCacheDir}/{$guid}{$cleanAttachmentFileName}");
206                         $destination = clean_path("{$this->et->userCacheDir}/{$guid}");
207                         $badExt = $this->safeAttachmentName($cleanAttachmentFileName);
208                         if ($badExt) {
209                                 //$destination = $destination . ".txt";
210                         } // if
211                         $fileName = $badExt ? $cleanAttachmentFileName . ".txt" : $cleanAttachmentFileName;
212                         if(move_uploaded_file($_FILES['email_attachment']['tmp_name'], $destination)) {
213                                 return array(
214                                         'guid' => $guid,
215                                         'name' => $GLOBALS['db']->helper->escape_quote($fileName),
216                                         'nameForDisplay' => $fileName
217                                 );
218                         } else {
219                                 $GLOBALS['log']->debug("Email Attachment [ {$cleanAttachmentFileName} ] could not be moved to cache dir");
220                                 return array();
221                         }
222                 }
223         }
224
225         function safeAttachmentName($filename) {
226                 global $sugar_config;
227                 $badExtension = false;
228                 //get position of last "." in file name
229                 $file_ext_beg = strrpos($filename, ".");
230                 $file_ext = "";
231
232                 //get file extension
233                 if($file_ext_beg !== false) {
234                         $file_ext = substr($filename, $file_ext_beg + 1);
235                 }
236
237                 //check to see if this is a file with extension located in "badext"
238                 foreach($sugar_config['upload_badext'] as $badExt) {
239                         if(strtolower($file_ext) == strtolower($badExt)) {
240                                 //if found, then append with .txt and break out of lookup
241                                 $filename = $filename . ".txt";
242                                 $badExtension = true;
243                                 break; // no need to look for more
244                         } // if
245                 } // foreach
246
247                 return $badExtension;
248         } // fn
249
250         /**
251          * takes output from email 2.0 to/cc/bcc fields and returns appropriate arrays for usage by PHPMailer
252          * @param string addresses
253          * @return array
254          */
255         function email2ParseAddresses($addresses) {
256                 $addresses = from_html($addresses);
257         $addresses = $this->et->unifyEmailString($addresses);
258
259                 $pattern = '/@.*,/U';
260                 preg_match_all($pattern, $addresses, $matchs);
261                 if (!empty($matchs[0])){
262                         $total = $matchs[0];
263                         foreach ($total as $match) {
264                                 $convertedPattern = str_replace(',', '::;::', $match);
265                                 $addresses = str_replace($match, $convertedPattern, $addresses);
266                         } //foreach
267                 }
268
269                 $exAddr = explode("::;::", $addresses);
270
271                 $ret = array();
272                 $clean = array("<", ">");
273                 $dirty = array("&lt;", "&gt;");
274
275                 foreach($exAddr as $addr) {
276                         $name = '';
277
278                         $addr = str_replace($dirty, $clean, $addr);
279
280                         if((strpos($addr, "<") === false) && (strpos($addr, ">") === false)) {
281                                 $address = $addr;
282                         } else {
283                                 $address = substr($addr, strpos($addr, "<") + 1, strpos($addr, ">") - 1 - strpos($addr, "<"));
284                                 $name = substr($addr, 0, strpos($addr, "<"));
285                         }
286
287                         $addrTemp = array();
288                         $addrTemp['email'] = trim($address);
289                         $addrTemp['display'] = trim($name);
290                         $ret[] = $addrTemp;
291                 }
292
293                 return $ret;
294         }
295
296         /**
297          * takes output from email 2.0 to/cc/bcc fields and returns appropriate arrays for usage by PHPMailer
298          * @param string addresses
299          * @return array
300          */
301         function email2ParseAddressesForAddressesOnly($addresses) {
302                 $addresses = from_html($addresses);
303                 $pattern = '/@.*,/U';
304                 preg_match_all($pattern, $addresses, $matchs);
305                 if (!empty($matchs[0])){
306                         $total = $matchs[0];
307                         foreach ($total as $match) {
308                                 $convertedPattern = str_replace(',', '::;::', $match);
309                                 $addresses = str_replace($match, $convertedPattern, $addresses);
310                         } //foreach
311                 }
312
313                 $exAddr = explode("::;::", $addresses);
314
315                 $ret = array();
316                 $clean = array("<", ">");
317                 $dirty = array("&lt;", "&gt;");
318
319                 foreach($exAddr as $addr) {
320                         $name = '';
321
322                         $addr = str_replace($dirty, $clean, $addr);
323
324                         if(strpos($addr, "<") && strpos($addr, ">")) {
325                                 $address = substr($addr, strpos($addr, "<") + 1, strpos($addr, ">") - 1 - strpos($addr, "<"));
326                         } else {
327                                 $address = $addr;
328                         }
329
330                         $ret[] = trim($address);
331                 }
332
333                 return $ret;
334         }
335
336         /**
337          * Determines MIME-type encoding as possible.
338          * @param string $fileLocation relative path to file
339          * @return string MIME-type
340          */
341         function email2GetMime($fileLocation) {
342                 if(function_exists('mime_content_type')) {
343                         $mime = mime_content_type($fileLocation);
344                 } elseif(function_exists('ext2mime')) {
345                         $mime = ext2mime($fileLocation);
346                 } else {
347                         $mime = 'application/octet-stream';
348                 }
349                 return $mime;
350         }
351
352
353         function sendEmailTest($mailserver_url, $port, $ssltls, $smtp_auth_req, $smtp_username, $smtppassword, $fromaddress, $toaddress, $mail_sendtype = 'smtp') {
354                 global $current_user,$app_strings;
355                 $mod_strings = return_module_language($GLOBALS['current_language'], 'Emails'); //Called from EmailMan as well.
356             $mail = new SugarPHPMailer();
357                 $mail->Mailer = strtolower($mail_sendtype);
358                 if($mail->Mailer == 'smtp')
359                 {
360                 $mail->Host = $mailserver_url;
361                 $mail->Port = $port;
362                 if (isset($ssltls) && !empty($ssltls)) {
363                         $mail->protocol = "ssl://";
364                 if ($ssltls == 1) {
365                     $mail->SMTPSecure = 'ssl';
366                 } // if
367                 if ($ssltls == 2) {
368                     $mail->SMTPSecure = 'tls';
369                 } // if
370                 } else {
371                         $mail->protocol = "tcp://";
372                 }
373                 if ($smtp_auth_req) {
374                         $mail->SMTPAuth = TRUE;
375                         $mail->Username = $smtp_username;
376                         $mail->Password = $smtppassword;
377                 }
378                 }
379                 else
380                     $mail->Mailer = 'sendmail';
381
382                 $mail->Subject = from_html($mod_strings['LBL_TEST_EMAIL_SUBJECT']);
383                 $mail->From = $fromaddress;
384                 $mail->FromName = $current_user->name;
385                 $mail->Sender = $mail->From;
386                 $mail->AddAddress($toaddress);
387                 $mail->Body = $mod_strings['LBL_TEST_EMAIL_BODY'];
388
389                 $return = array();
390
391                 if(!$mail->Send()) {
392                 ob_clean();
393                 $return['status'] = false;
394                 $return['errorMessage'] = $app_strings['LBL_EMAIL_ERROR_PREPEND']. $mail->ErrorInfo;
395                 return $return;
396                 } // if
397                 $return['status'] = true;
398         return $return;
399         } // fn
400
401         function decodeDuringSend($htmlData) {
402             $htmlData = str_replace("sugarLessThan", "&lt;", $htmlData);
403             $htmlData = str_replace("sugarGreaterThan", "&gt;", $htmlData);
404                 return $htmlData;
405         }
406
407         /**
408          * Returns true or false if this email is a draft.
409          *
410          * @param array $request
411          * @return bool True indicates this email is a draft.
412          */
413         function isDraftEmail($request)
414         {
415             return ( isset($request['saveDraft']) || ($this->type == 'draft' && $this->status == 'draft') );
416         }
417
418         /**
419          * Sends Email for Email 2.0
420          */
421         function email2Send($request) {
422                 global $mod_strings;
423                 global $app_strings;
424                 global $current_user;
425                 global $sugar_config;
426                 global $locale;
427                 global $timedate;
428                 global $beanList;
429                 global $beanFiles;
430         $OBCharset = $locale->getPrecedentPreference('default_email_charset');
431
432                 /**********************************************************************
433                  * Sugar Email PREP
434                  */
435                 /* preset GUID */
436
437                 $orignialId = "";
438                 if(!empty($this->id)) {
439                         $orignialId =   $this->id;
440                 } // if
441
442                 if(empty($this->id)) {
443                         $this->id = create_guid();
444                         $this->new_with_id = true;
445                 }
446
447                 /* satisfy basic HTML email requirements */
448                 $this->name = $request['sendSubject'];
449                 $this->description_html = '&lt;html&gt;&lt;body&gt;'.$request['sendDescription'].'&lt;/body&gt;&lt;/html&gt;';
450
451                 /**********************************************************************
452                  * PHPMAILER PREP
453                  */
454                 $mail = new SugarPHPMailer();
455                 $mail = $this->setMailer($mail, '', $_REQUEST['fromAccount']);
456                 if (empty($mail->Host) && !$this->isDraftEmail($request))
457                 {
458             $this->status = 'send_error';
459
460             if ($mail->oe->type == 'system')
461                 echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $app_strings['LBL_EMAIL_INVALID_SYSTEM_OUTBOUND']);
462              else
463                 echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $app_strings['LBL_EMAIL_INVALID_PERSONAL_OUTBOUND']);
464
465             return false;
466                 }
467
468                 $subject = $this->name;
469                 $mail->Subject = from_html($this->name);
470
471                 // work-around legacy code in SugarPHPMailer
472                 if($_REQUEST['setEditor'] == 1) {
473                         $_REQUEST['description_html'] = $_REQUEST['sendDescription'];
474                         $this->description_html = $_REQUEST['description_html'];
475                 } else {
476                         $this->description_html = '';
477                         $this->description = $_REQUEST['sendDescription'];
478                 }
479                 // end work-around
480
481                 if ( $this->isDraftEmail($request) )
482                 {
483                         if($this->type != 'draft' && $this->status != 'draft') {
484                         $this->id = create_guid();
485                         $this->new_with_id = true;
486                         $this->date_entered = "";
487                         } // if
488                         $q1 = "update emails_email_addr_rel set deleted = 1 WHERE email_id = '{$this->id}'";
489                         $r1 = $this->db->query($q1);
490                 } // if
491
492                 if (isset($request['saveDraft'])) {
493                         $this->type = 'draft';
494                         $this->status = 'draft';
495                         $forceSave = true;
496                 } else {
497                         /* Apply Email Templates */
498                         // do not parse email templates if the email is being saved as draft....
499                     $toAddresses = $this->email2ParseAddresses($_REQUEST['sendTo']);
500                 $sea = new SugarEmailAddress();
501                 $object_arr = array();
502
503                         if( isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type']) &&
504                                 isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id']) &&
505                                 ($_REQUEST['parent_type'] == 'Accounts' ||
506                                 $_REQUEST['parent_type'] == 'Contacts' ||
507                                 $_REQUEST['parent_type'] == 'Leads' ||
508                                 $_REQUEST['parent_type'] == 'Users' ||
509                                 $_REQUEST['parent_type'] == 'Prospects')) {
510                                         if(isset($beanList[$_REQUEST['parent_type']]) && !empty($beanList[$_REQUEST['parent_type']])) {
511                                                 $className = $beanList[$_REQUEST['parent_type']];
512                                                 if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) {
513                                                         if(!class_exists($className)) {
514                                                                 require_once($beanFiles[$className]);
515                                                         }
516                                                         $bean = new $className();
517                                                         $bean->retrieve($_REQUEST['parent_id']);
518                                         $object_arr[$bean->module_dir] = $bean->id;
519                                                 } // if
520                                         } // if
521                         }
522                         foreach($toAddresses as $addrMeta) {
523                                 $addr = $addrMeta['email'];
524                                 $beans = $sea->getBeansByEmailAddress($addr);
525                                 foreach($beans as $bean) {
526                                         if (!isset($object_arr[$bean->module_dir])) {
527                                                 $object_arr[$bean->module_dir] = $bean->id;
528                                         }
529                                 }
530                         }
531
532                 /* template parsing */
533                 if (empty($object_arr)) {
534                   $object_arr= array('Contacts' => '123');
535                 }
536                 $object_arr['Users'] = $current_user->id;
537                 $this->description_html = EmailTemplate::parse_template($this->description_html, $object_arr);
538                 $this->name = EmailTemplate::parse_template($this->name, $object_arr);
539                 $this->description = EmailTemplate::parse_template($this->description, $object_arr);
540                 $this->description = html_entity_decode($this->description,ENT_COMPAT,'UTF-8');
541                         if($this->type != 'draft' && $this->status != 'draft') {
542                         $this->id = create_guid();
543                         $this->date_entered = "";
544                         $this->new_with_id = true;
545                         $this->type = 'out';
546                         $this->status = 'sent';
547                         }
548         }
549
550         if(isset($_REQUEST['parent_type']) && empty($_REQUEST['parent_type']) &&
551                         isset($_REQUEST['parent_id']) && empty($_REQUEST['parent_id']) ) {
552                                 $this->parent_id = "";
553                                 $this->parent_type = "";
554                 } // if
555
556
557         $mail->Subject = $this->name;
558         $mail = $this->handleBody($mail);
559         $mail->Subject = $this->name;
560         $this->description_html = from_html($this->description_html);
561         $this->description_html = $this->decodeDuringSend($this->description_html);
562                 $this->description = $this->decodeDuringSend($this->description);
563
564                 /* from account */
565                 $replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user);
566                 $replyToName = "";
567                 if(empty($request['fromAccount'])) {
568                         $defaults = $current_user->getPreferredEmail();
569                         $mail->From = $defaults['email'];
570                         $mail->FromName = $defaults['name'];
571                         $replyToName = $mail->FromName;
572                         //$replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user);
573                 } else {
574                         // passed -> user -> system default
575                         $ie = new InboundEmail();
576                         $ie->retrieve($request['fromAccount']);
577                         $storedOptions = unserialize(base64_decode($ie->stored_options));
578                         $fromName = "";
579                         $fromAddress = "";
580                         $replyToName = "";
581                         //$replyToAddress = "";
582                         if (!empty($storedOptions)) {
583                                 $fromAddress = $storedOptions['from_addr'];
584                                 $fromName = from_html($storedOptions['from_name']);
585                                 $replyToAddress = (isset($storedOptions['reply_to_addr']) ? $storedOptions['reply_to_addr'] : "");
586                                 $replyToName = (isset($storedOptions['reply_to_name']) ? from_html($storedOptions['reply_to_name']) : "");
587                         } // if
588                         $defaults = $current_user->getPreferredEmail();
589                         // Personal Account doesn't have reply To Name and Reply To Address. So add those columns on UI
590                         // After adding remove below code
591
592                         // code to remove
593                         if ($ie->is_personal)
594                         {
595                                 if (empty($replyToAddress))
596                                 {
597                                         $replyToAddress = $current_user->emailAddress->getReplyToAddress($current_user);
598                                 } // if
599                                 if (empty($replyToName))
600                                 {
601                                         $replyToName = $defaults['name'];
602                                 } // if
603                                 //Personal accounts can have a reply_address, which should
604                                 //overwrite the users set default.
605                                 if( !empty($storedOptions['reply_to_addr']) )
606                                         $replyToAddress = $storedOptions['reply_to_addr'];
607
608                         }
609                         // end of code to remove
610                         $mail->From = (!empty($fromAddress)) ? $fromAddress : $defaults['email'];
611                         $mail->FromName = (!empty($fromName)) ? $fromName : $defaults['name'];
612                         $replyToName = (!empty($replyToName)) ? $replyToName : $mail->FromName;
613                 }
614
615                 $mail->Sender = $mail->From; /* set Return-Path field in header to reduce spam score in emails sent via Sugar's Email module */
616
617                 if (!empty($replyToAddress)) {
618                         $mail->AddReplyTo($replyToAddress,$locale->translateCharsetMIME(trim( $replyToName), 'UTF-8', $OBCharset));
619                 } else {
620                         $mail->AddReplyTo($mail->From,$locale->translateCharsetMIME(trim( $mail->FromName), 'UTF-8', $OBCharset));
621                 } // else
622         $emailAddressCollection = array(); // used in linking to beans below
623                 // handle to/cc/bcc
624                 foreach($this->email2ParseAddresses($request['sendTo']) as $addr_arr) {
625                         if(empty($addr_arr['email'])) continue;
626
627                         if(empty($addr_arr['display'])) {
628                                 $mail->AddAddress($addr_arr['email'], "");
629                         } else {
630                                 $mail->AddAddress($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset));
631                         }
632                         $emailAddressCollection[] = $addr_arr['email'];
633                 }
634                 foreach($this->email2ParseAddresses($request['sendCc']) as $addr_arr) {
635                         if(empty($addr_arr['email'])) continue;
636
637                         if(empty($addr_arr['display'])) {
638                                 $mail->AddCC($addr_arr['email'], "");
639                         } else {
640                                 $mail->AddCC($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset));
641                         }
642                         $emailAddressCollection[] = $addr_arr['email'];
643                 }
644
645                 foreach($this->email2ParseAddresses($request['sendBcc']) as $addr_arr) {
646                         if(empty($addr_arr['email'])) continue;
647
648                         if(empty($addr_arr['display'])) {
649                                 $mail->AddBCC($addr_arr['email'], "");
650                         } else {
651                                 $mail->AddBCC($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset));
652                         }
653                         $emailAddressCollection[] = $addr_arr['email'];
654                 }
655
656
657                 /* parse remove attachments array */
658                 $removeAttachments = array();
659                 if(!empty($request['templateAttachmentsRemove'])) {
660                         $exRemove = explode("::", $request['templateAttachmentsRemove']);
661
662                         foreach($exRemove as $file) {
663                                 $removeAttachments = substr($file, 0, 36);
664                         }
665                 }
666
667                 /* handle attachments */
668                 if(!empty($request['attachments'])) {
669                         $exAttachments = explode("::", $request['attachments']);
670
671                         foreach($exAttachments as $file) {
672                                 $file = trim(from_html($file));
673                                 $file = str_replace("\\", "", $file);
674                                 if(!empty($file)) {
675                                         //$fileLocation = $this->et->userCacheDir."/{$file}";
676                                         $fileGUID = substr($file, 0, 36);
677                                         $fileLocation = $this->et->userCacheDir."/{$fileGUID}";
678                                         $filename = substr($file, 36, strlen($file)); // strip GUID     for PHPMailer class to name outbound file
679
680                                         $mail->AddAttachment($fileLocation,$filename, 'base64', $this->email2GetMime($fileLocation));
681                                         //$mail->AddAttachment($fileLocation, $filename, 'base64');
682
683                                         // only save attachments if we're archiving or drafting
684                                         if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) {
685                                                 $note = new Note();
686                                                 $note->id = create_guid();
687                                                 $note->new_with_id = true; // duplicating the note with files
688                                                 $note->parent_id = $this->id;
689                                                 $note->parent_type = $this->module_dir;
690                                                 $note->name = $filename;
691                                                 $note->filename = $filename;
692                                                 $noteFile = "{$sugar_config['upload_dir']}{$note->id}";
693                                                 $note->file_mime_type = $this->email2GetMime($fileLocation);
694
695                                                 if(!copy($fileLocation, $noteFile)) {
696                                                         $GLOBALS['log']->debug("EMAIL 2.0: could not copy attachment file to cache/upload [ {$fileLocation} ]");
697                                                 }
698
699                                                 $note->save();
700                                         }
701                                 }
702                         }
703                 }
704
705                 /* handle sugar documents */
706                 if(!empty($request['documents'])) {
707                         $exDocs = explode("::", $request['documents']);
708
709
710
711
712                         foreach($exDocs as $docId) {
713                                 $docId = trim($docId);
714                                 if(!empty($docId)) {
715                                         $doc = new Document();
716                                         $docRev = new DocumentRevision();
717                                         $doc->retrieve($docId);
718                                         $docRev->retrieve($doc->document_revision_id);
719
720                                         $filename = $docRev->filename;
721                                         $fileLocation = "{$sugar_config['upload_dir']}{$docRev->id}";
722                                         $mime_type = $docRev->file_mime_type;
723                                         $mail->AddAttachment($fileLocation,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $mime_type);
724
725                                         // only save attachments if we're archiving or drafting
726                                         if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) {
727                                                 $note = new Note();
728                                                 $note->id = create_guid();
729                                                 $note->new_with_id = true; // duplicating the note with files
730                                                 $note->parent_id = $this->id;
731                                                 $note->parent_type = $this->module_dir;
732                                                 $note->name = $filename;
733                                                 $note->filename = $filename;
734                                                 $note->file_mime_type = $mime_type;
735                                                 $noteFile = "{$sugar_config['upload_dir']}{$note->id}";
736
737                                                 if(!copy($fileLocation, $noteFile)) {
738                                                         $GLOBALS['log']->debug("EMAIL 2.0: could not copy SugarDocument revision file to {$sugar_config['upload_dir']} [ {$fileLocation} ]");
739                                                 }
740
741                                                 $note->save();
742                                         }
743                                 }
744                         }
745                 }
746
747                 /* handle template attachments */
748                 if(!empty($request['templateAttachments'])) {
749
750                         $exNotes = explode("::", $request['templateAttachments']);
751                         foreach($exNotes as $noteId) {
752                                 $noteId = trim($noteId);
753                                 if(!empty($noteId)) {
754                                         $note = new Note();
755                                         $note->retrieve($noteId);
756                                         if (!empty($note->id)) {
757                                                 $filename = $note->filename;
758                                                 $fileLocation = "{$sugar_config['upload_dir']}{$note->id}";
759                                                 $mime_type = $note->file_mime_type;
760                                                 if (!$note->embed_flag) {
761                                                         $mail->AddAttachment($fileLocation,$filename, 'base64', $mime_type);
762                                                         // only save attachments if we're archiving or drafting
763                                                         if((($this->type == 'draft') && !empty($this->id)) || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) {
764
765                                                                 if ($note->parent_id != $this->id)
766                                                                     $this->saveTempNoteAttachments($filename,$fileLocation, $mime_type);
767                                                         } // if
768
769                                                 } // if
770                                         } else {
771                                                 //$fileLocation = $this->et->userCacheDir."/{$file}";
772                                                 $fileGUID = substr($noteId, 0, 36);
773                                                 $fileLocation = $this->et->userCacheDir."/{$fileGUID}";
774                                                 //$fileLocation = $this->et->userCacheDir."/{$noteId}";
775                                                 $filename = substr($noteId, 36, strlen($noteId)); // strip GUID for PHPMailer class to name outbound file
776
777                                                 $mail->AddAttachment($fileLocation,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $this->email2GetMime($fileLocation));
778
779                                                 //If we are saving an email we were going to forward we need to save the attachments as well.
780                                                 if( (($this->type == 'draft') && !empty($this->id))
781                                                       || (isset($request['saveToSugar']) && $request['saveToSugar'] == 1))
782                                                   {
783                                                       $mimeType = $this->email2GetMime($fileLocation);
784                                                       $this->saveTempNoteAttachments($filename,$fileLocation, $mimeType);
785                                                  } // if
786                                         }
787                                 }
788                         }
789                 }
790
791
792
793                 /**********************************************************************
794                  * Final Touches
795                  */
796                 /* save email to sugar? */
797                 $forceSave = false;
798
799                 if($this->type == 'draft' && !isset($request['saveDraft'])) {
800                         // sending a draft email
801                         $this->type = 'out';
802                         $this->status = 'sent';
803                         $forceSave = true;
804                 } elseif(isset($request['saveDraft'])) {
805                         $this->type = 'draft';
806                         $this->status = 'draft';
807                         $forceSave = true;
808                 }
809
810                       /**********************************************************************
811          * SEND EMAIL (finally!)
812          */
813         $mailSent = false;
814         if ($this->type != 'draft') {
815             $mail->prepForOutbound();
816             $mail->Body = $this->decodeDuringSend($mail->Body);
817             $mail->AltBody = $this->decodeDuringSend($mail->AltBody);
818             if (!$mail->Send()) {
819                 $this->status = 'send_error';
820                 ob_clean();
821                 echo($app_strings['LBL_EMAIL_ERROR_PREPEND']. $mail->ErrorInfo);
822                 return false;
823             }
824         }
825
826                 if ((!(empty($orignialId) || isset($request['saveDraft']) || ($this->type == 'draft' && $this->status == 'draft'))) &&
827                         (($_REQUEST['composeType'] == 'reply') || ($_REQUEST['composeType'] == 'replyAll') || ($_REQUEST['composeType'] == 'replyCase')) && ($orignialId != $this->id)) {
828                         $originalEmail = new Email();
829                         $originalEmail->retrieve($orignialId);
830                         $originalEmail->reply_to_status = 1;
831                         $originalEmail->save();
832                         $this->reply_to_status = 0;
833                 } // if
834
835                 if ($_REQUEST['composeType'] == 'reply' || $_REQUEST['composeType'] == 'replyCase') {
836                         if (isset($_REQUEST['ieId']) && isset($_REQUEST['mbox'])) {
837                                 $emailFromIe = new InboundEmail();
838                                 $emailFromIe->retrieve($_REQUEST['ieId']);
839                                 $emailFromIe->mailbox = $_REQUEST['mbox'];
840                                 if (isset($emailFromIe->id) && $emailFromIe->is_personal) {
841                                         if ($emailFromIe->isPop3Protocol()) {
842                                                 $emailFromIe->mark_answered($this->uid, 'pop3');
843                                         }
844                                         elseif ($emailFromIe->connectMailserver() == 'true') {
845                                                 $emailFromIe->markEmails($this->uid, 'answered');
846                                                 $emailFromIe->mark_answered($this->uid);
847                                         }
848                                 }
849                         }
850                 }
851
852
853                 if(     $forceSave ||
854                         $this->type == 'draft' ||
855                         (isset($request['saveToSugar']) && $request['saveToSugar'] == 1)) {
856
857                         // saving a draft OR saving a sent email
858                         $decodedFromName = mb_decode_mimeheader($mail->FromName);
859                         $this->from_addr = "{$decodedFromName} <{$mail->From}>";
860                         $this->from_addr_name = $this->from_addr;
861                         $this->to_addrs = $_REQUEST['sendTo'];
862                         $this->to_addrs_names = $_REQUEST['sendTo'];
863                         $this->cc_addrs = $_REQUEST['sendCc'];
864                         $this->cc_addrs_names = $_REQUEST['sendCc'];
865                         $this->bcc_addrs = $_REQUEST['sendBcc'];
866                         $this->bcc_addrs_names = $_REQUEST['sendBcc'];
867                         $this->assigned_user_id = $current_user->id;
868
869                         $this->date_sent = $timedate->convert_to_gmt_datetime('now');
870                 $this->date_sent = $timedate->to_display_date_time($this->date_sent);
871                         ///////////////////////////////////////////////////////////////////
872                         ////    LINK EMAIL TO SUGARBEANS BASED ON EMAIL ADDY
873
874                         if( isset($_REQUEST['parent_type']) && !empty($_REQUEST['parent_type']) &&
875                                 isset($_REQUEST['parent_id']) && !empty($_REQUEST['parent_id']) ) {
876                         $this->parent_id = $_REQUEST['parent_id'];
877                         $this->parent_type = $_REQUEST['parent_type'];
878                                         $q = "SELECT count(*) c FROM emails_beans WHERE  email_id = '{$this->id}' AND bean_id = '{$_REQUEST['parent_id']}' AND bean_module = '{$_REQUEST['parent_type']}'";
879                                         $r = $this->db->query($q);
880                                         $a = $this->db->fetchByAssoc($r);
881                                         if($a['c'] <= 0) {
882                                                 if(isset($beanList[$_REQUEST['parent_type']]) && !empty($beanList[$_REQUEST['parent_type']])) {
883                                                         $className = $beanList[$_REQUEST['parent_type']];
884                                                         if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) {
885                                                                 if(!class_exists($className)) {
886                                                                         require_once($beanFiles[$className]);
887                                                                 }
888                                                                 $bean = new $className();
889                                                                 $bean->retrieve($_REQUEST['parent_id']);
890                                                                 if($bean->load_relationship('emails')) {
891                                                                         $bean->emails->add($this->id);
892                                                                 } // if
893
894                                                         } // if
895
896                                                 } // if
897
898                                         } // if
899
900                                 } else {
901                                         if(!class_exists('aCase')) {
902
903                                         }
904                                         else{
905                                                 $c = new aCase();
906                                                 if($caseId = InboundEmail::getCaseIdFromCaseNumber($mail->Subject, $c)) {
907                                                         $c->retrieve($caseId);
908                                                         $c->load_relationship('emails');
909                                                         $c->emails->add($this->id);
910                                                         $this->parent_type = "Cases";
911                                                         $this->parent_id = $caseId;
912                                                 } // if
913                                         }
914
915                                 } // else
916
917                         ////    LINK EMAIL TO SUGARBEANS BASED ON EMAIL ADDY
918                         ///////////////////////////////////////////////////////////////////
919                         $this->save();
920                 }
921
922                 if(!empty($request['fromAccount'])) {
923                         if (isset($ie->id) && !$ie->isPop3Protocol()) {
924                                 $sentFolder = $ie->get_stored_options("sentFolder");
925                                 if (!empty($sentFolder)) {
926                                         $data = $mail->CreateHeader() . "\r\n" . $mail->CreateBody() . "\r\n";
927                                         $ie->mailbox = $sentFolder;
928                                         if ($ie->connectMailserver() == 'true') {
929                                                 $connectString = $ie->getConnectString($ie->getServiceString(), $ie->mailbox);
930                                                 $returnData = imap_append($ie->conn,$connectString, $data, "\\Seen");
931                                                 if (!$returnData) {
932                                                         $GLOBALS['log']->debug("could not copy email to {$ie->mailbox} for {$ie->name}");
933                                                 } // if
934                                         } else {
935                                                 $GLOBALS['log']->debug("could not connect to mail serve for folder {$ie->mailbox} for {$ie->name}");
936                                         } // else
937                                 } else {
938                                         $GLOBALS['log']->debug("could not copy email to {$ie->mailbox} sent folder as its empty");
939                                 } // else
940                         } // if
941                 } // if
942                 return true;
943         } // end email2send
944
945         /**
946          * Generates a comma sperated name and addresses to be used in compose email screen for contacts or leads
947          * from listview
948          */
949         function getNamePlusEmailAddressesForCompose($table, $idsArray) {
950                 global $locale;
951                 global $db;
952                 $table = strtolower($table);
953                 $returndata = array();
954                 $idsString = "";
955                 foreach($idsArray as $id) {
956                         if ($idsString != "") {
957                                 $idsString = $idsString . ",";
958                         } // if
959                         $idsString = $idsString . "'" . $id . "'";
960                 } // foreach
961                 $where = "({$table}.deleted = 0 AND {$table}.id in ({$idsString}))";
962
963                 $selectColumn = "{$table}.first_name, {$table}.last_name, {$table}.salutation, {$table}.title";
964                 if ($table == 'accounts') {
965                         $selectColumn = "{$table}.name";
966                 }
967                 $query = "SELECT {$table}.id, {$selectColumn}, eabr.primary_address, ea.email_address";
968                 $query .= " FROM {$table} ";
969                 $query .= "JOIN email_addr_bean_rel eabr ON ({$table}.id = eabr.bean_id and eabr.deleted=0) ";
970                 $query .= "JOIN email_addresses ea ON (eabr.email_address_id = ea.id) ";
971                 $query .= " WHERE ({$where}) ORDER BY eabr.primary_address DESC";
972                 $r = $this->db->query($query);
973
974                 while($a = $this->db->fetchByAssoc($r)) {
975                         if (!isset($returndata[$a['id']])) {
976                                 if ($table == 'accounts') {
977                                         $returndata[$a['id']] = from_html($a['name']) . " <".from_html($a['email_address']).">";
978                                 } else {
979                                         $full_name = from_html($locale->getLocaleFormattedName($a['first_name'], $a['last_name'], $a['salutation'], $a['title']));
980                                         $returndata[$a['id']] = "{$full_name} <".from_html($a['email_address']).">";
981                                 } // else
982                         }
983                 }
984
985                 return join(",", array_values($returndata));
986     }
987
988         /**
989          * Overrides
990          */
991         ///////////////////////////////////////////////////////////////////////////
992         ////    SAVERS
993         function save($check_notify = false) {
994                 if($this->isDuplicate) {
995                         $GLOBALS['log']->debug("EMAIL - tried to save a duplicate Email record");
996                 } else {
997
998                         if(empty($this->id)) {
999                                 $this->id = create_guid();
1000                                 $this->new_with_id = true;
1001                         }
1002                         $this->from_addr_name = $this->cleanEmails($this->from_addr_name);
1003                         $this->to_addrs_names = $this->cleanEmails($this->to_addrs_names);
1004                         $this->cc_addrs_names = $this->cleanEmails($this->cc_addrs_names);
1005                         $this->bcc_addrs_names = $this->cleanEmails($this->bcc_addrs_names);
1006                         $this->reply_to_addr = $this->cleanEmails($this->reply_to_addr);
1007                         $this->description = to_html($this->safeText(from_html($this->description)));
1008                         $this->description_html = $this->safeText($this->description_html);
1009                         $this->saveEmailText();
1010                         $this->saveEmailAddresses();
1011
1012                         $GLOBALS['log']->debug('-------------------------------> Email called save()');
1013
1014                         // handle legacy concatenation of date and time fields
1015                         if(empty($this->date_sent)) $this->date_sent = $this->date_start." ".$this->time_start;
1016                         parent::save($check_notify);
1017                 }
1018         }
1019
1020         /**
1021          * Helper function to save temporary attachments assocaited to an email as note.
1022          *
1023          * @param string $filename
1024          * @param string $fileLocation
1025          * @param string $mimeType
1026          */
1027         function saveTempNoteAttachments($filename,$fileLocation, $mimeType)
1028         {
1029             global $sugar_config;
1030
1031             $tmpNote = new Note();
1032             $tmpNote->id = create_guid();
1033             $tmpNote->new_with_id = true;
1034             $tmpNote->parent_id = $this->id;
1035             $tmpNote->parent_type = $this->module_dir;
1036             $tmpNote->name = $filename;
1037             $tmpNote->filename = $filename;
1038             $tmpNote->file_mime_type = $mimeType;
1039             $noteFile = "{$sugar_config['upload_dir']}{$tmpNote->id}";
1040             if(!copy($fileLocation, $noteFile))
1041             $GLOBALS['log']->fatal("EMAIL 2.0: could not copy SugarDocument revision file to {$sugar_config['upload_dir']} [ {$fileLocation} ]");
1042             $tmpNote->save();
1043         }
1044         /**
1045          * Handles normalization of Email Addressess
1046          */
1047         function saveEmailAddresses() {
1048                 // from, single address
1049                 $fromId = $this->emailAddress->getEmailGUID(from_html($this->from_addr));
1050         if(!empty($fromId)){
1051                   $this->linkEmailToAddress($fromId, 'from');
1052         }
1053
1054                 // to, multiple
1055                 $replace = array(",",";");
1056                 $toaddrs = str_replace($replace, "::", from_html($this->to_addrs));
1057                 $exToAddrs = explode("::", $toaddrs);
1058
1059                 if(!empty($exToAddrs)) {
1060                         foreach($exToAddrs as $toaddr) {
1061                                 $toaddr = trim($toaddr);
1062                                 if(!empty($toaddr)) {
1063                                         $toId = $this->emailAddress->getEmailGUID($toaddr);
1064                                         $this->linkEmailToAddress($toId, 'to');
1065                                 }
1066                         }
1067                 }
1068
1069                 // cc, multiple
1070                 $ccAddrs = str_replace($replace, "::", from_html($this->cc_addrs));
1071                 $exccAddrs = explode("::", $ccAddrs);
1072
1073                 if(!empty($exccAddrs)) {
1074                         foreach($exccAddrs as $ccAddr) {
1075                                 $ccAddr = trim($ccAddr);
1076                                 if(!empty($ccAddr)) {
1077                                         $ccId = $this->emailAddress->getEmailGUID($ccAddr);
1078                                         $this->linkEmailToAddress($ccId, 'cc');
1079                                 }
1080                         }
1081                 }
1082
1083                 // bcc, multiple
1084                 $bccAddrs = str_replace($replace, "::", from_html($this->bcc_addrs));
1085                 $exbccAddrs = explode("::", $bccAddrs);
1086                 if(!empty($exbccAddrs)) {
1087                         foreach($exbccAddrs as $bccAddr) {
1088                                 $bccAddr = trim($bccAddr);
1089                                 if(!empty($bccAddr)) {
1090                                         $bccId = $this->emailAddress->getEmailGUID($bccAddr);
1091                                         $this->linkEmailToAddress($bccId, 'bcc');
1092                                 }
1093                         }
1094                 }
1095         }
1096
1097         function linkEmailToAddress($id, $type) {
1098                 // TODO: make this update?
1099                 $q1 = "SELECT * FROM emails_email_addr_rel WHERE email_id = '{$this->id}' AND email_address_id = '{$id}' AND address_type = '{$type}' AND deleted = 0";
1100                 $r1 = $this->db->query($q1);
1101                 $a1 = $this->db->fetchByAssoc($r1);
1102
1103                 if(!empty($a1) && !empty($a1['id'])) {
1104                         return $a1['id'];
1105                 } else {
1106                         $guid = create_guid();
1107                         $q2 = "INSERT INTO emails_email_addr_rel VALUES('{$guid}', '{$this->id}', '{$type}', '{$id}', 0)";
1108                         $r2 = $this->db->query($q2);
1109                 }
1110
1111                 return $guid;
1112         }
1113
1114         function cleanEmails($emails)
1115         {
1116                 $emails = str_replace(array(",",";"), "::", from_html($emails));
1117                 $addrs = explode("::", $emails);
1118                 $res = array();
1119                 foreach($addrs as $addr) {
1120             $parts = $this->emailAddress->splitEmailAddress($addr);
1121             if(empty($parts["email"])) {
1122                 continue;
1123             }
1124             if(!empty($parts["name"])) {
1125                 $res[] = "{$parts["name"]} <{$parts["email"]}>";
1126             } else {
1127                 $res[] .= $parts["email"];
1128             }
1129                 }
1130         return join(", ", $res);
1131         }
1132
1133         function saveEmailText() {
1134                 $isOracle = ($this->db->dbType == "oci8") ? true : false;
1135                 if ($isOracle) {
1136                 } else {
1137                         $description = $this->db->quote(trim($this->description));
1138                         $description_html = $this->db->quoteForEmail(trim($this->description_html));
1139                         $raw_source = $this->db->quote(trim($this->raw_source));
1140                         $fromAddressName = $this->db->helper->escape_quote($this->from_addr_name);
1141                         $toAddressName = $this->db->helper->escape_quote($this->to_addrs_names);
1142                         $ccAddressName = $this->db->helper->escape_quote($this->cc_addrs_names);
1143                         $bccAddressName = $this->db->helper->escape_quote($this->bcc_addrs_names);
1144                         $replyToAddrName = $this->db->helper->escape_quote($this->reply_to_addr);
1145
1146                         if(!$this->new_with_id) {
1147                                 $q = "UPDATE emails_text SET from_addr = '{$fromAddressName}', to_addrs = '{$toAddressName}', cc_addrs = '{$ccAddressName}', bcc_addrs = '{$bccAddressName}', reply_to_addr = '{$replyToAddrName}', description = '{$description}', description_html = '{$description_html}', raw_source = '{$raw_source}' WHERE email_id = '{$this->id}'";
1148                         } else {
1149                                 $q = "INSERT INTO emails_text (email_id, from_addr, to_addrs, cc_addrs, bcc_addrs, reply_to_addr, description, description_html, raw_source, deleted) VALUES('{$this->id}', '{$fromAddressName}', '{$toAddressName}', '{$ccAddressName}', '{$bccAddressName}', '{$replyToAddrName}', '{$description}', '{$description_html}', '{$raw_source}', 0)";
1150                         }
1151                         $this->db->query($q);
1152
1153                 } // else
1154         }
1155
1156
1157         ///////////////////////////////////////////////////////////////////////////
1158         ////    RETRIEVERS
1159         function retrieve($id, $encoded=true, $deleted=true) {
1160                 // cn: bug 11915, return SugarBean's retrieve() call bean instead of $this
1161                 $ret = parent::retrieve($id, $encoded, $deleted);
1162
1163                 if($ret) {
1164                         $ret->retrieveEmailText();
1165                         $ret->retrieveEmailAddresses();
1166                         $ret->raw_source = to_html($ret->safeText(from_html($ret->raw_source)));
1167                         $ret->description = to_html($ret->safeText(from_html($ret->description)));
1168                         $ret->description_html = $ret->safeText($ret->description_html);
1169
1170                         $ret->date_start = '';
1171                         $ret->time_start = '';
1172                         $dateSent = explode(' ', $ret->date_sent);
1173                         if (!empty($dateSent)) {
1174                             $ret->date_start = $dateSent[0];
1175                             if ( isset($dateSent[1]) )
1176                                 $ret->time_start = $dateSent[1];
1177                         }
1178                         // for Email 2.0
1179                         foreach($ret as $k => $v) {
1180                                 $this->$k = $v;
1181                         }
1182                 }
1183                 return $ret;
1184         }
1185
1186
1187         /**
1188          * Retrieves email addresses from GUIDs
1189          */
1190         function retrieveEmailAddresses() {
1191                 $return = array();
1192
1193                 $q = "SELECT email_address, address_type
1194                                 FROM emails_email_addr_rel eam
1195                                 JOIN email_addresses ea ON ea.id = eam.email_address_id
1196                                 WHERE eam.email_id = '{$this->id}' AND eam.deleted=0";
1197                 $r = $this->db->query($q);
1198
1199                 while($a = $this->db->fetchByAssoc($r)) {
1200                         if(!isset($return[$a['address_type']])) {
1201                                 $return[$a['address_type']] = array();
1202                         }
1203                         $return[$a['address_type']][] = $a['email_address'];
1204                 }
1205
1206                 if(count($return) > 0) {
1207                         if(isset($return['from'])) {
1208                                 $this->from_addr = implode(", ", $return['from']);
1209                         }
1210                         if(isset($return['to'])) {
1211                                 $this->to_addrs = implode(", ", $return['to']);
1212                         }
1213                         if(isset($return['cc'])) {
1214                                 $this->cc_addrs = implode(", ", $return['cc']);
1215                         }
1216                         if(isset($return['bcc'])) {
1217                                 $this->bcc_addrs = implode(", ", $return['bcc']);
1218                         }
1219                 }
1220         }
1221
1222         /**
1223          * Handles longtext fields
1224          */
1225         function retrieveEmailText() {
1226                 $q = "SELECT from_addr, reply_to_addr, to_addrs, cc_addrs, bcc_addrs, description, description_html, raw_source FROM emails_text WHERE email_id = '{$this->id}'";
1227                 $r = $this->db->query($q);
1228                 $a = $this->db->fetchByAssoc($r, -1, false);
1229
1230                 $this->description = $a['description'];
1231                 $this->description_html = $a['description_html'];
1232                 $this->raw_source = $a['raw_source'];
1233                 $this->from_addr_name = $a['from_addr'];
1234                 $this->reply_to_addr  = $a['reply_to_addr'];
1235                 $this->to_addrs_names = $a['to_addrs'];
1236                 $this->cc_addrs_names = $a['cc_addrs'];
1237                 $this->bcc_addrs_names = $a['bcc_addrs'];
1238         }
1239
1240         function delete($id='') {
1241                 if(empty($id))
1242                         $id = $this->id;
1243
1244                 $q  = "UPDATE emails SET deleted = 1 WHERE id = '{$id}'";
1245                 $qt = "UPDATE emails_text SET deleted = 1 WHERE email_id = '{$id}'";
1246                 $r  = $this->db->query($q);
1247                 $rt = $this->db->query($qt);
1248         }
1249
1250         /**
1251          * creates the standard "Forward" info at the top of the forwarded message
1252          * @return string
1253          */
1254         function getForwardHeader() {
1255                 global $mod_strings;
1256                 global $current_user;
1257
1258                 //$from = str_replace(array("&gt;","&lt;"), array(")","("), $this->from_name);
1259                 $from = to_html($this->from_name);
1260                 $subject = to_html($this->name);
1261                 $ret  = "<br /><br />";
1262                 $ret .= $this->replyDelimiter."{$mod_strings['LBL_FROM']} {$from}<br />";
1263                 $ret .= $this->replyDelimiter."{$mod_strings['LBL_DATE_SENT']} {$this->date_sent}<br />";
1264                 $ret .= $this->replyDelimiter."{$mod_strings['LBL_TO']} {$this->to_addrs}<br />";
1265                 $ret .= $this->replyDelimiter."{$mod_strings['LBL_CC']} {$this->cc_addrs}<br />";
1266                 $ret .= $this->replyDelimiter."{$mod_strings['LBL_SUBJECT']} {$subject}<br />";
1267                 $ret .= $this->replyDelimiter."<br />";
1268
1269                 return $ret;
1270                 //return from_html($ret);
1271         }
1272
1273     /**
1274      * retrieves Notes that belong to this Email and stuffs them into the "attachments" attribute
1275      */
1276     function getNotes($id, $duplicate=false) {
1277         if(!class_exists('Note')) {
1278
1279         }
1280
1281         $exRemoved = array();
1282                 if(isset($_REQUEST['removeAttachment'])) {
1283                         $exRemoved = explode('::', $_REQUEST['removeAttachment']);
1284                 }
1285
1286         $noteArray = array();
1287         $q = "SELECT id FROM notes WHERE parent_id = '".$id."'";
1288         $r = $this->db->query($q);
1289
1290         while($a = $this->db->fetchByAssoc($r)) {
1291                 if(!in_array($a['id'], $exRemoved)) {
1292                     $note = new Note();
1293                     $note->retrieve($a['id']);
1294
1295                     // duplicate actual file when creating forwards
1296                         if($duplicate) {
1297                                 if(!class_exists('UploadFile')) {
1298                                         require_once('include/upload_file.php');
1299                                 }
1300                                 // save a brand new Note
1301                                 $noteDupe->id = create_guid();
1302                                 $noteDupe->new_with_id = true;
1303                                         $noteDupe->parent_id = $this->id;
1304                                         $noteDupe->parent_type = $this->module_dir;
1305
1306                                         $noteFile = new UploadFile('none');
1307                                         $noteFile->duplicate_file($a['id'], $note->id, $note->filename);
1308
1309                                         $note->save();
1310                         }
1311                         // add Note to attachments array
1312                     $this->attachments[] = $note;
1313                 }
1314         }
1315     }
1316
1317         /**
1318          * creates the standard "Reply" info at the top of the forwarded message
1319          * @return string
1320          */
1321         function getReplyHeader() {
1322                 global $mod_strings;
1323                 global $current_user;
1324
1325                 $from = str_replace(array("&gt;","&lt;", ">","<"), array(")","(",")","("), $this->from_name);
1326                 $ret  = "<br>{$mod_strings['LBL_REPLY_HEADER_1']} {$this->date_start}, {$this->time_start}, {$from} {$mod_strings['LBL_REPLY_HEADER_2']}";
1327
1328                 return from_html($ret);
1329         }
1330
1331         /**
1332          * Quotes plain-text email text
1333          * @param string $text
1334          * @return string
1335          */
1336         function quotePlainTextEmail($text) {
1337                 $quoted = "\n";
1338
1339                 // plain-text
1340                 $desc = nl2br(trim($text));
1341                 $exDesc = explode('<br />', $desc);
1342
1343                 foreach($exDesc as $k => $line) {
1344                         $quoted .= '> '.trim($line)."\r";
1345                 }
1346
1347                 return $quoted;
1348         }
1349
1350         /**
1351          * "quotes" (i.e., "> my text yadda" the HTML part of an email
1352          * @param string $text HTML text to quote
1353          * @return string
1354          */
1355         function quoteHtmlEmail($text) {
1356                 $text = trim(from_html($text));
1357
1358                 if(empty($text)) {
1359                         return '';
1360                 }
1361                 $out = "<div style='border-left:1px solid #00c; padding:5px; margin-left:10px;'>{$text}</div>";
1362
1363                 return $out;
1364         }
1365
1366         /**
1367          * "quotes" (i.e., "> my text yadda" the HTML part of an email
1368          * @param string $text HTML text to quote
1369          * @return string
1370          */
1371         function quoteHtmlEmailForNewEmailUI($text) {
1372                 $text = trim($text);
1373
1374                 if(empty($text)) {
1375                         return '';
1376                 }
1377                 $text = str_replace("\n", "\n<BR/>", $text);
1378                 $out = "<div style='border-left:1px solid #00c; padding:5px; margin-left:10px;'>{$text}</div>";
1379
1380                 return $out;
1381         }
1382
1383
1384
1385         ///////////////////////////////////////////////////////////////////////////
1386         ////    LEGACY CODE
1387         /**
1388          * Safes description text (both HTML and Plain Text) for display
1389          * @param string str The text to safe
1390          * @return string Safed text
1391          */
1392         function safeText($str) {
1393                 // Safe_HTML
1394                 $this->safe->clear();
1395                 $ret = $this->safe->parse($str);
1396
1397                 // Julian's XSS cleaner
1398                 $potentials = clean_xss($str, false);
1399
1400                 if(is_array($potentials) && !empty($potentials)) {
1401                         //_ppl($potentials);
1402                         foreach($potentials as $bad) {
1403                                 $ret = str_replace($bad, "", $ret);
1404                         }
1405                 }
1406
1407                 // clean <HTML> and <BODY> tags
1408                 $html = '#<\\\\\?HTML[\w =\'\"\&]*>#sim';
1409                 $body = '#<\\\\\?BODY[\w =\'\"\&]*>#sim';
1410
1411                 $ret = preg_replace($html, "", $ret);
1412                 $ret = preg_replace($body, "", $ret);
1413
1414                 return $ret;
1415         }
1416
1417         /**
1418          * Ensures that the user is able to send outbound emails
1419          */
1420         function check_email_settings() {
1421                 global $current_user;
1422
1423                 $mail_fromaddress = $current_user->emailAddress->getPrimaryAddress($current_user);
1424                 $replyToName = $current_user->getPreference('mail_fromname');
1425                 $mail_fromname = (!empty($replyToName)) ? $current_user->getPreference('mail_fromname') : $current_user->full_name;
1426
1427                 if(empty($mail_fromaddress)) {
1428                         return false;
1429                 }
1430                 if(empty($mail_fromname)) {
1431                         return false;
1432                 }
1433
1434         $send_type = $current_user->getPreference('mail_sendtype') ;
1435                 if (!empty($send_type) && $send_type == "SMTP") {
1436                         $mail_smtpserver = $current_user->getPreference('mail_smtpserver');
1437                         $mail_smtpport = $current_user->getPreference('mail_smtpport');
1438                         $mail_smtpauth_req = $current_user->getPreference('mail_smtpauth_req');
1439                         $mail_smtpuser = $current_user->getPreference('mail_smtpuser');
1440                         $mail_smtppass = $current_user->getPreference('mail_smtppass');
1441                         if (empty($mail_smtpserver) ||
1442                                 empty($mail_smtpport) ||
1443                 (!empty($mail_smtpauth_req) && ( empty($mail_smtpuser) || empty($mail_smtppass)))
1444                         ) {
1445                                 return false;
1446                         }
1447                 }
1448                 return true;
1449         }
1450
1451         /**
1452          * outputs JS to set fields in the MassUpdate form in the "My Inbox" view
1453          */
1454         function js_set_archived() {
1455                 global $mod_strings;
1456                 $script = '
1457                 <script type="text/javascript" language="JavaScript"><!-- Begin
1458                         function setArchived() {
1459                                 var form = document.getElementById("MassUpdate");
1460                                 var status = document.getElementById("mass_status");
1461                                 var ok = false;
1462
1463                                 for(var i=0; i < form.elements.length; i++) {
1464                                         if(form.elements[i].name == "mass[]") {
1465                                                 if(form.elements[i].checked == true) {
1466                                                         ok = true;
1467                                                 }
1468                                         }
1469                                 }
1470
1471                                 if(ok == true) {
1472                                         var user = document.getElementById("mass_assigned_user_name");
1473                                         var team = document.getElementById("team");
1474
1475                                         user.value = "";
1476                                         for(var j=0; j<status.length; j++) {
1477                                                 if(status.options[j].value == "archived") {
1478                                                         status.options[j].selected = true;
1479                                                         status.selectedIndex = j; // for IE
1480                                                 }
1481                                         }
1482
1483                                         form.submit();
1484                                 } else {
1485                                         alert("'.$mod_strings['ERR_ARCHIVE_EMAIL'].'");
1486                                 }
1487
1488                         }
1489                 //  End --></script>';
1490                 return $script;
1491         }
1492
1493         /**
1494          * replaces the javascript in utils.php - more specialized
1495          */
1496         function u_get_clear_form_js($type='', $group='', $assigned_user_id='') {
1497                 $uType                          = '';
1498                 $uGroup                         = '';
1499                 $uAssigned_user_id      = '';
1500
1501                 if(!empty($type)) { $uType = '&type='.$type; }
1502                 if(!empty($group)) { $uGroup = '&group='.$group; }
1503                 if(!empty($assigned_user_id)) { $uAssigned_user_id = '&assigned_user_id='.$assigned_user_id; }
1504
1505                 $the_script = '
1506                 <script type="text/javascript" language="JavaScript"><!-- Begin
1507                         function clear_form(form) {
1508                                 var newLoc = "index.php?action=" + form.action.value + "&module=" + form.module.value + "&query=true&clear_query=true'.$uType.$uGroup.$uAssigned_user_id.'";
1509                                 if(typeof(form.advanced) != "undefined"){
1510                                         newLoc += "&advanced=" + form.advanced.value;
1511                                 }
1512                                 document.location.href= newLoc;
1513                         }
1514                 //  End --></script>';
1515                 return $the_script;
1516         }
1517
1518         function pickOneButton() {
1519                 global $theme;
1520                 global $mod_strings;
1521                 $out = '<div><input     title="'.$mod_strings['LBL_BUTTON_GRAB_TITLE'].'"
1522                                                 accessKey="'.$mod_strings['LBL_BUTTON_GRAB_KEY'].'"
1523                                                 class="button"
1524                                                 type="button" name="button"
1525                                                 onClick="window.location=\'index.php?module=Emails&action=Grab\';"
1526                                                 style="margin-bottom:2px"
1527                                                 value="  '.$mod_strings['LBL_BUTTON_GRAB'].'  "></div>';
1528                 return $out;
1529         }
1530
1531         /**
1532          * Determines what Editor (HTML or Plain-text) the current_user uses;
1533          * @return string Editor type
1534          */
1535         function getUserEditorPreference() {
1536                 global $sugar_config;
1537                 global $current_user;
1538
1539                 $editor = '';
1540
1541                 if(!isset($sugar_config['email_default_editor'])) {
1542                         $sugar_config = $current_user->setDefaultsInConfig();
1543                 }
1544
1545                 $userEditor = $current_user->getPreference('email_editor_option');
1546                 $systemEditor = $sugar_config['email_default_editor'];
1547
1548                 if($userEditor != '') {
1549                         $editor = $userEditor;
1550                 } else {
1551                         $editor = $systemEditor;
1552                 }
1553
1554                 return $editor;
1555         }
1556
1557         /**
1558          * takes the mess we pass from EditView and tries to create some kind of order
1559          * @param array addrs
1560          * @param array addrs_ids (from contacts)
1561          * @param array addrs_names (from contacts);
1562          * @param array addrs_emails (from contacts);
1563          * @return array Parsed assoc array to feed to PHPMailer
1564          */
1565         function parse_addrs($addrs, $addrs_ids, $addrs_names, $addrs_emails) {
1566                 // cn: bug 9406 - enable commas to separate email addresses
1567                 $addrs = str_replace(",", ";", $addrs);
1568
1569                 $ltgt = array('&lt;','&gt;');
1570                 $gtlt = array('<','>');
1571
1572                 $return                         = array();
1573                 $addrs                          = str_replace($ltgt, '', $addrs);
1574                 $addrs_arr                      = explode(";",$addrs);
1575                 $addrs_arr                      = $this->remove_empty_fields($addrs_arr);
1576                 $addrs_ids_arr          = explode(";",$addrs_ids);
1577                 $addrs_ids_arr          = $this->remove_empty_fields($addrs_ids_arr);
1578                 $addrs_emails_arr       = explode(";",$addrs_emails);
1579                 $addrs_emails_arr       = $this->remove_empty_fields($addrs_emails_arr);
1580                 $addrs_names_arr        = explode(";",$addrs_names);
1581                 $addrs_names_arr        = $this->remove_empty_fields($addrs_names_arr);
1582
1583                 ///////////////////////////////////////////////////////////////////////
1584                 ////    HANDLE EMAILS HAND-WRITTEN
1585                 $contactRecipients = array();
1586                 $knownEmails = array();
1587
1588                 foreach($addrs_arr as $i => $v) {
1589                         if(trim($v) == "")
1590                                 continue; // skip any "blanks" - will always have 1
1591
1592                         $recipient = array();
1593
1594                         //// get the email to see if we're dealing with a dupe
1595                         //// what crappy coding
1596                         preg_match("/[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i",$v, $match);
1597
1598                         if(!empty($match[0]) && !in_array(trim($match[0]), $knownEmails)) {
1599                                 $knownEmails[] = $match[0];
1600                                 $recipient['email'] = $match[0];
1601
1602                                 //// handle the Display name
1603                                 $display = trim(str_replace($match[0], '', $v));
1604
1605                                 //// only trigger a "displayName" <email@address> when necessary
1606                                 if(isset($addrs_names_arr[$i])){
1607                                                 $recipient['display'] = $addrs_names_arr[$i];
1608                                 }
1609                                 else if(!empty($display)) {
1610                                         $recipient['display'] = $display;
1611                                 }
1612                                 if(isset($addrs_ids_arr[$i]) && $addrs_emails_arr[$i] == $match[0]){
1613                                         $recipient['contact_id'] = $addrs_ids_arr[$i];
1614                                 }
1615                                 $return[] = $recipient;
1616                         }
1617                 }
1618
1619                 return $return;
1620         }
1621
1622         function remove_empty_fields(&$arr) {
1623                 $newarr = array();
1624
1625                 foreach($arr as $field) {
1626                         $field = trim($field);
1627                         if(empty($field)) {
1628                                 continue;
1629                         }
1630                         array_push($newarr,$field);
1631                 }
1632                 return $newarr;
1633         }
1634
1635         /**
1636          * handles attachments of various kinds when sending email
1637          */
1638         function handleAttachments() {
1639
1640
1641
1642
1643                 global $mod_strings;
1644
1645         ///////////////////////////////////////////////////////////////////////////
1646         ////    ATTACHMENTS FROM DRAFTS
1647         if(($this->type == 'out' || $this->type == 'draft') && $this->status == 'draft' && isset($_REQUEST['record'])) {
1648             $this->getNotes($_REQUEST['record']); // cn: get notes from OLD email for use in new email
1649         }
1650         ////    END ATTACHMENTS FROM DRAFTS
1651         ///////////////////////////////////////////////////////////////////////////
1652
1653         ///////////////////////////////////////////////////////////////////////////
1654         ////    ATTACHMENTS FROM FORWARDS
1655         // Bug 8034 Jenny - Need the check for type 'draft' here to handle cases where we want to save
1656         // forwarded messages as drafts.  We still need to save the original message's attachments.
1657         if(($this->type == 'out' || $this->type == 'draft') &&
1658                 isset($_REQUEST['origType']) && $_REQUEST['origType'] == 'forward' &&
1659                 isset($_REQUEST['return_id']) && !empty($_REQUEST['return_id'])
1660         ) {
1661             $this->getNotes($_REQUEST['return_id'], true);
1662         }
1663
1664         // cn: bug 8034 - attachments from forward/replies lost when saving in draft
1665         if(isset($_REQUEST['prior_attachments']) && !empty($_REQUEST['prior_attachments']) && $this->new_with_id == true) {
1666                 $exIds = explode(",", $_REQUEST['prior_attachments']);
1667                 if(!isset($_REQUEST['template_attachment'])) {
1668                         $_REQUEST['template_attachment'] = array();
1669                 }
1670                 $_REQUEST['template_attachment'] = array_merge($_REQUEST['template_attachment'], $exIds);
1671         }
1672         ////    END ATTACHMENTS FROM FORWARDS
1673         ///////////////////////////////////////////////////////////////////////////
1674
1675                 ///////////////////////////////////////////////////////////////////////////
1676                 ////    ATTACHMENTS FROM TEMPLATES
1677                 // to preserve individual email integrity, we must dupe Notes and associated files
1678                 // for each outbound email - good for integrity, bad for filespace
1679                 if(isset($_REQUEST['template_attachment']) && !empty($_REQUEST['template_attachment'])) {
1680                         $removeArr = array();
1681                         $noteArray = array();
1682
1683                         if(isset($_REQUEST['temp_remove_attachment']) && !empty($_REQUEST['temp_remove_attachment'])) {
1684                                 $removeArr = $_REQUEST['temp_remove_attachment'];
1685                         }
1686
1687
1688                         foreach($_REQUEST['template_attachment'] as $noteId) {
1689                                 if(in_array($noteId, $removeArr)) {
1690                                         continue;
1691                                 }
1692                                 $noteTemplate = new Note();
1693                                 $noteTemplate->retrieve($noteId);
1694                                 $noteTemplate->id = create_guid();
1695                                 $noteTemplate->new_with_id = true; // duplicating the note with files
1696                                 $noteTemplate->parent_id = $this->id;
1697                                 $noteTemplate->parent_type = $this->module_dir;
1698                                 $noteTemplate->date_entered = '';
1699                                 $noteTemplate->save();
1700
1701                                 $noteFile = new UploadFile('none');
1702                                 $noteFile->duplicate_file($noteId, $noteTemplate->id, $noteTemplate->filename);
1703                                 $noteArray[] = $noteTemplate;
1704                         }
1705                         $this->attachments = array_merge($this->attachments, $noteArray);
1706                 }
1707                 ////    END ATTACHMENTS FROM TEMPLATES
1708                 ///////////////////////////////////////////////////////////////////////////
1709
1710                 ///////////////////////////////////////////////////////////////////////////
1711                 ////    ADDING NEW ATTACHMENTS
1712                 $max_files_upload = 10;
1713         // Jenny - Bug 8211 Since attachments for drafts have already been processed,
1714         // we don't need to re-process them.
1715         if($this->status != "draft") {
1716                 $notes_list = array();
1717                 if(!empty($this->id) && !$this->new_with_id) {
1718                         $note = new Note();
1719                         $where = "notes.parent_id='{$this->id}'";
1720                         $notes_list = $note->get_full_list("", $where, true);
1721                 }
1722                 $this->attachments = array_merge($this->attachments, $notes_list);
1723         }
1724                 // cn: Bug 5995 - rudimentary error checking
1725                 $filesError = array(
1726                         0 => 'UPLOAD_ERR_OK - There is no error, the file uploaded with success.',
1727                         1 => 'UPLOAD_ERR_INI_SIZE - The uploaded file exceeds the upload_max_filesize directive in php.ini.',
1728                         2 => 'UPLOAD_ERR_FORM_SIZE - The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
1729                         3 => 'UPLOAD_ERR_PARTIAL - The uploaded file was only partially uploaded.',
1730                         4 => 'UPLOAD_ERR_NO_FILE - No file was uploaded.',
1731                         5 => 'UNKNOWN ERROR',
1732                         6 => 'UPLOAD_ERR_NO_TMP_DIR - Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.',
1733                         7 => 'UPLOAD_ERR_CANT_WRITE - Failed to write file to disk. Introduced in PHP 5.1.0.',
1734                 );
1735
1736                 for($i = 0; $i < $max_files_upload; $i++) {
1737                         // cn: Bug 5995 - rudimentary error checking
1738                         if (!isset($_FILES["email_attachment{$i}"])) {
1739                                 $GLOBALS['log']->debug("Email Attachment {$i} does not exist.");
1740                                 continue;
1741                         }
1742                         if($_FILES['email_attachment'.$i]['error'] != 0 && $_FILES['email_attachment'.$i]['error'] != 4) {
1743                                 $GLOBALS['log']->debug('Email Attachment could not be attach due to error: '.$filesError[$_FILES['email_attachment'.$i]['error']]);
1744                                 continue;
1745                         }
1746
1747                         $note = new Note();
1748                         $note->parent_id = $this->id;
1749                         $note->parent_type = $this->module_dir;
1750                         $upload_file = new UploadFile('email_attachment'.$i);
1751
1752                         if(empty($upload_file)) {
1753                                 continue;
1754                         }
1755
1756                         if(isset($_FILES['email_attachment'.$i]) && $upload_file->confirm_upload()) {
1757                                 $note->filename = $upload_file->get_stored_file_name();
1758                                 $note->file = $upload_file;
1759                                 $note->name = $mod_strings['LBL_EMAIL_ATTACHMENT'].': '.$note->file->original_file_name;
1760
1761                                 $this->attachments[] = $note;
1762                         }
1763                 }
1764
1765                 $this->saved_attachments = array();
1766                 foreach($this->attachments as $note) {
1767                         if(!empty($note->id)) {
1768                                 array_push($this->saved_attachments, $note);
1769                                 continue;
1770                         }
1771                         $note->parent_id = $this->id;
1772                         $note->parent_type = 'Emails';
1773                         $note->file_mime_type = $note->file->mime_type;
1774                         $note_id = $note->save();
1775
1776                         $this->saved_attachments[] = $note;
1777
1778                         $note->id = $note_id;
1779                         $note->file->final_move($note->id);
1780                 }
1781                 ////    END NEW ATTACHMENTS
1782                 ///////////////////////////////////////////////////////////////////////////
1783
1784                 ///////////////////////////////////////////////////////////////////////////
1785                 ////    ATTACHMENTS FROM DOCUMENTS
1786                 for($i=0; $i<10; $i++) {
1787                         if(isset($_REQUEST['documentId'.$i]) && !empty($_REQUEST['documentId'.$i])) {
1788                                 $doc = new Document();
1789                                 $docRev = new DocumentRevision();
1790                                 $docNote = new Note();
1791                                 $noteFile = new UploadFile('none');
1792
1793                                 $doc->retrieve($_REQUEST['documentId'.$i]);
1794                                 $docRev->retrieve($doc->document_revision_id);
1795
1796                                 $this->saved_attachments[] = $docRev;
1797
1798                                 // cn: bug 9723 - Emails with documents send GUID instead of Doc name
1799                                 $docNote->name = $docRev->getDocumentRevisionNameForDisplay();
1800                                 $docNote->filename = $docRev->filename;
1801                                 $docNote->description = $doc->description;
1802                                 $docNote->parent_id = $this->id;
1803                                 $docNote->parent_type = 'Emails';
1804                                 $docNote->file_mime_type = $docRev->file_mime_type;
1805                                 $docId = $docNote = $docNote->save();
1806
1807                                 $noteFile->duplicate_file($docRev->id, $docId, $docRev->filename);
1808                         }
1809                 }
1810
1811                 ////    END ATTACHMENTS FROM DOCUMENTS
1812                 ///////////////////////////////////////////////////////////////////////////
1813
1814                 ///////////////////////////////////////////////////////////////////////////
1815                 ////    REMOVE ATTACHMENTS
1816         if(isset($_REQUEST['remove_attachment']) && !empty($_REQUEST['remove_attachment'])) {
1817             foreach($_REQUEST['remove_attachment'] as $noteId) {
1818                 $q = 'UPDATE notes SET deleted = 1 WHERE id = \''.$noteId.'\'';
1819                 $this->db->query($q);
1820             }
1821         }
1822
1823         //this will remove attachments that have been selected to be removed from drafts.
1824         if(isset($_REQUEST['removeAttachment']) && !empty($_REQUEST['removeAttachment'])) {
1825             $exRemoved = explode('::', $_REQUEST['removeAttachment']);
1826             foreach($exRemoved as $noteId) {
1827                 $q = 'UPDATE notes SET deleted = 1 WHERE id = \''.$noteId.'\'';
1828                 $this->db->query($q);
1829             }
1830         }
1831                 ////    END REMOVE ATTACHMENTS
1832                 ///////////////////////////////////////////////////////////////////////////
1833         }
1834
1835
1836         /**
1837          * Determines if an email body (HTML or Plain) has a User signature already in the content
1838          * @param array Array of signatures
1839          * @return bool
1840          */
1841         function hasSignatureInBody($sig) {
1842                 // strpos can't handle line breaks - normalize
1843                 $html = $this->removeAllNewlines($this->description_html);
1844                 $htmlSig = $this->removeAllNewlines($sig['signature_html']);
1845                 $plain = $this->removeAllNewlines($this->description);
1846                 $plainSig = $this->removeAllNewlines($sig['signature']);
1847
1848                 // cn: bug 11621 - empty sig triggers notice error
1849                 if(!empty($htmlSig) && false !== strpos($html, $htmlSig)) {
1850                         return true;
1851                 } elseif(!empty($plainSig) && false !== strpos($plain, $plainSig)) {
1852                         return true;
1853                 } else {
1854                         return false;
1855                 }
1856         }
1857
1858         /**
1859          * internal helper
1860          * @param string String to be normalized
1861          * @return string
1862          */
1863         function removeAllNewlines($str) {
1864                 $bad = array("\r\n", "\n\r", "\n", "\r");
1865                 $good = array('', '', '', '');
1866
1867                 return str_replace($bad, $good, strip_tags(br2nl(from_html($str))));
1868         }
1869
1870
1871
1872         /**
1873          * Set navigation anchors to aid DetailView record navigation (VCR buttons)
1874          * @param string uri The URI from the referring page (always ListView)
1875          * @return array start Array of the URI broken down with a special "current_view" for My Inbox Navs
1876          */
1877         function getStartPage($uri) {
1878                 if(strpos($uri, '&')) { // "&" to ensure that we can explode the GET vars - else we're gonna trigger a Notice error
1879                         $serial = substr($uri, (strpos($uri, '?')+1), strlen($uri));
1880                         $exUri = explode('&', $serial);
1881                         $start = array('module' => '', 'action' => '', 'group' => '', 'record' => '', 'type' => '');
1882
1883                         foreach($exUri as $k => $pair) {
1884                                 $exPair = explode('=', $pair);
1885                                 $start[$exPair[0]] = $exPair[1];
1886                         }
1887
1888                         // specific views for current_user
1889                         if(isset($start['assigned_user_id'])) {
1890                                 $start['current_view'] = "{$start['action']}&module={$start['module']}&assigned_user_id={$start['assigned_user_id']}&type={$start['type']}";
1891                         }
1892
1893                         return $start;
1894                 } else {
1895                         return array();
1896                 }
1897         }
1898
1899         /**
1900          * preps SMTP info for email transmission
1901          * @param object mail SugarPHPMailer object
1902          * @param string mailer_id
1903          * @param string ieId
1904          * @return object mail SugarPHPMailer object
1905          */
1906         function setMailer($mail, $mailer_id='', $ieId='') {
1907                 global $current_user;
1908
1909                 require_once("include/OutboundEmail/OutboundEmail.php");
1910                 $oe = new OutboundEmail();
1911                 $oe = $oe->getInboundMailerSettings($current_user, $mailer_id, $ieId);
1912
1913                 // ssl or tcp - keeping outside isSMTP b/c a default may inadvertantly set ssl://
1914                 $mail->protocol = ($oe->mail_smtpssl) ? "ssl://" : "tcp://";
1915         if($oe->mail_sendtype == "SMTP")
1916         {
1917                 //Set mail send type information
1918                 $mail->Mailer = "smtp";
1919                 $mail->Host = $oe->mail_smtpserver;
1920                 $mail->Port = $oe->mail_smtpport;
1921             if ($oe->mail_smtpssl == 1) {
1922                 $mail->SMTPSecure = 'ssl';
1923             } // if
1924             if ($oe->mail_smtpssl == 2) {
1925                 $mail->SMTPSecure = 'tls';
1926             } // if
1927
1928                 if($oe->mail_smtpauth_req) {
1929                         $mail->SMTPAuth = TRUE;
1930                         $mail->Username = $oe->mail_smtpuser;
1931                         $mail->Password = $oe->mail_smtppass;
1932                 }
1933         }
1934         else
1935                         $mail->Mailer = "sendmail";
1936
1937                 $mail->oe = $oe;
1938                 return $mail;
1939         }
1940
1941         /**
1942          * preps SugarPHPMailer object for HTML or Plain text sends
1943          * @param object SugarPHPMailer instance
1944          */
1945         function handleBody($mail) {
1946                 global $current_user;
1947                 global $sugar_config;
1948                 ///////////////////////////////////////////////////////////////////////
1949                 ////    HANDLE EMAIL FORMAT PREFERENCE
1950                 // the if() below is HIGHLY dependent on the Javascript unchecking the Send HTML Email box
1951                 // HTML email
1952                 if( (isset($_REQUEST['setEditor']) /* from Email EditView navigation */
1953                         && $_REQUEST['setEditor'] == 1
1954                         && trim($_REQUEST['description_html']) != '')
1955                         || trim($this->description_html) != '' /* from email templates */
1956             && $current_user->getPreference('email_editor_option', 'global') !== 'plain' //user preference is not set to plain text
1957                 ) {
1958                     $this->handleBodyInHTMLformat($mail);
1959                 } else {
1960                         // plain text only
1961                         $this->description_html = '';
1962                         $mail->IsHTML(false);
1963                         $plainText = from_html($this->description);
1964                         $plainText = str_replace("&nbsp;", " ", $plainText);
1965                         $plainText = str_replace("</p>", "</p><br />", $plainText);
1966                         $plainText = strip_tags(br2nl($plainText));
1967                         $plainText = str_replace("&amp;", "&", $plainText);
1968             $plainText = str_replace("&#39;", "'", $plainText);
1969                         $mail->Body = wordwrap($plainText, 996);
1970                         $mail->Body = $this->decodeDuringSend($mail->Body);
1971                         $this->description = $mail->Body;
1972                 }
1973
1974                 // wp: if plain text version has lines greater than 998, use base64 encoding
1975                 foreach(explode("\n", ($mail->ContentType == "text/html") ? $mail->AltBody : $mail->Body) as $line) {
1976                         if(strlen($line) > 998) {
1977                                 $mail->Encoding = 'base64';
1978                                 break;
1979                         }
1980                 }
1981                 ////    HANDLE EMAIL FORMAT PREFERENCE
1982                 ///////////////////////////////////////////////////////////////////////
1983
1984                 return $mail;
1985         }
1986
1987         /**
1988          * Retrieve function from handlebody() to unit test easily
1989          * @param $mail
1990          * @return formatted $mail body
1991          */
1992         function handleBodyInHTMLformat($mail) {
1993                 global $current_user;
1994                 global $sugar_config;
1995                 // wp: if body is html, then insert new lines at 996 characters. no effect on client side
1996                 // due to RFC 2822 which limits email lines to 998
1997                 $mail->IsHTML(true);
1998                 $body = from_html(wordwrap($this->description_html, 996));
1999                 $mail->Body = $body;
2000
2001                 // cn: bug 9725
2002                 // new plan is to use the selected type (html or plain) to fill the other
2003                 $plainText = from_html($this->description_html);
2004                 $plainText = strip_tags(br2nl($plainText));
2005                 $mail->AltBody = $plainText;
2006                 $this->description = $plainText;
2007
2008                 $fileBasePath = "{$sugar_config['cache_dir']}images/";
2009                 $filePatternSearch = "{$sugar_config['cache_dir']}";
2010                 $filePatternSearch = str_replace("/", "\/", $filePatternSearch);
2011                 $filePatternSearch = $filePatternSearch . "images\/";
2012                 if(strpos($mail->Body, "\"{$fileBasePath}") !== FALSE)
2013                 {  //cache/images
2014                         $matches = array();
2015                         preg_match_all("/{$filePatternSearch}.+?\"/i", $mail->Body, $matches);
2016                         foreach($matches[0] as $match) {
2017                                 $filename = str_replace($fileBasePath, '', $match);
2018                                 $filename = urldecode(substr($filename, 0, -1));
2019                                 $cid = $filename;
2020                                 $file_location = clean_path(getcwd()."/{$sugar_config['cache_dir']}images/{$filename}");
2021                                 $mime_type = "image/".strtolower(substr($filename, strrpos($filename, ".")+1, strlen($filename)));
2022
2023                                 if(file_exists($file_location)) {
2024                                         $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $mime_type);
2025                                 }
2026                         }
2027
2028                         //replace references to cache with cid tag
2029                         $mail->Body = str_replace("/" . $fileBasePath,'cid:',$mail->Body);
2030                         $mail->Body = str_replace($fileBasePath,'cid:',$mail->Body);
2031                         // remove bad img line from outbound email
2032                         $regex = '#<img[^>]+src[^=]*=\"\/([^>]*?[^>]*)>#sim';
2033                         $mail->Body = preg_replace($regex, '', $mail->Body);
2034                 }
2035                 $fileBasePath = "{$sugar_config['upload_dir']}";
2036                 $filePatternSearch = "{$sugar_config['upload_dir']}";
2037                 $filePatternSearch = str_replace("/", "\/", $filePatternSearch);
2038                 if(strpos($mail->Body, "\"{$fileBasePath}") !== FALSE)
2039                 {
2040                         $matches = array();
2041                         preg_match_all("/{$filePatternSearch}.+?\"/i", $mail->Body, $matches);
2042                         foreach($matches[0] as $match) {
2043                                 $filename = str_replace($fileBasePath, '', $match);
2044                                 $filename = urldecode(substr($filename, 0, -1));
2045                                 $cid = $filename;
2046                                 $file_location = clean_path(getcwd()."/{$sugar_config['upload_dir']}{$filename}");
2047                                 $mime_type = "image/".strtolower(substr($filename, strrpos($filename, ".")+1, strlen($filename)));
2048
2049                                 if(file_exists($file_location)) {
2050                                         $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $mime_type);
2051                                 }
2052                         }
2053
2054                         //replace references to cache with cid tag
2055                         $mail->Body = str_replace("/" . $fileBasePath,'cid:',$mail->Body);
2056                         $mail->Body = str_replace($fileBasePath,'cid:',$mail->Body);
2057
2058                         // remove bad img line from outbound email
2059                         $regex = '#<img[^>]+src[^=]*=\"\/([^>]*?[^>]*)>#sim';
2060                         $mail->Body = preg_replace($regex, '', $mail->Body);
2061                 }
2062
2063                 //Replace any embeded images using the secure entryPoint for src url.
2064                 $noteImgRegex = "/<img[^>]*[\s]+src[^=]*=\"index.php\?entryPoint=download\&amp;id=([^\&]*)[^>]*>/im";
2065         $embededImageMatches = array();
2066         preg_match_all($noteImgRegex, $mail->Body, $embededImageMatches,PREG_SET_ORDER);
2067
2068         foreach ($embededImageMatches as $singleMatch )
2069         {
2070             $fullMatch = $singleMatch[0];
2071             $noteId = $singleMatch[1];
2072             $cid = $noteId;
2073             $filename = $noteId;
2074
2075             //Retrieve note for mimetype
2076             $tmpNote = new Note();
2077             $tmpNote->retrieve($noteId);
2078             //Replace the src part of img tag with new cid tag
2079             $cidRegex = "/src=\"([^\"]*)\"/im";
2080             $replaceMatch = preg_replace($cidRegex, "src=\"cid:$noteId\"", $fullMatch);
2081
2082             //Replace the body, old tag for new tag
2083             $mail->Body = str_replace($fullMatch, $replaceMatch, $mail->Body);
2084
2085             //Attach the file
2086             $file_location = clean_path(getcwd()."/{$sugar_config['upload_dir']}{$noteId}");
2087
2088             if(file_exists($file_location))
2089                                         $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64', $tmpNote->file_mime_type);
2090         }
2091         //End Replace
2092
2093
2094                 $mail->Body = from_html($mail->Body);
2095         }
2096
2097         /**
2098          * Sends Email
2099          * @return bool True on success
2100          */
2101         function send() {
2102                 global $mod_strings,$app_strings;
2103                 global $current_user;
2104                 global $sugar_config;
2105                 global $locale;
2106         $OBCharset = $locale->getPrecedentPreference('default_email_charset');
2107                 $mail = new SugarPHPMailer();
2108
2109                 foreach ($this->to_addrs_arr as $addr_arr) {
2110                         if ( empty($addr_arr['display'])) {
2111                                 $mail->AddAddress($addr_arr['email'], "");
2112                         } else {
2113                                 $mail->AddAddress($addr_arr['email'],$locale->translateCharsetMIME(trim( $addr_arr['display']), 'UTF-8', $OBCharset));
2114                         }
2115                 }
2116                 foreach ($this->cc_addrs_arr as $addr_arr) {
2117                         if ( empty($addr_arr['display'])) {
2118                                 $mail->AddCC($addr_arr['email'], "");
2119                         } else {
2120                                 $mail->AddCC($addr_arr['email'],$locale->translateCharsetMIME(trim($addr_arr['display']), 'UTF-8', $OBCharset));
2121                         }
2122                 }
2123
2124                 foreach ($this->bcc_addrs_arr as $addr_arr) {
2125                         if ( empty($addr_arr['display'])) {
2126                                 $mail->AddBCC($addr_arr['email'], "");
2127                         } else {
2128                                 $mail->AddBCC($addr_arr['email'],$locale->translateCharsetMIME(trim($addr_arr['display']), 'UTF-8', $OBCharset));
2129                         }
2130                 }
2131
2132                 $mail = $this->setMailer($mail);
2133
2134                 // FROM ADDRESS
2135                 if(!empty($this->from_addr)) {
2136                         $mail->From = $this->from_addr;
2137                 } else {
2138                         $mail->From = $current_user->getPreference('mail_fromaddress');
2139                         $this->from_addr = $mail->From;
2140                 }
2141                 // FROM NAME
2142                 if(!empty($this->from_name)) {
2143                         $mail->FromName = $this->from_name;
2144                 } else {
2145                         $mail->FromName =  $current_user->getPreference('mail_fromname');
2146                         $this->from_name = $mail->FromName;
2147                 }
2148
2149                 //Reply to information for case create and autoreply.
2150                 if(!empty($this->reply_to_name)) {
2151                         $ReplyToName = $this->reply_to_name;
2152                 } else {
2153                         $ReplyToName = $mail->FromName;
2154                 }
2155                 if(!empty($this->reply_to_addr)) {
2156                         $ReplyToAddr = $this->reply_to_addr;
2157                 } else {
2158                         $ReplyToAddr = $mail->From;
2159                 }
2160                 $mail->Sender = $mail->From; /* set Return-Path field in header to reduce spam score in emails sent via Sugar's Email module */
2161                 $mail->AddReplyTo($ReplyToAddr,$locale->translateCharsetMIME(trim($ReplyToName), 'UTF-8', $OBCharset));
2162
2163                 //$mail->Subject = html_entity_decode($this->name, ENT_QUOTES, 'UTF-8');
2164                 $mail->Subject = $this->name;
2165
2166                 ///////////////////////////////////////////////////////////////////////
2167                 ////    ATTACHMENTS
2168                 foreach($this->saved_attachments as $note) {
2169                         $mime_type = 'text/plain';
2170                         if($note->object_name == 'Note') {
2171                                 if(!empty($note->file->temp_file_location) && is_file($note->file->temp_file_location)) { // brandy-new file upload/attachment
2172                                         $file_location = $sugar_config['upload_dir'].$note->id;
2173                                         $filename = $note->file->original_file_name;
2174                                         $mime_type = $note->file->mime_type;
2175                                 } else { // attachment coming from template/forward
2176                                         $file_location = rawurldecode(UploadFile::get_file_path($note->filename,$note->id));
2177                                         // cn: bug 9723 - documents from EmailTemplates sent with Doc Name, not file name.
2178                                         $filename = !empty($note->filename) ? $note->filename : $note->name;
2179                                         $mime_type = $note->file_mime_type;
2180                                 }
2181                         } elseif($note->object_name == 'DocumentRevision') { // from Documents
2182                                 $filePathName = $note->id;
2183                                 // cn: bug 9723 - Emails with documents send GUID instead of Doc name
2184                                 $filename = $note->getDocumentRevisionNameForDisplay();
2185                                 $file_location = getcwd().'/'.$GLOBALS['sugar_config']['upload_dir'].$filePathName;
2186                                 $mime_type = $note->file_mime_type;
2187                         }
2188
2189                         // strip out the "Email attachment label if exists
2190                         $filename = str_replace($mod_strings['LBL_EMAIL_ATTACHMENT'].': ', '', $filename);
2191
2192                         //is attachment in our list of bad files extensions?  If so, append .txt to file location
2193                         //get position of last "." in file name
2194                         $file_ext_beg = strrpos($file_location,".");
2195                         $file_ext = "";
2196                         //get file extension
2197                         if($file_ext_beg >0){
2198                                 $file_ext = substr($file_location, $file_ext_beg+1 );
2199                         }
2200                         //check to see if this is a file with extension located in "badext"
2201                         foreach($sugar_config['upload_badext'] as $badExt) {
2202                         if(strtolower($file_ext) == strtolower($badExt)) {
2203                                 //if found, then append with .txt to filename and break out of lookup
2204                                 //this will make sure that the file goes out with right extension, but is stored
2205                                 //as a text in db.
2206                                 $file_location = $file_location . ".txt";
2207                                 break; // no need to look for more
2208                         }
2209                 }
2210                         $mail->AddAttachment($file_location,$locale->translateCharsetMIME(trim($filename), 'UTF-8', $OBCharset), 'base64', $mime_type);
2211
2212                         // embedded Images
2213                         if($note->embed_flag == true) {
2214                                 $cid = $filename;
2215                                 $mail->AddEmbeddedImage($file_location, $cid, $filename, 'base64',$mime_type);
2216                         }
2217                 }
2218                 ////    END ATTACHMENTS
2219                 ///////////////////////////////////////////////////////////////////////
2220
2221                 $mail = $this->handleBody($mail);
2222
2223                 $GLOBALS['log']->debug('Email sending --------------------- ');
2224
2225                 ///////////////////////////////////////////////////////////////////////
2226                 ////    I18N TRANSLATION
2227                 $mail->prepForOutbound();
2228                 ////    END I18N TRANSLATION
2229                 ///////////////////////////////////////////////////////////////////////
2230
2231                 if($mail->Send()) {
2232                         ///////////////////////////////////////////////////////////////////
2233                         ////    INBOUND EMAIL HANDLING
2234                         // mark replied
2235                         if(!empty($_REQUEST['inbound_email_id'])) {
2236                                 $ieMail = new Email();
2237                                 $ieMail->retrieve($_REQUEST['inbound_email_id']);
2238                                 $ieMail->status = 'replied';
2239                                 $ieMail->save();
2240                         }
2241                         $GLOBALS['log']->debug(' --------------------- buh bye -- sent successful');
2242                         ////    END INBOUND EMAIL HANDLING
2243                         ///////////////////////////////////////////////////////////////////
2244                         return true;
2245                 }
2246             $GLOBALS['log']->debug($app_strings['LBL_EMAIL_ERROR_PREPEND'].$mail->ErrorInfo);
2247                 return false;
2248         }
2249
2250
2251         function listviewACLHelper(){
2252                 $array_assign = parent::listviewACLHelper();
2253                 $is_owner = false;
2254                 if(!empty($this->parent_name)){
2255
2256                         if(!empty($this->parent_name_owner)){
2257                                 global $current_user;
2258                                 $is_owner = $current_user->id == $this->parent_name_owner;
2259                         }
2260                 }
2261                 if(!ACLController::moduleSupportsACL($this->parent_type) || ACLController::checkAccess($this->parent_type, 'view', $is_owner)){
2262                         $array_assign['PARENT'] = 'a';
2263                 } else {
2264                         $array_assign['PARENT'] = 'span';
2265                 }
2266                 $is_owner = false;
2267                 if(!empty($this->contact_name)) {
2268                         if(!empty($this->contact_name_owner)) {
2269                                 global $current_user;
2270                                 $is_owner = $current_user->id == $this->contact_name_owner;
2271                         }
2272                 }
2273                 if(ACLController::checkAccess('Contacts', 'view', $is_owner)) {
2274                         $array_assign['CONTACT'] = 'a';
2275                 } else {
2276                         $array_assign['CONTACT'] = 'span';
2277                 }
2278
2279                 return $array_assign;
2280         }
2281
2282         function getSystemDefaultEmail() {
2283                 $email = array();
2284
2285                 $r1 = $this->db->query('SELECT config.value FROM config WHERE name=\'fromaddress\'');
2286                 $r2 = $this->db->query('SELECT config.value FROM config WHERE name=\'fromname\'');
2287                 $a1 = $this->db->fetchByAssoc($r1);
2288                 $a2 = $this->db->fetchByAssoc($r2);
2289
2290                 $email['email'] = $a1['value'];
2291                 $email['name']  = $a2['value'];
2292
2293                 return $email;
2294         }
2295
2296
2297     function create_new_list_query($order_by, $where,$filter=array(),$params=array(), $show_deleted = 0,$join_type='', $return_array = false,$parentbean=null, $singleSelect = false) {
2298
2299                 if ($return_array) {
2300                         return parent::create_new_list_query($order_by, $where,$filter,$params, $show_deleted,$join_type, $return_array,$parentbean, $singleSelect);
2301                 }
2302         $custom_join = $this->custom_fields->getJOIN();
2303
2304                 $query = "SELECT ".$this->table_name.".*, users.user_name as assigned_user_name\n";
2305
2306         if($custom_join){
2307                         $query .= $custom_join['select'];
2308                 }
2309         $query .= " FROM emails\n";
2310         if ($where != "" && (strpos($where, "contacts.first_name") > 0))  {
2311                         $query .= " LEFT JOIN emails_beans ON emails.id = emails_beans.email_id\n";
2312         }
2313
2314         $query .= " LEFT JOIN users ON emails.assigned_user_id=users.id \n";
2315         if ($where != "" && (strpos($where, "contacts.first_name") > 0))  {
2316
2317         $query .= " JOIN contacts ON contacts.id= emails_beans.bean_id AND emails_beans.bean_module='Contacts' and contacts.deleted=0 \n";
2318         }
2319
2320                 if($custom_join){
2321                         $query .= $custom_join['join'];
2322                 }
2323
2324                 if($show_deleted == 0) {
2325                         $where_auto = " emails.deleted=0 \n";
2326                 }else if($show_deleted == 1){
2327                         $where_auto = " emails.deleted=1 \n";
2328                 }
2329
2330         if($where != "")
2331                         $query .= "WHERE $where AND ".$where_auto;
2332                 else
2333                         $query .= "WHERE ".$where_auto;
2334
2335                 if($order_by != "")
2336                         $query .= " ORDER BY $order_by";
2337                 else
2338                         $query .= " ORDER BY date_sent DESC";
2339
2340                 return $query;
2341     } // fn
2342
2343
2344         function fill_in_additional_list_fields() {
2345                 global $timedate;
2346                 $this->fill_in_additional_detail_fields();
2347
2348                 $this->link_action = 'DetailView';
2349                 ///////////////////////////////////////////////////////////////////////
2350                 //populate attachment_image, used to display attachment icon.
2351                 $query =  "select 1 from notes where notes.parent_id = '$this->id' and notes.deleted = 0";
2352                 $result =$this->db->query($query,true," Error filling in additional list fields: ");
2353
2354                 $row = $this->db->fetchByAssoc($result);
2355
2356                 if ($row !=null) {
2357                         $this->attachment_image = SugarThemeRegistry::current()->getImage('attachment',"","","");
2358                 } else {
2359                         $this->attachment_image = SugarThemeRegistry::current()->getImage('blank',"","","");
2360                 }
2361                 ///////////////////////////////////////////////////////////////////////
2362                 if(empty($this->contact_id) && !empty($this->parent_id) && !empty($this->parent_type) && $this->parent_type === 'Contacts' && !empty($this->parent_name) ){
2363                         $this->contact_id = $this->parent_id;
2364                         $this->contact_name = $this->parent_name;
2365                 }
2366         }
2367
2368         function fill_in_additional_detail_fields() {
2369                 global $app_list_strings,$mod_strings;
2370                 // Fill in the assigned_user_name
2371                 $this->assigned_user_name = get_assigned_user_name($this->assigned_user_id, '');
2372                 //if ($this->parent_type == 'Contacts') {
2373                         $query  = "SELECT contacts.first_name, contacts.last_name, contacts.phone_work, contacts.id, contacts.assigned_user_id contact_name_owner, 'Contacts' contact_name_mod FROM contacts, emails_beans ";
2374                         $query .= "WHERE emails_beans.email_id='$this->id' AND emails_beans.bean_id=contacts.id AND emails_beans.bean_module = 'Contacts' AND emails_beans.deleted=0 AND contacts.deleted=0";
2375                         if(!empty($this->parent_id)){
2376                                 $query .= " AND contacts.id= '".$this->parent_id."' ";
2377                         }else if(!empty($_REQUEST['record'])){
2378                                 $query .= " AND contacts.id= '".$_REQUEST['record']."' ";
2379                         }
2380                         $result =$this->db->query($query,true," Error filling in additional detail fields: ");
2381
2382                         // Get the id and the name.
2383                         $row = $this->db->fetchByAssoc($result);
2384                         if($row != null)
2385                         {
2386
2387                                 $contact = new Contact();
2388                                 $contact->retrieve($row['id']);
2389                                 $this->contact_name = $contact->full_name;
2390                                 $this->contact_phone = $row['phone_work'];
2391                                 $this->contact_id = $row['id'];
2392                                 $this->contact_email = $contact->emailAddress->getPrimaryAddress($contact);
2393                                 $this->contact_name_owner = $row['contact_name_owner'];
2394                                 $this->contact_name_mod = $row['contact_name_mod'];
2395                                 $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name");
2396                                 $GLOBALS['log']->debug("Call($this->id): contact_phone = $this->contact_phone");
2397                                 $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id");
2398                                 $GLOBALS['log']->debug("Call($this->id): contact_email1 = $this->contact_email");
2399                         }
2400                         else {
2401                                 $this->contact_name = '';
2402                                 $this->contact_phone = '';
2403                                 $this->contact_id = '';
2404                                 $this->contact_email = '';
2405                                 $this->contact_name_owner = '';
2406                                 $this->contact_name_mod = '';
2407                                 $GLOBALS['log']->debug("Call($this->id): contact_name = $this->contact_name");
2408                                 $GLOBALS['log']->debug("Call($this->id): contact_phone = $this->contact_phone");
2409                                 $GLOBALS['log']->debug("Call($this->id): contact_id = $this->contact_id");
2410                                 $GLOBALS['log']->debug("Call($this->id): contact_email1 = $this->contact_email");
2411                         }
2412                 //}
2413                 $this->created_by_name = get_assigned_user_name($this->created_by);
2414                 $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
2415
2416                 $this->link_action = 'DetailView';
2417
2418                 if(!empty($this->type)) {
2419                         if($this->type == 'out' && $this->status == 'send_error') {
2420                                 $this->type_name = $mod_strings['LBL_NOT_SENT'];
2421                         } else {
2422                                 $this->type_name = $app_list_strings['dom_email_types'][$this->type];
2423                         }
2424
2425                         if(($this->type == 'out' && $this->status == 'send_error') || $this->type == 'draft') {
2426                                 $this->link_action = 'EditView';
2427                         }
2428                 }
2429
2430                 //todo this  isset( $app_list_strings['dom_email_status'][$this->status]) is hack for 3261.
2431                 if(!empty($this->status) && isset( $app_list_strings['dom_email_status'][$this->status])) {
2432                         $this->status_name = $app_list_strings['dom_email_status'][$this->status];
2433                 }
2434
2435                 if ( empty($this->name ) &&  empty($_REQUEST['record'])) {
2436                         $this->name = $mod_strings['LBL_NO_SUBJECT'];
2437                 }
2438
2439                 $this->fill_in_additional_parent_fields();
2440         }
2441
2442
2443
2444         function create_export_query(&$order_by, &$where) {
2445                 $contact_required = stristr($where, "contacts");
2446                 $custom_join = $this->custom_fields->getJOIN(true, true,$where);
2447
2448                 if($contact_required) {
2449                         $query = "SELECT emails.*, contacts.first_name, contacts.last_name";
2450                         if($custom_join) {
2451                                 $query .= $custom_join['select'];
2452                         }
2453
2454                         $query .= " FROM contacts, emails, emails_contacts ";
2455                         $where_auto = "emails_contacts.contact_id = contacts.id AND emails_contacts.email_id = emails.id AND emails.deleted=0 AND contacts.deleted=0";
2456                 } else {
2457                         $query = 'SELECT emails.*';
2458                         if($custom_join) {
2459                                 $query .= $custom_join['select'];
2460                         }
2461
2462             $query .= ' FROM emails ';
2463             $where_auto = "emails.deleted=0";
2464                 }
2465
2466                 if($custom_join){
2467                         $query .= $custom_join['join'];
2468                 }
2469
2470                 if($where != "")
2471                         $query .= "where $where AND ".$where_auto;
2472         else
2473                         $query .= "where ".$where_auto;
2474
2475         if($order_by != "")
2476                         $query .= " ORDER BY $order_by";
2477         else
2478                         $query .= " ORDER BY emails.name";
2479         return $query;
2480     }
2481
2482         function get_list_view_data() {
2483                 global $app_list_strings;
2484                 global $theme;
2485                 global $current_user;
2486                 global $timedate;
2487                 global $mod_strings;
2488
2489                 $email_fields = $this->get_list_view_array();
2490                 $this->retrieveEmailText();
2491                 $email_fields['FROM_ADDR'] = $this->from_addr_name;
2492                 $mod_strings = return_module_language($GLOBALS['current_language'], 'Emails'); // hard-coding for Home screen ListView
2493
2494                 if($this->status != 'replied') {
2495                         $email_fields['QUICK_REPLY'] = '<a  href="index.php?module=Emails&action=Compose&replyForward=true&reply=reply&record='.$this->id.'&inbound_email_id='.$this->id.'">'.$mod_strings['LNK_QUICK_REPLY'].'</a>';
2496                         $email_fields['STATUS'] = ($email_fields['REPLY_TO_STATUS'] == 1 ? $mod_strings['LBL_REPLIED'] : $email_fields['STATUS']);
2497                 } else {
2498                         $email_fields['QUICK_REPLY'] = $mod_strings['LBL_REPLIED'];
2499                 }
2500                 if(!empty($this->parent_type)) {
2501                         $email_fields['PARENT_MODULE'] = $this->parent_type;
2502                 } else {
2503                         switch($this->intent) {
2504                                 case 'support':
2505                                         $email_fields['CREATE_RELATED'] = '<a href="index.php?module=Cases&action=EditView&inbound_email_id='.$this->id.'" ><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('CreateCases.gif').'">'.$mod_strings['LBL_CREATE_CASE'].'</a>';
2506                                 break;
2507
2508                                 case 'sales':
2509                                         $email_fields['CREATE_RELATED'] = '<a href="index.php?module=Leads&action=EditView&inbound_email_id='.$this->id.'" ><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('CreateLeads.gif').'">'.$mod_strings['LBL_CREATE_LEAD'].'</a>';
2510                                 break;
2511
2512                                 case 'contact':
2513                                         $email_fields['CREATE_RELATED'] = '<a href="index.php?module=Contacts&action=EditView&inbound_email_id='.$this->id.'" ><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('CreateContacts.gif').'">'.$mod_strings['LBL_CREATE_CONTACT'].'</a>';
2514                                 break;
2515
2516                                 case 'bug':
2517                                         $email_fields['CREATE_RELATED'] = '<a href="index.php?module=Bugs&action=EditView&inbound_email_id='.$this->id.'" ><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('CreateBugs.gif').'">'.$mod_strings['LBL_CREATE_BUG'].'</a>';
2518                                 break;
2519
2520                                 case 'task':
2521                                         $email_fields['CREATE_RELATED'] = '<a href="index.php?module=Tasks&action=EditView&inbound_email_id='.$this->id.'" ><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('CreateTasks.gif').'">'.$mod_strings['LBL_CREATE_TASK'].'</a>';
2522                                 break;
2523
2524                                 case 'bounce':
2525                                 break;
2526
2527                                 case 'pick':
2528                                 // break;
2529
2530                                 case 'info':
2531                                 //break;
2532
2533                                 default:
2534                                         $email_fields['CREATE_RELATED'] = $this->quickCreateForm();
2535                                 break;
2536                         }
2537
2538                 }
2539
2540                 //BUG 17098 - MFH changed $this->from_addr to $this->to_addrs
2541                 $email_fields['CONTACT_NAME']           = empty($this->contact_name) ? '</a>'.$this->trimLongTo($this->to_addrs).'<a>' : $this->contact_name;
2542                 $email_fields['CONTACT_ID']             = empty($this->contact_id) ? '' : $this->contact_id;
2543                 $email_fields['ATTACHMENT_IMAGE']       = $this->attachment_image;
2544                 $email_fields['LINK_ACTION']            = $this->link_action;
2545
2546         if(isset($this->type_name))
2547                 $email_fields['TYPE_NAME'] = $this->type_name;
2548
2549                 return $email_fields;
2550         }
2551
2552     function quickCreateForm() {
2553         global $mod_strings, $app_strings, $currentModule, $current_language;
2554
2555         // Coming from the home page via Dashlets
2556         if($currentModule != 'Email')
2557                 $mod_strings = return_module_language($current_language, 'Emails');
2558         return $mod_strings['LBL_QUICK_CREATE']."&nbsp;<a id='$this->id' onclick='return quick_create_overlib(\"{$this->id}\", \"".SugarThemeRegistry::current()->__toString()."\");' href=\"#\" >".SugarThemeRegistry::current()->getImage("advanced_search","alt='".$mod_strings['LBL_QUICK_CREATE']."'  border='0' align='absmiddle'")."</a>";
2559     }
2560
2561     /**
2562      * Searches all imported emails and returns the result set as an array.
2563      *
2564      */
2565     function searchImportedEmails($sort = '', $direction='')
2566     {
2567         require_once('include/TimeDate.php');
2568                 global $timedate;
2569                 global $current_user;
2570                 global $beanList;
2571                 global $sugar_config;
2572                 global $app_strings;
2573
2574                 $emailSettings = $current_user->getPreference('emailSettings', 'Emails');
2575                 // cn: default to a low number until user specifies otherwise
2576                 if(empty($emailSettings['showNumInList']))
2577                         $pageSize = 20;
2578         else
2579             $pageSize = $emailSettings['showNumInList'];
2580
2581         if( isset($_REQUEST['start']) && isset($_REQUEST['limit']) )
2582                $page = ceil($_REQUEST['start'] / $_REQUEST['limit']) + 1;
2583             else
2584                $page = 1;
2585
2586              //Determine sort ordering
2587
2588              //Sort ordering parameters in the request do not coincide with actual column names
2589              //so we need to remap them.
2590              $hrSortLocal = array(
2591             'flagged' => 'type',
2592             'status'  => 'reply_to_status',
2593             'from'    => 'emails_text.from_addr',
2594             'subject' => 'name',
2595             'date'    => 'date_sent',
2596             'AssignedTo' => 'assigned_user_id',
2597             'flagged' => 'flagged'
2598         );
2599
2600              $sort = !empty($_REQUEST['sort']) ? $_REQUEST['sort'] : "";
2601          $direction = !empty($_REQUEST['dir']) ? $_REQUEST['dir'] : "";
2602
2603          $order = ( !empty($sort) && !empty($direction) ) ? " ORDER BY {$hrSortLocal[$sort]} {$direction}" : "";
2604
2605          //Get our main query.
2606                 $fullQuery = $this->_genereateSearchImportedEmailsQuery();
2607
2608                 //Perform a count query needed for pagination.
2609                 $countQuery = $this->create_list_count_query($fullQuery);
2610                 $count_rs = $this->db->query($countQuery, false, 'Error executing count query for imported emails search');
2611                 $count_row = $this->db->fetchByAssoc($count_rs);
2612                 $total_count = ($count_row != null) ? $count_row['c'] : 0;
2613
2614         $start = ($page - 1) * $pageSize;
2615
2616         //Execute the query
2617                 $rs = $this->db->limitQuery($fullQuery . $order, $start, $pageSize);
2618
2619                 $return = array();
2620
2621                 while($a = $this->db->fetchByAssoc($rs)) {
2622                         $temp = array();
2623                         $temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1;
2624                         $temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1;
2625                         $temp['subject'] = $a['name'];
2626                         $temp['date']   = $timedate->to_display_date_time($a['date_sent']);
2627                         $temp['uid'] = $a['id'];
2628                         $temp['ieId'] = $a['mailbox_id'];
2629                         $temp['site_url'] = $sugar_config['site_url'];
2630                         $temp['seen'] = ($a['status'] == 'unread') ? 0 : 1;
2631                         $temp['type'] = $a['type'];
2632                         $temp['mbox'] = 'sugar::Emails';
2633                         $temp['hasAttach'] =  $this->doesImportedEmailHaveAttachment($a['id']);
2634                         //To and from addresses may be stored in emails_text, if nothing is found, revert to
2635                         //regular email addresses.
2636                         $temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']);
2637                         $temp['from']   = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']);
2638                         if( empty($temp['from']) || empty($temp['to_addrs']) )
2639                         {
2640                         //Retrieve email addresses seperatly.
2641                         $tmpEmail = new Email();
2642                         $tmpEmail->id = $a['id'];
2643                         $tmpEmail->retrieveEmailAddresses();
2644                         $temp['from'] = $tmpEmail->from_addr;
2645                         $temp['to_addrs'] = $tmpEmail->to_addrs;
2646                         }
2647
2648                         $return[] = $temp;
2649                 }
2650
2651                 $metadata = array();
2652                 $metadata['totalCount'] = $total_count;
2653                 $metadata['out'] = $return;
2654
2655                 return $metadata;
2656     }
2657
2658     /**
2659      * Determine if an imported email has an attachment by examining the relationship to notes.
2660      *
2661      * @param string $id
2662      * @return boolean
2663      */
2664     function doesImportedEmailHaveAttachment($id)
2665         {
2666            $hasAttachment = FALSE;
2667            $query = "SELECT id FROM notes where parent_id='$id' AND parent_type='Emails' AND file_mime_type is not null AND deleted=0";
2668            $rs = $this->db->limitQuery($query, 0, 1);
2669            $row = $this->db->fetchByAssoc($rs);
2670            if( !empty($row['id']) )
2671                $hasAttachment = TRUE;
2672
2673            return (int) $hasAttachment;
2674         }
2675
2676     /**
2677      * Generate the query used for searching imported emails.
2678      *
2679      * @return String Query to be executed.
2680      */
2681     function _genereateSearchImportedEmailsQuery()
2682     {
2683                 global $timedate;
2684
2685         $additionalWhereClause = $this->_generateSearchImportWhereClause();
2686
2687         $query = array();
2688         $fullQuery = "";
2689         $query['select'] = "emails.id , emails.mailbox_id, emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status,
2690                                       emails_text.from_addr, emails_text.to_addrs  FROM emails ";
2691
2692         $query['joins'] = " JOIN emails_text on emails.id = emails_text.email_id ";
2693
2694         //Handle from and to addr joins
2695         if( !empty($_REQUEST['from_addr']) )
2696         {
2697             $query['joins'] .= "INNER JOIN emails_email_addr_rel er_from ON er_from.email_id = emails.id AND er_from.deleted = 0 INNER JOIN email_addresses ea_from ON ea_from.id = er_from.email_address_id
2698                                 AND er_from.address_type='from' AND ea_from.email_address='" . strtolower($_REQUEST['from_addr']) . "'";
2699         }
2700
2701         if( !empty($_REQUEST['to_addrs'])  )
2702         {
2703             $query['joins'] .= "INNER JOIN emails_email_addr_rel er_to ON er_to.email_id = emails.id AND er_to.deleted = 0 INNER JOIN email_addresses ea_to ON ea_to.id = er_to.email_address_id
2704                                     AND er_to.address_type='to' AND ea_to.email_address='" . strtolower($_REQUEST['to_addrs']) . "'";
2705         }
2706
2707         $query['where'] = " WHERE (emails.type= 'inbound' OR emails.type='archived' OR emails.type='out') AND emails.deleted = 0 ";
2708                 if( !empty($additionalWhereClause) )
2709             $query['where'] .= "AND $additionalWhereClause";
2710
2711         //If we are explicitly looking for attachments.  Do not use a distinct query as the to_addr is defined
2712         //as a text which equals clob in oracle and the distinct query can not be executed correctly.
2713         $addDistinctKeyword = "";
2714         if( !empty($_REQUEST['attachmentsSearch']) &&  $_REQUEST['attachmentsSearch'] == 1) //1 indicates yes
2715             $query['where'] .= " AND EXISTS ( SELECT id FROM notes n WHERE n.parent_id = emails.id AND n.deleted = 0 AND n.filename is not null )";
2716         else if( !empty($_REQUEST['attachmentsSearch']) &&  $_REQUEST['attachmentsSearch'] == 2 )
2717              $query['where'] .= " AND NOT EXISTS ( SELECT id FROM notes n WHERE n.parent_id = emails.id AND n.deleted = 0 AND n.filename is not null )";
2718
2719         $fullQuery = "SELECT " . $query['select'] . " " . $query['joins'] . " " . $query['where'];
2720
2721         return $fullQuery;
2722     }
2723         /**
2724      * Generate the where clause for searching imported emails.
2725      *
2726      */
2727     function _generateSearchImportWhereClause()
2728     {
2729         global $timedate;
2730
2731         //The clear button was removed so if a user removes the asisgned user name, do not process the id.
2732         if( empty($_REQUEST['assigned_user_name']) && !empty($_REQUEST['assigned_user_id'])  )
2733             unset($_REQUEST['assigned_user_id']);
2734
2735         $availableSearchParam = array('name' => array('table_name' =>'emails'),
2736                                         'data_parent_id_search' => array('table_name' =>'emails','db_key' => 'parent_id','opp' => '='),
2737                                         'assigned_user_id' => array('table_name' => 'emails', 'opp' => '=') );
2738
2739                 $additionalWhereClause = array();
2740                 foreach ($availableSearchParam as $key => $properties)
2741                 {
2742                       if( !empty($_REQUEST[$key]) )
2743                       {
2744                           $db_key =  isset($properties['db_key']) ? $properties['db_key'] : $key;
2745                           $searchValue = $_REQUEST[$key];
2746
2747                           $opp = isset($properties['opp']) ? $properties['opp'] : 'like';
2748                           if($opp == 'like')
2749                               $searchValue = $searchValue . "%";
2750
2751                           $additionalWhereClause[] = "{$properties['table_name']}.$db_key $opp '$searchValue' ";
2752                       }
2753         }
2754
2755         $isDateFromSearchSet = !empty($_REQUEST['dateFrom']);
2756         $isdateToSearchSet = !empty($_REQUEST['dateTo']);
2757         $bothDateRangesSet = $isDateFromSearchSet & $isdateToSearchSet;
2758
2759         //Hanlde date from and to seperately
2760         if($bothDateRangesSet)
2761         {
2762             $dbFormatDateFrom = $timedate->to_db_date($_REQUEST['dateFrom'], false);
2763             $dbFormatDateFrom = db_convert("'" . $dbFormatDateFrom . "'",'datetime');
2764
2765             $dbFormatDateTo = $timedate->to_db_date($_REQUEST['dateTo'], false);
2766             $dbFormatDateTo = db_convert("'" . $dbFormatDateTo . "'",'datetime');
2767
2768             $additionalWhereClause[] = "( emails.date_sent >= $dbFormatDateFrom AND
2769                                           emails.date_sent <= $dbFormatDateTo )";
2770         }
2771         elseif ($isdateToSearchSet)
2772         {
2773             $dbFormatDateTo = $timedate->to_db_date($_REQUEST['dateTo'], false);
2774             $dbFormatDateTo = db_convert("'" . $dbFormatDateTo . "'",'datetime');
2775             $additionalWhereClause[] = "emails.date_sent <= $dbFormatDateTo ";
2776         }
2777         elseif ($isDateFromSearchSet)
2778         {
2779             $dbFormatDateFrom = $timedate->to_db_date($_REQUEST['dateFrom'], false);
2780             $dbFormatDateFrom = db_convert("'" . $dbFormatDateFrom . "'",'datetime');
2781             $additionalWhereClause[] = "emails.date_sent >= $dbFormatDateFrom ";
2782         }
2783
2784         $additionalWhereClause = implode(" AND ", $additionalWhereClause);
2785
2786         return $additionalWhereClause;
2787     }
2788
2789
2790
2791         /**
2792          * takes a long TO: string of emails and returns the first appended by an
2793          * elipse
2794          */
2795         function trimLongTo($str) {
2796                 if(strpos($str, ',')) {
2797                         $exStr = explode(',', $str);
2798                         return $exStr[0].'...';
2799                 } elseif(strpos($str, ';')) {
2800                         $exStr = explode(';', $str);
2801                         return $exStr[0].'...';
2802                 } else {
2803                         return $str;
2804                 }
2805         }
2806
2807         function get_summary_text() {
2808                 return $this->name;
2809         }
2810
2811
2812
2813         function distributionForm($where) {
2814                 global $app_list_strings;
2815                 global $app_strings;
2816                 global $mod_strings;
2817                 global $theme;
2818                 global $current_user;
2819
2820                 $distribution   = get_select_options_with_id($app_list_strings['dom_email_distribution'], '');
2821                 $_SESSION['distribute_where'] = $where;
2822
2823
2824                 $out = '<form name="Distribute" id="Distribute">';
2825                 $out .= get_form_header($mod_strings['LBL_DIST_TITLE'], '', false);
2826                 $out .=<<<eoq
2827                 <script>
2828                         enableQS(true);
2829                 </script>
2830 eoq;
2831                 $out .= '
2832                 <table cellpadding="0" cellspacing="0" width="100%" border="0">
2833                         <tr>
2834                                 <td>
2835                                         <script type="text/javascript">
2836
2837
2838                                                 function checkDeps(form) {
2839                                                         return;
2840                                                 }
2841
2842                                                 function mySubmit() {
2843                                                         var assform = document.getElementById("Distribute");
2844                                                         var select = document.getElementById("userSelect");
2845                                                         var assign1 = assform.r1.checked;
2846                                                         var assign2 = assform.r2.checked;
2847                                                         var dist = assform.dm.value;
2848                                                         var assign = false;
2849                                                         var users = false;
2850                                                         var rules = false;
2851                                                         var warn1 = "'.$mod_strings['LBL_WARN_NO_USERS'].'";
2852                                                         var warn2 = "";
2853
2854                                                         if(assign1 || assign2) {
2855                                                                 assign = true;
2856
2857                                                         }
2858
2859                                                         for(i=0; i<select.options.length; i++) {
2860                                                                 if(select.options[i].selected == true) {
2861                                                                         users = true;
2862                                                                         warn1 = "";
2863                                                                 }
2864                                                         }
2865
2866                                                         if(dist != "") {
2867                                                                 rules = true;
2868                                                         } else {
2869                                                                 warn2 = "'.$mod_strings['LBL_WARN_NO_DIST'].'";
2870                                                         }
2871
2872                                                         if(assign && users && rules) {
2873
2874                                                                 if(document.getElementById("r1").checked) {
2875                                                                         var mu = document.getElementById("MassUpdate");
2876                                                                         var grabbed = "";
2877
2878                                                                         for(i=0; i<mu.elements.length; i++) {
2879                                                                                 if(mu.elements[i].type == "checkbox" && mu.elements[i].checked && mu.elements[i].name.value != "massall") {
2880                                                                                         if(grabbed != "") { grabbed += "::"; }
2881                                                                                         grabbed += mu.elements[i].value;
2882                                                                                 }
2883                                                                         }
2884                                                                         var formgrab = document.getElementById("grabbed");
2885                                                                         formgrab.value = grabbed;
2886                                                                 }
2887                                                                 assform.submit();
2888                                                         } else {
2889                                                                 alert("'.$mod_strings['LBL_ASSIGN_WARN'].'" + "\n" + warn1 + "\n" + warn2);
2890                                                         }
2891                                                 }
2892
2893                                                 function submitDelete() {
2894                                                         if(document.getElementById("r1").checked) {
2895                                                                 var mu = document.getElementById("MassUpdate");
2896                                                                 var grabbed = "";
2897
2898                                                                 for(i=0; i<mu.elements.length; i++) {
2899                                                                         if(mu.elements[i].type == "checkbox" && mu.elements[i].checked && mu.elements[i].name != "massall") {
2900                                                                                 if(grabbed != "") { grabbed += "::"; }
2901                                                                                 grabbed += mu.elements[i].value;
2902                                                                         }
2903                                                                 }
2904                                                                 var formgrab = document.getElementById("grabbed");
2905                                                                 formgrab.value = grabbed;
2906                                                         }
2907                                                         if(grabbed == "") {
2908                                                                 alert("'.$mod_strings['LBL_MASS_DELETE_ERROR'].'");
2909                                                         } else {
2910                                                                 document.getElementById("Distribute").submit();
2911                                                         }
2912                                                 }
2913
2914                                         </script>
2915                                                 <input type="hidden" name="module" value="Emails">
2916                                                 <input type="hidden" name="action" id="action">
2917                                                 <input type="hidden" name="grabbed" id="grabbed">
2918
2919                                         <table cellpadding="1" cellspacing="0" width="100%" border="0" class="edit view">
2920                                                 <tr height="20">
2921                                                         <td scope="col" scope="row" NOWRAP align="center">
2922                                                                 &nbsp;'.$mod_strings['LBL_ASSIGN_SELECTED_RESULTS_TO'].'&nbsp;';
2923                                         $out .= $this->userSelectTable();
2924                                         $out .= '</td>
2925                                                         <td scope="col" scope="row" NOWRAP align="left">
2926                                                                 &nbsp;'.$mod_strings['LBL_USING_RULES'].'&nbsp;
2927                                                                 <select name="distribute_method" id="dm" onChange="checkDeps(this.form);">'.$distribution.'</select>
2928                                                         </td>';
2929
2930
2931                                         $out .= '</td>
2932                                                         </tr>';
2933
2934
2935                                         $out .= '<tr>
2936                                                                 <td scope="col" width="50%" scope="row" NOWRAP align="right" colspan="2">
2937                                                                 <input title="'.$mod_strings['LBL_BUTTON_DISTRIBUTE_TITLE'].'"
2938                                                                         id="dist_button"
2939                                                                         accessKey="'.$mod_strings['LBL_BUTTON_DISTRIBUTE_KEY'].'"
2940                                                                         class="button" onClick="AjaxObject.detailView.handleAssignmentDialogAssignAction();"
2941                                                                         type="button" name="button"
2942                                                                         value="  '.$mod_strings['LBL_BUTTON_DISTRIBUTE'].'  ">';
2943                                         $out .= '</tr>
2944                                         </table>
2945                                 </td>
2946                         </tr>
2947                 </table>
2948                 </form>';
2949         return $out;
2950         }
2951
2952         function userSelectTable() {
2953                 global $theme;
2954                 global $mod_strings;
2955
2956                 $colspan = 1;
2957                 $setTeamUserFunction = '';
2958
2959
2960                 // get users
2961                 $r = $this->db->query("SELECT users.id, users.user_name, users.first_name, users.last_name FROM users WHERE deleted=0 AND status = 'Active' AND is_group=0 ORDER BY users.last_name, users.first_name");
2962
2963                 $userTable = '<table cellpadding="0" cellspacing="0" border="0">';
2964                 $userTable .= '<tr><td colspan="2"><b>'.$mod_strings['LBL_USER_SELECT'].'</b></td></tr>';
2965                 $userTable .= '<tr><td><input type="checkbox" style="border:0px solid #000000" onClick="toggleAll(this); setCheckMark(); checkDeps(this.form);"></td> <td>'.$mod_strings['LBL_TOGGLE_ALL'].'</td></tr>';
2966                 $userTable .= '<tr><td colspan="2"><select style="visibility:hidden;" name="users[]" id="userSelect" multiple size="12">';
2967
2968                 while($a = $this->db->fetchByAssoc($r)) {
2969                         $userTable .= '<option value="'.$a['id'].'" id="'.$a['id'].'">'.$a['first_name'].' '.$a['last_name'].'</option>';
2970                 }
2971                 $userTable .= '</select></td></tr>';
2972                 $userTable .= '</table>';
2973
2974                 $out  = '<script type="text/javascript">';
2975                 $out .= $setTeamUserFunction;
2976                 $out .= '
2977                                         function setCheckMark() {
2978                                                 var select = document.getElementById("userSelect");
2979
2980                                                 for(i=0 ; i<select.options.length; i++) {
2981                                                         if(select.options[i].selected == true) {
2982                                                                 document.getElementById("checkMark").style.display="";
2983                                                                 return;
2984                                                         }
2985                                                 }
2986
2987                                                 document.getElementById("checkMark").style.display="none";
2988                                                 return;
2989                                         }
2990
2991                                         function showUserSelect() {
2992                                                 var targetTable = document.getElementById("user_select");
2993                                                 targetTable.style.visibility="visible";
2994                                                 var userSelectTable = document.getElementById("userSelect");
2995                                                 userSelectTable.style.visibility="visible";
2996                                                 return;
2997                                         }
2998                                         function hideUserSelect() {
2999                                                 var targetTable = document.getElementById("user_select");
3000                                                 targetTable.style.visibility="hidden";
3001                                                 var userSelectTable = document.getElementById("userSelect");
3002                                                 userSelectTable.style.visibility="hidden";
3003                                                 return;
3004                                         }
3005                                         function toggleAll(toggle) {
3006                                                 if(toggle.checked) {
3007                                                         var stat = true;
3008                                                 } else {
3009                                                         var stat = false;
3010                                                 }
3011                                                 var form = document.getElementById("userSelect");
3012                                                 for(i=0; i<form.options.length; i++) {
3013                                                         form.options[i].selected = stat;
3014                                                 }
3015                                         }
3016
3017
3018                                 </script>
3019                         <span id="showUsersDiv" style="position:relative;">
3020                                 <a href="#" id="showUsers" onClick="javascript:showUserSelect();">
3021                                         <img border="0" src="'.SugarThemeRegistry::current()->getImageURL('Users.gif').'"></a>&nbsp;
3022                                 <a href="#" id="showUsers" onClick="javascript:showUserSelect();">
3023                                         <span style="display:none;" id="checkMark"><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('check_inline.gif').'"></span>
3024                                 </a>
3025
3026
3027                                 <div id="user_select" style="width:200px;position:absolute;left:2;top:2;visibility:hidden;z-index:1000;">
3028                                 <table cellpadding="0" cellspacing="0" border="0" class="list view">
3029                                         <tr height="20">
3030                                                 <td  colspan="'.$colspan.'" id="hiddenhead" onClick="hideUserSelect();" onMouseOver="this.style.border = \'outset red 1px\';" onMouseOut="this.style.border = \'inset white 0px\';this.style.borderBottom = \'inset red 1px\';">
3031                                                         <a href="#" onClick="javascript:hideUserSelect();"><img border="0" src="'.SugarThemeRegistry::current()->getImageURL('close.gif').'"></a>
3032                                                         '.$mod_strings['LBL_USER_SELECT'].'
3033                                                 </td>
3034                                         </tr>
3035                                         <tr>';
3036 //<td valign="middle" height="30"  colspan="'.$colspan.'" id="hiddenhead" onClick="hideUserSelect();" onMouseOver="this.style.border = \'outset red 1px\';" onMouseOut="this.style.border = \'inset white 0px\';this.style.borderBottom = \'inset red 1px\';">
3037                 $out .= '               <td style="padding:5px" class="oddListRowS1" bgcolor="#fdfdfd" valign="top" align="left" style="left:0;top:0;">
3038                                                         '.$userTable.'
3039                                                 </td>
3040                                         </tr>
3041                                 </table></div>
3042                         </span>';
3043                 return $out;
3044         }
3045
3046         function checkInbox($type) {
3047                 global $theme;
3048                 global $mod_strings;
3049                 $out = '<div><input     title="'.$mod_strings['LBL_BUTTON_CHECK_TITLE'].'"
3050                                                 accessKey="'.$mod_strings['LBL_BUTTON_CHECK_KEY'].'"
3051                                                 class="button"
3052                                                 type="button" name="button"
3053                                                 onClick="window.location=\'index.php?module=Emails&action=Check&type='.$type.'\';"
3054                                                 style="margin-bottom:2px"
3055                                                 value="  '.$mod_strings['LBL_BUTTON_CHECK'].'  "></div>';
3056                 return $out;
3057         }
3058
3059         /**
3060          * Guesses Primary Parent id from From: email address.  Cascades guesses from Accounts to Contacts to Leads to
3061          * Users.  This will not affect the many-to-many relationships already constructed as this is, at best,
3062          * informational linking.
3063          */
3064         function fillPrimaryParentFields() {
3065                 if(empty($this->from_addr))
3066                         return;
3067
3068                 $GLOBALS['log']->debug("*** Email trying to guess Primary Parent from address [ {$this->from_addr} ]");
3069
3070                 $tables = array('accounts');
3071                 $ret = array();
3072                 // loop through types to get hits
3073                 foreach($tables as $table) {
3074                         $q = "SELECT name, id FROM {$table} WHERE email1 = '{$this->from_addr}' OR email2 = '{$this->from_addr}' AND deleted = 0";
3075                         $r = $this->db->query($q);
3076                         while($a = $this->db->fetchByAssoc($r)) {
3077                                 if(!empty($a['name']) && !empty($a['id'])) {
3078                                         $this->parent_type      = ucwords($table);
3079                                         $this->parent_id        = $a['id'];
3080                                         $this->parent_name      = $a['name'];
3081                                         return;
3082                                 }
3083                         }
3084                 }
3085         }
3086
3087
3088
3089 } // end class def