]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarFolders/SugarFolders.php
Release 6.1.4
[Github/sugarcrm.git] / include / SugarFolders / SugarFolders.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42  * Reserved. Contributor(s): ______________________________________..
43  *********************************************************************************/
44
45 require_once("include/ytree/Tree.php");
46 require_once("include/ytree/ExtNode.php");
47
48 /**
49  * Polymorphic buckets - place any item in a folder
50  */
51 class SugarFolder {
52
53         // public attributes
54         var $id;
55         var $name;
56         var $parent_folder;
57         var $has_child = 0; // flag node has child
58         var $is_group = 0;
59         var $is_dynamic = 0;
60         var $dynamic_query = '';
61         var $assign_to_id;
62         var $created_by;
63         var $modified_by;
64         var $date_created;
65         var $date_modified;
66         var $deleted;
67         var $folder_type;
68
69         var $db;
70         var $new_with_id = false;
71
72         // core queries
73         var $core = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f left join inbound_email i on f.id = i.groupfolder_id ";
74         var $coreSubscribed = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f LEFT JOIN folders_subscriptions fs ON f.id = fs.folder_id LEFT JOIN inbound_email i on  i.groupfolder_id = f.id ";
75         var $coreWhere = "WHERE f.deleted = 0 ";
76         var $coreWhereSubscribed = "WHERE f.deleted = 0 AND fs.assigned_user_id = ";
77         var $coreOrderBy = " ORDER BY f.is_dynamic, f.is_group, f.name ASC ";
78
79         var $hrSortLocal = array(
80             'flagged' => 'type',
81             'status'  => 'reply_to_status',
82             'from'    => 'emails_text.from_addr',
83             'subject' => 'name',
84             'date'    => 'date_sent',
85             'AssignedTo' => 'assigned_user_id',
86             'flagged' => 'flagged'
87         );
88     var $defaultSort = 'date';
89     var $defaultDirection = "DESC";
90
91         // private attributes
92         var $_depth;
93
94         /**
95          * Sole constructor
96          */
97         function SugarFolder() {
98                 $this->db = DBManagerFactory::getInstance();
99         }
100
101         function deleteEmailFromAllFolder($id) {
102                 $q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' ";
103                 $r = $this->db->query($q);
104         }
105
106         function deleteEmailFromFolder($id) {
107                 $q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
108                 $r = $this->db->query($q);
109         }
110
111         function checkEmailExistForFolder($id) {
112                 $q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
113                 $r = $this->db->query($q);
114                 $a = $this->db->fetchByAssoc($r);
115                 if ($a['c'] > 0) {
116                         return true;
117                 } else {
118                         return false;
119                 } // else
120         }
121         /**
122          * Moves beans from one folder to another folder
123          * @param string fromFolder GUID of source folder
124          * @param string toFolder GUID of destination folder
125          * @param string beanId GUID of SugarBean being moved
126          */
127         function move($fromFolder, $toFolder, $beanId) {
128                 $q = "UPDATE folders_rel SET folder_id = '{$toFolder}' WHERE folder_id = '{$fromFolder}' AND polymorphic_id = '{$beanId}' AND deleted = 0";
129                 $r = $this->db->query($q);
130         }
131
132         /**
133          * Copies one bean from one folder to another
134          */
135         function copyBean($fromFolder, $toFolder, $beanId, $module) {
136                 $q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
137                                 VALUES('{$guid}', '{$toFolder}', '{$module}', '{$beanId}', 0)";
138                 $r = $this->db->query($q);
139         }
140
141         /**
142          * Creates a new group Folder from the passed fields
143          * @param array fields
144          */
145         function setFolder($fields) {
146
147                 global $current_user;
148                 if(empty($fields['groupFoldersUser'])) {
149                         $fields['groupFoldersUser'] = $current_user->id;
150                 }
151
152                 $this->name = $fields['name'];
153                 $this->parent_folder = $fields['parent_folder'];
154                 $this->has_child = 0;
155                 $this->is_group = 1;
156                 $this->assign_to_id = $fields['groupFoldersUser'];
157
158                 $this->save();
159         }
160
161         /**
162          * Returns GUIDs of folders that the user in focus is subscribed to
163          * @param object user User object in focus
164          * @return array
165          */
166         function getSubscriptions($user) {
167                 if(empty($user)) {
168                         global $current_user;
169                         $user = $current_user;
170                 }
171
172                 $q = "SELECT folder_id FROM folders_subscriptions WHERE assigned_user_id = '{$user->id}'";
173                 $r = $this->db->query($q);
174                 $ret = array();
175                 while($a = $this->db->fetchByAssoc($r)) {
176                         $ret[] = $a['folder_id'];
177                 }
178                 return $ret;
179         }
180
181         /**
182          * Sets a user's preferences for subscribe folders (Sugar only)
183          * @param array subs Array of IDs for subscribed folders
184          */
185         function setSubscriptions($subs) {
186                 global $current_user;
187
188                 if(empty($current_user->id)) {
189                         $GLOBALS['log']->fatal("*** FOLDERS: tried to update folder subscriptions for a user with no ID");
190                         return false;
191                 }
192
193                 $cleanSubscriptions = array();
194
195                 // ensure parent folders are selected, regardless.
196                 foreach($subs as $id) {
197                         $id = trim($id);
198                         if(!empty($id)) {
199                                 $cleanSubscriptions[] = $id;
200                                 $qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
201                                 $rChk = $this->db->query($qChk);
202                                 $aChk = $this->db->fetchByAssoc($rChk);
203
204                                 if(!empty($aChk['parent_folder'])) {
205                                         $cleanSubscriptions = $this->getParentIDRecursive($aChk['parent_folder'], $cleanSubscriptions);
206                                 }
207                         }
208                 }
209
210                 $this->clearSubscriptions();
211
212                 foreach($cleanSubscriptions as $id) {
213                     $this->insertFolderSubscription($id, $current_user->id);
214                 }
215         }
216
217         /**
218          * Given a folder id and user id, create a folder subscription entry.
219          *
220          * @param String $folderId
221          * @param String $userID
222          * @return String The id of the newly created folder subscription.
223          */
224         function insertFolderSubscription($folderId, $userID)
225         {
226             $guid = create_guid();
227                 $query = "INSERT INTO folders_subscriptions (id, folder_id, assigned_user_id) VALUES ('{$guid}', '{$folderId}', '{$userID}')";
228                 $r = $this->db->query($query);
229                 return $guid;
230         }
231         /**
232          * Recursively finds parent node until it hits root
233          * @param string id Starting id to follow up
234          * @param array ret collected ids
235          * @return array of IDs
236          */
237         function getParentIDRecursive($id, $ret=array()) {
238                 $q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
239                 $r = $this->db->query($q);
240                 $a = $this->db->fetchByAssoc($r);
241
242                 if(!in_array($id, $ret)) {
243                         $ret[] = $id;
244                 }
245
246                 if($a['parent_folder'] != '') {
247                         $qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
248                         $rChk = $this->db->query($qChk);
249                         $aChk = $this->db->fetchByAssoc($rChk);
250
251                         if(!empty($aChk['parent_folder'])) {
252                                 $ret = $this->getParentIDRecursive($aChk['parent_folder'], $ret);
253                         }
254                 }
255
256                 return $ret;
257         }
258
259         /**
260          * Deletes subscriptions to folders in preparation for reset
261          */
262         function clearSubscriptions() {
263                 global $current_user;
264
265                 if(!empty($current_user->id)) {
266                         $q = "DELETE FROM folders_subscriptions WHERE assigned_user_id = '{$current_user->id}'";
267                         $r = $this->db->query($q);
268                 }
269         }
270
271         
272         /**
273          * Deletes all subscriptions for a particular folder id
274          *
275          * @return unknown
276          */
277         function clearSubscriptionsForFolder($folderID) 
278         {
279             $query = "DELETE FROM folders_subscriptions WHERE folder_id = '$folderID'";
280             $r = $this->db->query($query);
281         } 
282         
283         function generateSugarsDynamicFolderQuery() {
284                 global $current_user;
285                 $type = $this->folder_type;
286                 $status = $type;
287                 if($type == "sent") {
288                         $type = "out";
289                 }
290                 if($type == 'inbound') {
291                         $ret = " AND status NOT IN ('sent', 'archived', 'draft') AND type NOT IN ('out', 'archived', 'draft')";
292                 } else {
293                         $ret = " AND status NOT IN ('archived') AND type NOT IN ('archived')";
294                 }
295                 $q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails" .
296                                                                    " JOIN emails_text on emails.id = emails_text.email_id
297                                    WHERE (type = '{$type}' OR status = '{$status}') AND assigned_user_id = '{$current_user->id}' AND emails.deleted = '0'";
298                 return $q . $ret;
299         } // fn
300
301
302         /**
303          * returns array of items for listView display in yui-ext Grid
304          */
305         function getListItemsForEmailXML($folderId, $page = 1, $pageSize = 10, $sort = '', $direction='') {
306                 require_once('include/TimeDate.php');
307                 global $timedate;
308                 global $current_user;
309                 global $beanList;
310                 global $sugar_config;
311                 global $app_strings;
312
313                 $this->retrieve($folderId);
314                 $start = ($page - 1) * $pageSize;
315
316                 $sort = (empty($sort)) ? $this->defaultSort : $sort;
317         $direction = (empty($direction)) ? $this->defaultDirection : $direction;
318         $order = " ORDER BY {$this->hrSortLocal[$sort]} {$direction}";
319
320                 if($this->is_dynamic) {
321                         $r = $this->db->limitQuery(from_html($this->generateSugarsDynamicFolderQuery() . $order), $start, $pageSize);
322                 } else {
323                         // get items and iterate through them
324                         $q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails JOIN folders_rel ON emails.id = folders_rel.polymorphic_id" .
325                                   " JOIN emails_text on emails.id = emails_text.email_id
326                   WHERE folders_rel.folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0";
327                         if ($this->is_group) {
328                                 $q = $q . " AND emails.assigned_user_id is null";
329                         }
330                         $r = $this->db->limitQuery($q . $order, $start, $pageSize);
331                 }
332
333                 $return = array();
334
335                 $email = new Email(); //Needed for email specific functions.
336                 
337                 while($a = $this->db->fetchByAssoc($r)) {
338
339                         $temp = array();
340                         $temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1;
341                         $temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1;
342                         $temp['from']   = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']);
343                         $temp['subject'] = $a['name'];
344                         $temp['date']   = $timedate->to_display_date_time($a['date_sent']);
345                         $temp['uid'] = $a['id'];
346                         $temp['mbox'] = 'sugar::'.$a['polymorphic_module'];
347                         $temp['ieId'] = $folderId;
348                         $temp['site_url'] = $sugar_config['site_url'];
349                         $temp['seen'] = ($a['status'] == 'unread') ? 0 : 1;
350                         $temp['type'] = $a['type'];
351                         $temp['hasAttach'] = $email->doesImportedEmailHaveAttachment($a['id']);
352                         $temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']);
353                         $return[] = $temp;
354                 }
355
356
357                 $metadata = array();
358                 $metadata['mbox'] = $app_strings['LBL_EMAIL_SUGAR_FOLDER'].': '.$this->name;
359                 $metadata['ieId'] = $folderId;
360                 $metadata['name'] = $this->name;
361                 $metadata['unreadChecked'] = ($current_user->getPreference('showUnreadOnly', 'Emails') == 1) ? 'CHECKED' : '';
362                 $metadata['out'] = $return;
363
364                 return $metadata;
365         }
366
367         function getCountItems ( $folderId ) {
368                 global $current_user ;
369                 global $beanList ;
370                 global $sugar_config ;
371                 global $app_strings ;
372
373                 $this->retrieve ( $folderId ) ;
374                 if ($this->is_dynamic) {
375                 $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
376                 $replacement = 'SELECT count(*) c FROM ';
377                 $modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
378                 $r = $this->db->query ( from_html ( $modified_select_query )) ;
379                 } else {
380                         // get items and iterate through them
381                         $q = "SELECT count(*) c FROM folders_rel JOIN emails ON emails.id = folders_rel.polymorphic_id" .
382                         " WHERE folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0" ;
383                         if ($this->is_group) {
384                                 $q .= " AND emails.assigned_user_id IS null";
385                         }
386                         $r = $this->db->query ( $q ) ;
387                 }
388
389                 $a = $this->db->fetchByAssoc($r);
390                 return $a['c'];
391         }
392
393     function getCountUnread ( $folderId ) {
394         global $current_user ;
395         global $beanList ;
396         global $sugar_config ;
397         global $app_strings ;
398
399         $this->retrieve ( $folderId ) ;
400         if ($this->is_dynamic) {
401                 $pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
402                 $replacement = 'SELECT count(*) c FROM ';
403                 $modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
404                 $r = $this->db->query (from_html($modified_select_query) . " AND emails.status = 'unread'") ;
405         } else {
406             // get items and iterate through them
407             $q = "SELECT count(*) c FROM folders_rel fr JOIN emails on fr.folder_id = '{$folderId}' AND fr.deleted = 0 " .
408                "AND fr.polymorphic_id = emails.id AND emails.status = 'unread' AND emails.deleted = 0" ;
409             if ($this->is_group) {
410                 $q .= " AND emails.assigned_user_id IS null";
411             }
412             $r = $this->db->query ( $q ) ;
413         }
414
415                 $a = $this->db->fetchByAssoc($r);
416         return $a['c'];
417     }
418
419
420         /**
421          * Convenience method, pass a SugarBean and User to this to add anything to a given folder
422          */
423         function addBean($bean, $user=null) {
424                 if(empty($bean->id) || empty($bean->module_dir)) {
425                         $GLOBALS['log']->fatal("*** FOLDERS: addBean() got empty bean - not saving");
426                         return false;
427                 } elseif(empty($this->id)) {
428                         $GLOBALS['log']->fatal("*** FOLDERS: addBean() is trying to save to a non-saved or non-existent folder");
429                         return false;
430                 }
431
432                 global $current_user;
433                 if($user == null) {
434                         $user = $current_user;
435                 }
436
437                 $guid = create_guid();
438
439                 $q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
440                                 VALUES('{$guid}', '{$this->id}', '{$bean->module_dir}', '{$bean->id}', 0)";
441                 $r = $this->db->query($q);
442                 return true;
443         }
444
445         /**
446          * Builds up a metacollection of user/group folders to be passed to processor methods
447          * @param object User object, defaults to $current_user
448          * @return array Array of abstract folder objects
449          */
450         function retrieveFoldersForProcessing($user, $subscribed=true) {
451                 global $sugar_config;
452                 global $current_language, $current_user;
453
454                 $emails_mod_strings = return_module_language($current_language, "Emails");
455                 $myEmailTypeString = 'inbound';
456                 $myDraftsTypeString = 'draft';
457                 $mySentEmailTypeString = 'sent';
458
459                 if(empty($user)) {
460                         global $current_user;
461                         $user = $current_user;
462                 }
463                 $rootWhere = '';
464         $teamSecurityClause = '';
465         
466                 
467
468                 if($sugar_config['dbconfig']['db_type'] == 'oci8') {
469                         $rootWhere .= "AND f.parent_folder IS NULL";
470                 } else {
471                         $rootWhere .= "AND f.parent_folder = ''";
472                 }
473
474                 if($subscribed) {
475                         $q = $this->coreSubscribed.$teamSecurityClause.$this->coreWhereSubscribed."'{$user->id}' ".$rootWhere.$this->coreOrderBy;
476                 } else {
477                         $q = $this->core.$teamSecurityClause.$this->coreWhere.$rootWhere.$this->coreOrderBy;
478                 }
479                 $r = $this->db->query($q);
480                 $return = array();
481
482                 $found = array();
483                 while($a = $this->db->fetchByAssoc($r)) {
484                         if ((($a['folder_type'] == $myEmailTypeString) ||
485                                 ($a['folder_type'] == $myDraftsTypeString) ||
486                                 ($a['folder_type'] == $mySentEmailTypeString)) &&
487                                 ($a['created_by'] != $current_user->id)) {
488
489                                 continue;
490                         } // if
491                         if (!isset($found[$a['id']])) {
492                 $found[$a['id']] = true;
493                             $return[] = $a;
494                         }
495                 }
496                 return $return;
497         }
498     /**
499          * Preps object array for async call from user's Settings->Folders
500          */
501         function getGroupFoldersForSettings($focusUser=null) {
502                 global $app_strings;
503
504                 $grp = array();
505
506                 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
507                 $subscriptions = $this->getSubscriptions($focusUser);
508
509                 foreach($folders as $a) {
510                         $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
511             $a['origName'] = $a['name'];
512             
513                         if($a['is_group'] == 1)
514                                 if ($a['deleted'] != 1) 
515                                         $grp[] = $a;
516                 }
517        
518                 return $grp;
519         }
520         /**
521          * Preps object array for async call from user's Settings->Folders
522          */
523         function getFoldersForSettings($focusUser=null) {
524                 global $app_strings;
525
526                 $user = array();
527                 $grp = array();
528                 $user[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 0, 'selected' => false);
529                 $grp[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 1, 'selected' => false, 'origName' => "");
530
531                 $folders = $this->retrieveFoldersForProcessing($focusUser, false);
532                 $subscriptions = $this->getSubscriptions($focusUser);
533
534                 foreach($folders as $a) {
535                         $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
536             $a['origName'] = $a['name'];
537                         if($a['is_group'] == 1) {
538                                 $grp[] = $a;
539                         } else {
540                                 $user[] = $a;
541                         }
542
543                         if($a['has_child'] == 1) {
544                                 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
545                                 $rGetChildren = $this->db->query($qGetChildren);
546
547                                 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
548                                         if($a['is_group']) {
549                                                 $this->_depth = 1;
550                                                 $grp = $this->getFoldersChildForSettings($aGetChildren, $grp, $subscriptions);
551                                         } else {
552                                                 $this->_depth = 1;
553                                                 $user = $this->getFoldersChildForSettings($aGetChildren, $user, $subscriptions);
554                                         }
555                                 }
556                         }
557                 }
558
559                 $ret = array(
560                         'userFolders'   => $user,
561                         'groupFolders'  => $grp,
562                 );
563                 return $ret;
564         }
565
566         function getFoldersChildForSettings($a, $collection, $subscriptions) {
567                 $a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
568                 $a['origName'] = $a['name'];
569                 for($i=0; $i<$this->_depth; $i++) {
570
571                         $a['name'] = ".".$a['name'];
572
573                 }
574                 $collection[] = $a;
575                         
576                 if($a['has_child'] == 1) {
577                         $this->_depth++;
578                         $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
579                         $rGetChildren = $this->db->query($qGetChildren);
580                         while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
581                                 $collection = $this->getFoldersChildForSettings($aGetChildren, $collection, $subscriptions);
582                         }
583                 }
584         
585                 return $collection;
586         }
587
588         /**
589          * Returns the number of "new" items (based on passed criteria)
590          * @param string id ID of folder
591          * @param array criteria
592          *              expected:
593          *              array('field' => 'status',
594          *                              'value' => 'unread');
595          * @param array
596          * @return int
597          */
598         function getCountNewItems($id, $criteria, $folder) {
599                 global $current_user;
600
601                 $sugarFolder = new SugarFolder();
602                 return $sugarFolder->getCountUnread($id);
603         }
604
605         /**
606          * Collects, sorts, and builds tree of user's folders
607          * @param objec $rootNode Reference to tree root node
608          * @param array $folderStates User pref folder open/closed states
609          * @param object $user Optional User in focus, default current_user
610          * @return array
611          */
612         function getUserFolders(&$rootNode, $folderStates, $user=null, $forRefresh=false) {
613                 if(empty($user)) {
614                         global $current_user;
615                         $user = $current_user;
616                 }
617                 global $mod_strings;
618                 $folders = $this->retrieveFoldersForProcessing($user, true);
619                 $subscriptions = $this->getSubscriptions($user);
620
621                 $refresh = ($forRefresh) ? array() : null;
622
623                 if(!is_array($folderStates)) {
624                         $folderStates = array();
625                 }
626
627                 foreach($folders as $a) {
628                         if ($a['deleted'] == 1)
629                                 continue;
630                         $label = ($a['name'] == 'My Email' ? $mod_strings['LNK_MY_INBOX'] : $a['name']);
631
632                         $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
633
634                         $folderNode = new ExtNode($a['id'], $label);
635                         $folderNode->dynamicloadfunction = '';
636                         $folderNode->expanded = false;
637
638                         if(array_key_exists('Home::'.$a['id'], $folderStates)) {
639                                 if($folderStates['Home::'.$a['id']] == 'open') {
640                                         $folderNode->expanded = true;
641                                 }
642                         }
643                         $nodePath = "Home::".$folderNode->_properties['id'];
644
645                         $folderNode->dynamic_load = true;
646                 //$folderNode->set_property('click', " SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
647                 $folderNode->set_property('ieId', 'folder');
648                 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
649                 $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
650                 $folderNode->set_property('mbox', $folderNode->_properties['id']);
651                 $folderNode->set_property('unseen', $unseen);
652                 $folderNode->set_property('id', $a['id']);
653                 $folderNode->set_property('folder_type', $a['folder_type']);
654                 $folderNode->set_property('children', array());
655
656                         if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
657                                 $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
658                                 $rGetChildren = $this->db->query($qGetChildren);
659
660                                 while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
661                                         if(in_array($aGetChildren['id'], $subscriptions)) {
662                                                 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
663                                         }
664                                 }
665                         }
666                         $rootNode->add_node($folderNode);
667                 }
668
669                 /* the code below is called only by Settings->Folders when selecting folders to subscribe to */
670                 if($forRefresh) {
671                         $metaNode = array();
672
673                         if(!empty($rootNode->nodes)) {
674                                 foreach($rootNode->nodes as $node) {
675                                         $metaNode[] = $this->buildTreeNodeRefresh($node, $subscriptions);
676                                 }
677                         }
678                         return $metaNode;
679                 }
680         }
681
682         /**
683          * Builds up a metanode for folder refresh (Sugar folders only)
684          */
685         function buildTreeNodeRefresh($folderNode, $subscriptions) {
686                 $metaNode = $folderNode->_properties;
687                 $metaNode['expanded'] = $folderNode->expanded;
688                 $metaNode['text'] = $folderNode->_label;
689                 if($metaNode['is_group'] == 'true') {
690                         $metaNode['cls'] = 'groupFolder';
691                 } else {
692                     $metaNode['cls'] = 'sugarFolder';
693                 }
694                 $metaNode['id'] = $folderNode->_properties['id'];
695                 $metaNode['children'] = array();
696                 $metaNode['type'] = 1;
697                 $metaNode['leaf'] = false;
698                 $metaNode['isTarget'] = true;
699                 $metaNode['allowChildren'] = true;
700
701                 if(!empty($folderNode->nodes)) {
702                         foreach($folderNode->nodes as $node) {
703                                 if(in_array($node->_properties['id'], $subscriptions))
704                                         $metaNode['children'][] = $this->buildTreeNodeRefresh($node, $subscriptions);
705                         }
706                 }
707                 return $metaNode;
708         }
709
710         /**
711          * Builds children nodes for folders for TreeView
712          * @return $folderNode TreeView node
713          */
714         function buildTreeNodeFolders($a, $nodePath, $folderStates, $subscriptions) {
715                 $label = $a['name'];
716                 global $mod_strings;
717                 if($a['name'] == 'My Drafts') {
718                         $label = $mod_strings['LBL_LIST_TITLE_MY_DRAFTS'];
719                 }
720                 if($a['name'] == 'Sent Emails') {
721                         $label = $mod_strings['LBL_LIST_TITLE_MY_SENT'];
722                 }
723                 $unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
724
725                 $folderNode = new ExtNode($a['id'], $label);
726                 $folderNode->dynamicloadfunction = '';
727                 $folderNode->expanded = false;
728
729                 $nodePath .= "::{$a['id']}";
730
731                 if(array_key_exists($nodePath, $folderStates)) {
732                         if($folderStates[$nodePath] == 'open') {
733                                 $folderNode->expanded = true;
734                         }
735                 }
736
737                 $folderNode->dynamic_load = true;
738         $folderNode->set_property('click', "SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
739         $folderNode->set_property('ieId', 'folder');
740         $folderNode->set_property('mbox', $a['id']);
741                 $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
742         $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
743         $folderNode->set_property('unseen', $unseen);
744             $folderNode->set_property('folder_type', $a['folder_type']);
745
746                 if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
747                         $qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}' ".$this->coreOrderBy;
748                         $rGetChildren = $this->db->query($qGetChildren);
749
750                         while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
751                                 $folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
752                         }
753                 }
754                 return $folderNode;
755         }
756
757         /**
758          * Flags a folder as deleted
759          * @return bool True on success
760          */
761         function delete() {
762                 global $current_user;
763
764                 if(!empty($this->id)) {
765                         if($this->has_child) {
766                                 $this->deleteChildrenCascade($this->id);
767                         }
768
769                         $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
770                         $q = "UPDATE folders SET deleted = 1 WHERE id = '{$this->id}'{$ownerCheck}";
771                         $r = $this->db->query($q);
772                         return true;
773                 }
774                 return false;
775         }
776
777         /**
778          * Deletes all children in a cascade
779          * @param string $id ID of parent
780          * @return bool True on success
781          */
782         function deleteChildrenCascade($id) {
783                 global $current_user;
784
785                 $canContinue = true;
786                 $checkInboundQuery = "SELECT count(*) c FROM inbound_email WHERE groupfolder_id = '{$id}' and deleted = 0";
787                 $resultSet = $this->db->query($checkInboundQuery);
788                 $a = $this->db->fetchByAssoc($resultSet);
789                 if ($a['c'] > 0) {
790                         return false;
791                 } // if
792
793                 $q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
794                 
795                 $checkEmailQuery = "SELECT count(*) c FROM folders_rel where polymorphic_module = 'Emails' and folder_id = '{$id}' and deleted = 0";
796                 $resultSet = $this->db->query($checkEmailQuery);
797                 $a = $this->db->fetchByAssoc($resultSet);
798                 if ($a['c'] > 0) {
799                         return false;
800                 } // if
801                 
802                 $q = "SELECT * FROM folders WHERE id = '{$id}'";
803                 $r = $this->db->query($q);
804                 $a = $this->db->fetchByAssoc($r);
805
806                 if($a['has_child'] == 1) {
807                         $q2 = "SELECT id FROM folders WHERE parent_folder = '{$id}'";
808                         $r2 = $this->db->query($q2);
809
810                         while($a2 = $this->db->fetchByAssoc($r2)) {
811                                 $canContinue = $this->deleteChildrenCascade($a2['id']);
812                         }
813                 }
814
815                 if ($canContinue) {
816                         // flag deleted
817                         $ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
818                         $q3 = "UPDATE folders SET deleted = 1 WHERE id = '{$id}'{$ownerCheck}";
819                         $r3 = $this->db->query($q3);
820
821                         // flag rels
822                         $qRel = "UPDATE folders_rel SET deleted = 1 WHERE folder_id = '{$id}'";
823                         $rRel = $this->db->query($qRel);
824
825                         // delete subscriptions
826                         $qSub = "DELETE FROM folders_subscriptions WHERE folder_id = '{$id}'";
827                         $rSub = $this->db->query($qSub);
828                 }
829                 return $canContinue;
830                 //_pp($q3);_pp($qRel);_pp($qSub);
831         }
832
833
834         /**
835          * Saves folder
836          * @return bool
837          */
838         function save($addSubscriptions = TRUE) {
839                 global $current_user;
840
841                 $this->dynamic_query = $this->db->helper->escape_quote($this->dynamic_query);
842
843                 if((empty($this->id) && $this->new_with_id == false) || (!empty($this->id) && $this->new_with_id == true)) 
844                 {
845                     
846                     if( empty($this->id) )
847                     {
848                             $guid = create_guid();
849                             $this->id = $guid;
850                     }
851                     
852                         $q = "INSERT INTO folders(id, name, folder_type, parent_folder, has_child, is_group, is_dynamic, dynamic_query, assign_to_id, ".
853                                 "created_by, modified_by, deleted)".
854
855                                 " VALUES('{$this->id}', '{$this->name}', '{$this->folder_type}', '{$this->parent_folder}', {$this->has_child}, {$this->is_group}, {$this->is_dynamic}, '{$this->dynamic_query}', '{$this->assign_to_id}', " .
856                                 "'{$current_user->id}', '{$current_user->id}', 0)";
857
858                         
859                         if($addSubscriptions)
860                         {
861                             // create default subscription
862                             $this->addSubscriptionsToGroupFolder();
863                         }
864
865                         // if parent_id is set, update parent's has_child flag
866                         $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
867                         $r3 = $this->db->query($q3);
868                 } 
869                 else {
870                         $q = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', dynamic_query = '{$this->dynamic_query}', assign_to_id = '{$this->assign_to_id}', " .
871                                 "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
872                 }
873
874                 $this->db->query($q, true);
875
876                 return true;
877         }
878
879         /**
880          * Add subscriptions to this group folder.
881          *
882          */
883         function addSubscriptionsToGroupFolder()
884         {
885             global $current_user;
886             
887             $this->createSubscriptionForUser($current_user->id);
888             
889         }
890         
891         
892         
893     /**
894          * Add subscriptions to this group folder.
895          *
896          */
897         function createSubscriptionForUser($user_id)
898         {
899            $guid2 = create_guid();
900            $query = "INSERT INTO folders_subscriptions VALUES('{$guid2}', '{$this->id}', '{$user_id}')";
901            $this->db->query($query);
902         }
903         
904         
905         function updateFolder($fields) {
906                 global $current_user;
907
908                 $this->dynamic_query = $this->db->helper->escape_quote($this->dynamic_query);
909                 $id = $fields['record'];
910                 $name = $fields['name'];
911                 $parent_folder = $fields['parent_folder'];
912                 // first do the retrieve
913                 $this->retrieve($id);
914                 if ($this->has_child) {
915                         $childrenArray = array();
916                         $this->findAllChildren($id, $childrenArray);
917                         if (in_array($parent_folder, $childrenArray)) {
918                                 return array('status' => "failed", 'message' => "Can not add this folder to its children");
919                         }
920                 }
921                 // update has_child to 0 for this parent folder if this is the only child it has
922                 $q1 = "select count(*) count from folders where deleted = 0 AND parent_folder = '{$this->parent_folder}'";
923                 $r1 = $this->db->query($q1);
924                 $a1 = $this->db->fetchByAssoc($r1);
925                 if ($a1['count'] == 1) {
926                         $q1 = "UPDATE folders SET has_child = 0 WHERE id = '{$this->parent_folder}'";
927                         $r1 = $this->db->query($q1);
928                 } // if
929
930
931                 $this->name = $name;
932                 $this->parent_folder = $parent_folder;
933                 $q2 = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}',                     dynamic_query = '{$this->dynamic_query}', " .
934                         "modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
935                 $r2 = $this->db->query($q2);
936                 if (!empty($this->parent_folder)) {
937                         $q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
938                         $r3 = $this->db->query($q3);
939                 } // if
940                 return array('status' => "done");
941
942         } // fn
943
944         function findAllChildren($folderId, &$childrenArray) {
945                 $q = "SELECT * FROM folders WHERE id = '{$folderId}'";
946                 $r = $this->db->query($q);
947                 $a = $this->db->fetchByAssoc($r);
948
949                 if($a['has_child'] == 1) {
950                         $q2 = "SELECT id FROM folders WHERE deleted = 0 AND parent_folder = '{$folderId}'";
951                         $r2 = $this->db->query($q2);
952
953                         while($a2 = $this->db->fetchByAssoc($r2)) {
954                                 $childrenArray[] = $a2['id'];
955                                 $this->findAllChildren($a2['id'], $childrenArray);
956                         } // while
957                 } // if
958
959         } // fn
960
961         /**
962          * Retrieves and populates object
963          * @param string $id ID of folder
964          * @return bool True on success
965          */
966         function retrieve($id) {
967                 $q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
968                 $r = $this->db->query($q);
969                 $a = $this->db->fetchByAssoc($r);
970
971                 if(!empty($a)) {
972                         foreach($a as $k => $v) {
973                                 if($k == 'dynamic_query') {
974                                         $v = from_html($v);
975                                 }
976                                 $this->$k = $v;
977                         }
978                         return true;
979                 }
980
981                 return false;
982         }
983 } // end class def