]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarEmailAddress/SugarEmailAddress.php
Release 6.1.5
[Github/sugarcrm.git] / include / SugarEmailAddress / SugarEmailAddress.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42  * Reserved. Contributor(s): ______________________________________..
43  *********************************************************************************/
44
45
46 require_once("include/JSON.php");
47
48
49 class SugarEmailAddress extends SugarBean {
50     var $table_name = 'email_addresses';
51     var $module_name = "EmailAddresses";
52     var $module_dir = 'EmailAddresses';
53     var $object_name = 'EmailAddress';
54
55     //bug 40068, According to rules in page 6 of http://www.apps.ietf.org/rfc/rfc3696.html#sec-3,
56         //allowed special characters ! # $ % & ' * + - / = ?  ^ _ ` . { | } ~ in local part
57     var $regex = "/^(['\.\-\+&'#!\$\*=\?\^_`\{\}~\/\w]+)*@((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|\w+([\.-]?\w+)*(\.[\w-]{2,})+)\$/";
58
59     var $db;
60     var $smarty;
61
62     var $addresses = array(); // array of emails
63     var $view = '';
64
65     static $count = 0;
66
67     /**
68      * Sole constructor
69      */
70     function SugarEmailAddress() {
71         parent::SugarBean();
72         $this->index = self::$count;
73         self::$count++;
74     }
75
76     /**
77      * Legacy email address handling.  This is to allow support for SOAP or customizations
78      * @param string $id
79      * @param string $module
80      */
81     function handleLegacySave($bean, $prefix = "") {
82         if(!isset($_REQUEST) || !isset($_REQUEST['useEmailWidget'])) {
83             if (empty($this->addresses) || !isset($_REQUEST['massupdate'])) {
84                 $this->addresses = array();
85                 $optOut = (isset($bean->email_opt_out) && $bean->email_opt_out == "1") ? true : false;
86                 $invalid = (isset($bean->invalid_email) && $bean->invalid_email == "1") ? true : false;
87
88                 $isPrimary = true;
89                 for($i = 1; $i <= 10; $i++){
90                     $email = 'email'.$i;
91                     if(isset($bean->$email) && !empty($bean->$email)){
92                         $opt_out_field = $email.'_opt_out';
93                         $invalid_field = $email.'_invalid';
94                         $field_optOut = (isset($bean->$opt_out_field)) ? $bean->$opt_out_field : $optOut;
95                         $field_invalid = (isset($bean->$invalid_field)) ? $bean->$invalid_field : $invalid;
96                         $this->addAddress($bean->$email, $isPrimary, false, $field_invalid, $field_optOut);
97                         $isPrimary = false;
98                     }
99                 }
100             }
101         }
102         $this->populateAddresses($bean->id, $bean->module_dir, array(),'');
103         if(isset($_REQUEST) && isset($_REQUEST['useEmailWidget'])) {
104             $this->populateLegacyFields($bean);
105         }
106     }
107
108     /**
109      * Fills standard email1 legacy fields
110      * @param string id
111      * @param string module
112      * @return object
113      */
114     function handleLegacyRetrieve(&$bean) {
115         $module_dir = $this->getCorrectedModule($bean->module_dir);
116         $this->addresses = $this->getAddressesByGUID($bean->id, $module_dir);
117         $this->populateLegacyFields($bean);
118
119         return;
120     }
121
122     function populateLegacyFields(&$bean){
123         $primary_found = false;
124         $alternate_found = false;
125         $alternate2_found = false;
126         foreach($this->addresses as $k=>$address) {
127             if ($primary_found && $alternate_found)
128                 break;
129             if ($address['primary_address'] == 1 && !$primary_found) {
130                 $primary_index = $k;
131                 $primary_found = true;
132             } elseif (!$alternate_found) {
133                 $alternate_index = $k;
134                 $alternate_found = true;
135             } elseif (!$alternate2_found){
136                 $alternate2_index = $k;
137                 $alternate2_found = true;
138             }
139         }
140
141         if ($primary_found) {
142             $bean->email1 = $this->addresses[$primary_index]['email_address'];
143             $bean->email_opt_out = $this->addresses[$primary_index]['opt_out'];
144             $bean->invalid_email = $this->addresses[$primary_index]['invalid_email'];
145             if ($alternate_found) {
146                 $bean->email2 = $this->addresses[$alternate_index]['email_address'];
147             }
148         } elseif ($alternate_found) {
149             // Use the first found alternate as email1.
150             $bean->email1 = $this->addresses[$alternate_index]['email_address'];
151             $bean->email_opt_out = $this->addresses[$alternate_index]['opt_out'];
152             $bean->invalid_email = $this->addresses[$alternate_index]['invalid_email'];
153             if ($alternate2_found) {
154                 $bean->email2 = $this->addresses[$alternate2_index]['email_address'];
155             }
156         }
157     }
158
159     /**
160      * Saves email addresses for a parent bean
161      * @param string $id Parent bean ID
162      * @param string $module Parent bean's module
163      * @param array $addresses Override of $_REQUEST vars, used to handle non-standard bean saves
164      * @param string $primary GUID of primary address
165      * @param string $replyTo GUID of reply-to address
166      * @param string $invalid GUID of invalid address
167      */
168     function save($id, $module, $new_addrs=array(), $primary='', $replyTo='', $invalid='', $optOut='', $in_workflow=false) {
169         if(empty($this->addresses) || $in_workflow){
170             $this->populateAddresses($id, $module, $new_addrs,$primary);
171         }
172
173         //find all email addresses..
174         $current_links=array();
175         // Need to correct this to handle the Employee/User split
176         $module = $this->getCorrectedModule($module);
177         $q2="select *  from email_addr_bean_rel eabr WHERE eabr.bean_id = '{$id}' AND eabr.bean_module = '{$module}' and eabr.deleted=0";
178         $r2 = $this->db->query($q2);
179         while(($row2=$this->db->fetchByAssoc($r2)) != null ) {
180             $current_links[$row2['email_address_id']]=$row2;
181         }
182
183         if (!empty($this->addresses)) {
184             // insert new relationships and create email address record, if they don't exist
185             foreach($this->addresses as $address) {
186                 if(!empty($address['email_address'])) {
187                     $guid = create_guid();
188                     $emailId = $this->AddUpdateEmailAddress($address['email_address'],$address['invalid_email'],$address['opt_out']);// this will save the email address if not found
189
190                     //verify linkage and flags.
191                     $upd_eabr="";
192                     if (isset($current_links[$emailId])) {
193                         if ($address['primary_address'] != $current_links[$emailId]['primary_address'] or $address['reply_to_address'] != $current_links[$emailId]['reply_to_address'] ) {
194                             $upd_eabr="UPDATE email_addr_bean_rel SET primary_address='{$address['primary_address']}', reply_to_address='{$address['reply_to_address']}' WHERE id='{$current_links[$emailId]['id']}'";
195                         }
196
197                         unset($current_links[$emailId]);
198                     } else {
199                         $upd_eabr = "INSERT INTO email_addr_bean_rel (id, email_address_id,bean_id, bean_module,primary_address,reply_to_address,date_created,date_modified,deleted) VALUES('{$guid}', '{$emailId}', '{$id}', '{$module}', {$address['primary_address']}, {$address['reply_to_address']}, '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', 0)";
200                     }
201
202                     if (!empty($upd_eabr)) {
203                         $r2 = $this->db->query($upd_eabr);
204                     }
205                 }
206             }
207         }
208
209         //delete link to dropped email address.
210         if (!empty($current_links)) {
211
212             $delete="";
213             foreach ($current_links as $eabr) {
214
215                 $delete.=empty($delete) ? "'".$eabr['id'] . "' " : ",'" . $eabr['id'] . "'";
216             }
217
218             $eabr_unlink="update email_addr_bean_rel set deleted=1 where id in ({$delete})";
219             $this->db->query($eabr_unlink);
220         }
221         return;
222     }
223
224     /**
225      * returns the number of email addresses found for a specifed bean
226      *
227      * @param  string $email       Address to match
228      * @param  object $bean        Bean to query against
229      * @param  string $addresstype Optional, pass a 1 to query against the primary address, 0 for the other addresses
230      * @return int                 Count of records found
231      */
232     function getCountEmailAddressByBean(
233         $email,
234         $bean,
235         $addresstype
236         )
237     {
238         $emailCaps = strtoupper(trim($email));
239         if(empty($emailCaps))
240             return 0;
241
242         $q = "SELECT *
243                 FROM email_addr_bean_rel eabl JOIN email_addresses ea
244                         ON (ea.id = eabl.email_address_id)
245                     JOIN {$bean->table_name} bean
246                         ON (eabl.bean_id = bean.id)
247                 WHERE ea.email_address_caps = '{$emailCaps}'
248                     and eabl.bean_module = '{$bean->module_dir}'
249                     and eabl.primary_address = '{$addresstype}'
250                     and eabl.deleted=0 ";
251
252         $r = $this->db->query($q);
253
254         // do it this way to make the count accurate in oracle
255         $i = 0;
256         while ($this->db->fetchByAssoc($r)) ++$i;
257
258         return $i;
259     }
260
261     /**
262      * This function returns a contact or user ID if a matching email is found
263      * @param   $email      the email address to match
264      * @param   $table      which table to query
265      */
266     function getRelatedId($email, $module) {
267         $email = trim(strtoupper($email));
268         $module = ucfirst($module);
269
270         $q = "SELECT bean_id FROM email_addr_bean_rel eabr
271                 JOIN email_addresses ea ON (eabr.email_address_id = ea.id)
272                 WHERE bean_module = '{$module}' AND ea.email_address_caps = '{$email}' AND eabr.deleted=0";
273
274         $r = $this->db->query($q, true);
275
276         $retArr = array();
277         while($a = $this->db->fetchByAssoc($r)) {
278             $retArr[] = $a['bean_id'];
279         }
280         if(count($retArr) > 0) {
281             return $retArr;
282         } else {
283             return false;
284         }
285     }
286
287     /**
288      * returns a collection of beans matching the email address
289      * @param string $email Address to match
290      * @return array
291      */
292     function getBeansByEmailAddress($email) {
293         global $beanList;
294         global $beanFiles;
295
296         $ret = array();
297
298         $email = trim($email);
299
300         if(empty($email)) {
301             return array();
302         }
303
304         $emailCaps = strtoupper($email);
305         $q = "SELECT * FROM email_addr_bean_rel eabl JOIN email_addresses ea ON (ea.id = eabl.email_address_id)
306                 WHERE ea.email_address_caps = '{$emailCaps}' and eabl.deleted=0 ";
307         $r = $this->db->query($q);
308
309         while($a = $this->db->fetchByAssoc($r)) {
310             if(isset($beanList[$a['bean_module']]) && !empty($beanList[$a['bean_module']])) {
311                 $className = $beanList[$a['bean_module']];
312
313                 if(isset($beanFiles[$className]) && !empty($beanFiles[$className])) {
314                     if(!class_exists($className)) {
315                         require_once($beanFiles[$className]);
316                     }
317
318                     $bean = new $className();
319                     $bean->retrieve($a['bean_id']);
320
321                     $ret[] = $bean;
322                 } else {
323                     $GLOBALS['log']->fatal("SUGAREMAILADDRESS: could not find valid class file for [ {$className} ]");
324                 }
325             } else {
326                 $GLOBALS['log']->fatal("SUGAREMAILADDRESS: could not find valid class [ {$a['bean_module']} ]");
327             }
328         }
329
330         return $ret;
331     }
332
333     /**
334      * Saves email addresses for a parent bean
335      * @param string $id Parent bean ID
336      * @param string $module Parent bean's module
337      * @param array $addresses Override of $_REQUEST vars, used to handle non-standard bean saves
338      * @param string $primary GUID of primary address
339      * @param string $replyTo GUID of reply-to address
340      * @param string $invalid GUID of invalid address
341      */
342     function populateAddresses($id, $module, $new_addrs=array(), $primary='', $replyTo='', $invalid='', $optOut='') {
343         $module = $this->getCorrectedModule($module);
344         //One last check for the ConvertLead action in which case we need to change $module to 'Leads'
345         $module = (isset($_REQUEST) && isset($_REQUEST['action']) && $_REQUEST['action'] == 'ConvertLead') ? 'Leads' : $module;
346
347         $post_from_email_address_widget = (isset($_REQUEST) && isset($_REQUEST['emailAddressWidget'])) ? true : false;
348         $primaryValue = $primary;
349         $widgetCount = 0;
350         $hasEmailValue = false;
351
352         if (isset($_REQUEST) && isset($_REQUEST[$module .'_email_widget_id'])) {
353
354             $fromRequest = false;
355             // determine which array to process
356             foreach($_REQUEST as $k => $v) {
357                 if(strpos($k, 'emailAddress') !== false) {
358                    $fromRequest = true;
359                    break;
360                 }
361             }
362
363                 $widget_id = $_REQUEST[$module .'_email_widget_id'];
364
365             //Iterate over the widgets for this module, in case there are multiple email widgets for this module
366             while(isset($_REQUEST[$module . $widget_id . "emailAddress" . $widgetCount]))
367             {
368                 if (empty($_REQUEST[$module . $widget_id . "emailAddress" . $widgetCount])) {
369                         $widgetCount++;
370                         continue;
371                 }
372
373                 $hasEmailValue = true;
374
375                 $eId = $module . $widget_id;
376                 if(isset($_REQUEST[$eId . 'emailAddressPrimaryFlag'])) {
377                    $primaryValue = $_REQUEST[$eId . 'emailAddressPrimaryFlag'];
378                 } else if(isset($_REQUEST[$module . 'emailAddressPrimaryFlag'])) {
379                    $primaryValue = $_REQUEST[$module . 'emailAddressPrimaryFlag'];
380                 }
381
382                 $optOutValues = array();
383                 if(isset($_REQUEST[$eId .'emailAddressOptOutFlag'])) {
384                    $optOutValues = $_REQUEST[$eId .'emailAddressOptOutFlag'];
385                 } else if(isset($_REQUEST[$module . 'emailAddressOptOutFlag'])) {
386                    $optOutValues = $_REQUEST[$module . 'emailAddressOptOutFlag'];
387                 }
388
389                 $invalidValues = array();
390                 if(isset($_REQUEST[$eId .'emailAddressInvalidFlag'])) {
391                    $invalidValues = $_REQUEST[$eId .'emailAddressInvalidFlag'];
392                 } else if(isset($_REQUEST[$module . 'emailAddressInvalidFlag'])) {
393                    $invalidValues = $_REQUEST[$module . 'emailAddressInvalidFlag'];
394                 }
395
396                 $deleteValues = array();
397                 if(isset($_REQUEST[$eId .'emailAddressDeleteFlag'])) {
398                    $deleteValues = $_REQUEST[$eId .'emailAddressDeleteFlag'];
399                 } else if(isset($_REQUEST[$module . 'emailAddressDeleteFlag'])) {
400                    $deleteValues = $_REQUEST[$module . 'emailAddressDeleteFlag'];
401                 }
402
403                 // prep from form save
404                 $primaryField = $primary;
405                 $replyToField = '';
406                 $invalidField = '';
407                 $optOutField = '';
408                 if($fromRequest && empty($primary) && isset($primaryValue)) {
409                     $primaryField = $primaryValue;
410                 }
411
412                 if($fromRequest && empty($replyTo)) {
413                     if(isset($_REQUEST[$eId .'emailAddressReplyToFlag'])) {
414                        $replyToField = $_REQUEST[$eId .'emailAddressReplyToFlag'];
415                     } else if(isset($_REQUEST[$module . 'emailAddressReplyToFlag'])) {
416                        $replyToField = $_REQUEST[$module . 'emailAddressReplyToFlag'];
417                     }
418                 }
419                 if($fromRequest && empty($new_addrs)) {
420                     foreach($_REQUEST as $k => $v) {
421                         if(preg_match('/'.$eId.'emailAddress[0-9]+$/i', $k) && !empty($v)) {
422                             $new_addrs[$k] = $v;
423                         }
424                     }
425                 }
426
427                 if($fromRequest && empty($new_addrs)) {
428                     foreach($_REQUEST as $k => $v) {
429                         if(preg_match('/'.$eId.'emailAddressVerifiedValue[0-9]+$/i', $k) && !empty($v)) {
430                             $validateFlag = str_replace("Value", "Flag", $k);
431                             if (isset($_REQUEST[$validateFlag]) && $_REQUEST[$validateFlag] == "true")
432                               $new_addrs[$k] = $v;
433                         }
434                     }
435                 }
436
437                 //empty the addresses array if the post happened from email address widget.
438                 if($post_from_email_address_widget) {
439                     $this->addresses=array();  //this gets populated during retrieve of the contact bean.
440                 } else {
441                     $optOutValues = array();
442                     $invalidValues = array();
443                     foreach($new_addrs as $k=>$email) {
444                        preg_match('/emailAddress([0-9])+$/', $k, $matches);
445                        $count = $matches[1];
446                        $result = $this->db->query("SELECT opt_out, invalid_email from email_addresses where email_address_caps = '" . strtoupper($email) . "'");
447                        if(!empty($result)) {
448                           $row=$this->db->fetchByAssoc($result);
449                           if(!empty($row['opt_out'])) {
450                              $optOutValues[$k] = "emailAddress$count";
451                           }
452                           if(!empty($row['invalid_email'])) {
453                              $invalidValues[$k] = "emailAddress$count";
454                           }
455                        }
456                     }
457                 }
458                 // Re-populate the addresses class variable if we have new address(es).
459                 if (!empty($new_addrs)) {
460                     foreach($new_addrs as $k => $reqVar) {
461                         //$key = preg_match("/^$eId/s", $k) ? substr($k, strlen($eId)) : $k;
462                         $reqVar = trim($reqVar);
463                         if(strpos($k, 'emailAddress') !== false) {
464                             if(!empty($reqVar) && !in_array($k, $deleteValues)) {
465                                 $primary    = ($k == $primaryValue) ? true : false;
466                                 $replyTo    = ($k == $replyToField) ? true : false;
467                                 $invalid    = (in_array($k, $invalidValues)) ? true : false;
468                                 $optOut     = (in_array($k, $optOutValues)) ? true : false;
469                                 $this->addAddress(trim($new_addrs[$k]), $primary, $replyTo, $invalid, $optOut);
470                             }
471                         }
472                     } //foreach
473                 }
474
475                 $widgetCount++;
476             }//End of Widget for loop
477         }
478
479         //If no widgets, set addresses array to empty
480         if($post_from_email_address_widget && !$hasEmailValue) {
481            $this->addresses = array();
482         }
483     }
484
485     /**
486      * Preps internal array structure for email addresses
487      * @param string $addr Email address
488      * @param bool $primary Default false
489      * @param bool $replyTo Default false
490      */
491     function addAddress($addr, $primary=false, $replyTo=false, $invalid=false, $optOut=false) {
492         $addr = html_entity_decode($addr, ENT_QUOTES);
493         if(preg_match($this->regex, $addr)) {
494             $primaryFlag = ($primary) ? '1' : '0';
495             $replyToFlag = ($replyTo) ? '1' : '0';
496             $invalidFlag = ($invalid) ? '1' : '0';
497             $optOutFlag = ($optOut) ? '1' : '0';
498
499             $addr = trim($addr);
500
501             // If we have such address already, remove it and add new one in.
502             foreach ($this->addresses as $k=>$address) {
503                 if ($address['email_address'] == $addr) {
504                     unset($this->addresses[$k]);
505                 } elseif ($primary && $address['primary_address'] == '1') {
506                     // We should only have one primary. If we are adding a primary but
507                     // we find an existing primary, reset this one's primary flag.
508                     $address['primary_address'] = '0';
509                 }
510             }
511
512             $this->addresses[] = array(
513                 'email_address' => $addr,
514                 'primary_address' => $primaryFlag,
515                 'reply_to_address' => $replyToFlag,
516                 'invalid_email' => $invalidFlag,
517                 'opt_out' => $optOutFlag,
518             );
519         } else {
520             $GLOBALS['log']->fatal("SUGAREMAILADDRESS: address did not validate [ {$addr} ]");
521         }
522     }
523
524     /**
525      * Updates invalid_email and opt_out flags for each address
526      */
527     function updateFlags() {
528         if(!empty($this->addresses)) {
529             foreach($this->addresses as $addressMeta) {
530                 if(isset($addressMeta['email_address']) && !empty($addressMeta['email_address'])) {
531                     $address = $this->_cleanAddress($addressMeta['email_address']);
532
533                     $q = "SELECT * FROM email_addresses WHERE email_address = '{$address}'";
534                     $r = $this->db->query($q);
535                     $a = $this->db->fetchByAssoc($r);
536
537                     if(!empty($a)) {
538                         if(isset($a['invalid_email']) && isset($addressMeta['invalid_email']) && isset($addressMeta['opt_out']) && $a['invalid_email'] != $addressMeta['invalid_email'] || $a['opt_out'] != $addressMeta['opt_out']) {
539                             $qUpdate = "UPDATE email_addresses SET invalid_email = {$addressMeta['invalid_email']}, opt_out = {$addressMeta['opt_out']}, date_modified = '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."' WHERE id = '{$a['id']}'";
540                             $rUpdate = $this->db->query($qUpdate);
541                         }
542                     }
543                 }
544             }
545         }
546     }
547
548     public function splitEmailAddress($addr)
549     {
550         $email = $this->_cleanAddress($addr);
551         if(!preg_match($this->regex, $email)) {
552             $email = ''; // remove bad email addr
553         }
554         $name = trim(str_replace(array($email, '<', '>', '"', "'"), '', $addr));
555         return array("name" => $name, "email" => strtolower($email));
556     }
557
558     /**
559      * PRIVATE UTIL
560      * Normalizes an RFC-clean email address, returns a string that is the email address only
561      * @param string $addr Dirty email address
562      * @return string clean email address
563      */
564     function _cleanAddress($addr) {
565         $addr = trim(from_html($addr));
566
567         if(strpos($addr, "<") !== false && strpos($addr, ">") !== false) {
568             $address = trim(substr($addr, strrpos($addr, "<") +1, strrpos($addr, ">") - strrpos($addr, "<") -1));
569         } else {
570             $address = trim($addr);
571         }
572
573         return $address;
574     }
575
576     /**
577      * preps a passed email address for email address storage
578      * @param array $addr Address in focus, must be RFC compliant
579      * @return string $id email_addresses ID
580      */
581     function getEmailGUID($addr) {
582         $address = $this->_cleanAddress($addr);
583         $addressCaps = strtoupper($address);
584
585         $q = "SELECT id FROM email_addresses WHERE email_address_caps = '{$addressCaps}'";
586         $r = $this->db->query($q);
587         $a = $this->db->fetchByAssoc($r);
588
589         if(!empty($a) && !empty($a['id'])) {
590             return $a['id'];
591         } else {
592             $guid = '';
593             if(!empty($address)){
594                 $guid = create_guid();
595                 $address = $GLOBALS['db']->quote($address);
596                 $addressCaps = $GLOBALS['db']->quote($addressCaps);
597                 $qa = "INSERT INTO email_addresses (id, email_address, email_address_caps, date_created, date_modified, deleted)
598                         VALUES('{$guid}', '{$address}', '{$addressCaps}', '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', 0)";
599                 $ra = $this->db->query($qa);
600             }
601             return $guid;
602         }
603     }
604
605     function AddUpdateEmailAddress($addr,$invalid=0,$opt_out=0) {
606
607         $address = $this->_cleanAddress($addr);
608         $addressCaps = strtoupper($this->db->quoteForEmail($address));
609
610         $q = "SELECT * FROM email_addresses WHERE email_address_caps = '{$addressCaps}' and deleted=0";
611         $r = $this->db->query($q);
612         $a = $this->db->fetchByAssoc($r);
613         if(!empty($a) && !empty($a['id'])) {
614             //verify the opt out and invalid flags.
615             if ($a['invalid_email'] != $invalid or $a['opt_out'] != $opt_out) {
616                 $upd_q="update email_addresses set invalid_email={$invalid}, opt_out={$opt_out},date_modified = '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."' where id='{$a['id']}'";
617                 $upd_r= $this->db->query($upd_q);
618             }
619             return $a['id'];
620         } else {
621             $guid = '';
622             if(!empty($address)){
623                 $guid = create_guid();
624                 $address = $GLOBALS['db']->quote($address);
625                 $addressCaps = $GLOBALS['db']->quote($addressCaps);
626                 $qa = "INSERT INTO email_addresses (id, email_address, email_address_caps, date_created, date_modified, deleted, invalid_email, opt_out)
627                         VALUES('{$guid}', '{$address}', '{$addressCaps}', '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', '".gmdate($GLOBALS['timedate']->get_db_date_time_format())."', 0 , $invalid, $opt_out)";
628                 $this->db->query($qa);
629             }
630             return $guid;
631         }
632     }
633
634     /**
635      * Returns Primary or newest email address
636      * @param object $focus Object in focus
637      * @return string email
638      */
639     function getPrimaryAddress($focus,$parent_id=null,$parent_type=null) {
640
641         $parent_type=empty($parent_type) ? $focus->module_dir : $parent_type;
642         $parent_id=empty($parent_id) ? $focus->id : $parent_id;
643
644         $q = "SELECT ea.email_address FROM email_addresses ea
645                 LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id
646                 WHERE ear.bean_module = '{$parent_type}'
647                 AND ear.bean_id = '{$parent_id}'
648                 AND ear.deleted = 0
649                 ORDER BY ear.primary_address DESC";
650         $r = $this->db->limitQuery($q, 0, 1);
651         $a = $this->db->fetchByAssoc($r);
652
653         if(isset($a['email_address'])) {
654             return $a['email_address'];
655         }
656         return '';
657     }
658
659     function getReplyToAddress($focus) {
660         $q = "SELECT ea.email_address FROM email_addresses ea
661                 LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id
662                 WHERE ear.bean_module = '{$focus->module_dir}'
663                 AND ear.bean_id = '{$focus->id}'
664                 AND ear.deleted = 0
665                 ORDER BY ear.reply_to_address DESC";
666         $r = $this->db->query($q);
667         $a = $this->db->fetchByAssoc($r);
668
669         if(isset($a['email_address'])) {
670             return $a['email_address'];
671         }
672         return '';
673     }
674
675     /**
676      * Returns all email addresses by parent's GUID
677      * @param string $id Parent's GUID
678      * @param string $module Parent's module
679      * @return array
680      */
681     function getAddressesByGUID($id, $module) {
682         $return = array();
683         $module = $this->getCorrectedModule($module);
684
685         $q = "SELECT ea.*, ear.* FROM email_addresses ea
686                 LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id
687                 WHERE ear.bean_module = '{$module}'
688                 AND ear.bean_id = '{$id}'
689                 AND ear.deleted = 0
690                 ORDER BY ear.reply_to_address, ear.primary_address DESC";
691         $r = $this->db->query($q);
692
693         while($a = $this->db->fetchByAssoc($r)) {
694             $return[] = $a;
695         }
696
697         return $return;
698     }
699
700     /**
701      * Returns the HTML/JS for the EmailAddress widget
702      * @param string $parent_id ID of parent bean, generally $focus
703      * @param string $module $focus' module
704      * @param bool asMetadata Default false
705      * @return string HTML/JS for widget
706      */
707     function getEmailAddressWidgetEditView($id, $module, $asMetadata=false, $tpl='',$tabindex='')
708     {
709         if ( !($this->smarty instanceOf Sugar_Smarty ) )
710             $this->smarty = new Sugar_Smarty();
711
712         global $app_strings, $dictionary, $beanList;
713
714                 $prefill = 'false';
715         $prefillData = 'new Object()';
716         $passedModule = $module;
717         $module = $this->getCorrectedModule($module);
718         $saveModule = $module;
719         if(isset($_POST['is_converted']) && $_POST['is_converted']==true){
720             $id=$_POST['return_id'];
721             $module=$_POST['return_module'];
722         }
723         $prefillDataArr = array();
724         if(!empty($id)) {
725             $prefillDataArr = $this->getAddressesByGUID($id, $module);
726             //When coming from convert leads, sometimes module is Contacts while the id is for a lead.
727                         if (empty($prefillDataArr) && $module == "Contacts")
728                             $prefillDataArr = $this->getAddressesByGUID($id, "Leads");
729                 } else if(isset($_REQUEST['full_form']) && !empty($_REQUEST['emailAddressWidget'])){
730                         $widget_id = isset($_REQUEST[$module . '_email_widget_id']) ? $_REQUEST[$module . '_email_widget_id'] : '0';
731             $count = 0;
732             $key = $module . $widget_id . 'emailAddress'.$count;
733             while(isset($_REQUEST[$key])) {
734                    $email = $_REQUEST[$key];
735                    $prefillDataArr[] =  array('email_address'=>$email,
736                                              'primary_address'=>isset($_REQUEST['emailAddressPrimaryFlag']) && $_REQUEST['emailAddressPrimaryFlag'] == $key,
737                                              'invalid_email'=>isset($_REQUEST['emailAddressInvalidFlag']) && in_array($key, $_REQUEST['emailAddressInvalidFlag']),
738                                              'opt_out'=>isset($_REQUEST['emailAddressOptOutFlag']) && in_array($key, $_REQUEST['emailAddressOptOutFlag']),
739                                              'reply_to_address'=>false
740                                         );
741                    $key = $module . $widget_id . 'emailAddress' . ++$count;
742             } //while
743         }
744
745         if(!empty($prefillDataArr)) {
746             $json = new JSON(JSON_LOOSE_TYPE);
747             $prefillData = $json->encode($prefillDataArr);
748             $prefill = !empty($prefillDataArr) ? 'true' : 'false';
749         }
750
751         $required = false;
752         $vardefs = $dictionary[$beanList[$passedModule]]['fields'];
753         if (!empty($vardefs['email1']) && isset($vardefs['email1']['required']) && $vardefs['email1']['required'])
754             $required = true;
755         $this->smarty->assign('required', $required);
756
757         $this->smarty->assign('module', $saveModule);
758         $this->smarty->assign('index', $this->index);
759         $this->smarty->assign('app_strings', $app_strings);
760         $this->smarty->assign('prefillEmailAddresses', $prefill);
761         $this->smarty->assign('prefillData', $prefillData);
762         $this->smarty->assign('tabindex', $tabindex);
763         //Set addDefaultAddress flag (do not add if it's from the Email module)
764         $this->smarty->assign('addDefaultAddress', (isset($_REQUEST['module']) && $_REQUEST['module'] == 'Emails') ? 'false' : 'true');
765         $form = $this->view;
766                 if ($this->view == "QuickCreate")
767                   $form = 'form_'.$this->view .'_'.$module;
768                 $this->smarty->assign('emailView', $form);
769
770
771         if($module == 'Users') {
772             $this->smarty->assign('useReplyTo', true);
773         } else {
774             $this->smarty->assign('useOptOut', true);
775             $this->smarty->assign('useInvalid', true);
776         }
777
778         $template = empty($tpl) ? "include/SugarEmailAddress/templates/forEditView.tpl" : $tpl;
779         $newEmail = $this->smarty->fetch($template);
780
781
782         if($asMetadata) {
783             // used by Email 2.0
784             $ret = array();
785             $ret['prefillData'] = $prefillDataArr;
786             $ret['html'] = $newEmail;
787
788             return $ret;
789         }
790
791         return $newEmail;
792     }
793
794
795     /**
796      * Returns the HTML/JS for the EmailAddress widget
797      * @param object $focus Bean in focus
798      * @return string HTML/JS for widget
799      */
800     function getEmailAddressWidgetDetailView($focus, $tpl='')
801     {
802         if ( !($this->smarty instanceOf Sugar_Smarty ) )
803             $this->smarty = new Sugar_Smarty();
804
805         global $app_strings;
806         global $current_user;
807         $assign = array();
808         if(empty($focus->id))return '';
809         $prefillData = $this->getAddressesByGUID($focus->id, $focus->module_dir);
810
811         foreach($prefillData as $addressItem) {
812             $key = ($addressItem['primary_address'] == 1) ? 'primary' : "";
813             $key = ($addressItem['reply_to_address'] == 1) ? 'reply_to' : $key;
814             $key = ($addressItem['opt_out'] == 1) ? 'opt_out' : $key;
815             $key = ($addressItem['invalid_email'] == 1) ? 'invalid' : $key;
816
817             $assign[] = array('key' => $key, 'address' => $current_user->getEmailLink2($addressItem['email_address'], $focus).$addressItem['email_address']."</a>");
818         }
819
820
821         $this->smarty->assign('app_strings', $app_strings);
822         $this->smarty->assign('emailAddresses', $assign);
823         $templateFile = empty($tpl) ? "include/SugarEmailAddress/templates/forDetailView.tpl" : $tpl;
824         $return = $this->smarty->fetch($templateFile);
825         return $return;
826     }
827
828
829     /**
830      * getEmailAddressWidgetDuplicatesView($focus)
831      * @param object $focus Bean in focus
832      * @return string HTML that contains hidden input values based off of HTML request
833      */
834     function getEmailAddressWidgetDuplicatesView($focus)
835     {
836         if ( !($this->smarty instanceOf Sugar_Smarty ) )
837             $this->smarty = new Sugar_Smarty();
838
839         $count = 0;
840         $emails = array();
841         $primary = null;
842         $optOut = array();
843         $invalid = array();
844         $mod = isset($focus) ? $focus->module_dir : "";
845
846         $widget_id = $_POST[$mod .'_email_widget_id'];
847         $this->smarty->assign('email_widget_id',$widget_id);
848         $this->smarty->assign('emailAddressWidget',$_POST['emailAddressWidget']);
849
850         if(isset($_POST[$mod . $widget_id . 'emailAddressPrimaryFlag'])) {
851            $primary = $_POST[$mod . $widget_id . 'emailAddressPrimaryFlag'];
852         }
853
854         while(isset($_POST[$mod . $widget_id . "emailAddress" . $count])) {
855             $emails[] = $_POST[$mod . $widget_id . 'emailAddress' . $count];
856             $count++;
857         }
858
859         if($count == 0) {
860            return "";
861         }
862
863         if(isset($_POST[$mod . $widget_id . 'emailAddressOptOutFlag'])) {
864            foreach($_POST[$mod . $widget_id . 'emailAddressOptOutFlag'] as $v) {
865               $optOut[] = $v;
866            }
867         }
868
869         if(isset($_POST[$mod . $widget_id . 'emailAddressInvalidFlag'])) {
870            foreach($_POST[$mod . $widget_id . 'emailAddressInvalidFlag'] as $v) {
871               $invalid[] = $v;
872            }
873         }
874
875         if(isset($_POST[$mod . $widget_id . 'emailAddressReplyToFlag'])) {
876            foreach($_POST[$mod . $widget_id . 'emailAddressReplyToFlag'] as $v) {
877               $replyTo[] = $v;
878            }
879         }
880
881         if(isset($_POST[$mod . $widget_id . 'emailAddressDeleteFlag'])) {
882            foreach($_POST[$mod . $widget_id . 'emailAddressDeleteFlag'] as $v) {
883               $delete[] = $v;
884            }
885         }
886
887         while(isset($_POST[$mod . $widget_id . "emailAddressVerifiedValue" . $count])) {
888             $verified[] = $_POST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count];
889             $count++;
890         }
891
892         $this->smarty->assign('emails', $emails);
893         $this->smarty->assign('primary', $primary);
894         $this->smarty->assign('optOut', $optOut);
895         $this->smarty->assign('invalid', $invalid);
896         $this->smarty->assign('replyTo', $invalid);
897         $this->smarty->assign('delete', $invalid);
898         $this->smarty->assign('verified', $invalid);
899         $this->smarty->assign('moduleDir', $mod);
900
901         return $this->smarty->fetch("include/SugarEmailAddress/templates/forDuplicatesView.tpl");
902     }
903
904     /**
905      * getFormBaseURL
906      *
907      */
908     function getFormBaseURL($focus) {
909         $get = "";
910         $count = 0;
911         $mod = isset($focus) ? $focus->module_dir : "";
912
913         $widget_id = $_POST[$mod .'_email_widget_id'];
914         $get .= '&' . $mod . '_email_widget_id='. $widget_id;
915         $get .= '&emailAddressWidget='.$_POST['emailAddressWidget'];
916
917         while(isset($_REQUEST[$mod . $widget_id . 'emailAddress' . $count])) {
918               $get .= "&" . $mod . $widget_id . "emailAddress" . $count . "=" . urlencode($_REQUEST[$mod . $widget_id . 'emailAddress' . $count]);
919               $count++;
920         } //while
921
922         while(isset($_REQUEST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count])) {
923               $get .= "&" . $mod . $widget_id . "emailAddressVerifiedValue" . $count . "=" . urlencode($_REQUEST[$mod . $widget_id . 'emailAddressVerifiedValue' . $count]);
924               $count++;
925         } //while
926
927         $options = array('emailAddressPrimaryFlag', 'emailAddressOptOutFlag', 'emailAddressInvalidFlag', 'emailAddressDeleteFlag', 'emailAddressReplyToFlag');
928
929         foreach($options as $option) {
930             $count = 0;
931             $optionIdentifier = $mod.$widget_id.$option;
932             if(isset($_REQUEST[$optionIdentifier])) {
933                if(is_array($_REQUEST[$optionIdentifier])) {
934                    foreach($_REQUEST[$optionIdentifier] as $optOut) {
935                       $get .= "&" . $optionIdentifier . "[" . $count . "]=" . $optOut;
936                       $count++;
937                    } //foreach
938                } else {
939                    $get .= "&" . $optionIdentifier . "=" . $_REQUEST[$optionIdentifier];
940                }
941             } //if
942         } //foreach
943         return $get;
944
945     }
946
947     function setView($view) {
948        $this->view = $view;
949     }
950
951 /**
952  * This function is here so the Employees/Users division can be handled cleanly in one place
953  * @param object $focus SugarBean
954  * @return string The value for the bean_module column in the email_addr_bean_rel table
955  */
956     function getCorrectedModule(&$module) {
957         return ($module == "Employees")? "Users" : $module;
958     }
959 } // end class def
960
961
962 /**
963  * Convenience function for MVC (Mystique)
964  * @param object $focus SugarBean
965  * @param string $field unused
966  * @param string $value unused
967  * @param string $view DetailView or EditView
968  * @return string
969  */
970 function getEmailAddressWidget($focus, $field, $value, $view, $tabindex='') {
971     $sea = new SugarEmailAddress();
972     $sea->setView($view);
973
974         if($view == 'EditView' || $view == 'QuickCreate' || $view == 'ConvertLead') {
975             $module = $focus->module_dir;
976             if ($view == 'ConvertLead' && $module == "Contacts")  $module = "Leads";
977
978             return $sea->getEmailAddressWidgetEditView($focus->id, $module, false,'',$tabindex);
979         }
980
981     return $sea->getEmailAddressWidgetDetailView($focus);
982 }
983
984 ?>